Tidy RX queue processing code:

* Formatting
 * Add a function to remove SKB from ath_buf.
 * Call aforementioned function early if we are accepting a frame, so that there's not chance the data can get stomped on by DMA. We should probably do this for ignored frames as well, but I got fed up trying to sort out the stack of goto.
 * Remove some KASSERT for skb users, as the SKB are always copied.


git-svn-id: http://madwifi-project.org/svn/madwifi/trunk@3594 0192ed92-7a03-0410-a25b-9323aeb14dbd
This commit is contained in:
mentor 2008-05-03 03:40:27 +00:00
parent 2ecfeab07e
commit 1b318d3853
3 changed files with 117 additions and 120 deletions

View File

@ -180,6 +180,7 @@ static void ath_node_free(struct ieee80211_node *);
#endif
static u_int8_t ath_node_getrssi(const struct ieee80211_node *);
static struct sk_buff *ath_rxbuf_take_skb(struct ath_softc *, struct ath_buf *);
static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *);
static void ath_recv_mgmt(struct ieee80211vap *, struct ieee80211_node *,
struct sk_buff *, int, int, u_int64_t);
@ -6334,22 +6335,34 @@ ath_alloc_skb(u_int size, u_int align)
return skb;
}
static struct sk_buff *
ath_rxbuf_take_skb(struct ath_softc *sc, struct ath_buf *bf) {
struct sk_buff *skb = bf->bf_skb;
bf->bf_skb = NULL;
KASSERT(bf->bf_skbaddr, ("bf->bf_skbaddr is 0"));
bus_unmap_single(sc->sc_bdev, bf->bf_skbaddr,
sc->sc_rxbufsize, BUS_DMA_FROMDEVICE);
bf->bf_skbaddr = 0;
return skb;
}
static int
ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
{
struct ath_hal *ah = sc->sc_ah;
struct ath_desc *ds = NULL;
struct sk_buff *skb;
/* NB: I'm being cautious by unmapping and releasing the SKB every
* time.
* XXX: I could probably keep rolling, but the DMA map/unmap logic
* doesn't seem clean enough and cycling the skb through the free
* function and slab allocator seems to scrub any un-reset values. */
if (bf->bf_skb != NULL) {
KASSERT(bf->bf_skbaddr, ("bf->bf_skbaddr is 0"));
bus_unmap_single(sc->sc_bdev, bf->bf_skbaddr,
sc->sc_rxbufsize, BUS_DMA_FROMDEVICE);
ieee80211_dev_kfree_skb(&bf->bf_skb);
skb = ath_rxbuf_take_skb(sc, bf);
ieee80211_dev_kfree_skb(&skb);
}
if (!bf->bf_skb) {
/* NB: Always use the same size for buffer allocations so that
* dynamically adding a monitor mode VAP to a running driver
@ -6364,15 +6377,13 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
__func__, size);
return -ENOMEM;
}
/*
* Reserve space for the header.
*/
/* Reserve space for the header. */
skb_reserve(bf->bf_skb, IEEE80211_MON_MAXHDROOM);
/*
* Cache-line-align. This is important (for the
/* Cache-line-align. This is important (for the
* 5210 at least) as not doing so causes bogus data
* in rx'd frames.
*/
* in RX'd frames. */
offset = ((unsigned long)bf->bf_skb->data) % sc->sc_cachelsz;
if (offset != 0)
skb_reserve(bf->bf_skb, sc->sc_cachelsz - offset);
@ -6612,8 +6623,8 @@ ath_rx_tasklet(TQUEUE_ARG data)
struct ath_desc *ds;
struct ath_rx_status *rs;
struct ieee80211_node *ni;
struct sk_buff* skb;
unsigned int len, phyerr, mic_fail = 0;
int is_mcast = 0;
int type = -1; /* undefined */
int init_ret = 0;
int bf_processed = 0;
@ -6622,17 +6633,16 @@ ath_rx_tasklet(TQUEUE_ARG data)
DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s started...\n", __func__);
do {
/*
* Get next rx buffer pending processing by rx tasklet...
/* Get next RX buffer pending processing by RX tasklet...
*
* Descriptors are now processed at in the first-level interrupt
* handler to support U-APSD trigger search. This must also be done
* even when U-APSD is not active to support other error handling
* that requires immediate attention. We check bf_status to find
* out if the bf's descriptors have been processed by the interrupt
* handler and are ready for this tasklet to consume them. We
* also never process/remove the self-linked entry at the end
*/
* handler to support U-APSD trigger search. This must also be
* done even when U-APSD is not active to support other error
* handling that requires immediate attention. We check
* bf_status to find out if the bf's descriptors have been
* processed by the interrupt handler and are ready for this
* tasklet to consume them. We also never process/remove the
* self-linked entry at the end. */
ATH_RXBUF_LOCK_IRQ(sc);
bf = STAILQ_FIRST(&sc->sc_rxbuf);
if (bf && (bf->bf_status & ATH_BUFSTATUS_RXDESC_DONE) &&
@ -6640,7 +6650,8 @@ ath_rx_tasklet(TQUEUE_ARG data)
STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
else {
if (bf && (bf->bf_status & ATH_BUFSTATUS_RXDESC_DONE))
EPRINTF(sc, "Warning: %s detected a non-empty skb that is self-linked. "
EPRINTF(sc, "Warning: %s detected a non-empty "
"skb that is self-linked. "
"This may be a driver bug.\n",
__func__);
bf = NULL;
@ -6651,8 +6662,6 @@ ath_rx_tasklet(TQUEUE_ARG data)
bf_processed++;
ds = bf->bf_desc;
is_mcast = (((const struct ieee80211_frame*)bf->bf_skb->data)->i_addr1[0] & 0x01) ||
(((const struct ieee80211_frame*)bf->bf_skb->data)->i_addr3[0] & 0x01);
#ifdef AR_DEBUG
if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
@ -6665,24 +6674,20 @@ ath_rx_tasklet(TQUEUE_ARG data)
if (len == 0)
goto rx_next;
if (rs->rs_more) {
/*
* Frame spans multiple descriptors; this
/* Frame spans multiple descriptors; this
* cannot happen yet as we don't support
* jumbograms. If not in monitor mode,
* discard the frame.
*/
* discard the frame. */
#ifndef ERROR_FRAMES
/*
* Enable this if you want to see
* error frames in Monitor mode.
*/
/* Enable this if you want to see
* error frames in Monitor mode. */
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
sc->sc_stats.ast_rx_toobig++;
errors++;
goto rx_next;
}
#endif
/* fall thru for monitor mode handling... */
/* Fall through for monitor mode handling... */
} else if (rs->rs_status != 0) {
errors++;
if (rs->rs_status & HAL_RXERR_CRC)
@ -6695,16 +6700,14 @@ ath_rx_tasklet(TQUEUE_ARG data)
sc->sc_stats.ast_rx_phy[phyerr]++;
}
if (rs->rs_status & HAL_RXERR_DECRYPT) {
/*
* Decrypt error. If the error occurred
/* Decrypt error. If the error occurred
* because there was no hardware key, then
* let the frame through so the upper layers
* can process it. This is necessary for 5210
* parts which have no way to setup a ``clear''
* key cache entry.
*
* XXX do key cache faulting
*/
* XXX: Do key cache faulting. */
if (rs->rs_keyix == HAL_RXKEYIX_INVALID)
goto rx_accept;
sc->sc_stats.ast_rx_badcrypt++;
@ -6722,24 +6725,25 @@ ath_rx_tasklet(TQUEUE_ARG data)
}
rx_accept:
skb_accepted++;
/*
* Sync and unmap the frame. At this point we're
* committed to passing the sk_buff somewhere so
* clear buf_skb; this means a new sk_buff must be
* allocated when the rx descriptor is setup again
* to receive another frame.
*/
/* Sync and unmap the frame. At this point we're committed
* to passing the sk_buff somewhere so clear bf_skb; this means
* a new sk_buff must be allocated when the RX descriptor is
* setup again to receive another frame.
* NB: Meta-data (rs, noise, tsf) in the ath_buf is still
* used. */
bus_dma_sync_single(sc->sc_bdev,
bf->bf_skbaddr, len, BUS_DMA_FROMDEVICE);
skb = ath_rxbuf_take_skb(sc, bf);
sc->sc_stats.ast_ant_rx[rs->rs_antenna]++;
sc->sc_devstats.rx_packets++;
sc->sc_devstats.rx_bytes += len;
skb_put(bf->bf_skb, len);
bf->bf_skb->protocol = __constant_htons(ETH_P_CONTROL);
skb_put(skb, len);
skb->protocol = __constant_htons(ETH_P_CONTROL);
ath_capture(dev, bf, bf->bf_skb, bf->bf_tsf, 0 /* RX */);
ath_capture(dev, bf, skb, bf->bf_tsf, 0 /* RX */);
/* Finished monitor mode handling, now reject error frames
* before passing to other VAPs. Ignore MIC failures here, as
@ -6747,22 +6751,22 @@ rx_accept:
if (rs->rs_status & ~(HAL_RXERR_MIC | HAL_RXERR_DECRYPT))
goto rx_next;
/* remove the CRC */
skb_trim(bf->bf_skb, bf->bf_skb->len - IEEE80211_CRC_LEN);
/* Remove the CRC. */
skb_trim(skb, skb->len - IEEE80211_CRC_LEN);
if (mic_fail) {
/* Ignore control frames which are reported with MIC
* error. */
if ((((struct ieee80211_frame *)bf->bf_skb->data)->i_fc[0] &
if ((((struct ieee80211_frame *)skb->data)->i_fc[0] &
IEEE80211_FC0_TYPE_MASK) ==
IEEE80211_FC0_TYPE_CTL)
goto drop_micfail;
ni = ieee80211_find_rxnode(ic, (const struct
ieee80211_frame_min *)bf->bf_skb->data);
ieee80211_frame_min *)skb->data);
if (ni) {
if (ni->ni_table)
ieee80211_check_mic(ni, bf->bf_skb);
ieee80211_check_mic(ni, skb);
ieee80211_unref_node(&ni);
}
@ -6783,17 +6787,16 @@ drop_micfail:
/* Normal receive. */
if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV))
ieee80211_dump_pkt(ic, bf->bf_skb->data, bf->bf_skb->len,
ieee80211_dump_pkt(ic, skb->data, skb->len,
sc->sc_hwmap[rs->rs_rate].ieeerate,
rs->rs_rssi);
{
struct ieee80211_frame * wh =
(struct ieee80211_frame *) bf->bf_skb->data;
(struct ieee80211_frame *)skb->data;
/* only print beacons */
if ((bf->bf_skb->len >= sizeof(struct ieee80211_frame)) &&
/* Only print beacons. */
if ((skb->len >= sizeof(struct ieee80211_frame)) &&
((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)
== IEEE80211_FC0_TYPE_MGT) &&
((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
@ -6812,69 +6815,64 @@ drop_micfail:
* are on-channel. */
if (!sc->sc_scanning && !(ic->ic_flags & IEEE80211_F_SCAN))
ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, rs->rs_rssi);
KASSERT((atomic_read(&bf->bf_skb->users) == 1),
("BAD starting skb reference count!"));
/*
* Locate the node for sender, track state, and then
* pass the (referenced) node up to the 802.11 layer
* for its use. If the sender is unknown spam the
* frame; it'll be dropped where it's not wanted.
*/
if (rs->rs_keyix != HAL_RXKEYIX_INVALID &&
/* Locate the node for sender, track state, and then pass the
* (referenced) node up to the 802.11 layer for its use. If
* the sender is unknown spam the frame; it'll be dropped
* where it's not wanted. */
if ((rs->rs_keyix != HAL_RXKEYIX_INVALID) &&
(ni = sc->sc_keyixmap[rs->rs_keyix]) != NULL) {
/* Fast path: node is present in the key map;
* grab a reference for processing the frame. */
ni = ieee80211_ref_node(ni);
type = ieee80211_input(ni->ni_vap, ni, bf->bf_skb, rs->rs_rssi, bf->bf_tsf);
ieee80211_unref_node(&ni);
} else {
/*
* No key index or no entry, do a lookup and
* add the node to the mapping table if possible.
*/
/* No key index or no entry, do a lookup and
* add the node to the mapping table if possible. */
ni = ieee80211_find_rxnode(ic,
(const struct ieee80211_frame_min *)bf->bf_skb->data);
(const struct ieee80211_frame_min *)skb->data);
if (ni != NULL) {
ieee80211_keyix_t keyix;
type = ieee80211_input(ni->ni_vap, ni, bf->bf_skb, rs->rs_rssi, bf->bf_tsf);
/*
* If the station has a key cache slot assigned
* update the key->node mapping table.
*/
keyix = ni->ni_ucastkey.wk_keyix;
if (keyix != IEEE80211_KEYIX_NONE &&
sc->sc_keyixmap[keyix] == NULL)
sc->sc_keyixmap[keyix] = ieee80211_ref_node(ni);
/* If the station has a key cache slot assigned
* update the key->node mapping table. */
ieee80211_keyix_t keyix =
ni->ni_ucastkey.wk_keyix;
if ((keyix != IEEE80211_KEYIX_NONE) &&
(sc->sc_keyixmap[keyix] == NULL))
sc->sc_keyixmap[keyix] =
ieee80211_ref_node(ni);
}
}
/* If a node is found, dispatch, else, dispatch to all. */
if (ni) {
type = ieee80211_input(ni->ni_vap, ni, skb,
rs->rs_rssi, bf->bf_tsf);
ieee80211_unref_node(&ni);
} else {
struct ieee80211vap *vap;
/* Create a new SKB copy for each VAP except the last
* one, which gets the original SKB. */
TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
type = ieee80211_input(vap, NULL, bf->bf_skb, rs->rs_rssi, bf->bf_tsf);
type = ieee80211_input(vap, NULL, skb,
rs->rs_rssi, bf->bf_tsf);
}
}
}
KASSERT((atomic_read(&bf->bf_skb->users) == 1),
("ieee80211_input changed skb reference count!"));
if (sc->sc_diversity) {
/*
* When using hardware fast diversity, change the default rx
* antenna if rx diversity chooses the other antenna 3
* times in a row.
*/
/* When using hardware fast diversity, change the default RX
* antenna if RX diversity chooses the other antenna 3
* times in a row. */
if (sc->sc_defant != rs->rs_antenna) {
if (++sc->sc_rxotherant >= 3)
ath_setdefantenna(sc, rs->rs_antenna);
} else
sc->sc_rxotherant = 0;
}
if (sc->sc_softled) {
/*
* Blink for any data frame. Otherwise do a
/* Blink for any data frame. Otherwise do a
* heartbeat-style blink when idle. The latter
* is mainly for station mode where we depend on
* periodic beacon frames to trigger the poll event.
*/
* periodic beacon frames to trigger the poll event. */
if (type == IEEE80211_FC0_TYPE_DATA) {
sc->sc_rxrate = rs->rs_rate;
ath_led_event(sc, ATH_LED_RX);
@ -6883,10 +6881,10 @@ drop_micfail:
}
rx_next:
KASSERT(bf != NULL, ("null bf"));
KASSERT(bf->bf_skb != NULL, ("null bf->bf_skb"));
if (0 != (init_ret = ath_rxbuf_init(sc, bf))) {
EPRINTF(sc, "Failed to reinitialize rxbuf: %d. Lost an RX buffer!\n", init_ret);
if ((init_ret = ath_rxbuf_init(sc, bf)) != 0) {
EPRINTF(sc, "Failed to reinitialize rxbuf: %d. "
"Lost an RX buffer!\n", init_ret);
break;
}
@ -6895,6 +6893,7 @@ rx_next:
STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
ATH_RXBUF_UNLOCK_IRQ(sc);
} while (1);
if (sc->sc_useintmit)
ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
if (!bf_processed)
@ -8514,7 +8513,7 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
/* ath_capture modifies skb data; must be last process
* in TX path. */
tskb = skb->next;
DPRINTF(sc, ATH_DEBUG_TX_PROC, "capture/free skb %p\n",
DPRINTF(sc, ATH_DEBUG_TX_PROC, "capture skb %p\n",
bf->bf_skb);
ath_capture(sc->sc_dev, bf, skb, bf->bf_tsf, 1 /* TX */);
skb = tskb;
@ -8524,7 +8523,7 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
* extra buffers */
for (i = 0; i < bf->bf_numdescff; i++) {
tskb = skb->next;
DPRINTF(sc, ATH_DEBUG_TX_PROC, "capture/free skb %p\n",
DPRINTF(sc, ATH_DEBUG_TX_PROC, "capture skb %p\n",
skb);
ath_capture(sc->sc_dev, bf, skb, bf->bf_tsf, 1 /* TX */);
skb = tskb;

View File

@ -213,7 +213,7 @@ ieee80211_input(struct ieee80211vap * vap, struct ieee80211_node *ni_or_null,
u_int8_t *bssid;
u_int16_t rxseq;
/* initialize ni as in the previous API */
/* Initialize ni as in the previous API. */
if (ni_or_null == NULL) {
/* This function does not 'own' vap->iv_bss, so we cannot
* guarantee its existence during the following call, hence
@ -224,11 +224,10 @@ ieee80211_input(struct ieee80211vap * vap, struct ieee80211_node *ni_or_null,
KASSERT(ni != NULL, ("null node"));
ni->ni_inact = ni->ni_inact_reload;
type = -1; /* undefined */
/*
* In monitor mode, send everything directly to bpf.
/* In monitor mode, send everything directly to bpf.
* Also do not process frames w/o i_addr2 any further.
* XXX may want to include the CRC
*/
* XXX: may want to include the CRC. */
if (vap->iv_opmode == IEEE80211_M_MONITOR)
goto out;
if (original_skb->len < sizeof(struct ieee80211_frame_min)) {
@ -252,12 +251,10 @@ ieee80211_input(struct ieee80211vap * vap, struct ieee80211_node *ni_or_null,
ieee80211_skb_copy_noderef(original_skb, skb);
original_skb = NULL; /* protect caller's skb */
/*
* Bit of a cheat here, we use a pointer for a 3-address
/* Bit of a cheat here, we use a pointer for a 3-address
* frame format but don't reference fields past outside
* ieee80211_frame_min w/o first validating the data is
* present.
*/
* present. */
wh = (struct ieee80211_frame *)skb->data;
if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=

View File

@ -294,7 +294,8 @@ struct ieee80211com {
struct net_device *ic_dev; /* associated device */
ieee80211com_lock_t ic_comlock; /* state update lock */
ieee80211com_lock_t ic_vapslock; /* vap state machine lock */
TAILQ_HEAD(, ieee80211vap) ic_vaps; /* list of vap instances */
TAILQ_HEAD(ieee80211vap_headtype,
ieee80211vap) ic_vaps; /* list of vap instances */
enum ieee80211_phytype ic_phytype; /* XXX wrong for multi-mode */
enum ieee80211_opmode ic_opmode; /* operation mode */
struct ifmedia ic_media; /* interface media config */