ath5k: decrease interrupt load for rx/tx interrupts
authorFelix Fietkau <nbd@openwrt.org>
Sun, 10 Apr 2011 16:23:39 +0000 (16:23 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 10 Apr 2011 16:23:39 +0000 (16:23 +0000)
SVN-Revision: 26579

package/mac80211/patches/470-ath5k_decrease_irq_load.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/470-ath5k_decrease_irq_load.patch b/package/mac80211/patches/470-ath5k_decrease_irq_load.patch
new file mode 100644 (file)
index 0000000..5273bb0
--- /dev/null
@@ -0,0 +1,140 @@
+--- a/drivers/net/wireless/ath/ath5k/ath5k.h
++++ b/drivers/net/wireless/ath/ath5k/ath5k.h
+@@ -872,6 +872,19 @@ enum ath5k_int {
+       AR5K_INT_QTRIG  =       0x40000000, /* Non common */
+       AR5K_INT_GLOBAL =       0x80000000,
++      AR5K_INT_TX_ALL = AR5K_INT_TXOK
++              | AR5K_INT_TXDESC
++              | AR5K_INT_TXERR
++              | AR5K_INT_TXEOL
++              | AR5K_INT_TXURN,
++
++      AR5K_INT_RX_ALL = AR5K_INT_RXOK
++              | AR5K_INT_RXDESC
++              | AR5K_INT_RXERR
++              | AR5K_INT_RXNOFRM
++              | AR5K_INT_RXEOL
++              | AR5K_INT_RXORN,
++
+       AR5K_INT_COMMON  = AR5K_INT_RXOK
+               | AR5K_INT_RXDESC
+               | AR5K_INT_RXERR
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_soft
+ }
+ static void
++ath5k_set_current_imask(struct ath5k_softc *sc)
++{
++      enum ath5k_int imask = sc->imask;
++      unsigned long flags;
++
++      spin_lock_irqsave(&sc->irqlock, flags);
++      if (sc->rx_pending)
++              imask &= ~AR5K_INT_RX_ALL;
++      if (sc->tx_pending)
++              imask &= ~AR5K_INT_TX_ALL;
++      ath5k_hw_set_imr(sc->ah, imask);
++      spin_unlock_irqrestore(&sc->irqlock, flags);
++}
++
++static void
+ ath5k_tasklet_rx(unsigned long data)
+ {
+       struct ath5k_rx_status rs = {};
+@@ -1506,6 +1521,8 @@ next:
+       } while (ath5k_rxbuf_setup(sc, bf) == 0);
+ unlock:
+       spin_unlock(&sc->rxbuflock);
++      sc->rx_pending = false;
++      ath5k_set_current_imask(sc);
+ }
+@@ -1693,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)
+       for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
+               if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
+                       ath5k_tx_processq(sc, &sc->txqs[i]);
++
++      sc->tx_pending = false;
++      ath5k_set_current_imask(sc);
+ }
+@@ -2122,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k
+        * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
+ }
++static void
++ath5k_schedule_rx(struct ath5k_softc *sc)
++{
++      sc->rx_pending = true;
++      tasklet_schedule(&sc->rxtq);
++}
++
++static void
++ath5k_schedule_tx(struct ath5k_softc *sc)
++{
++      sc->tx_pending = true;
++      tasklet_schedule(&sc->txtq);
++}
++
+ irqreturn_t
+ ath5k_intr(int irq, void *dev_id)
+ {
+@@ -2164,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)
+                               ieee80211_queue_work(sc->hw, &sc->reset_work);
+                       }
+                       else
+-                              tasklet_schedule(&sc->rxtq);
++                              ath5k_schedule_rx(sc);
+               } else {
+                       if (status & AR5K_INT_SWBA) {
+                               tasklet_hi_schedule(&sc->beacontq);
+@@ -2182,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)
+                               ath5k_hw_update_tx_triglevel(ah, true);
+                       }
+                       if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
+-                              tasklet_schedule(&sc->rxtq);
++                              ath5k_schedule_rx(sc);
+                       if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
+                                       | AR5K_INT_TXERR | AR5K_INT_TXEOL))
+-                              tasklet_schedule(&sc->txtq);
++                              ath5k_schedule_tx(sc);
+                       if (status & AR5K_INT_BMISS) {
+                               /* TODO */
+                       }
+@@ -2204,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)
+       } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
++      if (sc->rx_pending || sc->tx_pending)
++              ath5k_set_current_imask(sc);
++
+       if (unlikely(!counter))
+               ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
+@@ -2575,6 +2612,8 @@ done:
+ static void stop_tasklets(struct ath5k_softc *sc)
+ {
++      sc->rx_pending = false;
++      sc->tx_pending = false;
+       tasklet_kill(&sc->rxtq);
+       tasklet_kill(&sc->txtq);
+       tasklet_kill(&sc->calib);
+--- a/drivers/net/wireless/ath/ath5k/base.h
++++ b/drivers/net/wireless/ath/ath5k/base.h
+@@ -207,6 +207,10 @@ struct ath5k_softc {
+       enum ath5k_int          imask;          /* interrupt mask copy */
++      spinlock_t              irqlock;
++      bool                    rx_pending;     /* rx tasklet pending */
++      bool                    tx_pending;     /* tx tasklet pending */
++
+       u8                      lladdr[ETH_ALEN];
+       u8                      bssidmask[ETH_ALEN];