Message ID | 20210909153320.2624649-1-bryan.odonoghue@linaro.org |
---|---|
State | New |
Headers | show |
Series | wcn36xx: Implement Idle Mode Power Save | expand |
Bryan O'Donoghue <bryan.odonoghue@linaro.org> wrote: > Idle Mode Power Save (IMPS) is a power saving mechanism which when called > by wcn36xx will cause the radio hardware to enter power collapse. > > This particular call maps nicely to a simple conjunction/disjunction around > IEEE80211_CONF_CHANGE_IDLE and IEEE80211_CONF_IDLE. > > Here we enter idle when we are not associated with an AP. The kernel will > incrementally toggle idle on/off in the process of trying to establish a > connection, thus saving power until we are connected to the AP again, at > which point we give way to BMPS if power_save is on. > > We've validated that with IMPS an apq8039 device which has the wcn36xx > module loaded but, has not authenticated with an AP will get to VMIN on > suspend and will not without IMPS. > > Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> > Tested-by: Benjamin Li <benl@squareup.com> > Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Patch applied to ath-next branch of ath.git, thanks. 0e159d2c0834 wcn36xx: Implement Idle Mode Power Save -- https://patchwork.kernel.org/project/linux-wireless/patch/20210909153320.2624649-1-bryan.odonoghue@linaro.org/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches _______________________________________________ wcn36xx mailing list wcn36xx@lists.infradead.org http://lists.infradead.org/mailman/listinfo/wcn36xx
Bryan O'Donoghue <bryan.odonoghue@linaro.org> wrote: > Idle Mode Power Save (IMPS) is a power saving mechanism which when called > by wcn36xx will cause the radio hardware to enter power collapse. > > This particular call maps nicely to a simple conjunction/disjunction around > IEEE80211_CONF_CHANGE_IDLE and IEEE80211_CONF_IDLE. > > Here we enter idle when we are not associated with an AP. The kernel will > incrementally toggle idle on/off in the process of trying to establish a > connection, thus saving power until we are connected to the AP again, at > which point we give way to BMPS if power_save is on. > > We've validated that with IMPS an apq8039 device which has the wcn36xx > module loaded but, has not authenticated with an AP will get to VMIN on > suspend and will not without IMPS. > > Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org> > Tested-by: Benjamin Li <benl@squareup.com> > Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Patch applied to ath-next branch of ath.git, thanks. 0e159d2c0834 wcn36xx: Implement Idle Mode Power Save -- https://patchwork.kernel.org/project/linux-wireless/patch/20210909153320.2624649-1-bryan.odonoghue@linaro.org/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 455143c4164e..5f1f2480459a 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -3384,11 +3384,11 @@ struct tl_hal_flush_ac_rsp_msg { struct wcn36xx_hal_enter_imps_req_msg { struct wcn36xx_hal_msg_header header; -}; +} __packed; -struct wcn36xx_hal_exit_imps_req { +struct wcn36xx_hal_exit_imps_req_msg { struct wcn36xx_hal_msg_header header; -}; +} __packed; struct wcn36xx_hal_enter_bmps_req_msg { struct wcn36xx_hal_msg_header header; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 2561ae9cde65..412c629705a6 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -443,6 +443,13 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_PS) wcn36xx_change_ps(wcn, hw->conf.flags & IEEE80211_CONF_PS); + if (changed & IEEE80211_CONF_CHANGE_IDLE) { + if (hw->conf.flags & IEEE80211_CONF_IDLE) + wcn36xx_smd_enter_imps(wcn); + else + wcn36xx_smd_exit_imps(wcn); + } + mutex_unlock(&wcn->conf_mutex); return 0; diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 57fa857b290b..599cb220b150 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -2184,6 +2184,59 @@ int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) return ret; } +int wcn36xx_smd_enter_imps(struct wcn36xx *wcn) +{ + struct wcn36xx_hal_enter_imps_req_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + INIT_HAL_MSG(msg_body, WCN36XX_HAL_ENTER_IMPS_REQ); + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending hal_enter_imps failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("hal_enter_imps response failed err=%d\n", ret); + goto out; + } + + wcn36xx_dbg(WCN36XX_DBG_HAL, "Entered idle mode\n"); +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + +int wcn36xx_smd_exit_imps(struct wcn36xx *wcn) +{ + struct wcn36xx_hal_exit_imps_req_msg msg_body; + int ret; + + mutex_lock(&wcn->hal_mutex); + INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_IMPS_REQ); + + PREPARE_HAL_BUF(wcn->hal_buf, msg_body); + + ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len); + if (ret) { + wcn36xx_err("Sending hal_exit_imps failed\n"); + goto out; + } + ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len); + if (ret) { + wcn36xx_err("hal_exit_imps response failed err=%d\n", ret); + goto out; + } + wcn36xx_dbg(WCN36XX_DBG_HAL, "Exited idle mode\n"); +out: + mutex_unlock(&wcn->hal_mutex); + return ret; +} + int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim) { struct wcn36xx_hal_set_power_params_req_msg msg_body; @@ -3060,6 +3113,8 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev, case WCN36XX_HAL_GTK_OFFLOAD_RSP: case WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP: case WCN36XX_HAL_HOST_RESUME_RSP: + case WCN36XX_HAL_ENTER_IMPS_RSP: + case WCN36XX_HAL_EXIT_IMPS_RSP: memcpy(wcn->hal_buf, buf, len); wcn->hal_rsp_len = len; complete(&wcn->hal_rsp_compl); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h index 75d1a6d663bb..dbca0bd1b6ae 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.h +++ b/drivers/net/wireless/ath/wcn36xx/smd.h @@ -165,4 +165,7 @@ int wcn36xx_smd_wlan_host_suspend_ind(struct wcn36xx *wcn); int wcn36xx_smd_host_resume(struct wcn36xx *wcn); +int wcn36xx_smd_enter_imps(struct wcn36xx *wcn); +int wcn36xx_smd_exit_imps(struct wcn36xx *wcn); + #endif /* _SMD_H_ */