aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-06-05 08:28:40 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-06-06 15:20:33 -0400
commit196ac1c13d4db6c276dbb1c9190c8d7d45a83f1f (patch)
tree68d2a1b99ec08d685381c812e38d0f18553e1cee
parent491b26b40222cc769c163e77177697dd7a63c316 (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.h8
-rw-r--r--net/mac80211/cfg.c7
-rw-r--r--net/mac80211/iface.c17
-rw-r--r--net/mac80211/mlme.c6
-rw-r--r--net/mac80211/offchannel.c4
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