X-Git-Url: https://git.archive.openwrt.org/?a=blobdiff_plain;f=package%2Fmac80211%2Fpatches%2F300-pending_work.patch;h=64067f2d48311cbecdb3e01b4221583bd88f2c1a;hb=c9641b552eb8ecccb7b0e31a0f7bac250a930e25;hp=0ca6a02b5f30c50fdc000a8d23e7b46412e9bda9;hpb=e690881d079b342e8a8143747690cc503e862dc1;p=openwrt.git diff --git a/package/mac80211/patches/300-pending_work.patch b/package/mac80211/patches/300-pending_work.patch index 0ca6a02b5f..64067f2d48 100644 --- a/package/mac80211/patches/300-pending_work.patch +++ b/package/mac80211/patches/300-pending_work.patch @@ -615,6 +615,28 @@ #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %pM aid %d: PS buffer for AC %d\n", sta->sta.addr, sta->sta.aid, ac); +@@ -1060,6 +1065,7 @@ static bool ieee80211_tx_prep_agg(struct + { + bool queued = false; + bool reset_agg_timer = false; ++ struct sk_buff *purge_skb = NULL; + + if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { + info->flags |= IEEE80211_TX_CTL_AMPDU; +@@ -1101,8 +1107,13 @@ static bool ieee80211_tx_prep_agg(struct + info->control.vif = &tx->sdata->vif; + info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; + __skb_queue_tail(&tid_tx->pending, skb); ++ if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER) ++ purge_skb = __skb_dequeue(&tid_tx->pending); + } + spin_unlock(&tx->sta->lock); ++ ++ if (purge_skb) ++ dev_kfree_skb(purge_skb); + } + + /* reset session timer */ --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -480,7 +480,7 @@ struct ieee80211_if_ibss { @@ -1592,7 +1614,37 @@ mode = ATH9K_PM_NETWORK_SLEEP; else goto unlock; -@@ -1955,6 +1957,7 @@ static void ath9k_config_bss(struct ath_ +@@ -1559,6 +1561,7 @@ static int ath9k_config(struct ieee80211 + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &hw->conf; ++ bool reset_channel = false; + + ath9k_ps_wakeup(sc); + mutex_lock(&sc->mutex); +@@ -1567,6 +1570,12 @@ static int ath9k_config(struct ieee80211 + sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); + if (sc->ps_idle) + ath_cancel_work(sc); ++ else ++ /* ++ * The chip needs a reset to properly wake up from ++ * full sleep ++ */ ++ reset_channel = ah->chip_fullsleep; + } + + /* +@@ -1595,7 +1604,7 @@ static int ath9k_config(struct ieee80211 + } + } + +- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ++ if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { + struct ieee80211_channel *curchan = hw->conf.channel; + int pos = curchan->hw_value; + int old_pos = -1; +@@ -1955,6 +1964,7 @@ static void ath9k_config_bss(struct ath_ sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); memset(&sc->caldata, 0, sizeof(sc->caldata)); @@ -1600,7 +1652,7 @@ } } -@@ -2300,6 +2303,7 @@ static int ath9k_tx_last_beacon(struct i +@@ -2300,6 +2310,7 @@ static int ath9k_tx_last_beacon(struct i struct ath_vif *avp; struct ath_buf *bf; struct ath_tx_status ts; @@ -1608,7 +1660,7 @@ int status; vif = sc->beacon.bslot[0]; -@@ -2310,7 +2314,7 @@ static int ath9k_tx_last_beacon(struct i +@@ -2310,7 +2321,7 @@ static int ath9k_tx_last_beacon(struct i if (!avp->is_bslot_active) return 0; @@ -1869,3 +1921,58 @@ if (on) REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, +--- a/drivers/net/wireless/rt2x00/rt2x00dev.c ++++ b/drivers/net/wireless/rt2x00/rt2x00dev.c +@@ -430,10 +430,14 @@ void rt2x00lib_txdone(struct queue_entry + /* + * If the data queue was below the threshold before the txdone + * handler we must make sure the packet queue in the mac80211 stack +- * is reenabled when the txdone handler has finished. ++ * is reenabled when the txdone handler has finished. This has to be ++ * serialized with rt2x00mac_tx(), otherwise we can wake up queue ++ * before it was stopped. + */ ++ spin_lock_bh(&entry->queue->tx_lock); + if (!rt2x00queue_threshold(entry->queue)) + rt2x00queue_unpause_queue(entry->queue); ++ spin_unlock_bh(&entry->queue->tx_lock); + } + EXPORT_SYMBOL_GPL(rt2x00lib_txdone); + +--- a/drivers/net/wireless/rt2x00/rt2x00mac.c ++++ b/drivers/net/wireless/rt2x00/rt2x00mac.c +@@ -152,13 +152,22 @@ void rt2x00mac_tx(struct ieee80211_hw *h + if (unlikely(rt2x00queue_write_tx_frame(queue, skb, false))) + goto exit_fail; + ++ /* ++ * Pausing queue has to be serialized with rt2x00lib_txdone(). Note ++ * we should not use spin_lock_bh variant as bottom halve was already ++ * disabled before ieee80211_xmit() call. ++ */ ++ spin_lock(&queue->tx_lock); + if (rt2x00queue_threshold(queue)) + rt2x00queue_pause_queue(queue); ++ spin_unlock(&queue->tx_lock); + + return; + + exit_fail: ++ spin_lock(&queue->tx_lock); + rt2x00queue_pause_queue(queue); ++ spin_unlock(&queue->tx_lock); + exit_free_skb: + ieee80211_free_txskb(hw, skb); + } +--- a/drivers/net/wireless/rt2x00/rt2x00queue.c ++++ b/drivers/net/wireless/rt2x00/rt2x00queue.c +@@ -619,6 +619,9 @@ int rt2x00queue_write_tx_frame(struct da + else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) + rt2x00queue_align_frame(skb); + ++ /* ++ * That function must be called with bh disabled. ++ */ + spin_lock(&queue->tx_lock); + + if (unlikely(rt2x00queue_full(queue))) {