diff --git a/core/cds/inc/cds_config.h b/core/cds/inc/cds_config.h index f6c456a157c3..9e9954ec6b1f 100644 --- a/core/cds/inc/cds_config.h +++ b/core/cds/inc/cds_config.h @@ -117,6 +117,7 @@ enum active_bpf_mode { * mode for uc packets * @active_mc_bc_bpf_mode: Setting that determines how BPF is applied in * active mode for MC/BC packets + * @auto_power_save_fail_mode: auto detect power save failure mode * Structure for holding cds ini parameters. */ @@ -172,5 +173,6 @@ struct cds_config_info { struct ol_tx_sched_wrr_ac_specs_t ac_specs[TX_WMM_AC_NUM]; enum active_bpf_mode active_uc_bpf_mode; enum active_bpf_mode active_mc_bc_bpf_mode; + bool auto_power_save_fail_mode; }; #endif /* !defined( __CDS_CONFIG_H ) */ diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index f4482edccf77..ad38d76b90b4 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -7116,6 +7116,24 @@ enum hdd_link_speed_rpt_type { #define CFG_ENABLE_MEMORY_DEBUG_DEFAULT (1) #endif +/* + * + * g_auto_detect_power_failure_mode - auto detect power save failure mode + * @Min: 0 : Recovery + * @Max: 1 : WMI + * @Default: 0 + * + * This ini specifies the behavior of FW in case of + * CHIP_POWER_SAVE_FAIL_DETECTED event + * + * Usage: External + * + * + */ +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME "g_auto_detect_power_failure_mode" +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_DEFAULT (0) +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_MIN (0) +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_MAX (1) /* * @@ -11069,6 +11087,7 @@ struct hdd_config { uint8_t enable_rts_sifsbursting; uint8_t max_mpdus_inampdu; uint16_t sap_max_mcs_txdata; + uint8_t auto_pwr_save_fail_mode; }; #define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var)) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index e1ee064f6ea2..d265901b0760 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -2439,4 +2439,23 @@ int hdd_dbs_scan_selection_init(hdd_context_t *hdd_ctx); */ void hdd_start_complete(int ret); + +/** + * hdd_chip_pwr_save_fail_detected_cb() - chip power save failure detected + * callback + * @hddctx: HDD context + * @data: chip power save failure detected data + * + * This function reads the chip power save failure detected data and fill in + * the skb with NL attributes and send up the NL event. + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ + +void hdd_chip_pwr_save_fail_detected_cb(void *hddctx, + struct chip_pwr_save_fail_detected_params + *data); + #endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/core/hdd/src/wlan_hdd_cfg.c b/core/hdd/src/wlan_hdd_cfg.c index 36fc46c57dfa..58b90a30af17 100644 --- a/core/hdd/src/wlan_hdd_cfg.c +++ b/core/hdd/src/wlan_hdd_cfg.c @@ -4427,6 +4427,14 @@ struct reg_table_entry g_registry_table[] = { CFG_TX_ORPHAN_ENABLE_DEFAULT, CFG_TX_ORPHAN_ENABLE_MIN, CFG_TX_ORPHAN_ENABLE_MAX), + + REG_VARIABLE(CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, auto_pwr_save_fail_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AUTO_DETECT_POWER_FAIL_MODE_DEFAULT, + CFG_AUTO_DETECT_POWER_FAIL_MODE_MIN, + CFG_AUTO_DETECT_POWER_FAIL_MODE_MAX), + }; @@ -5928,6 +5936,10 @@ void hdd_cfg_print(hdd_context_t *pHddCtx) hdd_info("Name = [%s] Value = [%d]", CFG_SAP_INTERNAL_RESTART_NAME, pHddCtx->config->sap_internal_restart); + hdd_debug("Name = [%s] Value = [%u]", + CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME, + pHddCtx->config->auto_pwr_save_fail_mode); + hdd_per_roam_print_ini_config(pHddCtx); hdd_he_print_ini_config(pHddCtx); hdd_info("Name = [%s] Value = [%d]", diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 0c55b0e3c997..2ebc47619595 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1275,6 +1275,11 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS }, + [QCA_NL80211_VENDOR_SUBCMD_PWR_SAVE_FAIL_DETECTED_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE + } + #ifdef WLAN_UMAC_CONVERGENCE COMMON_VENDOR_EVENTS #endif @@ -3421,6 +3426,67 @@ wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy, return ret; } +#define PWR_SAVE_FAIL_CMD_INDEX \ + QCA_NL80211_VENDOR_SUBCMD_PWR_SAVE_FAIL_DETECTED_INDEX +/** + * hdd_chip_pwr_save_fail_detected_cb() - chip power save failure detected + * callback + * @hddctx: HDD context + * @data: chip power save failure detected data + * + * This function reads the chip power save failure detected data and fill in + * the skb with NL attributes and send up the NL event. + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +void hdd_chip_pwr_save_fail_detected_cb(void *hddctx, + struct chip_pwr_save_fail_detected_params + *data) +{ + hdd_context_t *hdd_ctx = hddctx; + struct sk_buff *skb; + int flags = cds_get_gfp_flags(); + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!data) { + hdd_notice("data is null"); + return; + } + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, NLMSG_HDRLEN + + sizeof(data->failure_reason_code) + + NLMSG_HDRLEN, PWR_SAVE_FAIL_CMD_INDEX, + flags); + + if (!skb) { + hdd_notice("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug(FL("failure reason code: %u"), + data->failure_reason_code); + + if (nla_put_u32(skb, + QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON, + data->failure_reason_code)) + goto fail; + + cfg80211_vendor_event(skb, flags); + EXIT(); + return; + +fail: + kfree_skb(skb); +} +#undef PWR_SAVE_FAIL_CMD_INDEX + static const struct nla_policy wlan_hdd_set_no_dfs_flag_config_policy[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX +1] = { diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 1e2bca3435ac..cd59da5ed5d5 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -8013,6 +8013,8 @@ static int hdd_update_cds_config(hdd_context_t *hdd_ctx) cds_cfg->fw_timeout_crash = hdd_ctx->config->fw_timeout_crash; cds_cfg->active_uc_bpf_mode = hdd_ctx->config->active_uc_bpf_mode; cds_cfg->active_mc_bc_bpf_mode = hdd_ctx->config->active_mc_bc_bpf_mode; + cds_cfg->auto_power_save_fail_mode = + hdd_ctx->config->auto_pwr_save_fail_mode; hdd_ra_populate_cds_config(cds_cfg, hdd_ctx); hdd_txrx_populate_cds_config(cds_cfg, hdd_ctx); @@ -9471,6 +9473,9 @@ int hdd_wlan_startup(struct device *dev) if (hdd_ctx->config->is_force_1x1) wma_cli_set_command(0, (int)WMI_PDEV_PARAM_SET_IOT_PATTERN, 1, PDEV_CMD); + /* set chip power save failure detected callback */ + sme_set_chip_pwr_save_fail_cb(hdd_ctx->hHal, + hdd_chip_pwr_save_fail_detected_cb); if (hdd_ctx->config->max_mpdus_inampdu) { set_value = hdd_ctx->config->max_mpdus_inampdu; @@ -11388,6 +11393,8 @@ static int hdd_update_pmo_config(hdd_context_t *hdd_ctx) psoc_cfg.sta_max_li_mod_dtim = hdd_ctx->config->fMaxLIModulatedDTIM; psoc_cfg.power_save_mode = hdd_ctx->config->enablePowersaveOffload; + psoc_cfg.auto_power_save_fail_mode = + hdd_ctx->config->auto_pwr_save_fail_mode; hdd_ra_populate_pmo_config(&psoc_cfg, hdd_ctx); hdd_nan_populate_pmo_config(&psoc_cfg, hdd_ctx); diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 76a0eda44316..6a635d88a1bb 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -1480,6 +1480,9 @@ QDF_STATUS hdd_wlan_re_init(void) /* Allow the phone to go to sleep */ hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + /* set chip power save failure detected callback */ + sme_set_chip_pwr_save_fail_cb(pHddCtx->hHal, + hdd_chip_pwr_save_fail_detected_cb); ret = hdd_register_cb(pHddCtx); if (ret) { diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index c7f58808591a..bb52482fba78 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -5676,6 +5676,17 @@ struct rssi_breach_event { struct qdf_mac_addr curr_bssid; }; +/** + * struct chip_pwr_save_fail_detected_params - chip power save failure detected + * event params + * @failure_reason_code:failure reason code + * @wake_lock_bitmap:bitmap for modules voting against sleep for long duration. + */ +struct chip_pwr_save_fail_detected_params { + uint32_t failure_reason_code; + uint32_t wake_lock_bitmap[4]; +}; + #define MAX_NUM_FW_SEGMENTS 4 /** @@ -6356,6 +6367,7 @@ struct sir_bpf_get_offload { * @wow_pno_complete_wake_up_count: pno complete wakeup count * @wow_pno_match_wake_up_count: pno match wakeup count * @wow_oem_response_wake_up_count: oem response wakeup count + * @pwr_save_fail_detected: pwr save fail detected wakeup count */ struct sir_wake_lock_stats { uint32_t wow_unspecified_wake_up_count; @@ -6374,6 +6386,7 @@ struct sir_wake_lock_stats { uint32_t wow_pno_complete_wake_up_count; uint32_t wow_pno_match_wake_up_count; uint32_t wow_oem_response_wake_up_count; + uint32_t pwr_save_fail_detected; }; /** @@ -6410,6 +6423,7 @@ struct sir_vdev_wow_stats { uint32_t pno_complete; uint32_t pno_match; uint32_t oem_response; + uint32_t pwr_save_fail_detected; }; /** diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index f0d69fc3a1b9..11b257ccc49e 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -1555,4 +1555,17 @@ QDF_STATUS sme_set_reorder_timeout(tHalHandle hal, QDF_STATUS sme_set_rx_set_blocksize(tHalHandle hal, struct sir_peer_set_rx_blocksize *req); +/* + * sme_set_chip_pwr_save_fail_cb() - set chip power save failure callback + * @hal: global hal handle + * @cb: callback function pointer + * + * This function stores the chip power save failure callback function. + * + * Return: QDF_STATUS enumeration. + */ + +QDF_STATUS sme_set_chip_pwr_save_fail_cb(tHalHandle hal, void (*cb)(void *, + struct chip_pwr_save_fail_detected_params *)); + #endif /* #if !defined( __SME_API_H ) */ diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index adad9ec18584..7a13c60f1734 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -242,6 +242,7 @@ typedef struct tagSmeStruct { void *encrypt_decrypt_context; void (*lost_link_info_cb)(void *context, struct sir_lost_link_info *lost_link_info); + bool (*set_connection_info_cb)(bool); bool (*get_connection_info_cb)(uint8_t *session_id, enum scan_reject_states *reason); @@ -249,6 +250,8 @@ typedef struct tagSmeStruct { struct rso_cmd_status *rso_status); void (*congestion_cb)(void *, uint32_t congestion, uint32_t vdev_id); void (*stats_ext2_cb)(void *, struct sir_sme_rx_aggr_hole_ind *); + void (*chip_power_save_fail_cb)(void *, + struct chip_pwr_save_fail_detected_params *); } tSmeStruct, *tpSmeStruct; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 60dcbed2ec30..4210a4a3bd35 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -14161,6 +14161,23 @@ bool sme_is_any_session_in_connected_state(tHalHandle h_hal) return ret; } +QDF_STATUS sme_set_chip_pwr_save_fail_cb(tHalHandle hal, + void (*cb)(void *, + struct chip_pwr_save_fail_detected_params *)) { + + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) { + sme_err("sme_AcquireGlobalLock failed!(status=%d)", status); + return status; + } + mac->sme.chip_power_save_fail_cb = cb; + sme_release_global_lock(&mac->sme); + return status; +} + /** * sme_set_rssi_monitoring() - set rssi monitoring * @hal: global hal handle diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 486693daa529..bf9290b14500 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1015,6 +1015,7 @@ typedef struct { * @ns_offload_req: cached ns offload request * @wow_stats: stat counters for WoW related events * It stores parameters per vdev in wma. + * @in_bmps : Whether bmps for this interface has been enabled */ struct wma_txrx_node { uint8_t addr[IEEE80211_ADDR_LEN]; @@ -1092,6 +1093,7 @@ struct wma_txrx_node { bool he_capable; uint32_t he_ops; #endif + bool in_bmps; }; #if defined(QCA_WIFI_FTM) @@ -1519,6 +1521,7 @@ typedef struct { struct he_capability he_cap; #endif bool tx_bfee_8ss_enabled; + bool in_imps; } t_wma_handle, *tp_wma_handle; /** @@ -2348,6 +2351,32 @@ uint16_t wma_vdev_get_pause_bitmap(uint8_t vdev_id) return iface->pause_bitmap; } +/** + * wma_vdev_is_device_in_low_pwr_mode - is device in power save mode + * @vdev_id: the Id of the vdev to configure + * + * Return: true if device is in low power mode else false + */ +static inline bool wma_vdev_is_device_in_low_pwr_mode(uint8_t vdev_id) +{ + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + + if (!wma) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return 0; + } + + iface = &wma->interfaces[vdev_id]; + if (!iface || !iface->handle) { + WMA_LOGE("%s: Failed to get iface handle: %p", + __func__, iface->handle); + return 0; + } + + return iface->in_bmps || wma->in_imps; +} + /** * wma_vdev_set_pause_bit() - Set a bit in vdev pause bitmap * @vdev_id: the Id of the vdev to configure @@ -2521,4 +2550,16 @@ QDF_STATUS wma_set_rx_reorder_timeout_val(tp_wma_handle wma_handle, QDF_STATUS wma_set_rx_blocksize(tp_wma_handle wma_handle, struct sir_peer_set_rx_blocksize *peer_rx_blocksize); +/* + * wma_chip_power_save_failure_detected_handler() - chip pwr save fail detected + * event handler + * @handle: wma handle + * @cmd_param_info: event handler data + * @len: length of @cmd_param_info + * + * Return: QDF_STATUS_SUCCESS on success; error code otherwise + */ +int wma_chip_power_save_failure_detected_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); #endif diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index a5f34cd9a9f3..053466557565 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -1461,6 +1461,8 @@ static const u8 *wma_wow_wake_reason_str(A_INT32 wake_reason) return "NAN_EVENT_WAKE_HOST"; case WOW_REASON_DEBUG_TEST: return "DEBUG_TEST"; + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + return "CHIP_POWER_FAILURE_DETECT"; default: return "unknown"; } @@ -1507,6 +1509,7 @@ static void wma_print_wow_stats(t_wma_handle *wma, case WOW_REASON_EXTSCAN: case WOW_REASON_RSSI_BREACH_EVENT: case WOW_REASON_OEM_RESPONSE_EVENT: + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: break; default: return; @@ -1558,6 +1561,9 @@ static void wma_inc_wow_stats(t_wma_handle *wma, case WOW_REASON_OEM_RESPONSE_EVENT: stats->oem_response++; break; + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + stats->pwr_save_fail_detected++; + break; } } diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index ebd187ad7618..301058f9452d 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -2555,6 +2555,14 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, void *cds_context, wma_rx_aggr_failure_event_handler, WMA_RX_SERIALIZER_CTX); + /* Register PWR_SAVE_FAIL event only in case of recovery(1) */ + if (cds_cfg->auto_power_save_fail_mode) { + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID, + wma_chip_power_save_failure_detected_handler, + WMA_RX_WORK_CTX); + } + wma_ndp_register_all_event_handlers(wma_handle); wma_register_debug_callback(); @@ -2563,6 +2571,8 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, void *cds_context, wma_vdev_update_pause_bitmap); pmo_register_get_pause_bitmap(wma_handle->psoc, wma_vdev_get_pause_bitmap); + pmo_register_is_device_in_low_pwr_mode(wma_handle->psoc, + wma_vdev_is_device_in_low_pwr_mode); wma_cbacks.wma_get_connection_info = wma_get_connection_info; wma_cbacks.wma_is_service_enabled = wma_is_service_enabled; qdf_status = policy_mgr_register_wma_cb(wma_handle->psoc, &wma_cbacks); @@ -3612,16 +3622,17 @@ QDF_STATUS wma_close(void *cds_ctx) wlan_psoc_set_tgt_if_handle(wma_handle->psoc, NULL); } - wlan_objmgr_psoc_release_ref(wma_handle->psoc, WLAN_LEGACY_WMA_ID); - wma_handle->psoc = NULL; - target_if_close(); - wma_target_if_close(wma_handle); - pmo_unregister_pause_bitmap_notifier(wma_handle->psoc, wma_vdev_update_pause_bitmap); pmo_unregister_get_pause_bitmap(wma_handle->psoc, wma_vdev_get_pause_bitmap); + pmo_unregister_is_device_in_low_pwr_mode(wma_handle->psoc, + wma_vdev_is_device_in_low_pwr_mode); + wlan_objmgr_psoc_release_ref(wma_handle->psoc, WLAN_LEGACY_WMA_ID); + wma_handle->psoc = NULL; + target_if_close(); + wma_target_if_close(wma_handle); WMA_LOGD("%s: Exit", __func__); return QDF_STATUS_SUCCESS; diff --git a/core/wma/src/wma_power.c b/core/wma/src/wma_power.c index 0f7cc71410a0..efd7e5b7073d 100644 --- a/core/wma/src/wma_power.c +++ b/core/wma/src/wma_power.c @@ -821,6 +821,8 @@ void wma_enable_sta_ps_mode(tp_wma_handle wma, tpEnablePsParams ps_req) return; } } + /* power save request succeeded */ + iface->in_bmps = true; } /** @@ -834,6 +836,7 @@ void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req) { QDF_STATUS ret; uint32_t vdev_id = ps_req->sessionid; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; WMA_LOGD("Disable Sta Mode Ps vdevId %d", vdev_id); @@ -843,6 +846,7 @@ void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req) WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id); return; } + iface->in_bmps = false; /* Disable UAPSD incase if additional Req came */ if (eSIR_ADDON_DISABLE_UAPSD == ps_req->psSetting) { @@ -1710,6 +1714,7 @@ QDF_STATUS wma_set_idle_ps_config(void *wma_ptr, uint32_t idle_ps) WMA_LOGE("Fail to Set Idle Ps Config %d", idle_ps); return QDF_STATUS_E_FAILURE; } + wma->in_imps = !!idle_ps; WMA_LOGD("Successfully Set Idle Ps Config %d", idle_ps); return QDF_STATUS_SUCCESS; diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index 1827c35a542a..ab2743a83963 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -4031,3 +4031,52 @@ tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type) return WIFI_PEER_INVALID; } } + +int wma_chip_power_save_failure_detected_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *param_buf; + wmi_chip_power_save_failure_detected_fixed_param *event; + struct chip_pwr_save_fail_detected_params pwr_save_fail_params; + tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context( + QDF_MODULE_ID_PE); + if (wma == NULL) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return -EINVAL; + } + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + if (!mac->sme.chip_power_save_fail_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = + (WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid pwr_save_fail_params breached event", + __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + pwr_save_fail_params.failure_reason_code = + event->power_save_failure_reason_code; + pwr_save_fail_params.wake_lock_bitmap[0] = + event->protocol_wake_lock_bitmap[0]; + pwr_save_fail_params.wake_lock_bitmap[1] = + event->protocol_wake_lock_bitmap[1]; + pwr_save_fail_params.wake_lock_bitmap[2] = + event->protocol_wake_lock_bitmap[2]; + pwr_save_fail_params.wake_lock_bitmap[3] = + event->protocol_wake_lock_bitmap[3]; + mac->sme.chip_power_save_fail_cb(mac->hHdd, + &pwr_save_fail_params); + + WMA_LOGD("%s: Invoke HDD pwr_save_fail callback", __func__); + return 0; +}