1 /** @file wifi_pwrmgr.c
2 *
3 * @brief This file provides all power management code for WIFI.
4 *
5 * Copyright 2008-2024 NXP
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 #include <mlan_api.h>
12
13 #include <wmerrno.h>
14 #include <osa.h>
15 #include <wifi.h>
16 #include <wifi_events.h>
17
18 #include <wmlog.h>
19 #if defined(RW610)
20 #include "wifi-imu.h"
21 #else
22 #include "wifi-sdio.h"
23 #endif
24 #include "wifi-internal.h"
25
26 #define pwr_e(...) wmlog_e("pwr", ##__VA_ARGS__)
27 #define pwr_w(...) wmlog_w("pwr", ##__VA_ARGS__)
28
29 #if CONFIG_PWR_DEBUG
30 #define pwr_d(...) wmlog("pwr", ##__VA_ARGS__)
31 #else
32 #define pwr_d(...)
33 #endif /* ! CONFIG_PWR_DEBUG */
34
35 #define MAX_LISTEN_INTERVAL_IN_BCON 49
36 #define MIN_LISTEN_INTERVAL_IN_TU 50
37 #define MAX_LISTEN_INTERVAL_IN_TU 65000
38 #define CLOSEST_DTIM_TO_LISTEN_INTERVAL 65534
39
40 static bool ieeeps_enabled;
41 static bool deepsleepps_enabled;
42
wifi_set_ps_cfg(t_u16 multiple_dtims,t_u16 bcn_miss_timeout,t_u16 local_listen_interval,t_u16 adhoc_wake_period,t_u16 mode,t_u16 delay_to_ps)43 void wifi_set_ps_cfg(t_u16 multiple_dtims,
44 t_u16 bcn_miss_timeout,
45 t_u16 local_listen_interval,
46 t_u16 adhoc_wake_period,
47 t_u16 mode,
48 t_u16 delay_to_ps)
49 {
50 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
51 pmadapter->bcn_miss_time_out = bcn_miss_timeout;
52 pmadapter->multiple_dtim = multiple_dtims;
53 pmadapter->local_listen_interval = local_listen_interval;
54 pmadapter->delay_to_ps = delay_to_ps;
55 pmadapter->enhanced_ps_mode = mode;
56 pmadapter->adhoc_awake_period = adhoc_wake_period;
57 }
58
wifi_configure_null_pkt_interval(unsigned int null_pkt_interval)59 void wifi_configure_null_pkt_interval(unsigned int null_pkt_interval)
60 {
61 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
62 pmadapter->null_pkt_interval = (t_u16)null_pkt_interval;
63 }
64
wifi_configure_listen_interval(int listen_interval)65 void wifi_configure_listen_interval(int listen_interval)
66 {
67 mlan_private *pmpriv = (mlan_private *)mlan_adap->priv[0];
68
69 pmpriv->listen_interval = (t_u16)listen_interval;
70
71 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
72 wifi_set_ps_cfg(CLOSEST_DTIM_TO_LISTEN_INTERVAL, DEFAULT_BCN_MISS_TIMEOUT, 0, 0, PS_MODE_AUTO, DELAY_TO_PS_DEFAULT);
73 pmadapter->local_listen_interval = (t_u16)listen_interval;
74 }
75
wifi_configure_delay_to_ps(unsigned int timeout_ms)76 void wifi_configure_delay_to_ps(unsigned int timeout_ms)
77 {
78 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
79
80 pmadapter->delay_to_ps = (t_u16)timeout_ms;
81 }
82
wifi_get_listen_interval()83 unsigned short wifi_get_listen_interval()
84 {
85 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
86
87 return (unsigned short)pmadapter->local_listen_interval;
88 }
89
wifi_get_delay_to_ps()90 unsigned int wifi_get_delay_to_ps()
91 {
92 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
93
94 return (unsigned int)pmadapter->delay_to_ps;
95 }
96
97 #if CONFIG_HOST_SLEEP
wifi_send_hs_cfg_cmd(mlan_bss_type interface,t_u32 ipv4_addr,t_u16 action,t_u32 conditions)98 int wifi_send_hs_cfg_cmd(mlan_bss_type interface, t_u32 ipv4_addr, t_u16 action, t_u32 conditions)
99 {
100 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
101 arpfilter_header *arpfilter = NULL;
102 filter_entry *entry = NULL;
103 void *pdata_buf = NULL;
104 hs_config_param hs_cfg_obj;
105 t_u8 *tlv = NULL;
106 MrvlIEtypes_MgmtFrameFilter_t *mgmt_filter_tlv = NULL;
107
108 (void)wifi_get_command_lock();
109
110 HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer();
111 (void)memset(cmd, 0x00, sizeof(HostCmd_DS_COMMAND));
112 (void)memset(&hs_cfg_obj, 0x00, sizeof(hs_config_param));
113
114 cmd->seq_num = (t_u16)(HostCmd_SET_SEQ_NO_BSS_INFO(0U /* seq_num */, 0U /* bss_num */, (t_u32)(interface)));
115 if (action == (t_u16)HS_CONFIGURE)
116 {
117 hs_cfg_obj.conditions = conditions;
118 hs_cfg_obj.gap = 0xc8;
119 #ifdef RW610
120 hs_cfg_obj.gpio = 0xff;
121 #else
122 hs_cfg_obj.gpio = HOST_WAKEUP_GPIO_PIN;
123 #endif
124 pdata_buf = &hs_cfg_obj;
125
126 /* wake conditions for broadcast is
127 * enabled when bit 0 is set.
128 * The code below sets the correct bit which
129 * firmware will use to give host wakeup
130 */
131 if ((conditions != (t_u32)(HOST_SLEEP_CFG_CANCEL)) &&
132 ((conditions & (t_u32)(WIFI_WAKE_ON_ARP_BROADCAST)) != 0U))
133 {
134 hs_cfg_obj.conditions |= (t_u32)(WIFI_WAKE_ON_ALL_BROADCAST);
135 hs_cfg_obj.conditions &= ~((t_u32)(WIFI_WAKE_ON_ARP_BROADCAST));
136 }
137 }
138
139 mlan_status status = wlan_ops_sta_prepare_cmd((mlan_private *)mlan_adap->priv[0], HostCmd_CMD_802_11_HS_CFG_ENH,
140 HostCmd_ACT_GEN_SET, 0, NULL, pdata_buf, cmd);
141 /* Construct the ARP filter TLV */
142 arpfilter = (arpfilter_header *)((uint32_t)cmd + cmd->size);
143 arpfilter->type = TLV_TYPE_ARP_FILTER;
144 arpfilter->len = 0;
145
146 if ((ipv4_addr != 0U) && (action == (t_u16)HS_CONFIGURE) &&
147 (conditions &
148 (WIFI_WAKE_ON_MULTICAST | WIFI_WAKE_ON_ALL_BROADCAST | WIFI_WAKE_ON_UNICAST | WIFI_WAKE_ON_ARP_BROADCAST)))
149 {
150 entry = (filter_entry *)((uint32_t)arpfilter + sizeof(arpfilter_header));
151 if ((conditions & (t_u32)(WIFI_WAKE_ON_MULTICAST)) != 0U)
152 {
153 entry->addr_type = ADDR_TYPE_MULTICAST;
154 entry->eth_type = ETHER_TYPE_ANY;
155 entry->ipv4_addr = IPV4_ADDR_ANY;
156 entry++;
157 arpfilter->len += sizeof(filter_entry);
158 }
159
160 if ((conditions & (t_u32)(WIFI_WAKE_ON_ALL_BROADCAST | WIFI_WAKE_ON_ARP_BROADCAST)) != 0U)
161 {
162 entry->addr_type = ADDR_TYPE_BROADCAST;
163 if ((conditions & (t_u32)(WIFI_WAKE_ON_ALL_BROADCAST)) != 0U)
164 {
165 entry->eth_type = ETHER_TYPE_ANY;
166 entry->ipv4_addr = IPV4_ADDR_ANY;
167 }
168 else
169 {
170 entry->eth_type = ETHER_TYPE_ARP;
171 entry->ipv4_addr = ipv4_addr;
172 }
173 entry++;
174 arpfilter->len += sizeof(filter_entry);
175 }
176
177 if ((conditions & (t_u32)(WIFI_WAKE_ON_UNICAST)) != 0U)
178 {
179 entry->addr_type = ADDR_TYPE_UNICAST;
180 entry->eth_type = ETHER_TYPE_ANY;
181 entry->ipv4_addr = IPV4_ADDR_ANY;
182 arpfilter->len += sizeof(filter_entry);
183 }
184 cmd->size = (t_u16)(cmd->size + sizeof(arpfilter_header) + arpfilter->len);
185 }
186 else if (action == (t_u16)HS_ACTIVATE)
187 {
188 arpfilter->len = 0;
189 cmd->size -= (t_u16)sizeof(t_u32);
190 }
191 else
192 {
193 /** Do nothing */
194 }
195 if (action == (t_u16)HS_CONFIGURE)
196 {
197 tlv = (t_u8 *)((uint32_t)cmd + cmd->size);
198
199 if (pmadapter->mgmt_filter[0].type)
200 {
201 int i = 0;
202 mgmt_frame_filter mgmt_filter[MAX_MGMT_FRAME_FILTER];
203 (void)memset(mgmt_filter, 0, MAX_MGMT_FRAME_FILTER * sizeof(mgmt_frame_filter));
204 mgmt_filter_tlv = (MrvlIEtypes_MgmtFrameFilter_t *)tlv;
205 mgmt_filter_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_MGMT_FRAME_WAKEUP);
206 tlv += sizeof(MrvlIEtypesHeader_t);
207 while (i < MAX_MGMT_FRAME_FILTER && pmadapter->mgmt_filter[i].type)
208 {
209 mgmt_filter[i].action = (t_u8)pmadapter->mgmt_filter[i].action;
210 mgmt_filter[i].type = (t_u8)pmadapter->mgmt_filter[i].type;
211 mgmt_filter[i].frame_mask = wlan_cpu_to_le32(pmadapter->mgmt_filter[i].frame_mask);
212 i++;
213 }
214 (void)memcpy((t_u8 *)mgmt_filter_tlv->filter, (t_u8 *)mgmt_filter, i * sizeof(mgmt_frame_filter));
215 tlv += i * sizeof(mgmt_frame_filter);
216 mgmt_filter_tlv->header.len = wlan_cpu_to_le16(i * sizeof(mgmt_frame_filter));
217 cmd->size += i * sizeof(mgmt_frame_filter) + sizeof(MrvlIEtypesHeader_t);
218 }
219 }
220
221 (void)wifi_wait_for_cmdresp(NULL);
222 return (int)status;
223 }
224
wifi_cancel_host_sleep(mlan_bss_type interface)225 int wifi_cancel_host_sleep(mlan_bss_type interface)
226 {
227 void *pdata_buf = NULL;
228 hs_config_param hs_cfg_obj;
229
230 wifi_get_command_lock();
231
232 HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer();
233 (void)memset(cmd, 0x00, sizeof(HostCmd_DS_COMMAND));
234 (void)memset(&hs_cfg_obj, 0x00, sizeof(hs_config_param));
235
236 cmd->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0 /* seq_num */, 0 /* bss_num */, interface);
237 hs_cfg_obj.conditions = HOST_SLEEP_CFG_CANCEL;
238 pdata_buf = &hs_cfg_obj;
239 mlan_status status = wlan_ops_sta_prepare_cmd((mlan_private *)mlan_adap->priv[0], HostCmd_CMD_802_11_HS_CFG_ENH,
240 HostCmd_ACT_GEN_SET, 0, NULL, pdata_buf, cmd);
241 wifi_wait_for_cmdresp(NULL);
242 return status;
243 }
244 #endif
245
wifi_send_power_save_command(ENH_PS_MODES action,t_u16 ps_bitmap,mlan_bss_type interface,void * pdata_buf)246 static int wifi_send_power_save_command(ENH_PS_MODES action, t_u16 ps_bitmap, mlan_bss_type interface, void *pdata_buf)
247 {
248 mlan_status status;
249 mlan_ds_auto_ds ds_param;
250
251 (void)wifi_get_command_lock();
252 HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer();
253 (void)memset(cmd, 0x00, sizeof(HostCmd_DS_COMMAND));
254
255 cmd->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0U /* seq_num */, 0U /* bss_num */, (t_u8)(interface));
256 if (ps_bitmap == BITMAP_AUTO_DS)
257 {
258 ds_param.idletime = (*(t_u16 *)pdata_buf);
259 pdata_buf = &ds_param;
260 }
261
262 cmd->result = 0x0;
263 status = wlan_cmd_enh_power_mode((mlan_private *)mlan_adap->priv[0], cmd, action, (t_u16)ps_bitmap, pdata_buf);
264
265 (void)wifi_wait_for_cmdresp(NULL);
266 return (int)status;
267 }
268
wifi_enter_ieee_power_save(void)269 int wifi_enter_ieee_power_save(void)
270 {
271 return wifi_send_power_save_command(EN_AUTO_PS, BITMAP_STA_PS, MLAN_BSS_TYPE_STA, NULL);
272 }
273
wifi_exit_ieee_power_save(void)274 int wifi_exit_ieee_power_save(void)
275 {
276 return wifi_send_power_save_command(DIS_AUTO_PS, BITMAP_STA_PS, MLAN_BSS_TYPE_STA, NULL);
277 }
278
279 #if (CONFIG_WNM_PS)
wifi_enter_wnm_power_save(t_u16 wnm_sleep_time)280 int wifi_enter_wnm_power_save(t_u16 wnm_sleep_time)
281 {
282 ((mlan_private *)mlan_adap->priv[0])->wnm_set = true;
283 t_u16 interval = wnm_sleep_time;
284 return wifi_send_power_save_command(EN_WNM_PS, BITMAP_STA_PS, MLAN_BSS_TYPE_STA, &interval);
285 }
286
wifi_exit_wnm_power_save(void)287 int wifi_exit_wnm_power_save(void)
288 {
289 return wifi_send_power_save_command(DIS_WNM_PS, BITMAP_STA_PS, MLAN_BSS_TYPE_STA, NULL);
290 }
291 #endif
292
wifi_enter_deepsleep_power_save(void)293 int wifi_enter_deepsleep_power_save(void)
294 {
295 t_u16 idletime = 0;
296 /* Set default idle time for deep sleep mode.
297 * If not set, fw will use 10ms as default value and this will
298 * cause small time gap between ps_wakeup and ps_sleep events
299 */
300 idletime = DEEP_SLEEP_IDLE_TIME;
301 return wifi_send_power_save_command(EN_AUTO_PS, BITMAP_AUTO_DS, MLAN_BSS_TYPE_STA, &idletime);
302 }
303
wifi_exit_deepsleep_power_save(void)304 int wifi_exit_deepsleep_power_save(void)
305 {
306 t_u16 idletime = 0;
307 return wifi_send_power_save_command(DIS_AUTO_PS, BITMAP_AUTO_DS, MLAN_BSS_TYPE_STA, &idletime);
308 }
309
wifi_set_power_save_mode(void)310 int wifi_set_power_save_mode(void)
311 {
312 t_u32 mode = BLOCK_CMD_IN_PRE_ASLEEP;
313
314 return wifi_send_power_save_command(EXT_PS_PARAM, 0U, MLAN_BSS_TYPE_STA, &mode);
315 }
316
wifi_uap_ps_inactivity_sleep_enter(mlan_bss_type type,unsigned int ctrl_bitmap,unsigned int min_sleep,unsigned int max_sleep,unsigned int inactivity_to,unsigned int min_awake,unsigned int max_awake)317 int wifi_uap_ps_inactivity_sleep_enter(mlan_bss_type type,
318 unsigned int ctrl_bitmap,
319 unsigned int min_sleep,
320 unsigned int max_sleep,
321 unsigned int inactivity_to,
322 unsigned int min_awake,
323 unsigned int max_awake)
324 {
325 mlan_ds_ps_mgmt data_buff;
326
327 (void)memset(&data_buff, 0x00, sizeof(mlan_ds_ps_mgmt));
328
329 data_buff.sleep_param.ctrl_bitmap = ctrl_bitmap;
330 data_buff.sleep_param.min_sleep = min_sleep;
331 data_buff.sleep_param.max_sleep = max_sleep;
332 data_buff.inact_param.inactivity_to = inactivity_to;
333 data_buff.inact_param.min_awake = min_awake;
334 data_buff.inact_param.max_awake = max_awake;
335 data_buff.ps_mode = PS_MODE_INACTIVITY;
336 data_buff.flags = PS_FLAG_INACT_SLEEP_PARAM | PS_FLAG_SLEEP_PARAM;
337
338 return wifi_send_power_save_command(EN_AUTO_PS, BITMAP_UAP_INACT_PS, type, &data_buff);
339 }
340
wifi_uap_ps_inactivity_sleep_exit(mlan_bss_type type)341 int wifi_uap_ps_inactivity_sleep_exit(mlan_bss_type type)
342 {
343 return wifi_send_power_save_command(DIS_AUTO_PS, BITMAP_UAP_INACT_PS, type, NULL);
344 }
345
send_sleep_confirm_command(mlan_bss_type interface)346 void send_sleep_confirm_command(mlan_bss_type interface)
347 {
348 OPT_Confirm_Sleep *ps_cfm_sleep;
349
350 HostCmd_DS_COMMAND *command = wifi_get_command_buffer();
351
352 (void)wifi_get_command_lock();
353 ps_cfm_sleep = (OPT_Confirm_Sleep *)(void *)(command);
354
355 (void)memset(ps_cfm_sleep, 0, sizeof(OPT_Confirm_Sleep));
356 ps_cfm_sleep->command = HostCmd_CMD_802_11_PS_MODE_ENH;
357 ps_cfm_sleep->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0U /* seq_num */, 0U /* bss_num */, (t_u8)(interface));
358
359 ps_cfm_sleep->size = (t_u16)sizeof(OPT_Confirm_Sleep);
360 ps_cfm_sleep->result = 0;
361 ps_cfm_sleep->action = (t_u16)SLEEP_CONFIRM;
362 ps_cfm_sleep->sleep_cfm.resp_ctrl = (t_u16)RESP_NEEDED;
363
364 /* If driver did not send out sleep confirm in the expected time,
365 FW would switch to awake and send out PS AWAKE event.
366 After received AWAKE event when presleep, state would switch to AWAKE.
367 So here only send out sleep confirm when state is presleep,
368 and would not send out sleep confirm if state has switched to AWAKE */
369 if (mlan_adap->ps_state == PS_STATE_PRE_SLEEP)
370 {
371 mlan_adap->ps_state = PS_STATE_SLEEP_CFM;
372 #if CONFIG_WIFI_PS_DEBUG
373 wcmdr_d("+");
374 #endif
375
376 /* Write mutex is used to avoid the case that, during waiting for sleep confirm cmd response,
377 * wifi_driver_tx task or other tx task might be scheduled and send data to FW */
378 (void)OSA_MutexLock((osa_mutex_handle_t)sleep_rwlock.write_mutex, osaWaitForever_c);
379
380 (void)wifi_wait_for_cmdresp(NULL);
381
382 OSA_MutexUnlock((osa_mutex_handle_t)sleep_rwlock.write_mutex);
383 }
384 else
385 {
386 (void)wifi_put_command_lock();
387 }
388 }
389
390 #if CONFIG_HOST_SLEEP
391 /* fixme: accept HostCmd_DS_COMMAND directly */
wifi_process_hs_cfg_resp(t_u8 * cmd_res_buffer)392 void wifi_process_hs_cfg_resp(t_u8 *cmd_res_buffer)
393 {
394 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
395 HostCmd_DS_802_11_HS_CFG_ENH *hs_cfg = (HostCmd_DS_802_11_HS_CFG_ENH *)(void *)(cmd_res_buffer + S_DS_GEN);
396 if (hs_cfg->action == (t_u16)HS_ACTIVATE)
397 {
398 pwr_d("Host sleep activated");
399 pmadapter->is_hs_configured = MFALSE;
400 wlan_update_rxreorder_tbl(pmadapter, MTRUE);
401 wifi_event_completion(WIFI_EVENT_HS_ACTIVATED, WIFI_EVENT_REASON_SUCCESS, NULL);
402 }
403 else
404 {
405 if (hs_cfg->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL)
406 {
407 pmadapter->is_hs_configured = MTRUE;
408 }
409 pwr_d("Host sleep configuration done");
410 }
411 }
412 #endif
413
wifi_process_ps_enh_response(t_u8 * cmd_res_buffer,t_u16 * ps_event,t_u16 * action)414 enum wifi_event_reason wifi_process_ps_enh_response(t_u8 *cmd_res_buffer, t_u16 *ps_event, t_u16 *action)
415 {
416 enum wifi_event_reason result = WIFI_EVENT_REASON_FAILURE;
417 MrvlIEtypesHeader_t *mrvl_tlv = NULL;
418 #if CONFIG_HOST_SLEEP
419 pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter;
420 #endif
421 #if CONFIG_PWR_DEBUG
422 MrvlIEtypes_ps_param_t *ps_tlv = NULL;
423 #endif /* CONFIG_PWR_DEBUG*/
424 HostCmd_DS_802_11_PS_MODE_ENH *ps_mode = (HostCmd_DS_802_11_PS_MODE_ENH *)(void *)(cmd_res_buffer + S_DS_GEN);
425
426 *ps_event = (t_u16)WIFI_EVENT_PS_INVALID;
427 *action = (t_u16)(ps_mode->action);
428 if (ps_mode->action == (t_u16)EN_AUTO_PS)
429 {
430 if ((ps_mode->params.auto_ps.ps_bitmap & BITMAP_AUTO_DS) != 0U)
431 {
432 pwr_d("Enabled deep sleep mode");
433 mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE);
434 while (mrvl_tlv->type != TLV_TYPE_AUTO_DS_PARAM)
435 {
436 mrvl_tlv =
437 (MrvlIEtypesHeader_t *)(void *)((uint8_t *)mrvl_tlv + mrvl_tlv->len + sizeof(MrvlIEtypesHeader_t));
438 }
439
440 *ps_event = (t_u16)WIFI_EVENT_DEEP_SLEEP;
441 deepsleepps_enabled = true;
442 }
443 if ((ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) != 0U)
444 {
445 pwr_d(
446 "Enabled IEEE power "
447 "save mode");
448 mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE);
449 while (mrvl_tlv->type != TLV_TYPE_PS_PARAM)
450 {
451 mrvl_tlv =
452 (MrvlIEtypesHeader_t *)(void *)((uint8_t *)mrvl_tlv + mrvl_tlv->len + sizeof(MrvlIEtypesHeader_t));
453 }
454 #if CONFIG_PWR_DEBUG
455 ps_tlv = (MrvlIEtypes_ps_param_t *)mrvl_tlv;
456 #endif /* CONFIG_PWR_DEBUG*/
457 pwr_d(
458 "pscfg: %u %u %u %u "
459 "%u %u",
460 ps_tlv->param.null_pkt_interval, ps_tlv->param.multiple_dtims, ps_tlv->param.local_listen_interval,
461 ps_tlv->param.bcn_miss_timeout, ps_tlv->param.delay_to_ps, ps_tlv->param.mode);
462
463 *ps_event = (t_u16)WIFI_EVENT_IEEE_PS;
464 ieeeps_enabled = true;
465 }
466 return WIFI_EVENT_REASON_SUCCESS;
467 }
468 else if (ps_mode->action == (t_u16)DIS_AUTO_PS)
469 {
470 if ((ps_mode->params.ps_bitmap & BITMAP_AUTO_DS) != 0U)
471 {
472 pwr_d("Disabled DeepSleep mode");
473 *ps_event = (t_u16)WIFI_EVENT_DEEP_SLEEP;
474 deepsleepps_enabled = false;
475 }
476 if ((ps_mode->params.ps_bitmap & BITMAP_STA_PS) != 0U)
477 {
478 pwr_d(
479 "Disabled IEEE power "
480 "save mode");
481 *ps_event = (t_u16)WIFI_EVENT_IEEE_PS;
482 ieeeps_enabled = false;
483 }
484 return WIFI_EVENT_REASON_SUCCESS;
485 }
486 #if (CONFIG_WNM_PS)
487 else if (ps_mode->action == EN_WNM_PS)
488 {
489 if ((ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) != 0)
490 {
491 mrvl_tlv = (MrvlIEtypesHeader_t *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE);
492 pwr_d("ps_enh_response: bitmap = 0x%x, type = 0x%x\n", ps_mode->params.auto_ps.ps_bitmap, mrvl_tlv->type);
493 if (((mlan_private *)mlan_adap->priv[0])->wnm_set == true)
494 {
495 pwr_d("Enable WNM PS mode, wait for the enable success event");
496 }
497 else
498 {
499 /* Do nothing */
500 }
501 }
502
503 *ps_event = (t_u16)WIFI_EVENT_WNM_PS;
504 result = WIFI_EVENT_REASON_SUCCESS;
505 }
506 else if (ps_mode->action == DIS_WNM_PS)
507 {
508 if ((ps_mode->params.ps_bitmap & BITMAP_STA_PS) != 0)
509 {
510 if (((mlan_private *)mlan_adap->priv[0])->wnm_set == true)
511 {
512 pwr_d(
513 "Disabled WNM power "
514 "save mode");
515 *ps_event = (t_u16)WIFI_EVENT_WNM_PS;
516 ((mlan_private *)mlan_adap->priv[0])->wnm_set = false;
517 }
518 else
519 {
520 /* Do nothing */
521 }
522 }
523
524 *ps_event = (t_u16)WIFI_EVENT_WNM_PS;
525 return WIFI_EVENT_REASON_SUCCESS;
526 }
527 #endif
528 else if (ps_mode->action == (t_u16)GET_PS)
529 {
530 if ((ps_mode->params.ps_bitmap & BITMAP_AUTO_DS) != 0U)
531 {
532 pwr_d("Deep sleep mode is on");
533 mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE);
534 while (mrvl_tlv->type != TLV_TYPE_AUTO_DS_PARAM)
535 {
536 mrvl_tlv =
537 (MrvlIEtypesHeader_t *)(void *)((uint8_t *)mrvl_tlv + mrvl_tlv->len + sizeof(MrvlIEtypesHeader_t));
538 }
539 }
540 if ((ps_mode->params.ps_bitmap & BITMAP_STA_PS) != 0U)
541 {
542 pwr_d("IEEE power save mode is on");
543 mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE);
544 while (mrvl_tlv->type != TLV_TYPE_PS_PARAM)
545 {
546 mrvl_tlv =
547 (MrvlIEtypesHeader_t *)(void *)((uint8_t *)mrvl_tlv + mrvl_tlv->len + sizeof(MrvlIEtypesHeader_t));
548 }
549 #if CONFIG_PWR_DEBUG
550 ps_tlv = (MrvlIEtypes_ps_param_t *)mrvl_tlv;
551 #endif /* CONFIG_PWR_DEBUG*/
552 pwr_d(
553 "pscfg: %u %u %u %u "
554 "%u %u\r\n",
555 ps_tlv->param.null_pkt_interval, ps_tlv->param.multiple_dtims, ps_tlv->param.local_listen_interval,
556 ps_tlv->param.bcn_miss_timeout, ps_tlv->param.delay_to_ps, ps_tlv->param.mode);
557 }
558 }
559 else if (ps_mode->action == (t_u16)SLEEP_CONFIRM)
560 {
561 #if CONFIG_WIFI_PS_DEBUG
562 wcmdr_d("#");
563 #endif
564
565 if ((ieeeps_enabled) && (deepsleepps_enabled))
566 {
567 *ps_event = (t_u16)WIFI_EVENT_IEEE_DEEP_SLEEP;
568 }
569 #if (CONFIG_WNM_PS)
570 else if ((((mlan_private *)mlan_adap->priv[0])->wnm_set) && (deepsleepps_enabled))
571 {
572 *ps_event = (t_u16)WIFI_EVENT_WNM_DEEP_SLEEP;
573 }
574 #endif
575 else if (ieeeps_enabled)
576 {
577 *ps_event = (t_u16)WIFI_EVENT_IEEE_PS;
578 }
579 else if (deepsleepps_enabled)
580 {
581 *ps_event = (t_u16)WIFI_EVENT_DEEP_SLEEP;
582 }
583 #if (CONFIG_WNM_PS)
584 else if (((mlan_private *)mlan_adap->priv[0])->wnm_set)
585 {
586 *ps_event = (t_u16)WIFI_EVENT_WNM_PS;
587 }
588 #endif
589 else
590 {
591 return WIFI_EVENT_REASON_FAILURE;
592 }
593
594 if (ieeeps_enabled || deepsleepps_enabled
595 #if CONFIG_WNM_PS
596 || (((mlan_private *)mlan_adap->priv[0])->wnm_set)
597 #endif
598 )
599 {
600 /* sleep confirm response needs to get the sleep_rwlock, for this lock
601 * is an indication that host needs to wakeup FW when reader (cmd/tx)
602 * could not get the sleep_rwlock */
603 int ret = OSA_RWLockWriteLock(&sleep_rwlock, osaWaitForever_c);
604 mlan_adap->ps_state = PS_STATE_SLEEP;
605 #if CONFIG_HOST_SLEEP
606 wakelock_put();
607 #endif
608 if (ret == WM_SUCCESS)
609 {
610 #if CONFIG_WIFI_PS_DEBUG
611 wcmdr_d("Get sleep rw lock successfully");
612 #endif
613 }
614 else
615 {
616 #if CONFIG_WIFI_PS_DEBUG
617 pwr_e("Failed to get sleep rw lock");
618 #endif
619 return WIFI_EVENT_REASON_FAILURE;
620 }
621 }
622 else
623 {
624 return WIFI_EVENT_REASON_FAILURE;
625 }
626
627 result = WIFI_EVENT_REASON_SUCCESS;
628 #if CONFIG_HOST_SLEEP
629 if (pmadapter->is_hs_configured)
630 {
631 pwr_d("Host sleep activated");
632 pmadapter->is_hs_configured = MFALSE;
633 wlan_update_rxreorder_tbl(pmadapter, MTRUE);
634 wifi_event_completion(WIFI_EVENT_SLEEP_CONFIRM_DONE, result, NULL);
635 }
636 #endif
637 }
638 else
639 { /* Do Nothing */
640 }
641
642 return result;
643 }
644
645 #if CONFIG_HOST_SLEEP
wifi_get_wakeup_reason(t_u16 * hs_wakeup_reason)646 int wifi_get_wakeup_reason(t_u16 *hs_wakeup_reason)
647 {
648 wifi_get_command_lock();
649 HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer();
650
651 (void)memset(cmd, 0x00, sizeof(HostCmd_DS_COMMAND));
652 cmd->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0 /* seq_num */, 0 /* bss_num */, BSS_TYPE_STA);
653 cmd->result = 0x0;
654
655 wlan_ops_sta_prepare_cmd((mlan_private *)mlan_adap->priv[0], HostCmd_CMD_HS_WAKEUP_REASON, HostCmd_ACT_GEN_GET, 0,
656 NULL, hs_wakeup_reason, cmd);
657 wifi_wait_for_cmdresp(hs_wakeup_reason);
658 return WM_SUCCESS;
659 }
660 #endif
661
662 #if CONFIG_P2P
wifi_wfd_ps_inactivity_sleep_enter(unsigned int ctrl_bitmap,unsigned int inactivity_to,unsigned int min_sleep,unsigned int max_sleep,unsigned int min_awake,unsigned int max_awake)663 int wifi_wfd_ps_inactivity_sleep_enter(unsigned int ctrl_bitmap,
664 unsigned int inactivity_to,
665 unsigned int min_sleep,
666 unsigned int max_sleep,
667 unsigned int min_awake,
668 unsigned int max_awake)
669 {
670 mlan_ds_ps_mgmt data_buff;
671 data_buff.sleep_param.ctrl_bitmap = ctrl_bitmap;
672 data_buff.sleep_param.min_sleep = min_sleep;
673 data_buff.sleep_param.max_sleep = max_sleep;
674 data_buff.inact_param.min_awake = min_awake;
675 data_buff.inact_param.max_awake = max_awake;
676 data_buff.inact_param.inactivity_to = inactivity_to;
677 data_buff.flags = PS_FLAG_INACT_SLEEP_PARAM | PS_FLAG_SLEEP_PARAM;
678
679 return wifi_send_power_save_command(EN_AUTO_PS, BITMAP_UAP_INACT_PS, MLAN_BSS_TYPE_WIFIDIRECT, &data_buff);
680 }
681
wifi_wfd_ps_inactivity_sleep_exit(void)682 int wifi_wfd_ps_inactivity_sleep_exit(void)
683 {
684 return wifi_send_power_save_command(DIS_AUTO_PS, BITMAP_UAP_INACT_PS, MLAN_BSS_TYPE_WIFIDIRECT, NULL);
685 }
686 #endif /* CONFIG_P2P*/
687