[RFC] Add the BMPS timer to enter/exit BMPS mode when running
Olof Johansson
dev at skyshaper.net
Tue Jul 23 12:08:35 EDT 2013
Hello Yanbo.
I have not checked the code yet but I'll try when I have some time.
However, could you maybe explain why this feature is necessary?
What would be the advantage of this over the DYNAMIC_PS functionality
that the firmware has?
Cheers
--
Olof
On Tue, Jul 23, 2013 at 4:58 PM, <dreamfly281 at gmail.com> wrote:
> From: Yanbo Li <yanbol at qti.qualcomm.com>
>
> Add the BMPS timer to enter/exit BMPS mode when system running
> The wcn36xx_vote_enter_full_power() and wcn36xx_vote_enter_bmps()
> can be used to manual avoid enter BMPS mode in some scenario
> like DHCP process or roaming.
>
> Signed-off-by: Yanbo Li <yanbol at qti.qualcomm.com>
>
> diff --git a/debug.c b/debug.c
> index 529dd54..b43f074 100644
> --- a/debug.c
> +++ b/debug.c
> @@ -36,7 +36,7 @@ static ssize_t read_file_bool_bmps(struct file *file, char __user *user_buf,
> struct wcn36xx *wcn = file->private_data;
> char buf[3];
>
> - if (wcn->pw_state == WCN36XX_BMPS)
> + if (wcn->pw_state & WCN36XX_BMPS_MODE)
> buf[0] = '1';
> else
> buf[0] = '0';
> @@ -50,9 +50,7 @@ static ssize_t write_file_bool_bmps(struct file *file,
> size_t count, loff_t *ppos)
> {
> struct wcn36xx *wcn = file->private_data;
> - struct ieee80211_vif *vif = container_of((void *)wcn->current_vif,
> - struct ieee80211_vif,
> - drv_priv);
> +
> char buf[32];
> int buf_size;
>
> @@ -64,8 +62,7 @@ static ssize_t write_file_bool_bmps(struct file *file,
> case 'y':
> case 'Y':
> case '1':
> - wcn36xx_enable_keep_alive_null_packet(wcn);
> - wcn36xx_pmc_enter_bmps_state(wcn, vif->bss_conf.sync_tsf);
> + wcn36xx_pmc_enter_bmps_state(wcn);
> break;
> case 'n':
> case 'N':
> diff --git a/dxe.c b/dxe.c
> index 5f47a70..5358515 100644
> --- a/dxe.c
> +++ b/dxe.c
> @@ -595,7 +595,7 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
> * mode and writing to the register will not wake up the chip. Instead
> * notify chip about new frame through SMSM bus.
> */
> - if ((wcn->pw_state == WCN36XX_BMPS) && is_low) {
> + if ((wcn->pw_state & WCN36XX_BMPS_MODE) && is_low) {
> smsm_change_state(SMSM_APPS_STATE,
> 0,
> WCN36XX_SMSM_WLAN_TX_ENABLE);
> diff --git a/main.c b/main.c
> index f0bd88c..ac2c838 100644
> --- a/main.c
> +++ b/main.c
> @@ -270,6 +270,7 @@ static void wcn36xx_stop(struct ieee80211_hw *hw)
> wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop");
>
> wcn36xx_debugfs_exit(wcn);
> + wcn36xx_pmc_deinit(wcn);
> wcn36xx_smd_stop(wcn);
> wcn36xx_dxe_deinit(wcn);
> wcn36xx_smd_close(wcn);
> @@ -714,15 +715,11 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
> static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow)
> {
> struct wcn36xx *wcn = hw->priv;
> - struct ieee80211_vif *vif = container_of((void *)wcn->current_vif,
> - struct ieee80211_vif,
> - drv_priv);
> +
> wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend");
>
> mutex_lock(&wcn->pm_mutex);
> - /* Enter BMPS only in connected state */
> - if ((wcn->aid > 0) && (wcn->pw_state != WCN36XX_BMPS))
> - wcn36xx_pmc_enter_bmps_state(wcn, vif->bss_conf.sync_tsf);
> + wcn36xx_pmc_enter_bmps_state(wcn);
> wcn->is_suspended = true;
> wcn->is_con_lost_pending = false;
>
> @@ -741,9 +738,6 @@ static int wcn36xx_resume(struct ieee80211_hw *hw)
> wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume");
>
> wcn->is_suspended = false;
> - if (wcn->pw_state == WCN36XX_BMPS)
> - wcn36xx_pmc_exit_bmps_state(wcn);
> -
> if (wcn->is_con_lost_pending) {
> wcn36xx_dbg(WCN36XX_DBG_MAC, "report connection lost");
> ieee80211_connection_loss(vif);
> diff --git a/pmc.c b/pmc.c
> index 31f4086..28b3f7a 100644
> --- a/pmc.c
> +++ b/pmc.c
> @@ -20,29 +20,98 @@
> */
> #include "wcn36xx.h"
>
> -int wcn36xx_pmc_init(struct wcn36xx *wcn)
> +static int wcn36xx_enable_keep_alive_null_packet(struct wcn36xx *wcn)
> {
> - wcn->pw_state = WCN36XX_FULL_POWER;
> - return 0;
> + wcn36xx_dbg(WCN36XX_DBG_PMC, "%s", __func__);
> + return wcn36xx_smd_keep_alive_req(wcn, WCN36XX_HAL_KEEP_ALIVE_NULL_PKT,
> + WCN36XX_KEEP_ALIVE_TIME_PERIOD);
> }
>
> -int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn, u64 tsf)
> +
> +static int wcn36xx_disable_keep_alive_null_packet(struct wcn36xx *wcn)
> {
> - /* TODO: Make sure the TX chain clean */
> - wcn36xx_smd_enter_bmps(wcn, tsf);
> - wcn->pw_state = WCN36XX_BMPS;
> - return 0;
> + return wcn36xx_smd_keep_alive_req(wcn, WCN36XX_HAL_KEEP_ALIVE_NULL_PKT,
> + 0);
> +}
> +
> +/*
> + *
> + * @return: 0 means enter BMPS success, other means not enter BMPS mode
> + */
> +int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn)
> +{
> + struct ieee80211_vif *vif = container_of((void *)wcn->current_vif,
> + struct ieee80211_vif,
> + drv_priv);
> + int ret = -1;
> +
> + if ((atomic_read(&wcn->full_power_cnt) == 0) && (wcn->aid > 0)) {
> + if (!(wcn->pw_state & WCN36XX_BMPS_MODE)) {
> + wcn36xx_enable_keep_alive_null_packet(wcn);
> + wcn36xx_smd_enter_bmps(wcn, vif->bss_conf.sync_tsf);
> + wcn->pw_state |= WCN36XX_BMPS_MODE;
> + ret = 0;
> + }
> + }
> +
> + return ret;
> }
>
> int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn)
> {
> - wcn36xx_smd_exit_bmps(wcn);
> + if ((atomic_read(&wcn->full_power_cnt) > 0) || (wcn->aid == 0)) {
> + if (wcn->pw_state & WCN36XX_BMPS_MODE) {
> + wcn36xx_disable_keep_alive_null_packet(wcn);
> + wcn36xx_smd_exit_bmps(wcn);
> + wcn->pw_state &= ~WCN36XX_BMPS_MODE;
> + }
> + }
> + return 0;
> +}
> +
> +/* TODO: For DHCP/roaming protect? */
> +void wcn36xx_vote_enter_full_power(struct wcn36xx *wcn)
> +{
> + atomic_inc(&wcn->full_power_cnt);
> +}
> +
> +/*
> + * This fucntion should be called pair with wcn36xx_vote_enter_full_power
> + */
> +void wcn36xx_vote_enter_bmps(struct wcn36xx *wcn)
> +{
> + if (atomic_read(&wcn->full_power_cnt) <= 0)
> + wcn36xx_warn("The vote bmps called without paired");
> + atomic_dec(&wcn->full_power_cnt);
> +}
> +
> +static void wcn36xx_pmc_bmps_measure_work(struct work_struct *work)
> +{
> + struct wcn36xx *wcn = container_of(work, struct wcn36xx,
> + bmps_work.work);
> +
> + /* Enter or Exit BMPS depend on the currently condition */
> + wcn36xx_pmc_enter_bmps_state(wcn);
> + wcn36xx_pmc_exit_bmps_state(wcn);
> +
> + ieee80211_queue_delayed_work(wcn->hw, &wcn->bmps_work,
> + msecs_to_jiffies(BMPS_MEASURE_TIMER_DEFAULT));
> +}
> +
> +int wcn36xx_pmc_init(struct wcn36xx *wcn)
> +{
> wcn->pw_state = WCN36XX_FULL_POWER;
> + atomic_set(&wcn->full_power_cnt, 0);
> +
> + INIT_DELAYED_WORK(&wcn->bmps_work, wcn36xx_pmc_bmps_measure_work);
> +
> + ieee80211_queue_delayed_work(wcn->hw, &wcn->bmps_work,
> + msecs_to_jiffies(BMPS_MEASURE_TIMER_DEFAULT));
> return 0;
> }
>
> -int wcn36xx_enable_keep_alive_null_packet(struct wcn36xx *wcn)
> +int wcn36xx_pmc_deinit(struct wcn36xx *wcn)
> {
> - wcn36xx_dbg(WCN36XX_DBG_PMC, "%s", __func__);
> - return wcn36xx_smd_keep_alive_req(wcn, WCN36XX_HAL_KEEP_ALIVE_NULL_PKT);
> + cancel_delayed_work(&wcn->bmps_work);
> + return 0;
> }
> diff --git a/pmc.h b/pmc.h
> index 2fd8b1e..068795a 100644
> --- a/pmc.h
> +++ b/pmc.h
> @@ -23,14 +23,19 @@
>
> struct wcn36xx;
>
> -enum wcn36xx_power_state {
> - WCN36XX_FULL_POWER,
> - WCN36XX_BMPS
> -};
> +#define WCN36XX_FULL_POWER 1
> +#define WCN36XX_BMPS_MODE 2
> +
> +
> +#define BMPS_MEASURE_TIMER_DEFAULT 5000 /* unit = ms */
>
> int wcn36xx_pmc_init(struct wcn36xx *wcn);
> -int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn, u64 tbtt);
> +int wcn36xx_pmc_deinit(struct wcn36xx *wcn);
> +
> +int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn);
> int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn);
> -int wcn36xx_enable_keep_alive_null_packet(struct wcn36xx *wcn);
> -int wcn36xx_enable_keep_alive_null_packet(struct wcn36xx *wcn);
> +
> +void wcn36xx_vote_enter_full_power(struct wcn36xx *wcn);
> +void wcn36xx_vote_enter_bmps(struct wcn36xx *wcn);
> +
> #endif /* _WCN36XX_PMC_H_ */
> diff --git a/smd.c b/smd.c
> index 60e4c02..3c70705 100644
> --- a/smd.c
> +++ b/smd.c
> @@ -1070,7 +1070,8 @@ int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn)
> /* Notice: This function should be called after associated, or else it
> * will be invalid
> */
> -int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, int packet_type)
> +int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, int packet_type,
> + u32 time_period)
> {
> struct wcn36xx_hal_keep_alive_req_msg msg_body;
>
> @@ -1079,9 +1080,9 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, int packet_type)
> if (packet_type == WCN36XX_HAL_KEEP_ALIVE_NULL_PKT) {
> msg_body.bss_index = 0;
> msg_body.packet_type = WCN36XX_HAL_KEEP_ALIVE_NULL_PKT;
> - msg_body.time_period = WCN36XX_KEEP_ALIVE_TIME_PERIOD;
> + msg_body.time_period = time_period;
> } else if (packet_type == WCN36XX_HAL_KEEP_ALIVE_UNSOLICIT_ARP_RSP) {
> - /* TODO: it also support ARP response type */
> + /* TODO: it also support send ARP response type */
> } else {
> wcn36xx_warn("unknow keep alive packet type %d", packet_type);
> return -1;
> diff --git a/smd.h b/smd.h
> index c8161fb..a856773 100644
> --- a/smd.h
> +++ b/smd.h
> @@ -89,7 +89,8 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn,
> u8 keyidx);
> int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, u64 tbtt);
> int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn);
> -int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, int packet_type);
> +int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn, int packet_type,
> + u32 time_period);
> int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2,
> u32 arg3, u32 arg4, u32 arg5);
> int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn);
> diff --git a/wcn36xx.h b/wcn36xx.h
> index 830ae2a..ee2edee 100644
> --- a/wcn36xx.h
> +++ b/wcn36xx.h
> @@ -175,7 +175,9 @@ struct wcn36xx {
> struct sk_buff *tx_ack_skb;
>
> /* Power management */
> - enum wcn36xx_power_state pw_state;
> + int pw_state;
> + atomic_t full_power_cnt;
> + struct delayed_work bmps_work;
>
> /* Debug file system entry */
> struct wcn36xx_dfs_entry dfs;
> --
> 1.7.9.5
>
>
> _______________________________________________
> wcn36xx mailing list
> wcn36xx at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/wcn36xx
More information about the wcn36xx
mailing list