diff --git a/core/hdd/inc/wlan_hdd_power.h b/core/hdd/inc/wlan_hdd_power.h index 19536f88bd26..e173d4f517db 100644 --- a/core/hdd/inc/wlan_hdd_power.h +++ b/core/hdd/inc/wlan_hdd_power.h @@ -189,6 +189,9 @@ int wlan_hdd_ipv4_changed(struct notifier_block *nb, int wlan_hdd_ipv6_changed(struct notifier_block *nb, unsigned long data, void *arg); +int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter, + uint8_t qpower); + #ifdef FEATURE_WLAN_DIAG_SUPPORT void hdd_wlan_suspend_resume_event(uint8_t state); #else diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 434f9a366fdc..4d438f93273d 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -3871,7 +3871,6 @@ wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { [QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND] = {.type = NLA_U8 }, }; - /** * __wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration * vendor command @@ -3901,6 +3900,7 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, u32 guard_time; uint8_t set_value; u32 ftm_capab; + uint8_t qpower; QDF_STATUS status; int attr_len; int access_policy = 0; @@ -3949,6 +3949,13 @@ __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, ret_val = -EPERM; } + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]) { + qpower = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]); + if (hdd_set_qpower_config(hdd_ctx, adapter, qpower) != 0) + ret_val = -EINVAL; + } + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]) { stats_avg_factor = nla_get_u16( tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]); diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index f735f8ebb1de..7355b4bea69d 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -2333,6 +2333,8 @@ enum qca_access_policy { * with access policy * @QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX: interface index for vdev specific * parameters + * @QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER: Unsigned 8bit length attribute to update + * power save config to turn off/on qpower * @QCA_WLAN_VENDOR_ATTR_CONFIG_LAST: last config * @QCA_WLAN_VENDOR_ATTR_CONFIG_MAX: max config */ @@ -2381,6 +2383,8 @@ enum qca_wlan_vendor_config { * not specified, the configurations are attributed to the respective * wiphy. */ QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX, + /* Unsigned 8-bit, for setting qpower dynamically */ + QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER = 25, /* keep last */ QCA_WLAN_VENDOR_ATTR_CONFIG_LAST, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX = diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 809c4924bc3b..7e82be6f9ae7 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -2304,3 +2304,48 @@ int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, return ret; } + +/** + * hdd_set_qpower_config() - set qpower config to firmware + * @adapter: HDD adapter + * @qpower: new qpower config value + * + * Return: 0 on success; Errno on failure + */ +int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter, + uint8_t qpower) +{ + QDF_STATUS qdf_status; + int status; + bool is_timer_running; + + if (!hddctx->config->enablePowersaveOffload) { + hdd_err("qpower is disabled in configuration"); + return -EINVAL; + } + if (qpower > PS_DUTY_CYCLING_QPOWER || + qpower < PS_LEGACY_NODEEPSLEEP) { + hdd_err("invalid qpower value=%d", qpower); + return -EINVAL; + } + hdd_info("updating qpower value=%d to wma", qpower); + qdf_status = wma_set_powersave_config(qpower); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("failed to update qpower %d", + qdf_status); + return -EINVAL; + } + is_timer_running = sme_is_auto_ps_timer_running( + WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId); + if (!is_timer_running) { + status = wlan_hdd_set_powersave(adapter, true, 0); + + if (status != 0) { + hdd_err("failed to put device in power save mode %d", + status); + return -EINVAL; + } + } + return 0; +} diff --git a/core/sme/inc/sme_power_save_api.h b/core/sme/inc/sme_power_save_api.h index 77e2934e8a52..9cfd859bcd9f 100644 --- a/core/sme/inc/sme_power_save_api.h +++ b/core/sme/inc/sme_power_save_api.h @@ -96,7 +96,7 @@ static inline void sme_set_pno_channel_prediction(void *request_buf, {} #endif -QDF_STATUS sme_is_auto_ps_timer_running(tHalHandle hal_ctx, +bool sme_is_auto_ps_timer_running(tHalHandle hal_ctx, uint32_t session_id); #endif /* #if !defined(__SME_POWER_SAVE_API_H) */ diff --git a/core/sme/src/common/sme_power_save.c b/core/sme/src/common/sme_power_save.c index db484af101cc..8de99d434323 100644 --- a/core/sme/src/common/sme_power_save.c +++ b/core/sme/src/common/sme_power_save.c @@ -1136,7 +1136,7 @@ QDF_STATUS sme_ps_close_per_session(tHalHandle hal_ctx, uint32_t session_id) return qdf_status; } -QDF_STATUS sme_is_auto_ps_timer_running(tHalHandle hal_ctx, +bool sme_is_auto_ps_timer_running(tHalHandle hal_ctx, uint32_t session_id) { tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index d2bb1098c54d..951048c535b0 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -296,9 +296,9 @@ bool wma_is_p2p_lo_capable(void); QDF_STATUS wma_p2p_lo_start(struct sir_p2p_lo_start *params); QDF_STATUS wma_p2p_lo_stop(u_int32_t vdev_id); QDF_STATUS wma_get_wakelock_stats(struct sir_wake_lock_stats *wake_lock_stats); - void wma_process_pdev_hw_mode_trans_ind(void *wma, wmi_pdev_hw_mode_transition_event_fixed_param *fixed_param, wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry, struct sir_hw_mode_trans_ind *hw_mode_trans_ind); +QDF_STATUS wma_set_powersave_config(uint8_t val); #endif diff --git a/core/wma/src/wma_power.c b/core/wma/src/wma_power.c index afda4ddbfd13..acf4eac4fb67 100644 --- a/core/wma/src/wma_power.c +++ b/core/wma/src/wma_power.c @@ -969,6 +969,29 @@ void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req) } } +/** + * wma_set_powersave_config() - update power save config in wma + * @val: new power save value + * + * This function update qpower value in wma layer + * + * Return: QDF_STATUS_SUCCESS on success, error number otherwise + */ +QDF_STATUS wma_set_powersave_config(uint8_t val) +{ + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return QDF_STATUS_E_INVAL; + } + wma_handle->powersave_mode = val; + + return QDF_STATUS_SUCCESS; +} + /** * wma_enable_uapsd_mode() - enable uapsd mode in fw * @wma: wma handle