[RFC] Add the BMPS timer to enter/exit BMPS mode when running
dreamfly281 at gmail.com
dreamfly281 at gmail.com
Tue Jul 23 10:58:25 EDT 2013
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
More information about the wcn36xx
mailing list