summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-06-21 08:59:39 +0300
committerJohn W. Linville <linville@tuxdriver.com>2010-06-21 15:39:59 -0400
commitf90754c15f47063671aea55268a9dd6a37b51492 (patch)
tree197c239a813e426d8a675449927e381352ad4875 /net
parentfb63bc41772259701a827e9a6117219a7393554f (diff)
downloadlinux-f90754c15f47063671aea55268a9dd6a37b51492.tar.gz
linux-f90754c15f47063671aea55268a9dd6a37b51492.tar.bz2
linux-f90754c15f47063671aea55268a9dd6a37b51492.zip
mac80211: Add interface for driver to temporarily disable dynamic ps
This mechanism introduced in this patch applies (at least) for hardware designs using a single shared antenna for both WLAN and BT. In these designs, the antenna must be toggled between WLAN and BT. In those hardware, managing WLAN co-existence with Bluetooth requires WLAN full power save whenever there is Bluetooth activity in order for WLAN to be able to periodically relinquish the antenna to be used for BT. This is because BT can only access the shared antenna when WLAN is idle or asleep. Some hardware, for instance the wl1271, are able to indicate to the host whenever there is BT traffic. In essence, the hardware will send an indication to the host whenever there is, for example, SCO traffic or A2DP traffic, and will send another indication when the traffic is over. The hardware gets information of Bluetooth traffic via hardware co-existence control lines - these lines are used to negotiate the shared antenna ownership. The hardware will give the antenna to BT whenever WLAN is sleeping. This patch adds the interface to mac80211 to facilitate temporarily disabling of dynamic power save as per request of the WLAN driver. This interface will immediately force WLAN to full powersave, hence allowing BT coexistence as described above. In these kind of shared antenna desings, when WLAN powersave is fully disabled, Bluetooth will not work simultaneously with WLAN at all. This patch does not address that problem. This interface will not change PSM state, so if PSM is disabled it will remain so. Solving this problem requires knowledge about BT state, and is best done in user-space. Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/mlme.c39
2 files changed, 40 insertions, 1 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index fb5430188e87..f9251d50192c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -855,6 +855,8 @@ struct ieee80211_local {
* this will override whatever chosen by mac80211 internally.
*/
int dynamic_ps_forced_timeout;
+ int dynamic_ps_user_timeout;
+ bool disable_dynamic_ps;
int user_power_level; /* in dBm */
int power_constr_level; /* in dBm */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 85c3ca33333e..d1962650b254 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -478,6 +478,39 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
}
}
+void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+ !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+ (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
+
+ local->disable_dynamic_ps = false;
+ conf->dynamic_ps_timeout = local->dynamic_ps_user_timeout;
+}
+EXPORT_SYMBOL(ieee80211_enable_dyn_ps);
+
+void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif)
+{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION ||
+ !(local->hw.flags & IEEE80211_HW_SUPPORTS_PS) ||
+ (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS));
+
+ local->disable_dynamic_ps = true;
+ conf->dynamic_ps_timeout = 0;
+ del_timer_sync(&local->dynamic_ps_timer);
+ ieee80211_queue_work(&local->hw,
+ &local->dynamic_ps_enable_work);
+}
+EXPORT_SYMBOL(ieee80211_disable_dyn_ps);
+
/* powersave */
static void ieee80211_enable_ps(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
@@ -553,6 +586,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
found->u.mgd.associated->beacon_ies &&
!(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
IEEE80211_STA_CONNECTION_POLL))) {
+ struct ieee80211_conf *conf = &local->hw.conf;
s32 beaconint_us;
if (latency < 0)
@@ -575,7 +609,10 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
else
timeout = 100;
}
- local->hw.conf.dynamic_ps_timeout = timeout;
+ local->dynamic_ps_user_timeout = timeout;
+ if (!local->disable_dynamic_ps)
+ conf->dynamic_ps_timeout =
+ local->dynamic_ps_user_timeout;
if (beaconint_us > latency) {
local->ps_sdata = NULL;