diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 8a8016514bd0..293a7aafa2b7 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -5426,6 +5426,7 @@ wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { .type = NLA_UNSPEC, .len = QDF_MAC_ADDR_SIZE}, [RX_BLOCKSIZE_WINLIMIT] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL] = {.type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA] = {.type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN] = {.type = NLA_U32 }, [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST] = {.type = NLA_U32 }, @@ -5735,7 +5736,7 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, struct hdd_context *hdd_ctx = wiphy_priv(wiphy); struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1]; int ret_val = 0; - u32 modulated_dtim; + u32 modulated_dtim, override_li; u16 stats_avg_factor; u32 guard_time; uint8_t set_value; @@ -5802,6 +5803,18 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, ret_val = -EPERM; } + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL]) { + override_li = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL]); + + status = sme_override_listen_interval(hdd_ctx->hHal, + adapter->sessionId, + override_li); + + if (status != QDF_STATUS_SUCCESS) + ret_val = -EPERM; + } + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]) { qpower = nla_get_u8( tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]); diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 9678fd0f4673..33780e14b5a4 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -960,6 +960,9 @@ QDF_STATUS sme_ext_change_channel(tHalHandle hHal, uint32_t channel, QDF_STATUS sme_configure_modulated_dtim(tHalHandle hal, uint8_t session_id, uint32_t modulated_dtim); +QDF_STATUS sme_override_listen_interval(tHalHandle h_hal, uint8_t session_id, + uint32_t override_li); + QDF_STATUS sme_configure_stats_avg_factor(tHalHandle hal, uint8_t session_id, uint16_t stats_avg_factor); diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 6005e4ded247..34d8f04c9e4b 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -13733,6 +13733,63 @@ QDF_STATUS sme_configure_modulated_dtim(tHalHandle h_hal, uint8_t session_id, return status; } +/** + * sme_override_listen_interval() - function to override static LI + * @h_hal: SME API to override listen interval + * @session_id: session ID + * @override_li: new LI value passed by user + * + * This function override (enable/disable) static a.k.a ini based LI + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_override_listen_interval(tHalHandle h_hal, uint8_t session_id, + uint32_t override_li) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + wma_cli_set_cmd_t *iwcmd; + + iwcmd = qdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_FATAL, + "%s: qdf_mem_malloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + status = sme_acquire_global_lock(&mac->sme); + + if (status == QDF_STATUS_SUCCESS) { + + iwcmd->param_value = override_li; + iwcmd->param_vdev_id = session_id; + iwcmd->param_id = GEN_PARAM_LISTEN_INTERVAL; + iwcmd->param_vp_dev = GEN_CMD; + msg.type = WMA_CLI_SET_CMD; + msg.reserved = 0; + msg.bodyptr = (void *)iwcmd; + + if (!QDF_IS_STATUS_SUCCESS( + scheduler_post_msg(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Can't post GEN_PARAM_LISTEN_INTERVAL", + __func__); + qdf_mem_free(iwcmd); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + qdf_mem_free(iwcmd); + } + + return status; +} + /* * sme_wifi_start_logger() - Send the start/stop logging command to WMA * to either start/stop logging diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index bb073acd5396..0c62e35e76dd 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1029,6 +1029,7 @@ typedef struct { * @plink_status_req: link status request * @psnr_req: snr request * @delay_before_vdev_stop: delay + * @override_li: dynamically user configured listen interval * @tx_streams: number of tx streams can be used by the vdev * @rx_streams: number of rx streams can be used by the vdev * @chain_mask: chain mask can be used by the vdev @@ -1101,6 +1102,7 @@ struct wma_txrx_node { #endif uint32_t alt_modulated_dtim; bool alt_modulated_dtim_enabled; + uint32_t override_li; uint32_t tx_streams; uint32_t rx_streams; uint32_t chain_mask; diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index 962d8c149e25..062bd40053c1 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -53,6 +53,7 @@ typedef void *WMA_HANDLE; * @GEN_PARAM_CAPTURE_TSF: read tsf * @GEN_PARAM_RESET_TSF_GPIO: reset tsf gpio * @GEN_VDEV_ROAM_SYNCH_DELAY: roam sync delay + * @GEN_PARAM_LISTEN_INTERVAL: listen interval */ enum GEN_PARAM { GEN_VDEV_PARAM_AMPDU = 0x1, @@ -62,6 +63,7 @@ enum GEN_PARAM { GEN_PARAM_CAPTURE_TSF, GEN_PARAM_RESET_TSF_GPIO, GEN_VDEV_ROAM_SYNCH_DELAY, + GEN_PARAM_LISTEN_INTERVAL, }; /** diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 05bbc46ba32c..5dfc60b43139 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -946,6 +946,70 @@ static void wma_set_modulated_dtim(tp_wma_handle wma, } } +/** + * wma_override_listen_interval() - function to override static/ini based LI + * @wma: wma handle + * @privcmd: structure containing parameters + * + * This function override static/ini based LI in firmware + * + * Return: none + */ +static void wma_override_listen_interval(tp_wma_handle wma, + wma_cli_set_cmd_t *privcmd) +{ + uint8_t vdev_id = privcmd->param_vdev_id; + struct wma_txrx_node *iface = + &wma->interfaces[vdev_id]; + u32 old_override_li, new_override_li, listen_interval; + struct sAniSirGlobal *mac; + QDF_STATUS ret; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + WMA_LOGE(FL("Failed to get mac context")); + return; + } + + old_override_li = iface->override_li; + new_override_li = privcmd->param_value; + iface->override_li = new_override_li; + + if (new_override_li && + (new_override_li != old_override_li)) { + listen_interval = new_override_li; + } else if (!new_override_li && + (new_override_li != old_override_li)) { + /* Configure default LI as we do on resume */ + if ((wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL, + &listen_interval) != eSIR_SUCCESS)) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get value for listen interval"); + listen_interval = POWERSAVE_DEFAULT_LISTEN_INTERVAL; + } + } else { + return; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + listen_interval); + if (QDF_IS_STATUS_ERROR(ret)) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", + vdev_id); + } + WMA_LOGD("%s: Set Listen Interval vdevId %d Listen Intv %d", + __func__, vdev_id, listen_interval); + ret = wma_vdev_set_param(wma->wmi_handle, + privcmd->param_vdev_id, + WMI_VDEV_PARAM_DTIM_POLICY, + NORMAL_DTIM); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to Set to Normal DTIM policy"); + +} + /** * wma_process_cli_set_cmd() - set parameters to fw @@ -1088,6 +1152,9 @@ static void wma_process_cli_set_cmd(tp_wma_handle wma, case GEN_PARAM_MODULATED_DTIM: wma_set_modulated_dtim(wma, privcmd); break; + case GEN_PARAM_LISTEN_INTERVAL: + wma_override_listen_interval(wma, privcmd); + break; default: WMA_LOGE("Invalid param id 0x%x", privcmd->param_id); diff --git a/core/wma/src/wma_power.c b/core/wma/src/wma_power.c index 440ffe9af902..1b783ee42d6e 100644 --- a/core/wma/src/wma_power.c +++ b/core/wma/src/wma_power.c @@ -1906,8 +1906,8 @@ static void wma_set_vdev_suspend_dtim(tp_wma_handle wma, uint8_t vdev_id) vdev_id); } - WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", - vdev_id, listen_interval); + WMA_LOGD("%s: Set Listen Interval vdevId %d Listen Intv %d", + __func__, vdev_id, listen_interval); iface->restore_dtim_setting = true; } @@ -1921,7 +1921,7 @@ static void wma_set_vdev_suspend_dtim(tp_wma_handle wma, uint8_t vdev_id) */ static inline uint8_t wma_is_user_set_li_params(struct wma_txrx_node *iface) { - return iface->alt_modulated_dtim_enabled ? 1 : 0; + return iface->alt_modulated_dtim_enabled || iface->override_li ? 1 : 0; } /** @@ -2027,8 +2027,8 @@ static void wma_set_vdev_resume_dtim(tp_wma_handle wma, uint8_t vdev_id) vdev_id); } - WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", - vdev_id, cfg_data_val); + WMA_LOGD("%s: Set Listen Interval vdevId %d Listen Intv %d", + __func__, vdev_id, cfg_data_val); iface->restore_dtim_setting = false;