mac80211: remove tasklet enable/disable
authorJohannes Berg <johannes@sipsolutions.net>
Fri, 21 Aug 2009 12:44:45 +0000 (14:44 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 28 Aug 2009 18:40:34 +0000 (14:40 -0400)
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>
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/rx.c

index d231c9323ad14a2b3c96f00d716486f922716d76..020a94a31106ab6668166203601d4a6fb12be384 100644 (file)
@@ -12,7 +12,11 @@ static inline int drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
 
 static inline int drv_start(struct ieee80211_local *local)
 {
-       int ret = local->ops->start(&local->hw);
+       int ret;
+
+       local->started = true;
+       smp_mb();
+       ret = local->ops->start(&local->hw);
        trace_drv_start(local, ret);
        return ret;
 }
@@ -21,6 +25,14 @@ static inline void drv_stop(struct ieee80211_local *local)
 {
        local->ops->stop(&local->hw);
        trace_drv_stop(local);
+
+       /* sync away all work on the tasklet before clearing started */
+       tasklet_disable(&local->tasklet);
+       tasklet_enable(&local->tasklet);
+
+       barrier();
+
+       local->started = false;
 }
 
 static inline int drv_add_interface(struct ieee80211_local *local,
index fa930e01295f98f29969d21b87cd67a9990386e8..dbd8411cc1bd6df502c6b53f95d318432d87f3d7 100644 (file)
@@ -667,6 +667,9 @@ struct ieee80211_local {
         */
        bool quiescing;
 
+       /* device is started */
+       bool started;
+
        int tx_headroom; /* required headroom for hardware/radiotap */
 
        /* Tasklet and skb queue to process calls from IRQ mode. All frames
index 5940e69fa33cd5f2dded52d2ce528a0ca8135e4c..d134bd79972f831964262acb0de1f2cfc241efbf 100644 (file)
@@ -277,11 +277,6 @@ static int ieee80211_open(struct net_device *dev)
                }
        }
 
-       if (local->open_count == 0) {
-               tasklet_enable(&local->tx_pending_tasklet);
-               tasklet_enable(&local->tasklet);
-       }
-
        /*
         * set_multicast_list will be invoked by the networking core
         * which will check whether any increments here were done in
@@ -552,11 +547,9 @@ static int ieee80211_stop(struct net_device *dev)
        ieee80211_recalc_ps(local, -1);
 
        if (local->open_count == 0) {
+               ieee80211_clear_tx_pending(local);
                ieee80211_stop_device(local);
 
-               tasklet_disable(&local->tx_pending_tasklet);
-               tasklet_disable(&local->tasklet);
-
                /* no reconfiguring after stop! */
                hw_reconf_flags = 0;
        }
index dd3b0816614d11e11f4daccb1931937b0d3ef8b1..797f53942e5f870093ff771b3d3bb523c664044a 100644 (file)
@@ -715,12 +715,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                skb_queue_head_init(&local->pending[i]);
        tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
                     (unsigned long)local);
-       tasklet_disable(&local->tx_pending_tasklet);
 
        tasklet_init(&local->tasklet,
                     ieee80211_tasklet_handler,
                     (unsigned long) local);
-       tasklet_disable(&local->tasklet);
 
        skb_queue_head_init(&local->skb_queue);
        skb_queue_head_init(&local->skb_queue_unreliable);
index dff2239db6e260a189673d6762ddd6706ea48252..b98f1afbfebfaa5606b1440523fabb6393c7b5a6 100644 (file)
@@ -2471,6 +2471,15 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                return;
        }
 
+       /*
+        * The same happens when we're not even started,
+        * but that's worth a warning.
+        */
+       if (WARN_ON(!local->started)) {
+               kfree_skb(skb);
+               return;
+       }
+
        if (status->flag & RX_FLAG_HT) {
                /* rate_idx is MCS index */
                if (WARN_ON(status->rate_idx < 0 ||