aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-21 08:44:45 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-28 14:40:34 -0400
commitea77f12f2cc0f31168f2e0259e65a22202ac4dc2 (patch)
tree8ac1288e1680ae2b6093b4fdca978a4ea86f7e21 /net/mac80211
parent3d54d25515838543e56889aa7e48f40d00719368 (diff)
mac80211: remove tasklet enable/disable
Due to the way the tasklets work in mac80211 there's no need to ever disable them. However, we need to clear the pending packets when taking down the last interface because otherwise the tx_pending_tasklet might be queued if the driver mucks with the queues (which it shouldn't). I've had a situation occasionally with ar9170 in which ksoftirq was using 100% CPU time because a disabled tasklet was scheduled, and I think that was due to ar9170 receiving a packet while the tasklet was disabled. That's strange and it really should not do that for other reasons, but there's no need to waste that much CPU time over it, it should just warn instead. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/driver-ops.h14
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/iface.c9
-rw-r--r--net/mac80211/main.c2
-rw-r--r--net/mac80211/rx.c9
5 files changed, 26 insertions, 11 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d231c9323ad1..020a94a31106 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -12,7 +12,11 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
12 12
13static inline int drv_start(struct ieee80211_local *local) 13static inline int drv_start(struct ieee80211_local *local)
14{ 14{
15 int ret = local->ops->start(&local->hw); 15 int ret;
16
17 local->started = true;
18 smp_mb();
19 ret = local->ops->start(&local->hw);
16 trace_drv_start(local, ret); 20 trace_drv_start(local, ret);
17 return ret; 21 return ret;
18} 22}
@@ -21,6 +25,14 @@ static inline void drv_stop(struct ieee80211_local *local)
21{ 25{
22 local->ops->stop(&local->hw); 26 local->ops->stop(&local->hw);
23 trace_drv_stop(local); 27 trace_drv_stop(local);
28
29 /* sync away all work on the tasklet before clearing started */
30 tasklet_disable(&local->tasklet);
31 tasklet_enable(&local->tasklet);
32
33 barrier();
34
35 local->started = false;
24} 36}
25 37
26static inline int drv_add_interface(struct ieee80211_local *local, 38static inline int drv_add_interface(struct ieee80211_local *local,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index fa930e01295f..dbd8411cc1bd 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -667,6 +667,9 @@ struct ieee80211_local {
667 */ 667 */
668 bool quiescing; 668 bool quiescing;
669 669
670 /* device is started */
671 bool started;
672
670 int tx_headroom; /* required headroom for hardware/radiotap */ 673 int tx_headroom; /* required headroom for hardware/radiotap */
671 674
672 /* Tasklet and skb queue to process calls from IRQ mode. All frames 675 /* Tasklet and skb queue to process calls from IRQ mode. All frames
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 5940e69fa33c..d134bd79972f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -277,11 +277,6 @@ static int ieee80211_open(struct net_device *dev)
277 } 277 }
278 } 278 }
279 279
280 if (local->open_count == 0) {
281 tasklet_enable(&local->tx_pending_tasklet);
282 tasklet_enable(&local->tasklet);
283 }
284
285 /* 280 /*
286 * set_multicast_list will be invoked by the networking core 281 * set_multicast_list will be invoked by the networking core
287 * which will check whether any increments here were done in 282 * which will check whether any increments here were done in
@@ -552,11 +547,9 @@ static int ieee80211_stop(struct net_device *dev)
552 ieee80211_recalc_ps(local, -1); 547 ieee80211_recalc_ps(local, -1);
553 548
554 if (local->open_count == 0) { 549 if (local->open_count == 0) {
550 ieee80211_clear_tx_pending(local);
555 ieee80211_stop_device(local); 551 ieee80211_stop_device(local);
556 552
557 tasklet_disable(&local->tx_pending_tasklet);
558 tasklet_disable(&local->tasklet);
559
560 /* no reconfiguring after stop! */ 553 /* no reconfiguring after stop! */
561 hw_reconf_flags = 0; 554 hw_reconf_flags = 0;
562 } 555 }
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index dd3b0816614d..797f53942e5f 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -715,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
715 skb_queue_head_init(&local->pending[i]); 715 skb_queue_head_init(&local->pending[i]);
716 tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, 716 tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
717 (unsigned long)local); 717 (unsigned long)local);
718 tasklet_disable(&local->tx_pending_tasklet);
719 718
720 tasklet_init(&local->tasklet, 719 tasklet_init(&local->tasklet,
721 ieee80211_tasklet_handler, 720 ieee80211_tasklet_handler,
722 (unsigned long) local); 721 (unsigned long) local);
723 tasklet_disable(&local->tasklet);
724 722
725 skb_queue_head_init(&local->skb_queue); 723 skb_queue_head_init(&local->skb_queue);
726 skb_queue_head_init(&local->skb_queue_unreliable); 724 skb_queue_head_init(&local->skb_queue_unreliable);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index dff2239db6e2..b98f1afbfebf 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2471,6 +2471,15 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
2471 return; 2471 return;
2472 } 2472 }
2473 2473
2474 /*
2475 * The same happens when we're not even started,
2476 * but that's worth a warning.
2477 */
2478 if (WARN_ON(!local->started)) {
2479 kfree_skb(skb);
2480 return;
2481 }
2482
2474 if (status->flag & RX_FLAG_HT) { 2483 if (status->flag & RX_FLAG_HT) {
2475 /* rate_idx is MCS index */ 2484 /* rate_idx is MCS index */
2476 if (WARN_ON(status->rate_idx < 0 || 2485 if (WARN_ON(status->rate_idx < 0 ||