Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/net/wireless/realtek/rtw88/ps.c
25924 views
1
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
/* Copyright(c) 2018-2019 Realtek Corporation
3
*/
4
5
#include "main.h"
6
#include "reg.h"
7
#include "fw.h"
8
#include "ps.h"
9
#include "mac.h"
10
#include "coex.h"
11
#include "debug.h"
12
13
static int rtw_ips_pwr_up(struct rtw_dev *rtwdev)
14
{
15
int ret;
16
17
ret = rtw_core_start(rtwdev);
18
if (ret)
19
rtw_err(rtwdev, "leave idle state failed\n");
20
21
rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE);
22
rtw_set_channel(rtwdev);
23
24
return ret;
25
}
26
27
int rtw_enter_ips(struct rtw_dev *rtwdev)
28
{
29
if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags))
30
return 0;
31
32
rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER);
33
34
rtw_core_stop(rtwdev);
35
rtw_hci_link_ps(rtwdev, true);
36
37
return 0;
38
}
39
40
static void rtw_restore_port_cfg_iter(void *data, struct ieee80211_vif *vif)
41
{
42
struct rtw_dev *rtwdev = data;
43
struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
44
u32 config = ~0;
45
46
rtw_vif_port_config(rtwdev, rtwvif, config);
47
}
48
49
int rtw_leave_ips(struct rtw_dev *rtwdev)
50
{
51
int ret;
52
53
if (test_bit(RTW_FLAG_POWERON, rtwdev->flags))
54
return 0;
55
56
rtw_hci_link_ps(rtwdev, false);
57
58
ret = rtw_ips_pwr_up(rtwdev);
59
if (ret) {
60
rtw_err(rtwdev, "failed to leave ips state\n");
61
return ret;
62
}
63
64
rtw_iterate_vifs(rtwdev, rtw_restore_port_cfg_iter, rtwdev);
65
66
return 0;
67
}
68
69
void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
70
{
71
u8 request, confirm, polling;
72
int ret;
73
74
request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr);
75
confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr);
76
77
/* toggle to request power mode, others remain 0 */
78
request ^= request | BIT_RPWM_TOGGLE;
79
if (enter) {
80
request |= POWER_MODE_LCLK;
81
if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)
82
request |= POWER_MODE_PG;
83
}
84
/* Each request require an ack from firmware */
85
request |= POWER_MODE_ACK;
86
87
if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_TX_WAKE))
88
request |= POWER_TX_WAKE;
89
90
rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request);
91
92
/* Check firmware get the power requset and ack via cpwm register */
93
ret = read_poll_timeout_atomic(rtw_read8, polling,
94
(polling ^ confirm) & BIT_RPWM_TOGGLE,
95
100, 15000, true, rtwdev,
96
rtwdev->hci.cpwm_addr);
97
if (ret) {
98
/* Hit here means that driver failed to get an ack from firmware.
99
* The reason could be that hardware is locked at Deep sleep,
100
* so most of the hardware circuits are not working, even
101
* register read/write; or firmware is locked in some state and
102
* cannot get the request. It should be treated as fatal error
103
* and requires an entire analysis about the firmware/hardware.
104
*/
105
WARN(1, "firmware failed to ack driver for %s Deep Power mode\n",
106
enter ? "entering" : "leaving");
107
rtw_fw_dump_dbg_info(rtwdev);
108
}
109
}
110
EXPORT_SYMBOL(rtw_power_mode_change);
111
112
static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev)
113
{
114
rtw_hci_deep_ps(rtwdev, false);
115
}
116
117
static int __rtw_fw_leave_lps_check_reg(struct rtw_dev *rtwdev)
118
{
119
int i;
120
121
/* Driver needs to wait for firmware to leave LPS state
122
* successfully. Firmware will send null packet to inform AP,
123
* and see if AP sends an ACK back, then firmware will restore
124
* the REG_TCR register.
125
*
126
* If driver does not wait for firmware, null packet with
127
* PS bit could be sent due to incorrect REG_TCR setting.
128
*
129
* In our test, 100ms should be enough for firmware to finish
130
* the flow. If REG_TCR Register is still incorrect after 100ms,
131
* just modify it directly, and throw a warn message.
132
*/
133
for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) {
134
if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0)
135
return 0;
136
msleep(20);
137
}
138
139
return -EBUSY;
140
}
141
142
static int __rtw_fw_leave_lps_check_c2h(struct rtw_dev *rtwdev)
143
{
144
if (wait_for_completion_timeout(&rtwdev->lps_leave_check,
145
LEAVE_LPS_TIMEOUT))
146
return 0;
147
return -EBUSY;
148
}
149
150
static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev)
151
{
152
bool ret = false;
153
struct rtw_fw_state *fw;
154
155
if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
156
fw = &rtwdev->wow_fw;
157
else
158
fw = &rtwdev->fw;
159
160
if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H))
161
ret = __rtw_fw_leave_lps_check_c2h(rtwdev);
162
else
163
ret = __rtw_fw_leave_lps_check_reg(rtwdev);
164
165
if (ret) {
166
rtw_write32_clr(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN);
167
rtw_warn(rtwdev, "firmware failed to leave lps state\n");
168
rtw_fw_dump_dbg_info(rtwdev);
169
}
170
}
171
172
static void rtw_fw_leave_lps_check_prepare(struct rtw_dev *rtwdev)
173
{
174
struct rtw_fw_state *fw;
175
176
if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
177
fw = &rtwdev->wow_fw;
178
else
179
fw = &rtwdev->fw;
180
181
if (rtw_fw_feature_check(fw, FW_FEATURE_LPS_C2H))
182
reinit_completion(&rtwdev->lps_leave_check);
183
}
184
185
static void rtw_leave_lps_core(struct rtw_dev *rtwdev)
186
{
187
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
188
189
conf->state = RTW_ALL_ON;
190
conf->awake_interval = 1;
191
conf->rlbm = 0;
192
conf->smart_ps = 0;
193
194
rtw_hci_link_ps(rtwdev, false);
195
rtw_fw_leave_lps_check_prepare(rtwdev);
196
rtw_fw_set_pwr_mode(rtwdev);
197
rtw_fw_leave_lps_check(rtwdev);
198
199
clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
200
201
rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE);
202
}
203
204
enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev)
205
{
206
if (test_bit(RTW_FLAG_WOWLAN, rtwdev->flags))
207
return rtwdev->lps_conf.wow_deep_mode;
208
else
209
return rtwdev->lps_conf.deep_mode;
210
}
211
212
static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev)
213
{
214
if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_NONE)
215
return;
216
217
if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) {
218
rtw_dbg(rtwdev, RTW_DBG_PS,
219
"Should enter LPS before entering deep PS\n");
220
return;
221
}
222
223
if (rtw_get_lps_deep_mode(rtwdev) == LPS_DEEP_MODE_PG)
224
rtw_fw_set_pg_info(rtwdev);
225
226
rtw_hci_deep_ps(rtwdev, true);
227
}
228
229
static void rtw_enter_lps_core(struct rtw_dev *rtwdev)
230
{
231
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
232
233
conf->state = RTW_RF_OFF;
234
conf->awake_interval = 1;
235
conf->rlbm = 1;
236
conf->smart_ps = 2;
237
238
rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE);
239
240
rtw_fw_set_pwr_mode(rtwdev);
241
rtw_hci_link_ps(rtwdev, true);
242
243
set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags);
244
}
245
246
static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
247
{
248
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
249
250
if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
251
return;
252
253
conf->mode = RTW_MODE_LPS;
254
conf->port_id = port_id;
255
256
rtw_enter_lps_core(rtwdev);
257
}
258
259
static void __rtw_leave_lps(struct rtw_dev *rtwdev)
260
{
261
struct rtw_lps_conf *conf = &rtwdev->lps_conf;
262
263
if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) {
264
rtw_dbg(rtwdev, RTW_DBG_PS,
265
"Should leave deep PS before leaving LPS\n");
266
__rtw_leave_lps_deep(rtwdev);
267
}
268
269
if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags))
270
return;
271
272
conf->mode = RTW_MODE_ACTIVE;
273
274
rtw_leave_lps_core(rtwdev);
275
}
276
277
void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id)
278
{
279
lockdep_assert_held(&rtwdev->mutex);
280
281
if (rtwdev->coex.stat.wl_force_lps_ctrl)
282
return;
283
284
__rtw_enter_lps(rtwdev, port_id);
285
__rtw_enter_lps_deep(rtwdev);
286
}
287
288
void rtw_leave_lps(struct rtw_dev *rtwdev)
289
{
290
lockdep_assert_held(&rtwdev->mutex);
291
292
__rtw_leave_lps_deep(rtwdev);
293
__rtw_leave_lps(rtwdev);
294
}
295
296
void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
297
{
298
lockdep_assert_held(&rtwdev->mutex);
299
300
__rtw_leave_lps_deep(rtwdev);
301
}
302
303
struct rtw_vif_recalc_lps_iter_data {
304
struct rtw_dev *rtwdev;
305
struct ieee80211_vif *found_vif;
306
int count;
307
};
308
309
static void __rtw_vif_recalc_lps(struct rtw_vif_recalc_lps_iter_data *data,
310
struct ieee80211_vif *vif)
311
{
312
if (data->count < 0)
313
return;
314
315
if (vif->type != NL80211_IFTYPE_STATION) {
316
data->count = -1;
317
return;
318
}
319
320
data->count++;
321
data->found_vif = vif;
322
}
323
324
static void rtw_vif_recalc_lps_iter(void *data, struct ieee80211_vif *vif)
325
{
326
__rtw_vif_recalc_lps(data, vif);
327
}
328
329
void rtw_recalc_lps(struct rtw_dev *rtwdev, struct ieee80211_vif *new_vif)
330
{
331
struct rtw_vif_recalc_lps_iter_data data = { .rtwdev = rtwdev };
332
333
if (new_vif)
334
__rtw_vif_recalc_lps(&data, new_vif);
335
rtw_iterate_vifs(rtwdev, rtw_vif_recalc_lps_iter, &data);
336
337
if (data.count == 1 && data.found_vif->cfg.ps) {
338
rtwdev->ps_enabled = true;
339
} else {
340
rtwdev->ps_enabled = false;
341
rtw_leave_lps(rtwdev);
342
}
343
}
344
345