/** @file wifi_pwrmgr.c * * @brief This file provides all power management code for WIFI. * * Copyright 2008-2024 NXP * * SPDX-License-Identifier: BSD-3-Clause * */ #include #include #include #include #include #include #if defined(RW610) #include "wifi-imu.h" #else #include "wifi-sdio.h" #endif #include "wifi-internal.h" #define pwr_e(...) wmlog_e("pwr", ##__VA_ARGS__) #define pwr_w(...) wmlog_w("pwr", ##__VA_ARGS__) #if CONFIG_PWR_DEBUG #define pwr_d(...) wmlog("pwr", ##__VA_ARGS__) #else #define pwr_d(...) #endif /* ! CONFIG_PWR_DEBUG */ #define MAX_LISTEN_INTERVAL_IN_BCON 49 #define MIN_LISTEN_INTERVAL_IN_TU 50 #define MAX_LISTEN_INTERVAL_IN_TU 65000 #define CLOSEST_DTIM_TO_LISTEN_INTERVAL 65534 static bool ieeeps_enabled; static bool deepsleepps_enabled; void 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) { pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; pmadapter->bcn_miss_time_out = bcn_miss_timeout; pmadapter->multiple_dtim = multiple_dtims; pmadapter->local_listen_interval = local_listen_interval; pmadapter->delay_to_ps = delay_to_ps; pmadapter->enhanced_ps_mode = mode; pmadapter->adhoc_awake_period = adhoc_wake_period; } void wifi_configure_null_pkt_interval(unsigned int null_pkt_interval) { pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; pmadapter->null_pkt_interval = (t_u16)null_pkt_interval; } void wifi_configure_listen_interval(int listen_interval) { mlan_private *pmpriv = (mlan_private *)mlan_adap->priv[0]; pmpriv->listen_interval = (t_u16)listen_interval; pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; wifi_set_ps_cfg(CLOSEST_DTIM_TO_LISTEN_INTERVAL, DEFAULT_BCN_MISS_TIMEOUT, 0, 0, PS_MODE_AUTO, DELAY_TO_PS_DEFAULT); pmadapter->local_listen_interval = (t_u16)listen_interval; } void wifi_configure_delay_to_ps(unsigned int timeout_ms) { pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; pmadapter->delay_to_ps = (t_u16)timeout_ms; } unsigned short wifi_get_listen_interval() { pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; return (unsigned short)pmadapter->local_listen_interval; } unsigned int wifi_get_delay_to_ps() { pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; return (unsigned int)pmadapter->delay_to_ps; } #if CONFIG_HOST_SLEEP int wifi_send_hs_cfg_cmd(mlan_bss_type interface, t_u32 ipv4_addr, t_u16 action, t_u32 conditions) { pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; arpfilter_header *arpfilter = NULL; filter_entry *entry = NULL; void *pdata_buf = NULL; hs_config_param hs_cfg_obj; t_u8 *tlv = NULL; MrvlIEtypes_MgmtFrameFilter_t *mgmt_filter_tlv = NULL; (void)wifi_get_command_lock(); HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer(); (void)memset(cmd, 0x00, sizeof(HostCmd_DS_COMMAND)); (void)memset(&hs_cfg_obj, 0x00, sizeof(hs_config_param)); cmd->seq_num = (t_u16)(HostCmd_SET_SEQ_NO_BSS_INFO(0U /* seq_num */, 0U /* bss_num */, (t_u32)(interface))); if (action == (t_u16)HS_CONFIGURE) { hs_cfg_obj.conditions = conditions; hs_cfg_obj.gap = 0xc8; #ifdef RW610 hs_cfg_obj.gpio = 0xff; #else hs_cfg_obj.gpio = HOST_WAKEUP_GPIO_PIN; #endif pdata_buf = &hs_cfg_obj; /* wake conditions for broadcast is * enabled when bit 0 is set. * The code below sets the correct bit which * firmware will use to give host wakeup */ if ((conditions != (t_u32)(HOST_SLEEP_CFG_CANCEL)) && ((conditions & (t_u32)(WIFI_WAKE_ON_ARP_BROADCAST)) != 0U)) { hs_cfg_obj.conditions |= (t_u32)(WIFI_WAKE_ON_ALL_BROADCAST); hs_cfg_obj.conditions &= ~((t_u32)(WIFI_WAKE_ON_ARP_BROADCAST)); } } mlan_status status = wlan_ops_sta_prepare_cmd((mlan_private *)mlan_adap->priv[0], HostCmd_CMD_802_11_HS_CFG_ENH, HostCmd_ACT_GEN_SET, 0, NULL, pdata_buf, cmd); /* Construct the ARP filter TLV */ arpfilter = (arpfilter_header *)((uint32_t)cmd + cmd->size); arpfilter->type = TLV_TYPE_ARP_FILTER; arpfilter->len = 0; if ((ipv4_addr != 0U) && (action == (t_u16)HS_CONFIGURE) && (conditions & (WIFI_WAKE_ON_MULTICAST | WIFI_WAKE_ON_ALL_BROADCAST | WIFI_WAKE_ON_UNICAST | WIFI_WAKE_ON_ARP_BROADCAST))) { entry = (filter_entry *)((uint32_t)arpfilter + sizeof(arpfilter_header)); if ((conditions & (t_u32)(WIFI_WAKE_ON_MULTICAST)) != 0U) { entry->addr_type = ADDR_TYPE_MULTICAST; entry->eth_type = ETHER_TYPE_ANY; entry->ipv4_addr = IPV4_ADDR_ANY; entry++; arpfilter->len += sizeof(filter_entry); } if ((conditions & (t_u32)(WIFI_WAKE_ON_ALL_BROADCAST | WIFI_WAKE_ON_ARP_BROADCAST)) != 0U) { entry->addr_type = ADDR_TYPE_BROADCAST; if ((conditions & (t_u32)(WIFI_WAKE_ON_ALL_BROADCAST)) != 0U) { entry->eth_type = ETHER_TYPE_ANY; entry->ipv4_addr = IPV4_ADDR_ANY; } else { entry->eth_type = ETHER_TYPE_ARP; entry->ipv4_addr = ipv4_addr; } entry++; arpfilter->len += sizeof(filter_entry); } if ((conditions & (t_u32)(WIFI_WAKE_ON_UNICAST)) != 0U) { entry->addr_type = ADDR_TYPE_UNICAST; entry->eth_type = ETHER_TYPE_ANY; entry->ipv4_addr = IPV4_ADDR_ANY; arpfilter->len += sizeof(filter_entry); } cmd->size = (t_u16)(cmd->size + sizeof(arpfilter_header) + arpfilter->len); } else if (action == (t_u16)HS_ACTIVATE) { arpfilter->len = 0; cmd->size -= (t_u16)sizeof(t_u32); } else { /** Do nothing */ } if (action == (t_u16)HS_CONFIGURE) { tlv = (t_u8 *)((uint32_t)cmd + cmd->size); if (pmadapter->mgmt_filter[0].type) { int i = 0; mgmt_frame_filter mgmt_filter[MAX_MGMT_FRAME_FILTER]; (void)memset(mgmt_filter, 0, MAX_MGMT_FRAME_FILTER * sizeof(mgmt_frame_filter)); mgmt_filter_tlv = (MrvlIEtypes_MgmtFrameFilter_t *)tlv; mgmt_filter_tlv->header.type = wlan_cpu_to_le16(TLV_TYPE_MGMT_FRAME_WAKEUP); tlv += sizeof(MrvlIEtypesHeader_t); while (i < MAX_MGMT_FRAME_FILTER && pmadapter->mgmt_filter[i].type) { mgmt_filter[i].action = (t_u8)pmadapter->mgmt_filter[i].action; mgmt_filter[i].type = (t_u8)pmadapter->mgmt_filter[i].type; mgmt_filter[i].frame_mask = wlan_cpu_to_le32(pmadapter->mgmt_filter[i].frame_mask); i++; } (void)memcpy((t_u8 *)mgmt_filter_tlv->filter, (t_u8 *)mgmt_filter, i * sizeof(mgmt_frame_filter)); tlv += i * sizeof(mgmt_frame_filter); mgmt_filter_tlv->header.len = wlan_cpu_to_le16(i * sizeof(mgmt_frame_filter)); cmd->size += i * sizeof(mgmt_frame_filter) + sizeof(MrvlIEtypesHeader_t); } } (void)wifi_wait_for_cmdresp(NULL); return (int)status; } int wifi_cancel_host_sleep(mlan_bss_type interface) { void *pdata_buf = NULL; hs_config_param hs_cfg_obj; wifi_get_command_lock(); HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer(); (void)memset(cmd, 0x00, sizeof(HostCmd_DS_COMMAND)); (void)memset(&hs_cfg_obj, 0x00, sizeof(hs_config_param)); cmd->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0 /* seq_num */, 0 /* bss_num */, interface); hs_cfg_obj.conditions = HOST_SLEEP_CFG_CANCEL; pdata_buf = &hs_cfg_obj; mlan_status status = wlan_ops_sta_prepare_cmd((mlan_private *)mlan_adap->priv[0], HostCmd_CMD_802_11_HS_CFG_ENH, HostCmd_ACT_GEN_SET, 0, NULL, pdata_buf, cmd); wifi_wait_for_cmdresp(NULL); return status; } #endif static int wifi_send_power_save_command(ENH_PS_MODES action, t_u16 ps_bitmap, mlan_bss_type interface, void *pdata_buf) { mlan_status status; mlan_ds_auto_ds ds_param; (void)wifi_get_command_lock(); HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer(); (void)memset(cmd, 0x00, sizeof(HostCmd_DS_COMMAND)); cmd->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0U /* seq_num */, 0U /* bss_num */, (t_u8)(interface)); if (ps_bitmap == BITMAP_AUTO_DS) { ds_param.idletime = (*(t_u16 *)pdata_buf); pdata_buf = &ds_param; } cmd->result = 0x0; status = wlan_cmd_enh_power_mode((mlan_private *)mlan_adap->priv[0], cmd, action, (t_u16)ps_bitmap, pdata_buf); (void)wifi_wait_for_cmdresp(NULL); return (int)status; } int wifi_enter_ieee_power_save(void) { return wifi_send_power_save_command(EN_AUTO_PS, BITMAP_STA_PS, MLAN_BSS_TYPE_STA, NULL); } int wifi_exit_ieee_power_save(void) { return wifi_send_power_save_command(DIS_AUTO_PS, BITMAP_STA_PS, MLAN_BSS_TYPE_STA, NULL); } #if (CONFIG_WNM_PS) int wifi_enter_wnm_power_save(t_u16 wnm_sleep_time) { ((mlan_private *)mlan_adap->priv[0])->wnm_set = true; t_u16 interval = wnm_sleep_time; return wifi_send_power_save_command(EN_WNM_PS, BITMAP_STA_PS, MLAN_BSS_TYPE_STA, &interval); } int wifi_exit_wnm_power_save(void) { return wifi_send_power_save_command(DIS_WNM_PS, BITMAP_STA_PS, MLAN_BSS_TYPE_STA, NULL); } #endif int wifi_enter_deepsleep_power_save(void) { t_u16 idletime = 0; /* Set default idle time for deep sleep mode. * If not set, fw will use 10ms as default value and this will * cause small time gap between ps_wakeup and ps_sleep events */ idletime = DEEP_SLEEP_IDLE_TIME; return wifi_send_power_save_command(EN_AUTO_PS, BITMAP_AUTO_DS, MLAN_BSS_TYPE_STA, &idletime); } int wifi_exit_deepsleep_power_save(void) { t_u16 idletime = 0; return wifi_send_power_save_command(DIS_AUTO_PS, BITMAP_AUTO_DS, MLAN_BSS_TYPE_STA, &idletime); } int wifi_set_power_save_mode(void) { t_u32 mode = BLOCK_CMD_IN_PRE_ASLEEP; return wifi_send_power_save_command(EXT_PS_PARAM, 0U, MLAN_BSS_TYPE_STA, &mode); } int 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) { mlan_ds_ps_mgmt data_buff; (void)memset(&data_buff, 0x00, sizeof(mlan_ds_ps_mgmt)); data_buff.sleep_param.ctrl_bitmap = ctrl_bitmap; data_buff.sleep_param.min_sleep = min_sleep; data_buff.sleep_param.max_sleep = max_sleep; data_buff.inact_param.inactivity_to = inactivity_to; data_buff.inact_param.min_awake = min_awake; data_buff.inact_param.max_awake = max_awake; data_buff.ps_mode = PS_MODE_INACTIVITY; data_buff.flags = PS_FLAG_INACT_SLEEP_PARAM | PS_FLAG_SLEEP_PARAM; return wifi_send_power_save_command(EN_AUTO_PS, BITMAP_UAP_INACT_PS, type, &data_buff); } int wifi_uap_ps_inactivity_sleep_exit(mlan_bss_type type) { return wifi_send_power_save_command(DIS_AUTO_PS, BITMAP_UAP_INACT_PS, type, NULL); } void send_sleep_confirm_command(mlan_bss_type interface) { OPT_Confirm_Sleep *ps_cfm_sleep; HostCmd_DS_COMMAND *command = wifi_get_command_buffer(); (void)wifi_get_command_lock(); ps_cfm_sleep = (OPT_Confirm_Sleep *)(void *)(command); (void)memset(ps_cfm_sleep, 0, sizeof(OPT_Confirm_Sleep)); ps_cfm_sleep->command = HostCmd_CMD_802_11_PS_MODE_ENH; ps_cfm_sleep->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0U /* seq_num */, 0U /* bss_num */, (t_u8)(interface)); ps_cfm_sleep->size = (t_u16)sizeof(OPT_Confirm_Sleep); ps_cfm_sleep->result = 0; ps_cfm_sleep->action = (t_u16)SLEEP_CONFIRM; ps_cfm_sleep->sleep_cfm.resp_ctrl = (t_u16)RESP_NEEDED; /* If driver did not send out sleep confirm in the expected time, FW would switch to awake and send out PS AWAKE event. After received AWAKE event when presleep, state would switch to AWAKE. So here only send out sleep confirm when state is presleep, and would not send out sleep confirm if state has switched to AWAKE */ if (mlan_adap->ps_state == PS_STATE_PRE_SLEEP) { mlan_adap->ps_state = PS_STATE_SLEEP_CFM; #if CONFIG_WIFI_PS_DEBUG wcmdr_d("+"); #endif /* Write mutex is used to avoid the case that, during waiting for sleep confirm cmd response, * wifi_driver_tx task or other tx task might be scheduled and send data to FW */ (void)OSA_MutexLock((osa_mutex_handle_t)sleep_rwlock.write_mutex, osaWaitForever_c); (void)wifi_wait_for_cmdresp(NULL); OSA_MutexUnlock((osa_mutex_handle_t)sleep_rwlock.write_mutex); } else { (void)wifi_put_command_lock(); } } #if CONFIG_HOST_SLEEP /* fixme: accept HostCmd_DS_COMMAND directly */ void wifi_process_hs_cfg_resp(t_u8 *cmd_res_buffer) { pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; HostCmd_DS_802_11_HS_CFG_ENH *hs_cfg = (HostCmd_DS_802_11_HS_CFG_ENH *)(void *)(cmd_res_buffer + S_DS_GEN); if (hs_cfg->action == (t_u16)HS_ACTIVATE) { pwr_d("Host sleep activated"); pmadapter->is_hs_configured = MFALSE; wlan_update_rxreorder_tbl(pmadapter, MTRUE); wifi_event_completion(WIFI_EVENT_HS_ACTIVATED, WIFI_EVENT_REASON_SUCCESS, NULL); } else { if (hs_cfg->params.hs_config.conditions != HOST_SLEEP_CFG_CANCEL) { pmadapter->is_hs_configured = MTRUE; } pwr_d("Host sleep configuration done"); } } #endif enum wifi_event_reason wifi_process_ps_enh_response(t_u8 *cmd_res_buffer, t_u16 *ps_event, t_u16 *action) { enum wifi_event_reason result = WIFI_EVENT_REASON_FAILURE; MrvlIEtypesHeader_t *mrvl_tlv = NULL; #if CONFIG_HOST_SLEEP pmlan_adapter pmadapter = ((mlan_private *)mlan_adap->priv[0])->adapter; #endif #if CONFIG_PWR_DEBUG MrvlIEtypes_ps_param_t *ps_tlv = NULL; #endif /* CONFIG_PWR_DEBUG*/ HostCmd_DS_802_11_PS_MODE_ENH *ps_mode = (HostCmd_DS_802_11_PS_MODE_ENH *)(void *)(cmd_res_buffer + S_DS_GEN); *ps_event = (t_u16)WIFI_EVENT_PS_INVALID; *action = (t_u16)(ps_mode->action); if (ps_mode->action == (t_u16)EN_AUTO_PS) { if ((ps_mode->params.auto_ps.ps_bitmap & BITMAP_AUTO_DS) != 0U) { pwr_d("Enabled deep sleep mode"); mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE); while (mrvl_tlv->type != TLV_TYPE_AUTO_DS_PARAM) { mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)mrvl_tlv + mrvl_tlv->len + sizeof(MrvlIEtypesHeader_t)); } *ps_event = (t_u16)WIFI_EVENT_DEEP_SLEEP; deepsleepps_enabled = true; } if ((ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) != 0U) { pwr_d( "Enabled IEEE power " "save mode"); mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE); while (mrvl_tlv->type != TLV_TYPE_PS_PARAM) { mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)mrvl_tlv + mrvl_tlv->len + sizeof(MrvlIEtypesHeader_t)); } #if CONFIG_PWR_DEBUG ps_tlv = (MrvlIEtypes_ps_param_t *)mrvl_tlv; #endif /* CONFIG_PWR_DEBUG*/ pwr_d( "pscfg: %u %u %u %u " "%u %u", ps_tlv->param.null_pkt_interval, ps_tlv->param.multiple_dtims, ps_tlv->param.local_listen_interval, ps_tlv->param.bcn_miss_timeout, ps_tlv->param.delay_to_ps, ps_tlv->param.mode); *ps_event = (t_u16)WIFI_EVENT_IEEE_PS; ieeeps_enabled = true; } return WIFI_EVENT_REASON_SUCCESS; } else if (ps_mode->action == (t_u16)DIS_AUTO_PS) { if ((ps_mode->params.ps_bitmap & BITMAP_AUTO_DS) != 0U) { pwr_d("Disabled DeepSleep mode"); *ps_event = (t_u16)WIFI_EVENT_DEEP_SLEEP; deepsleepps_enabled = false; } if ((ps_mode->params.ps_bitmap & BITMAP_STA_PS) != 0U) { pwr_d( "Disabled IEEE power " "save mode"); *ps_event = (t_u16)WIFI_EVENT_IEEE_PS; ieeeps_enabled = false; } return WIFI_EVENT_REASON_SUCCESS; } #if (CONFIG_WNM_PS) else if (ps_mode->action == EN_WNM_PS) { if ((ps_mode->params.auto_ps.ps_bitmap & BITMAP_STA_PS) != 0) { mrvl_tlv = (MrvlIEtypesHeader_t *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE); pwr_d("ps_enh_response: bitmap = 0x%x, type = 0x%x\n", ps_mode->params.auto_ps.ps_bitmap, mrvl_tlv->type); if (((mlan_private *)mlan_adap->priv[0])->wnm_set == true) { pwr_d("Enable WNM PS mode, wait for the enable success event"); } else { /* Do nothing */ } } *ps_event = (t_u16)WIFI_EVENT_WNM_PS; result = WIFI_EVENT_REASON_SUCCESS; } else if (ps_mode->action == DIS_WNM_PS) { if ((ps_mode->params.ps_bitmap & BITMAP_STA_PS) != 0) { if (((mlan_private *)mlan_adap->priv[0])->wnm_set == true) { pwr_d( "Disabled WNM power " "save mode"); *ps_event = (t_u16)WIFI_EVENT_WNM_PS; ((mlan_private *)mlan_adap->priv[0])->wnm_set = false; } else { /* Do nothing */ } } *ps_event = (t_u16)WIFI_EVENT_WNM_PS; return WIFI_EVENT_REASON_SUCCESS; } #endif else if (ps_mode->action == (t_u16)GET_PS) { if ((ps_mode->params.ps_bitmap & BITMAP_AUTO_DS) != 0U) { pwr_d("Deep sleep mode is on"); mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE); while (mrvl_tlv->type != TLV_TYPE_AUTO_DS_PARAM) { mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)mrvl_tlv + mrvl_tlv->len + sizeof(MrvlIEtypesHeader_t)); } } if ((ps_mode->params.ps_bitmap & BITMAP_STA_PS) != 0U) { pwr_d("IEEE power save mode is on"); mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)ps_mode + AUTO_PS_FIX_SIZE); while (mrvl_tlv->type != TLV_TYPE_PS_PARAM) { mrvl_tlv = (MrvlIEtypesHeader_t *)(void *)((uint8_t *)mrvl_tlv + mrvl_tlv->len + sizeof(MrvlIEtypesHeader_t)); } #if CONFIG_PWR_DEBUG ps_tlv = (MrvlIEtypes_ps_param_t *)mrvl_tlv; #endif /* CONFIG_PWR_DEBUG*/ pwr_d( "pscfg: %u %u %u %u " "%u %u\r\n", ps_tlv->param.null_pkt_interval, ps_tlv->param.multiple_dtims, ps_tlv->param.local_listen_interval, ps_tlv->param.bcn_miss_timeout, ps_tlv->param.delay_to_ps, ps_tlv->param.mode); } } else if (ps_mode->action == (t_u16)SLEEP_CONFIRM) { #if CONFIG_WIFI_PS_DEBUG wcmdr_d("#"); #endif if ((ieeeps_enabled) && (deepsleepps_enabled)) { *ps_event = (t_u16)WIFI_EVENT_IEEE_DEEP_SLEEP; } #if (CONFIG_WNM_PS) else if ((((mlan_private *)mlan_adap->priv[0])->wnm_set) && (deepsleepps_enabled)) { *ps_event = (t_u16)WIFI_EVENT_WNM_DEEP_SLEEP; } #endif else if (ieeeps_enabled) { *ps_event = (t_u16)WIFI_EVENT_IEEE_PS; } else if (deepsleepps_enabled) { *ps_event = (t_u16)WIFI_EVENT_DEEP_SLEEP; } #if (CONFIG_WNM_PS) else if (((mlan_private *)mlan_adap->priv[0])->wnm_set) { *ps_event = (t_u16)WIFI_EVENT_WNM_PS; } #endif else { return WIFI_EVENT_REASON_FAILURE; } if (ieeeps_enabled || deepsleepps_enabled #if CONFIG_WNM_PS || (((mlan_private *)mlan_adap->priv[0])->wnm_set) #endif ) { /* sleep confirm response needs to get the sleep_rwlock, for this lock * is an indication that host needs to wakeup FW when reader (cmd/tx) * could not get the sleep_rwlock */ int ret = OSA_RWLockWriteLock(&sleep_rwlock, osaWaitForever_c); mlan_adap->ps_state = PS_STATE_SLEEP; #if CONFIG_HOST_SLEEP wakelock_put(); #endif if (ret == WM_SUCCESS) { #if CONFIG_WIFI_PS_DEBUG wcmdr_d("Get sleep rw lock successfully"); #endif } else { #if CONFIG_WIFI_PS_DEBUG pwr_e("Failed to get sleep rw lock"); #endif return WIFI_EVENT_REASON_FAILURE; } } else { return WIFI_EVENT_REASON_FAILURE; } result = WIFI_EVENT_REASON_SUCCESS; #if CONFIG_HOST_SLEEP if (pmadapter->is_hs_configured) { pwr_d("Host sleep activated"); pmadapter->is_hs_configured = MFALSE; wlan_update_rxreorder_tbl(pmadapter, MTRUE); wifi_event_completion(WIFI_EVENT_SLEEP_CONFIRM_DONE, result, NULL); } #endif } else { /* Do Nothing */ } return result; } #if CONFIG_HOST_SLEEP int wifi_get_wakeup_reason(t_u16 *hs_wakeup_reason) { wifi_get_command_lock(); HostCmd_DS_COMMAND *cmd = wifi_get_command_buffer(); (void)memset(cmd, 0x00, sizeof(HostCmd_DS_COMMAND)); cmd->seq_num = HostCmd_SET_SEQ_NO_BSS_INFO(0 /* seq_num */, 0 /* bss_num */, BSS_TYPE_STA); cmd->result = 0x0; wlan_ops_sta_prepare_cmd((mlan_private *)mlan_adap->priv[0], HostCmd_CMD_HS_WAKEUP_REASON, HostCmd_ACT_GEN_GET, 0, NULL, hs_wakeup_reason, cmd); wifi_wait_for_cmdresp(hs_wakeup_reason); return WM_SUCCESS; } #endif #if CONFIG_P2P int 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) { mlan_ds_ps_mgmt data_buff; data_buff.sleep_param.ctrl_bitmap = ctrl_bitmap; data_buff.sleep_param.min_sleep = min_sleep; data_buff.sleep_param.max_sleep = max_sleep; data_buff.inact_param.min_awake = min_awake; data_buff.inact_param.max_awake = max_awake; data_buff.inact_param.inactivity_to = inactivity_to; data_buff.flags = PS_FLAG_INACT_SLEEP_PARAM | PS_FLAG_SLEEP_PARAM; return wifi_send_power_save_command(EN_AUTO_PS, BITMAP_UAP_INACT_PS, MLAN_BSS_TYPE_WIFIDIRECT, &data_buff); } int wifi_wfd_ps_inactivity_sleep_exit(void) { return wifi_send_power_save_command(DIS_AUTO_PS, BITMAP_UAP_INACT_PS, MLAN_BSS_TYPE_WIFIDIRECT, NULL); } #endif /* CONFIG_P2P*/