mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-14 00:04:00 +08:00
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>
This commit is contained in:
parent
3d54d25515
commit
ea77f12f2c
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 ||
|
||||
|
Loading…
Reference in New Issue
Block a user