2014-05-23 18:48:35 +00:00
|
|
|
commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873
|
2014-05-19 19:51:45 +00:00
|
|
|
Author: Felix Fietkau <nbd@openwrt.org>
|
2014-05-23 18:48:35 +00:00
|
|
|
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>
|
|
|
|
|
2014-05-20 09:35:17 +00:00
|
|
|
--- 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--)
|
2014-05-23 18:48:35 +00:00
|
|
|
--- 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|