aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2011-01-26 12:23:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-28 15:44:28 -0500
commit0d95521ea74735826cb2e28bebf6a07392c75bfa (patch)
tree593a9acbca2a6246f4244855bc7d4498b6dfa5bd /drivers/net/wireless/ath
parent4d9067405c21e8596087d929f3d858d0aa5002ff (diff)
ath9k: use split rx buffers to get rid of order-1 skb allocations
With this change, less CPU time is spent trying to look for consecutive pages for rx skbs. This also reduces the socket memory required for IP/UDP reassembly. Only two buffers per frame are supported. Frames spanning more buffers will be dropped, but the buffer size is enough to handle the required AMSDU size. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c88
3 files changed, 71 insertions, 24 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index dd9a7d740c98..73db9576af57 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -310,6 +310,8 @@ struct ath_rx {
310 struct ath_descdma rxdma; 310 struct ath_descdma rxdma;
311 struct ath_buf *rx_bufptr; 311 struct ath_buf *rx_bufptr;
312 struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; 312 struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
313
314 struct sk_buff *frag;
313}; 315};
314 316
315int ath_startrecv(struct ath_softc *sc); 317int ath_startrecv(struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 422be2675a06..23c016a81bcf 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1294,6 +1294,11 @@ static void ath9k_stop(struct ieee80211_hw *hw)
1294 } else 1294 } else
1295 sc->rx.rxlink = NULL; 1295 sc->rx.rxlink = NULL;
1296 1296
1297 if (sc->rx.frag) {
1298 dev_kfree_skb_any(sc->rx.frag);
1299 sc->rx.frag = NULL;
1300 }
1301
1297 /* disable HAL and put h/w to sleep */ 1302 /* disable HAL and put h/w to sleep */
1298 ath9k_hw_disable(ah); 1303 ath9k_hw_disable(ah);
1299 ath9k_hw_configpcipowersave(ah, 1, 1); 1304 ath9k_hw_configpcipowersave(ah, 1, 1);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index b2b12a293c70..daf171d2f610 100644
--- 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_softc *sc, int nbufs)
209 int error = 0, i; 209 int error = 0, i;
210 u32 size; 210 u32 size;
211 211
212
213 common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN +
214 ah->caps.rx_status_len,
215 min(common->cachelsz, (u16)64));
216
217 ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize - 212 ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize -
218 ah->caps.rx_status_len); 213 ah->caps.rx_status_len);
219 214
@@ -300,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
300 sc->sc_flags &= ~SC_OP_RXFLUSH; 295 sc->sc_flags &= ~SC_OP_RXFLUSH;
301 spin_lock_init(&sc->rx.rxbuflock); 296 spin_lock_init(&sc->rx.rxbuflock);
302 297
298 common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
299 sc->sc_ah->caps.rx_status_len;
300
303 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { 301 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
304 return ath_rx_edma_init(sc, nbufs); 302 return ath_rx_edma_init(sc, nbufs);
305 } else { 303 } else {
306 common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
307 min(common->cachelsz, (u16)64));
308
309 ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", 304 ath_dbg(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
310 common->cachelsz, common->rx_bufsize); 305 common->cachelsz, common->rx_bufsize);
311 306
@@ -815,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_common *common,
815 if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len)) 810 if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len))
816 return false; 811 return false;
817 812
818 /* 813 /* Only use error bits from the last fragment */
819 * rs_more indicates chained descriptors which can be used
820 * to link buffers together for a sort of scatter-gather
821 * operation.
822 * reject the frame, we don't support scatter-gather yet and
823 * the frame is probably corrupt anyway
824 */
825 if (rx_stats->rs_more) 814 if (rx_stats->rs_more)
826 return false; 815 return true;
827 816
828 /* 817 /*
829 * The rx_stats->rs_status will not be set until the end of the 818 * The rx_stats->rs_status will not be set until the end of the
@@ -981,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
981 if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error)) 970 if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
982 return -EINVAL; 971 return -EINVAL;
983 972
973 /* Only use status info from the last fragment */
974 if (rx_stats->rs_more)
975 return 0;
976
984 ath9k_process_rssi(common, hw, hdr, rx_stats); 977 ath9k_process_rssi(common, hw, hdr, rx_stats);
985 978
986 if (ath9k_process_rate(common, hw, rx_stats, rx_status)) 979 if (ath9k_process_rate(common, hw, rx_stats, rx_status))
@@ -1582,7 +1575,7 @@ div_comb_done:
1582int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) 1575int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1583{ 1576{
1584 struct ath_buf *bf; 1577 struct ath_buf *bf;
1585 struct sk_buff *skb = NULL, *requeue_skb; 1578 struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb;
1586 struct ieee80211_rx_status *rxs; 1579 struct ieee80211_rx_status *rxs;
1587 struct ath_hw *ah = sc->sc_ah; 1580 struct ath_hw *ah = sc->sc_ah;
1588 struct ath_common *common = ath9k_hw_common(ah); 1581 struct ath_common *common = ath9k_hw_common(ah);
@@ -1633,8 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1633 if (!skb) 1626 if (!skb)
1634 continue; 1627 continue;
1635 1628
1636 hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len); 1629 /*
1637 rxs = IEEE80211_SKB_RXCB(skb); 1630 * Take frame header from the first fragment and RX status from
1631 * the last one.
1632 */
1633 if (sc->rx.frag)
1634 hdr_skb = sc->rx.frag;
1635 else
1636 hdr_skb = skb;
1637
1638 hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len);
1639 rxs = IEEE80211_SKB_RXCB(hdr_skb);
1638 1640
1639 ath_debug_stat_rx(sc, &rs); 1641 ath_debug_stat_rx(sc, &rs);
1640 1642
@@ -1643,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1643 * chain it back at the queue without processing it. 1645 * chain it back at the queue without processing it.
1644 */ 1646 */
1645 if (flush) 1647 if (flush)
1646 goto requeue; 1648 goto requeue_drop_frag;
1647 1649
1648 retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, 1650 retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
1649 rxs, &decrypt_error); 1651 rxs, &decrypt_error);
1650 if (retval) 1652 if (retval)
1651 goto requeue; 1653 goto requeue_drop_frag;
1652 1654
1653 rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; 1655 rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
1654 if (rs.rs_tstamp > tsf_lower && 1656 if (rs.rs_tstamp > tsf_lower &&
@@ -1668,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1668 * skb and put it at the tail of the sc->rx.rxbuf list for 1670 * skb and put it at the tail of the sc->rx.rxbuf list for
1669 * processing. */ 1671 * processing. */
1670 if (!requeue_skb) 1672 if (!requeue_skb)
1671 goto requeue; 1673 goto requeue_drop_frag;
1672 1674
1673 /* Unmap the frame */ 1675 /* Unmap the frame */
1674 dma_unmap_single(sc->dev, bf->bf_buf_addr, 1676 dma_unmap_single(sc->dev, bf->bf_buf_addr,
@@ -1679,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1679 if (ah->caps.rx_status_len) 1681 if (ah->caps.rx_status_len)
1680 skb_pull(skb, ah->caps.rx_status_len); 1682 skb_pull(skb, ah->caps.rx_status_len);
1681 1683
1682 ath9k_rx_skb_postprocess(common, skb, &rs, 1684 if (!rs.rs_more)
1683 rxs, decrypt_error); 1685 ath9k_rx_skb_postprocess(common, hdr_skb, &rs,
1686 rxs, decrypt_error);
1684 1687
1685 /* We will now give hardware our shiny new allocated skb */ 1688 /* We will now give hardware our shiny new allocated skb */
1686 bf->bf_mpdu = requeue_skb; 1689 bf->bf_mpdu = requeue_skb;
@@ -1697,6 +1700,38 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1697 break; 1700 break;
1698 } 1701 }
1699 1702
1703 if (rs.rs_more) {
1704 /*
1705 * rs_more indicates chained descriptors which can be
1706 * used to link buffers together for a sort of
1707 * scatter-gather operation.
1708 */
1709 if (sc->rx.frag) {
1710 /* too many fragments - cannot handle frame */
1711 dev_kfree_skb_any(sc->rx.frag);
1712 dev_kfree_skb_any(skb);
1713 skb = NULL;
1714 }
1715 sc->rx.frag = skb;
1716 goto requeue;
1717 }
1718
1719 if (sc->rx.frag) {
1720 int space = skb->len - skb_tailroom(hdr_skb);
1721
1722 sc->rx.frag = NULL;
1723
1724 if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) {
1725 dev_kfree_skb(skb);
1726 goto requeue_drop_frag;
1727 }
1728
1729 skb_copy_from_linear_data(skb, skb_put(hdr_skb, skb->len),
1730 skb->len);
1731 dev_kfree_skb_any(skb);
1732 skb = hdr_skb;
1733 }
1734
1700 /* 1735 /*
1701 * change the default rx antenna if rx diversity chooses the 1736 * change the default rx antenna if rx diversity chooses the
1702 * other antenna 3 times in a row. 1737 * other antenna 3 times in a row.
@@ -1722,6 +1757,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1722 1757
1723 ieee80211_rx(hw, skb); 1758 ieee80211_rx(hw, skb);
1724 1759
1760requeue_drop_frag:
1761 if (sc->rx.frag) {
1762 dev_kfree_skb_any(sc->rx.frag);
1763 sc->rx.frag = NULL;
1764 }
1725requeue: 1765requeue:
1726 if (edma) { 1766 if (edma) {
1727 list_add_tail(&bf->list, &sc->rx.rxbuf); 1767 list_add_tail(&bf->list, &sc->rx.rxbuf);