Skip to content

Commit

Permalink
ath9k: use split rx buffers to get rid of order-1 skb allocations
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Felix Fietkau authored and John W. Linville committed Jan 28, 2011
1 parent 4d90674 commit 0d95521
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 24 deletions.
2 changes: 2 additions & 0 deletions drivers/net/wireless/ath/ath9k/ath9k.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,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);
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/wireless/ath/ath9k/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,11 @@ static void ath9k_stop(struct ieee80211_hw *hw)
} 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);
Expand Down
88 changes: 64 additions & 24 deletions drivers/net/wireless/ath/ath9k/recv.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,6 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
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);

Expand Down Expand Up @@ -300,12 +295,12 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
sc->sc_flags &= ~SC_OP_RXFLUSH;
spin_lock_init(&sc->rx.rxbuflock);

common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
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);

Expand Down Expand Up @@ -815,15 +810,9 @@ static bool ath9k_rx_accept(struct ath_common *common,
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
Expand Down Expand Up @@ -981,6 +970,10 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
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))
Expand Down Expand Up @@ -1582,7 +1575,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
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);
Expand Down Expand Up @@ -1633,8 +1626,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
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);

Expand All @@ -1643,12 +1645,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
* 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 &&
Expand All @@ -1668,7 +1670,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
* 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,
Expand All @@ -1679,8 +1681,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
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;
Expand All @@ -1697,6 +1700,38 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
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.
Expand All @@ -1722,6 +1757,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)

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);
Expand Down

0 comments on commit 0d95521

Please sign in to comment.