ath9k: optimize memory allocations - improves performance and reduces ath9k RAM usage...
authorFelix Fietkau <nbd@openwrt.org>
Wed, 26 Jan 2011 17:28:12 +0000 (17:28 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Wed, 26 Jan 2011 17:28:12 +0000 (17:28 +0000)
SVN-Revision: 25115

package/mac80211/patches/550-ath9k_optimize_memory_allocation.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/550-ath9k_optimize_memory_allocation.patch b/package/mac80211/patches/550-ath9k_optimize_memory_allocation.patch
new file mode 100644 (file)
index 0000000..8d3d62a
--- /dev/null
@@ -0,0 +1,200 @@
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -1291,6 +1291,11 @@ static void ath9k_stop(struct ieee80211_
+       } else
+               sc->rx.rxlink = NULL;
++      if (sc->rx.frag) {
++              dev_kfree_skb_any(sc->rx.frag);
++              sc->rx.frag = NULL;
++      }
++
+       /* disable HAL and put h/w to sleep */
+       ath9k_hw_disable(ah);
+       ath9k_hw_configpcipowersave(ah, 1, 1);
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -209,11 +209,6 @@ static int ath_rx_edma_init(struct ath_s
+       int error = 0, i;
+       u32 size;
+-
+-      common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN +
+-                                   ah->caps.rx_status_len,
+-                                   min(common->cachelsz, (u16)64));
+-
+       ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize -
+                                   ah->caps.rx_status_len);
+@@ -300,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, in
+       sc->sc_flags &= ~SC_OP_RXFLUSH;
+       spin_lock_init(&sc->rx.rxbuflock);
++      common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + common->cachelsz +
++                           sc->sc_ah->caps.rx_status_len;
++
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               return ath_rx_edma_init(sc, nbufs);
+       } else {
+-              common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
+-                              min(common->cachelsz, (u16)64));
+-
+               ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+                       common->cachelsz, common->rx_bufsize);
+@@ -815,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_c
+       if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len))
+               return false;
+-      /*
+-       * rs_more indicates chained descriptors which can be used
+-       * to link buffers together for a sort of scatter-gather
+-       * operation.
+-       * reject the frame, we don't support scatter-gather yet and
+-       * the frame is probably corrupt anyway
+-       */
++      /* Only use error bits from the last fragment */
+       if (rx_stats->rs_more)
+-              return false;
++              return true;
+       /*
+        * The rx_stats->rs_status will not be set until the end of the
+@@ -981,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struc
+       if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
+               return -EINVAL;
++      /* Only use status info from the last fragment */
++      if (rx_stats->rs_more)
++              return 0;
++
+       ath9k_process_rssi(common, hw, hdr, rx_stats);
+       if (ath9k_process_rate(common, hw, rx_stats, rx_status))
+@@ -1582,7 +1575,7 @@ div_comb_done:
+ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
+ {
+       struct ath_buf *bf;
+-      struct sk_buff *skb = NULL, *requeue_skb;
++      struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb;
+       struct ieee80211_rx_status *rxs;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+@@ -1633,8 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc,
+               if (!skb)
+                       continue;
+-              hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len);
+-              rxs =  IEEE80211_SKB_RXCB(skb);
++              /*
++               * Take frame header from the first fragment and RX status from
++               * the last one.
++               */
++              if (sc->rx.frag)
++                      hdr_skb = sc->rx.frag;
++              else
++                      hdr_skb = skb;
++
++              hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len);
++              rxs = IEEE80211_SKB_RXCB(hdr_skb);
+               ath_debug_stat_rx(sc, &rs);
+@@ -1643,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc,
+                * chain it back at the queue without processing it.
+                */
+               if (flush)
+-                      goto requeue;
++                      goto requeue_drop_frag;
+               retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
+                                                rxs, &decrypt_error);
+               if (retval)
+-                      goto requeue;
++                      goto requeue_drop_frag;
+               rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
+               if (rs.rs_tstamp > tsf_lower &&
+@@ -1668,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc,
+                * skb and put it at the tail of the sc->rx.rxbuf list for
+                * processing. */
+               if (!requeue_skb)
+-                      goto requeue;
++                      goto requeue_drop_frag;
+               /* Unmap the frame */
+               dma_unmap_single(sc->dev, bf->bf_buf_addr,
+@@ -1679,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc,
+               if (ah->caps.rx_status_len)
+                       skb_pull(skb, ah->caps.rx_status_len);
+-              ath9k_rx_skb_postprocess(common, skb, &rs,
+-                                       rxs, decrypt_error);
++              if (!rs.rs_more)
++                      ath9k_rx_skb_postprocess(common, hdr_skb, &rs,
++                                               rxs, decrypt_error);
+               /* We will now give hardware our shiny new allocated skb */
+               bf->bf_mpdu = requeue_skb;
+@@ -1697,6 +1700,38 @@ int ath_rx_tasklet(struct ath_softc *sc,
+                       break;
+               }
++              if (rs.rs_more) {
++                      /*
++                       * rs_more indicates chained descriptors which can be
++                       * used to link buffers together for a sort of
++                       * scatter-gather operation.
++                       */
++                      if (sc->rx.frag) {
++                              /* too many fragments - cannot handle frame */
++                              dev_kfree_skb_any(sc->rx.frag);
++                              dev_kfree_skb_any(skb);
++                              skb = NULL;
++                      }
++                      sc->rx.frag = skb;
++                      goto requeue;
++              }
++
++              if (sc->rx.frag) {
++                      int space = skb->len - skb_tailroom(hdr_skb);
++
++                      sc->rx.frag = NULL;
++
++                      if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) {
++                              dev_kfree_skb(skb);
++                              goto requeue_drop_frag;
++                      }
++
++                      skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len),
++                                                skb->len);
++                      dev_kfree_skb_any(skb);
++                      skb = hdr_skb;
++              }
++
+               /*
+                * change the default rx antenna if rx diversity chooses the
+                * other antenna 3 times in a row.
+@@ -1722,6 +1757,11 @@ int ath_rx_tasklet(struct ath_softc *sc,
+               ieee80211_rx(hw, skb);
++requeue_drop_frag:
++              if (sc->rx.frag) {
++                      dev_kfree_skb_any(sc->rx.frag);
++                      sc->rx.frag = NULL;
++              }
+ requeue:
+               if (edma) {
+                       list_add_tail(&bf->list, &sc->rx.rxbuf);
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -311,6 +311,8 @@ struct ath_rx {
+       struct ath_descdma rxdma;
+       struct ath_buf *rx_bufptr;
+       struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
++
++      struct sk_buff *frag;
+ };
+ int ath_startrecv(struct ath_softc *sc);