diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-01-26 12:23:27 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-01-28 15:44:28 -0500 |
commit | 0d95521ea74735826cb2e28bebf6a07392c75bfa (patch) | |
tree | 593a9acbca2a6246f4244855bc7d4498b6dfa5bd /drivers/net/wireless/ath | |
parent | 4d9067405c21e8596087d929f3d858d0aa5002ff (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.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 88 |
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 | ||
315 | int ath_startrecv(struct ath_softc *sc); | 317 | int 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: | |||
1582 | int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) | 1575 | int 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 | ||
1760 | requeue_drop_frag: | ||
1761 | if (sc->rx.frag) { | ||
1762 | dev_kfree_skb_any(sc->rx.frag); | ||
1763 | sc->rx.frag = NULL; | ||
1764 | } | ||
1725 | requeue: | 1765 | requeue: |
1726 | if (edma) { | 1766 | if (edma) { |
1727 | list_add_tail(&bf->list, &sc->rx.rxbuf); | 1767 | list_add_tail(&bf->list, &sc->rx.rxbuf); |