diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-06-05 08:28:40 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-06-06 15:20:33 -0400 |
commit | 196ac1c13d4db6c276dbb1c9190c8d7d45a83f1f (patch) | |
tree | 68d2a1b99ec08d685381c812e38d0f18553e1cee | |
parent | 491b26b40222cc769c163e77177697dd7a63c316 (diff) |
mac80211: do remain-on-channel while idle
The IDLE handling in HW off-channel is broken right
now since we turn off IDLE only when the off-channel
period already started. Therefore, all drivers that
use it today (only iwlwifi!) must support off-channel
while idle, so playing with idle isn't needed at all.
Off-channel in general, since it's no longer used for
authentication/association, shouldn't affect PS, so
also remove that logic.
Also document a small caveat for reporting TX status
from off-channel frames in HW remain-on-channel.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | include/net/mac80211.h | 8 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 7 | ||||
-rw-r--r-- | net/mac80211/iface.c | 17 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 6 | ||||
-rw-r--r-- | net/mac80211/offchannel.c | 4 |
5 files changed, 17 insertions, 25 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d2ed86da8e4c..6e700bf8d4a5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -2183,7 +2183,13 @@ enum ieee80211_rate_control_changed { | |||
2183 | * offload. Frames to transmit on the off-channel channel are transmitted | 2183 | * offload. Frames to transmit on the off-channel channel are transmitted |
2184 | * normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the | 2184 | * normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the |
2185 | * duration (which will always be non-zero) expires, the driver must call | 2185 | * duration (which will always be non-zero) expires, the driver must call |
2186 | * ieee80211_remain_on_channel_expired(). This callback may sleep. | 2186 | * ieee80211_remain_on_channel_expired(). |
2187 | * The driver must not call ieee80211_remain_on_channel_expired() before | ||
2188 | * the TX status for a frame that was sent off-channel, otherwise the TX | ||
2189 | * status is reported to userspace in an invalid way. | ||
2190 | * Note that this callback may be called while the device is in IDLE and | ||
2191 | * must be accepted in this case. | ||
2192 | * This callback may sleep. | ||
2187 | * @cancel_remain_on_channel: Requests that an ongoing off-channel period is | 2193 | * @cancel_remain_on_channel: Requests that an ongoing off-channel period is |
2188 | * aborted before it expires. This callback may sleep. | 2194 | * aborted before it expires. This callback may sleep. |
2189 | * | 2195 | * |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d99359a6f76d..a16907919709 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -2187,8 +2187,6 @@ static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local, | |||
2187 | local->hw_roc_cookie = 0; | 2187 | local->hw_roc_cookie = 0; |
2188 | local->hw_roc_channel = NULL; | 2188 | local->hw_roc_channel = NULL; |
2189 | 2189 | ||
2190 | ieee80211_recalc_idle(local); | ||
2191 | |||
2192 | return 0; | 2190 | return 0; |
2193 | } | 2191 | } |
2194 | 2192 | ||
@@ -2248,7 +2246,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2248 | struct ieee80211_work *wk; | 2246 | struct ieee80211_work *wk; |
2249 | const struct ieee80211_mgmt *mgmt = (void *)buf; | 2247 | const struct ieee80211_mgmt *mgmt = (void *)buf; |
2250 | u32 flags; | 2248 | u32 flags; |
2251 | bool is_offchan = false; | 2249 | bool is_offchan = false, in_hw_roc = false; |
2252 | 2250 | ||
2253 | if (dont_wait_for_ack) | 2251 | if (dont_wait_for_ack) |
2254 | flags = IEEE80211_TX_CTL_NO_ACK; | 2252 | flags = IEEE80211_TX_CTL_NO_ACK; |
@@ -2268,6 +2266,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2268 | if (chan == local->hw_roc_channel) { | 2266 | if (chan == local->hw_roc_channel) { |
2269 | /* TODO: check channel type? */ | 2267 | /* TODO: check channel type? */ |
2270 | is_offchan = false; | 2268 | is_offchan = false; |
2269 | in_hw_roc = true; | ||
2271 | flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | 2270 | flags |= IEEE80211_TX_CTL_TX_OFFCHAN; |
2272 | } | 2271 | } |
2273 | 2272 | ||
@@ -2370,7 +2369,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2370 | * wait is involved, we might otherwise not be on | 2369 | * wait is involved, we might otherwise not be on |
2371 | * the right channel for long enough! | 2370 | * the right channel for long enough! |
2372 | */ | 2371 | */ |
2373 | if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) { | 2372 | if (!is_offchan && !wait && (in_hw_roc || !sdata->vif.bss_conf.idle)) { |
2374 | ieee80211_tx_skb(sdata, skb); | 2373 | ieee80211_tx_skb(sdata, skb); |
2375 | return 0; | 2374 | return 0; |
2376 | } | 2375 | } |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ede5f4959904..968d71c50713 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1456,7 +1456,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1456 | { | 1456 | { |
1457 | struct ieee80211_sub_if_data *sdata; | 1457 | struct ieee80211_sub_if_data *sdata; |
1458 | int count = 0; | 1458 | int count = 0; |
1459 | bool working = false, scanning = false, hw_roc = false; | 1459 | bool working = false, scanning = false; |
1460 | struct ieee80211_work *wk; | 1460 | struct ieee80211_work *wk; |
1461 | unsigned int led_trig_start = 0, led_trig_stop = 0; | 1461 | unsigned int led_trig_start = 0, led_trig_stop = 0; |
1462 | 1462 | ||
@@ -1493,9 +1493,11 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1493 | count++; | 1493 | count++; |
1494 | } | 1494 | } |
1495 | 1495 | ||
1496 | list_for_each_entry(wk, &local->work_list, list) { | 1496 | if (!local->ops->remain_on_channel) { |
1497 | working = true; | 1497 | list_for_each_entry(wk, &local->work_list, list) { |
1498 | wk->sdata->vif.bss_conf.idle = false; | 1498 | working = true; |
1499 | wk->sdata->vif.bss_conf.idle = false; | ||
1500 | } | ||
1499 | } | 1501 | } |
1500 | 1502 | ||
1501 | if (local->scan_sdata && | 1503 | if (local->scan_sdata && |
@@ -1504,9 +1506,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1504 | local->scan_sdata->vif.bss_conf.idle = false; | 1506 | local->scan_sdata->vif.bss_conf.idle = false; |
1505 | } | 1507 | } |
1506 | 1508 | ||
1507 | if (local->hw_roc_channel) | ||
1508 | hw_roc = true; | ||
1509 | |||
1510 | list_for_each_entry(sdata, &local->interfaces, list) { | 1509 | list_for_each_entry(sdata, &local->interfaces, list) { |
1511 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | 1510 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || |
1512 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1511 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
@@ -1518,7 +1517,7 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1518 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); | 1517 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); |
1519 | } | 1518 | } |
1520 | 1519 | ||
1521 | if (working || scanning || hw_roc) | 1520 | if (working || scanning) |
1522 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; | 1521 | led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; |
1523 | else | 1522 | else |
1524 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; | 1523 | led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; |
@@ -1530,8 +1529,6 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
1530 | 1529 | ||
1531 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); | 1530 | ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); |
1532 | 1531 | ||
1533 | if (hw_roc) | ||
1534 | return ieee80211_idle_off(local, "hw remain-on-channel"); | ||
1535 | if (working) | 1532 | if (working) |
1536 | return ieee80211_idle_off(local, "working"); | 1533 | return ieee80211_idle_off(local, "working"); |
1537 | if (scanning) | 1534 | if (scanning) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e7c4ec4ce166..0f45d02e0ba7 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -930,11 +930,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
930 | return; | 930 | return; |
931 | } | 931 | } |
932 | 932 | ||
933 | if (!list_empty(&local->work_list)) { | ||
934 | local->ps_sdata = NULL; | ||
935 | goto change; | ||
936 | } | ||
937 | |||
938 | list_for_each_entry(sdata, &local->interfaces, list) { | 933 | list_for_each_entry(sdata, &local->interfaces, list) { |
939 | if (!ieee80211_sdata_running(sdata)) | 934 | if (!ieee80211_sdata_running(sdata)) |
940 | continue; | 935 | continue; |
@@ -1007,7 +1002,6 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
1007 | local->ps_sdata = NULL; | 1002 | local->ps_sdata = NULL; |
1008 | } | 1003 | } |
1009 | 1004 | ||
1010 | change: | ||
1011 | ieee80211_change_ps(local); | 1005 | ieee80211_change_ps(local); |
1012 | } | 1006 | } |
1013 | 1007 | ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 935aa4b6deee..8f482b15bc51 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -207,8 +207,6 @@ static void ieee80211_hw_roc_start(struct work_struct *work) | |||
207 | GFP_KERNEL); | 207 | GFP_KERNEL); |
208 | } | 208 | } |
209 | 209 | ||
210 | ieee80211_recalc_idle(local); | ||
211 | |||
212 | mutex_unlock(&local->mtx); | 210 | mutex_unlock(&local->mtx); |
213 | } | 211 | } |
214 | 212 | ||
@@ -260,8 +258,6 @@ static void ieee80211_hw_roc_done(struct work_struct *work) | |||
260 | local->hw_roc_channel = NULL; | 258 | local->hw_roc_channel = NULL; |
261 | local->hw_roc_cookie = 0; | 259 | local->hw_roc_cookie = 0; |
262 | 260 | ||
263 | ieee80211_recalc_idle(local); | ||
264 | |||
265 | mutex_unlock(&local->mtx); | 261 | mutex_unlock(&local->mtx); |
266 | } | 262 | } |
267 | 263 | ||