ath9k: fix an rx descriptor processing race condition
authorFelix Fietkau <nbd@openwrt.org>
Sat, 10 Aug 2013 14:04:15 +0000 (14:04 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sat, 10 Aug 2013 14:04:15 +0000 (14:04 +0000)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Backport of r37746

SVN-Revision: 37747

package/mac80211/patches/556-ath9k_fix_rx_race.patch [new file with mode: 0644]
package/mac80211/patches/560-ath9k_tx_queueing_rework.patch

diff --git a/package/mac80211/patches/556-ath9k_fix_rx_race.patch b/package/mac80211/patches/556-ath9k_fix_rx_race.patch
new file mode 100644 (file)
index 0000000..69030d2
--- /dev/null
@@ -0,0 +1,82 @@
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -79,10 +79,6 @@ struct ath_config {
+                      sizeof(struct ath_buf_state));           \
+       } while (0)
+-#define ATH_RXBUF_RESET(_bf) do {             \
+-              (_bf)->bf_stale = false;        \
+-      } while (0)
+-
+ /**
+  * enum buffer_type - Buffer type flags
+  *
+@@ -317,6 +313,7 @@ struct ath_rx {
+       struct ath_descdma rxdma;
+       struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
++      struct ath_buf *buf_hold;
+       struct sk_buff *frag;
+       u32 ampdu_ref;
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -42,8 +42,6 @@ static void ath_rx_buf_link(struct ath_s
+       struct ath_desc *ds;
+       struct sk_buff *skb;
+-      ATH_RXBUF_RESET(bf);
+-
+       ds = bf->bf_desc;
+       ds->ds_link = 0; /* link to null */
+       ds->ds_data = bf->bf_buf_addr;
+@@ -70,6 +68,14 @@ static void ath_rx_buf_link(struct ath_s
+       sc->rx.rxlink = &ds->ds_link;
+ }
++static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_buf *bf)
++{
++      if (sc->rx.buf_hold)
++              ath_rx_buf_link(sc, sc->rx.buf_hold);
++
++      sc->rx.buf_hold = bf;
++}
++
+ static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
+ {
+       /* XXX block beacon interrupts */
+@@ -117,7 +123,6 @@ static bool ath_rx_edma_buf_link(struct 
+       skb = bf->bf_mpdu;
+-      ATH_RXBUF_RESET(bf);
+       memset(skb->data, 0, ah->caps.rx_status_len);
+       dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+                               ah->caps.rx_status_len, DMA_TO_DEVICE);
+@@ -432,6 +437,7 @@ int ath_startrecv(struct ath_softc *sc)
+       if (list_empty(&sc->rx.rxbuf))
+               goto start_recv;
++      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);
+@@ -677,6 +683,9 @@ static struct ath_buf *ath_get_next_rx_b
+       }
+       bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
++      if (bf == sc->rx.buf_hold)
++              return NULL;
++
+       ds = bf->bf_desc;
+       /*
+@@ -1391,7 +1400,7 @@ requeue:
+               if (edma) {
+                       ath_rx_edma_buf_link(sc, qtype);
+               } else {
+-                      ath_rx_buf_link(sc, bf);
++                      ath_rx_buf_relink(sc, bf);
+                       ath9k_hw_rxena(ah);
+               }
+       } while (1);
index 814bca81a6a05e89fac9fa5cbe16bd12bca7f533..c5bcbbedfc238b33756986afe1ff005c49d18813 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/net/wireless/ath/ath9k/ath9k.h
 +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
-@@ -137,7 +137,8 @@ int ath_descdma_setup(struct ath_softc *
+@@ -133,7 +133,8 @@ int ath_descdma_setup(struct ath_softc *
  #define ATH_AGGR_ENCRYPTDELIM      10
  /* minimum h/w qdepth to be sustained to maximize aggregation */
  #define ATH_AGGR_MIN_QDEPTH        2
@@ -10,7 +10,7 @@
  
  #define IEEE80211_SEQ_SEQ_SHIFT    4
  #define IEEE80211_SEQ_MAX          4096
-@@ -174,12 +175,6 @@ int ath_descdma_setup(struct ath_softc *
+@@ -170,12 +171,6 @@ int ath_descdma_setup(struct ath_softc *
  
  #define ATH_TX_COMPLETE_POLL_INT      1000
  
@@ -23,7 +23,7 @@
  #define ATH_TXFIFO_DEPTH 8
  struct ath_txq {
        int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
-@@ -212,8 +207,9 @@ struct ath_frame_info {
+@@ -208,8 +203,9 @@ struct ath_frame_info {
        int framelen;
        enum ath9k_key_type keytype;
        u8 keyix;
@@ -34,7 +34,7 @@
  };
  
  struct ath_buf_state {
-@@ -241,6 +237,7 @@ struct ath_buf {
+@@ -237,6 +233,7 @@ struct ath_buf {
  struct ath_atx_tid {
        struct list_head list;
        struct sk_buff_head buf_q;
@@ -42,7 +42,7 @@
        struct ath_node *an;
        struct ath_atx_ac *ac;
        unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
-@@ -268,6 +265,7 @@ struct ath_node {
+@@ -264,6 +261,7 @@ struct ath_node {
        u8 mpdudensity;
  
        bool sleeping;
@@ -50,7 +50,7 @@
  
  #if defined(CPTCFG_MAC80211_DEBUGFS) && defined(CPTCFG_ATH9K_DEBUGFS)
        struct dentry *node_stat;
-@@ -367,6 +365,7 @@ void ath9k_release_buffered_frames(struc
+@@ -364,6 +362,7 @@ void ath9k_release_buffered_frames(struc
  /********/
  
  struct ath_vif {