qcacld-3.0: Auto Detect SoC Power Collapse Failure changes

Add host support for detecting SOC power collapse failures in FW and
communicating the same to framework.

Change-Id: Icee39c896802c4d7136e0b8ef442a33feeb4799c
CRs-Fixed: 1112979
This commit is contained in:
Ravi Kumar Bokka 2017-03-27 14:48:23 +05:30 • committed by snandini
commit 05c14e5c50
16 changed files with 292 additions and 5 deletions

View file

@ -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 ) */

View file

@ -7116,6 +7116,24 @@ enum hdd_link_speed_rpt_type {
#define CFG_ENABLE_MEMORY_DEBUG_DEFAULT (1)
#endif
/*
* <ini>
* 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
*
* </ini>
*/
#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)
/*
* <ini>
@ -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))

View file

@ -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) */

View file

@ -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]",

View file

@ -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] = {

View file

@ -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);

View file

@ -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) {

View file

@ -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;
};
/**

View file

@ -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 ) */

View file

@ -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 ) */

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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;
}