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