📄 if_ath.c.svn-base
字号:
HAL_BOOL ret; unsigned long __axq_lockflags[HAL_NUM_TX_QUEUES]; struct ath_txq * txq; int i; u_int8_t old_privFlags = sc->sc_curchan.privFlags; /* ath_hal_reset() resets all TXDP pointers, so we need to * lock all TXQ to avoid race condition with * ath_tx_txqaddbuf() and ath_tx_processq() */ for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { txq = &sc->sc_txq[i]; spin_lock_irqsave(&txq->axq_lock, __axq_lockflags[i]); } } ret = ath_hal_reset(sc->sc_ah, sc->sc_opmode, channel, bChannelChange, status); /* Restore all TXDP pointers, if appropriate, and unlock in * the reverse order we locked */ for (i = HAL_NUM_TX_QUEUES - 1; i >= 0; i--) { /* only take care of configured TXQ */ if (ATH_TXQ_SETUP(sc, i)) { struct ath_buf *bf; u_int32_t txdp; txq = &sc->sc_txq[i]; /* Check that TXDP is NULL */ txdp = ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum); if (txdp != 0) { DPRINTF(sc, ATH_DEBUG_WATCHDOG, "TXQ%d: BUG TXDP:%08x is " "not NULL\n", txq->axq_qnum, txdp); } /* We restore TXDP to the first "In Progress" TX * descriptor. We skip "Done" TX descriptors in * order to avoid sending duplicate packets */ STAILQ_FOREACH(bf, &txq->axq_q, bf_list) { if (ath_hal_txprocdesc(sc->sc_ah, bf->bf_desc, &bf->bf_dsstatus.ds_txstat) == HAL_EINPROGRESS) { DPRINTF(sc, ATH_DEBUG_WATCHDOG, "TXQ%d: restoring" " TXDP:%08llx\n", txq->axq_qnum, (u_int64_t)bf->bf_daddr); ath_hw_puttxbuf(sc, txq->axq_qnum, bf->bf_daddr, __func__); ath_hal_txstart(sc->sc_ah, txq->axq_qnum); } } spin_unlock_irqrestore(&txq->axq_lock, __axq_lockflags[i]); } } /* On failure, we return immediately */ if (!ret) return ret; /* Do the same as in ath_getchannels() */ ath_radar_correct_dfs_flags(sc, channel); /* Restore CHANNEL_DFS_CLEAR and CHANNEL_INTERFERENCE flags */#define CHANNEL_DFS_FLAGS (CHANNEL_DFS_CLEAR|CHANNEL_INTERFERENCE) channel->privFlags = (channel->privFlags & ~CHANNEL_DFS_FLAGS) | (old_privFlags & CHANNEL_DFS_FLAGS); /* On success, we update sc->sc_curchan which can be needed by other * functions below , like ath_radar_update() at least */ sc->sc_curchan = *channel;#ifdef ATH_CAP_TPC if (sc->sc_hastpc && (hal_tpc != ath_hal_gettpc(sc->sc_ah))) { EPRINTF(sc, "TPC HAL capability out of sync. Got %d!\n", ath_hal_gettpc(sc->sc_ah)); ath_hal_settpc(sc->sc_ah, hal_tpc); }#endif#if 0 /* Setting via HAL does not work, so it is done manually below. */ if (sc->sc_hasintmit) ath_hal_setintmit(sc->sc_ah, sc->sc_useintmit);#endif ath_override_intmit_if_disabled(sc); if (sc->sc_dmasize_stomp) ath_hal_set_dmasize_pcie(sc->sc_ah); if (sc->sc_softled) ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin); ath_update_txpow(sc); /* Update TX power state. */ ath_hal_setdiversity(sc->sc_ah, sc->sc_diversity); ath_setdefantenna(sc, sc->sc_rxantenna); /* XXX: Any other clobbered features? */ ath_radar_update(sc); ath_rp_flush(sc); return ret;}/* Returns true if we can transmit any frames : this is not the case if : * - we are on a DFS channel * - 802.11h is enabled * - Channel Availability Check is not done or a radar has been detected */static intath_chan_unavail(struct ath_softc *sc){ return sc->sc_dfs_cac || ((sc->sc_curchan.privFlags & CHANNEL_DFS) && (sc->sc_curchan.privFlags & CHANNEL_INTERFERENCE));}static inline int_ath_cac_running_dbgmsg(struct ath_softc *sc, const char *func){ int b = sc->sc_dfs_cac; if (b) DPRINTF(sc, ATH_DEBUG_DOTH, "%s: Invoked a transmit function during DFS " "channel availability check!\n", func); return b;}static inline int_ath_chan_unavail_dbgmsg(struct ath_softc *sc, const char *func){ int b = ath_chan_unavail(sc); if (b) DPRINTF(sc, ATH_DEBUG_DOTH, "%s: Invoked a transmit function during DFS " "channel availability check OR while radar " "interference is detected!\n", func); return b;}/* Extend 15-bit timestamp from RX descriptor to a full 64-bit TSF using the * provided hardware TSF. The result is the closest value relative to hardware * TSF. *//* NB: Not all chipsets return the same precision rstamp */static __inline u_int64_tath_extend_tsf(u_int64_t tsf, u_int32_t rstamp){#define TSTAMP_RX_MASK 0x7fff u_int64_t result; result = (tsf & ~TSTAMP_RX_MASK) | rstamp; if (result > tsf) { if ((result - tsf) > (TSTAMP_RX_MASK / 2)) result -= (TSTAMP_RX_MASK + 1); } else { if ((tsf - result) > (TSTAMP_RX_MASK / 2)) result += (TSTAMP_RX_MASK + 1); } return result;}/* Swap transmit descriptor pointer for HW. */static __inline u_int32_tath_ds_link_swap(u_int32_t dp){#ifdef AH_NEED_DESC_SWAP return swab32(dp);#else return (dp);#endif}static __inline u_int32_tath_get_last_ds_link(struct ath_txq *txq){ struct ath_desc *ds = ath_txq_last_desc(txq); return (ds ? ds->ds_link : 0);}static voidath_intr_process_rx_descriptors(struct ath_softc *sc, int *pneedmark, u_int64_t hw_tsf){ struct ath_hal *ah = sc->sc_ah; struct ath_desc *ds; struct ath_rx_status *rs; struct sk_buff *skb; struct ieee80211_node *ni; struct ath_node *an; struct ieee80211_qosframe *qwh; struct ath_txq *uapsd_xmit_q = sc->sc_uapsdq; struct ieee80211com *ic = &sc->sc_ic; int ac, retval; u_int32_t last_rs_tstamp = 0; int check_for_radar = 0; struct ath_buf *prev_rxbufcur; u_int8_t tid; u_int16_t frame_seq; int count = 0; int rollover = 0;#define PA2DESC(_sc, _pa) \ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) /* XXXAPSD: build in check against max triggers we could see * based on ic->ic_uapsdmaxtriggers. */ /* Do not move hw_tsf processing and noise processing out to the rx * tasklet. The ONLY place we can properly correct for TSF errors and * get accurate noise floor information is in the interrupt handler. * We collect the first hw_tsf in the ath_intr (the interrupt handler) * so it can be passed to some helper functions... later in this * function, however, we read it again to perform rollover adjustments. * * The HW returns a 15-bit TS on rx. We get interrupts after multiple * packets are queued up. Sometimes (read often), the 15-bit counter * in the hardware has rolled over one or more times. We correct for * this in the interrupt function and store the adjusted TSF in the * buffer. * * We also store noise during interrupt, since HW does not log * this per packet and the rx queue is too late. Multiple interrupts * will have occurred, and the noise value at that point is totally * unrelated to conditions during receiption. This is as close as we * get to reality. This value is used in monitor mode and by tools like * Wireshark and Kismet. */ ATH_RXBUF_LOCK_IRQ(sc); if (sc->sc_rxbufcur == NULL) sc->sc_rxbufcur = STAILQ_FIRST(&sc->sc_rxbuf); prev_rxbufcur = sc->sc_rxbufcur; /* FIRST PASS - PROCESS DESCRIPTORS */ { struct ath_buf *bf; for (bf = prev_rxbufcur; bf; bf = STAILQ_NEXT(bf, bf_list)) { ds = bf->bf_desc; if (ds->ds_link == bf->bf_daddr) { /* NB: never process the self-linked entry at * the end */ break; } if (bf->bf_status & ATH_BUFSTATUS_RXDESC_DONE) { /* already processed this buffer (shouldn't * occur if we change code to always process * descriptors in rx intr handler - as opposed * to sometimes processing in the rx tasklet) */ continue; } skb = bf->bf_skb; if (skb == NULL) { EPRINTF(sc, "Dropping; skb is NULL in received ath_buf.\n"); continue; } /* XXXAPSD: consider new HAL call that does only the * subset of ath_hal_rxprocdesc we require * for trigger search. */ /* NB: descriptor memory doesn't need to be sync'd * due to the way it was allocated. */ /* Must provide the virtual address of the current * descriptor, the physical address, and the virtual * address of the next descriptor in the h/w chain. * This allows the HAL to look ahead to see if the * hardware is done with a descriptor by checking the * done bit in the following descriptor and the address * of the current descriptor the DMA engine is working * on. All this is necessary because of our use of * a self-linked list to avoid rx overruns. */ rs = &bf->bf_dsstatus.ds_rxstat; retval = ath_hal_rxprocdesc(ah, ds, bf->bf_daddr, PA2DESC(sc, ds->ds_link), hw_tsf, rs); if (HAL_EINPROGRESS == retval) break; /* update the per packet TSF with rs_tstamp */ bf->bf_tsf = rs->rs_tstamp; bf->bf_status |= ATH_BUFSTATUS_RXTSTAMP; count ++; DPRINTF(sc, ATH_DEBUG_TSF, "rs_tstamp=%10llx count=%d\n", bf->bf_tsf, count); /* compute rollover */ if (last_rs_tstamp > rs->rs_tstamp) { rollover ++; DPRINTF(sc, ATH_DEBUG_TSF, "%d rollover detected\n", rollover); } last_rs_tstamp = rs->rs_tstamp; /* Do not allow negative RSSI values */ if (rs->rs_rssi < 0) rs->rs_rssi = 0; /* Capture noise per-interrupt, since it may change * by the time the receive queue gets around to * processing these buffers, and multiple interrupts * may have occurred in the intervening timeframe. */ bf->bf_channoise = ic->ic_channoise; if ((HAL_RXERR_PHY == rs->rs_status) && (HAL_PHYERR_RADAR == (rs->rs_phyerr & 0x1f)) && !(bf->bf_status & ATH_BUFSTATUS_RADAR_DONE) && (ic->ic_flags & IEEE80211_F_DOTH)) check_for_radar = 1; /* XXX: We do not support frames spanning multiple * descriptors */ bf->bf_status |= ATH_BUFSTATUS_RXDESC_DONE; if (rs->rs_status) { /* Skip past the error now */ continue; } /* Prepare wireless header for examination */ bus_dma_sync_single(sc->sc_bdev, bf->bf_skbaddr, sizeof(struct ieee80211_qosframe), BUS_DMA_FROMDEVICE); qwh = (struct ieee80211_qosframe *)skb->data; /* Find the node; it MUST be in the keycache. */ if (rs->rs_keyix == HAL_RXKEYIX_INVALID || (ni = sc->sc_keyixmap[rs->rs_keyix]) == NULL) { /* * XXX: this can occur if WEP mode is used for * non-Atheros clients (since we do not * know which of the 4 WEP keys will be * used at association time, so cannot * setup a key-cache entry. * The Atheros client can convey this in * the Atheros IE.) * * The fix is to use the hash lookup on * the node here. */#if 0 /* This print is very chatty, so removing for now. */ DPRINTF(sc, ATH_DEBUG_UAPSD, "U-APSD node (" MAC_FMT ") " "has invalid keycache entry\n", MAC_ADDR(qwh->i_addr2));#endif continue; } if (!(ni->ni_flags & IEEE80211_NODE_UAPSD)) continue; /* * Must deal with change of state here, since otherwise * there would be a race (on two quick frames from STA) * between this code and the tasklet where we would: * - miss a trigger on entry to PS if we're already * trigger hunting * - generate spurious SP on exit (due to frame * following exit frame) */ if ((!!(qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) != !!(ni->ni_flags & IEEE80211_NODE_PWR_MGT))) { /* * NB: do not require lock here since this runs * at intr "proper" time and cannot be * interrupted by RX tasklet (code there has * lock). May want to place a macro here * (that does nothing) to make this more clear. */ ni->ni_flags |= IEEE80211_NODE_PS_CHANGED; ni->ni_pschangeseq = *(__le16 *)(&qwh->i_seq[0]); ni->ni_flags &= ~IEEE80211_NODE_UAPSD_SP; ni->ni_flags ^= IEEE80211_NODE_PWR_MGT; if (qwh->i_fc[1] & IEEE80211_FC1_PWR_MGT) { ni->ni_flags |= IEEE80211_NODE_UAPSD_TRIG; ic->ic_uapsdmaxtriggers++; WME_UAPSD_NODE_TRIGSEQINIT(ni); DPRINTF(sc, ATH_DEBUG_UAPSD, "Node (" MAC_FMT ") became U-APSD " "triggerable (%d)\n", MAC_ADDR(qwh->i_addr2), ic->ic_uapsdmaxtriggers); } else { ni->ni_flags &= ~IEEE80211_NODE_UAPSD_TRIG; ic->ic_uapsdmaxtriggers--; DPRINTF(sc, ATH_DEBUG_UAPSD, "Node (" MAC_FMT ") no longer U-APSD" " triggerable (%d)\n", MAC_ADDR(qwh->i_addr2), ic->ic_uapsdmaxtriggers); /* * XXX: Rapidly thrashing sta could get * out-of-order frames due this flush
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -