164 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873
 | 
						|
Author: Felix Fietkau <nbd@openwrt.org>
 | 
						|
Date:   Fri May 23 19:58:14 2014 +0200
 | 
						|
 | 
						|
    mac80211: reduce packet loss notifications under load
 | 
						|
    
 | 
						|
    During strong signal fluctuations under high throughput, few consecutive
 | 
						|
    failed A-MPDU transmissions can easily trigger packet loss notification,
 | 
						|
    and thus (in AP mode) client disconnection.
 | 
						|
    
 | 
						|
    Reduce the number of false positives by checking the A-MPDU status flag
 | 
						|
    and treating a failed A-MPDU as a single packet.
 | 
						|
    
 | 
						|
    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 | 
						|
 | 
						|
commit 7b7843a36fbcc568834404c7430ff895d8502131
 | 
						|
Author: Felix Fietkau <nbd@openwrt.org>
 | 
						|
Date:   Fri May 23 19:26:32 2014 +0200
 | 
						|
 | 
						|
    mac80211: fix a memory leak on sta rate selection table
 | 
						|
    
 | 
						|
    Cc: stable@vger.kernel.org
 | 
						|
    Reported-by: Christophe Prévotaux <cprevotaux@nltinc.com>
 | 
						|
    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 | 
						|
 | 
						|
commit 96892d6aa0a153423070addf3070bc79578b3897
 | 
						|
Author: Felix Fietkau <nbd@openwrt.org>
 | 
						|
Date:   Mon May 19 21:20:49 2014 +0200
 | 
						|
 | 
						|
    ath9k: avoid passing buffers to the hardware during flush
 | 
						|
    
 | 
						|
    The commit "ath9k: fix possible hang on flush" changed the receive code
 | 
						|
    to always link rx descriptors of processed frames, even when flushing.
 | 
						|
    In some cases, this leads to flushed rx buffers being passed to the
 | 
						|
    hardware while rx is already stopped.
 | 
						|
    
 | 
						|
    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 | 
						|
 | 
						|
--- a/drivers/net/wireless/ath/ath9k/recv.c
 | 
						|
+++ b/drivers/net/wireless/ath/ath9k/recv.c
 | 
						|
@@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_slee
 | 
						|
  * buffer (or rx fifo). This can incorrectly acknowledge packets
 | 
						|
  * to a sender if last desc is self-linked.
 | 
						|
  */
 | 
						|
-static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf)
 | 
						|
+static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf,
 | 
						|
+			    bool flush)
 | 
						|
 {
 | 
						|
 	struct ath_hw *ah = sc->sc_ah;
 | 
						|
 	struct ath_common *common = ath9k_hw_common(ah);
 | 
						|
@@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_s
 | 
						|
 			     common->rx_bufsize,
 | 
						|
 			     0);
 | 
						|
 
 | 
						|
-	if (sc->rx.rxlink == NULL)
 | 
						|
-		ath9k_hw_putrxbuf(ah, bf->bf_daddr);
 | 
						|
-	else
 | 
						|
+	if (sc->rx.rxlink)
 | 
						|
 		*sc->rx.rxlink = bf->bf_daddr;
 | 
						|
+	else if (!flush)
 | 
						|
+		ath9k_hw_putrxbuf(ah, bf->bf_daddr);
 | 
						|
 
 | 
						|
 	sc->rx.rxlink = &ds->ds_link;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf)
 | 
						|
+static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf,
 | 
						|
+			      bool flush)
 | 
						|
 {
 | 
						|
 	if (sc->rx.buf_hold)
 | 
						|
-		ath_rx_buf_link(sc, sc->rx.buf_hold);
 | 
						|
+		ath_rx_buf_link(sc, sc->rx.buf_hold, flush);
 | 
						|
 
 | 
						|
 	sc->rx.buf_hold = bf;
 | 
						|
 }
 | 
						|
@@ -442,7 +444,7 @@ int ath_startrecv(struct ath_softc *sc)
 | 
						|
 	sc->rx.buf_hold = NULL;
 | 
						|
 	sc->rx.rxlink = NULL;
 | 
						|
 	list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
 | 
						|
-		ath_rx_buf_link(sc, bf);
 | 
						|
+		ath_rx_buf_link(sc, bf, false);
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	/* We could have deleted elements so the list may be empty now */
 | 
						|
@@ -1118,12 +1120,12 @@ requeue_drop_frag:
 | 
						|
 requeue:
 | 
						|
 		list_add_tail(&bf->list, &sc->rx.rxbuf);
 | 
						|
 
 | 
						|
-		if (edma) {
 | 
						|
-			ath_rx_edma_buf_link(sc, qtype);
 | 
						|
-		} else {
 | 
						|
-			ath_rx_buf_relink(sc, bf);
 | 
						|
+		if (!edma) {
 | 
						|
+			ath_rx_buf_relink(sc, bf, flush);
 | 
						|
 			if (!flush)
 | 
						|
 				ath9k_hw_rxena(ah);
 | 
						|
+		} else if (!flush) {
 | 
						|
+			ath_rx_edma_buf_link(sc, qtype);
 | 
						|
 		}
 | 
						|
 
 | 
						|
 		if (!budget--)
 | 
						|
--- a/net/mac80211/sta_info.c
 | 
						|
+++ b/net/mac80211/sta_info.c
 | 
						|
@@ -227,6 +227,7 @@ struct sta_info *sta_info_get_by_idx(str
 | 
						|
  */
 | 
						|
 void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
 | 
						|
 {
 | 
						|
+	struct ieee80211_sta_rates *rates;
 | 
						|
 	int i;
 | 
						|
 
 | 
						|
 	if (sta->rate_ctrl)
 | 
						|
@@ -238,6 +239,10 @@ void sta_info_free(struct ieee80211_loca
 | 
						|
 		kfree(sta->tx_lat);
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	rates = rcu_dereference_protected(sta->sta.rates, true);
 | 
						|
+	if (rates)
 | 
						|
+		kfree(rates);
 | 
						|
+
 | 
						|
 	sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
 | 
						|
 
 | 
						|
 	kfree(sta);
 | 
						|
--- a/net/mac80211/status.c
 | 
						|
+++ b/net/mac80211/status.c
 | 
						|
@@ -541,6 +541,23 @@ static void ieee80211_tx_latency_end_msr
 | 
						|
  */
 | 
						|
 #define STA_LOST_PKT_THRESHOLD	50
 | 
						|
 
 | 
						|
+static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
 | 
						|
+{
 | 
						|
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 | 
						|
+
 | 
						|
+	/* This packet was aggregated but doesn't carry status info */
 | 
						|
+	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
 | 
						|
+	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
 | 
						|
+		return;
 | 
						|
+
 | 
						|
+	if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD)
 | 
						|
+		return;
 | 
						|
+
 | 
						|
+	cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
 | 
						|
+				    sta->lost_packets, GFP_ATOMIC);
 | 
						|
+	sta->lost_packets = 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
 void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 | 
						|
 {
 | 
						|
 	struct sk_buff *skb2;
 | 
						|
@@ -680,12 +697,8 @@ void ieee80211_tx_status(struct ieee8021
 | 
						|
 			if (info->flags & IEEE80211_TX_STAT_ACK) {
 | 
						|
 				if (sta->lost_packets)
 | 
						|
 					sta->lost_packets = 0;
 | 
						|
-			} else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) {
 | 
						|
-				cfg80211_cqm_pktloss_notify(sta->sdata->dev,
 | 
						|
-							    sta->sta.addr,
 | 
						|
-							    sta->lost_packets,
 | 
						|
-							    GFP_ATOMIC);
 | 
						|
-				sta->lost_packets = 0;
 | 
						|
+			} else {
 | 
						|
+				ieee80211_lost_packet(sta, skb);
 | 
						|
 			}
 | 
						|
 		}
 | 
						|
 
 |