ath9k: add some rx path fixes
authorFelix Fietkau <nbd@openwrt.org>
Mon, 19 May 2014 19:51:45 +0000 (19:51 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 19 May 2014 19:51:45 +0000 (19:51 +0000)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
SVN-Revision: 40780

package/kernel/mac80211/patches/300-pending_work.patch
package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch
package/kernel/mac80211/patches/523-ath9k_use_configured_antenna_gain.patch
package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch
package/kernel/mac80211/patches/552-ath9k_p2p_ps_support.patch

index ce19e7db5fc69cd030a2df4baeef891f1e305b3d..ef81721529eee36aa5faa2a55a14cd6d887d177f 100644 (file)
@@ -1,3 +1,26 @@
+commit 230ab8c1880266c9cfceac962e2d48309dea79a7
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Mon May 19 21:48:56 2014 +0200
+
+    ath9k: re-schedule rx processing after budget exceeded
+    
+    Should improve rx stability under load
+    
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+commit 27647baeaee1b12bc3c57ccf1c7eba53bcd7fe53
+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>
+
 commit 92e9dd662542683856e62a5e7e43fcf5b9da5c4a
 Author: Henning Rogge <hrogge@gmail.com>
 Date:   Thu May 1 10:03:46 2014 +0200
@@ -359,7 +382,97 @@ Date:   Sun Apr 6 23:35:28 2014 +0200
                __skb_queue_head_init(&tid->retry_q);
 --- a/drivers/net/wireless/ath/ath9k/recv.c
 +++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -975,6 +975,7 @@ int ath_rx_tasklet(struct ath_softc *sc,
+@@ -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;
+ }
+@@ -106,7 +108,7 @@ static void ath_opmode_init(struct ath_s
+ }
+ static bool ath_rx_edma_buf_link(struct ath_softc *sc,
+-                               enum ath9k_rx_qtype qtype)
++                               enum ath9k_rx_qtype qtype, bool flush)
+ {
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_rx_edma *rx_edma;
+@@ -127,7 +129,8 @@ static bool ath_rx_edma_buf_link(struct 
+                               ah->caps.rx_status_len, DMA_TO_DEVICE);
+       SKB_CB_ATHBUF(skb) = bf;
+-      ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype);
++      if (!flush)
++              ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype);
+       __skb_queue_tail(&rx_edma->rx_fifo, skb);
+       return true;
+@@ -145,7 +148,7 @@ static void ath_rx_addbuffer_edma(struct
+       }
+       list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list)
+-              if (!ath_rx_edma_buf_link(sc, qtype))
++              if (!ath_rx_edma_buf_link(sc, qtype, false))
+                       break;
+ }
+@@ -442,7 +445,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 */
+@@ -636,7 +639,7 @@ static bool ath_edma_get_buffers(struct 
+       if (ret == -EINVAL) {
+               /* corrupt descriptor, skip this one and the following one */
+               list_add_tail(&bf->list, &sc->rx.rxbuf);
+-              ath_rx_edma_buf_link(sc, qtype);
++              ath_rx_edma_buf_link(sc, qtype, false);
+               skb = skb_peek(&rx_edma->rx_fifo);
+               if (skb) {
+@@ -645,7 +648,7 @@ static bool ath_edma_get_buffers(struct 
+                       __skb_unlink(skb, &rx_edma->rx_fifo);
+                       list_add_tail(&bf->list, &sc->rx.rxbuf);
+-                      ath_rx_edma_buf_link(sc, qtype);
++                      ath_rx_edma_buf_link(sc, qtype, false);
+               }
+               bf = NULL;
+@@ -975,6 +978,7 @@ int ath_rx_tasklet(struct ath_softc *sc,
        u64 tsf = 0;
        unsigned long flags;
        dma_addr_t new_buf_addr;
@@ -367,7 +480,7 @@ Date:   Sun Apr 6 23:35:28 2014 +0200
  
        if (edma)
                dma_type = DMA_BIDIRECTIONAL;
-@@ -1113,15 +1114,17 @@ requeue_drop_frag:
+@@ -1113,15 +1117,17 @@ requeue_drop_frag:
                }
  requeue:
                list_add_tail(&bf->list, &sc->rx.rxbuf);
@@ -375,10 +488,12 @@ Date:   Sun Apr 6 23:35:28 2014 +0200
 -                      continue;
  
                if (edma) {
-                       ath_rx_edma_buf_link(sc, qtype);
+-                      ath_rx_edma_buf_link(sc, qtype);
++                      ath_rx_edma_buf_link(sc, qtype, flush);
                } else {
-                       ath_rx_buf_relink(sc, bf);
+-                      ath_rx_buf_relink(sc, bf);
 -                      ath9k_hw_rxena(ah);
++                      ath_rx_buf_relink(sc, bf, flush);
 +                      if (!flush)
 +                              ath9k_hw_rxena(ah);
                }
@@ -388,6 +503,13 @@ Date:   Sun Apr 6 23:35:28 2014 +0200
        } while (1);
  
        if (!(ah->imask & ATH9K_INT_RXEOL)) {
+@@ -1129,5 +1135,5 @@ requeue:
+               ath9k_hw_set_interrupts(ah);
+       }
+-      return 0;
++      return !budget;
+ }
 --- a/drivers/net/wireless/ath/ath9k/ahb.c
 +++ b/drivers/net/wireless/ath/ath9k/ahb.c
 @@ -86,7 +86,6 @@ static int ath_ahb_probe(struct platform
@@ -565,3 +687,49 @@ Date:   Sun Apr 6 23:35:28 2014 +0200
                                sta->last_rx_rate_idx = status->rate_idx;
                                sta->last_rx_rate_flag = status->flag;
                                sta->last_rx_rate_vht_flag = status->vht_flag;
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -442,6 +442,8 @@ void ath9k_tasklet(unsigned long data)
+       ath9k_ps_wakeup(sc);
+       spin_lock(&sc->sc_pcu_lock);
++      sc->intrstatus = 0;
++
+       if (status & ATH9K_INT_FATAL) {
+               type = RESET_TYPE_FATAL_INT;
+               ath9k_queue_reset(sc, type);
+@@ -510,10 +512,12 @@ void ath9k_tasklet(unsigned long data)
+       if (status & rxmask) {
+               /* Check for high priority Rx first */
+               if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
+-                  (status & ATH9K_INT_RXHP))
+-                      ath_rx_tasklet(sc, 0, true);
++                  (status & ATH9K_INT_RXHP) &&
++                  ath_rx_tasklet(sc, 0, true))
++                      sc->intrstatus |= ATH9K_INT_RXHP;
+-              ath_rx_tasklet(sc, 0, false);
++              if (ath_rx_tasklet(sc, 0, false))
++                      sc->intrstatus |= ATH9K_INT_RXLP;
+       }
+       if (status & ATH9K_INT_TX) {
+@@ -541,6 +545,9 @@ void ath9k_tasklet(unsigned long data)
+       /* re-enable hardware interrupt */
+       ath9k_hw_enable_interrupts(ah);
++      if (sc->intrstatus)
++              tasklet_schedule(&sc->intr_tq);
++
+ out:
+       spin_unlock(&sc->sc_pcu_lock);
+       ath9k_ps_restore(sc);
+@@ -607,7 +614,7 @@ irqreturn_t ath_isr(int irq, void *dev)
+               return IRQ_NONE;
+       /* Cache the status */
+-      sc->intrstatus = status;
++      sc->intrstatus |= status;
+       if (status & SCHED_INTR)
+               sched = true;
index 24bc0626ede87bd4057a66f5c3a8f91c2191186f..ebc3633f60fa8f1547ecd822464b318873d34492 100644 (file)
@@ -14,7 +14,7 @@
  
  out:
        spin_unlock_bh(&sc->sc_pcu_lock);
-@@ -1370,6 +1374,7 @@ static int ath9k_config(struct ieee80211
+@@ -1377,6 +1381,7 @@ static int ath9k_config(struct ieee80211
                sc->config.txpowlimit = 2 * conf->power_level;
                ath9k_cmn_update_txpow(ah, sc->curtxpow,
                                       sc->config.txpowlimit, &sc->curtxpow);
index b84a99134a63916570e460bec3971578f7e02750..2903bd9d14a8d14a7ca7340e1d9a4b480e2da56c 100644 (file)
@@ -21,7 +21,7 @@
        if (ant_gain > max_gain)
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1370,7 +1370,10 @@ static int ath9k_config(struct ieee80211
+@@ -1377,7 +1377,10 @@ static int ath9k_config(struct ieee80211
        }
  
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
index 44aa905649a0825b2decf908861a0f68aa6b411a..419717ae0a09a57d2dc984e9bda3e6942e5bb132 100644 (file)
                REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
 --- a/drivers/net/wireless/ath/ath9k/main.c
 +++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -603,6 +603,11 @@ irqreturn_t ath_isr(int irq, void *dev)
+@@ -610,6 +610,11 @@ irqreturn_t ath_isr(int irq, void *dev)
        ath9k_debug_sync_cause(sc, sync_cause);
        status &= ah->imask;    /* discard unasked-for bits */
  
index 8cf9e612c5e46e2b800a5c0cf9feb7dd148da0e4..3b09aef608b7e3767b8ad5aeae17f3cb81e1bb1a 100644 (file)
@@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
        return true;
  }
  
-@@ -1128,6 +1130,8 @@ static int ath9k_add_interface(struct ie
+@@ -1135,6 +1137,8 @@ static int ath9k_add_interface(struct ie
        if (ath9k_uses_beacons(vif->type))
                ath9k_beacon_assign_slot(sc, vif);
  
@@ -36,7 +36,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
        an->sc = sc;
        an->sta = NULL;
        an->vif = vif;
-@@ -1172,6 +1176,29 @@ static int ath9k_change_interface(struct
+@@ -1179,6 +1183,29 @@ static int ath9k_change_interface(struct
        return 0;
  }
  
@@ -66,7 +66,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  static void ath9k_remove_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif)
  {
-@@ -1183,6 +1210,13 @@ static void ath9k_remove_interface(struc
+@@ -1190,6 +1217,13 @@ static void ath9k_remove_interface(struc
  
        mutex_lock(&sc->mutex);
  
@@ -80,7 +80,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
        sc->nvifs--;
        sc->tx99_vif = NULL;
  
-@@ -1649,6 +1683,72 @@ static void ath9k_bss_assoc_iter(void *d
+@@ -1656,6 +1690,72 @@ static void ath9k_bss_assoc_iter(void *d
                ath9k_set_assoc_state(sc, vif);
  }
  
@@ -153,7 +153,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif,
                                   struct ieee80211_bss_conf *bss_conf,
-@@ -1723,6 +1823,12 @@ static void ath9k_bss_info_changed(struc
+@@ -1730,6 +1830,12 @@ static void ath9k_bss_info_changed(struc
                }
        }
  
@@ -237,7 +237,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
 --- a/drivers/net/wireless/ath/ath9k/recv.c
 +++ b/drivers/net/wireless/ath/ath9k/recv.c
-@@ -539,6 +539,9 @@ static void ath_rx_ps_beacon(struct ath_
+@@ -542,6 +542,9 @@ static void ath_rx_ps_beacon(struct ath_
                ath_dbg(common, PS,
                        "Reconfigure beacon timers based on synchronized timestamp\n");
                ath9k_set_beacon(sc);