📄 ar5212_xmit.c
字号:
else ahp->ah_txErrInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXDESCINT_ENABLE) ahp->ah_txDescInterruptMask |= 1 << q; else ahp->ah_txDescInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXEOLINT_ENABLE) ahp->ah_txEolInterruptMask |= 1 << q; else ahp->ah_txEolInterruptMask &= ~(1 << q); if (qi->tqi_qflags & HAL_TXQ_TXURNINT_ENABLE) ahp->ah_txUrnInterruptMask |= 1 << q; else ahp->ah_txUrnInterruptMask &= ~(1 << q); setTxQInterrupts(ah, qi); return AH_TRUE;}/* * Get the TXDP for the specified queue */uint32_tar5212GetTxDP(struct ath_hal *ah, u_int q){ HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); return OS_REG_READ(ah, AR_QTXDP(q));}/* * Set the TxDP for the specified queue */HAL_BOOLar5212SetTxDP(struct ath_hal *ah, u_int q, uint32_t txdp){ HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); /* * Make sure that TXE is deasserted before setting the TXDP. If TXE * is still asserted, setting TXDP will have no effect. */ HALASSERT((OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) == 0); OS_REG_WRITE(ah, AR_QTXDP(q), txdp); return AH_TRUE;}/* * Set Transmit Enable bits for the specified queue */HAL_BOOLar5212StartTxDma(struct ath_hal *ah, u_int q){ HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: queue %u\n", __func__, q); /* Check to be sure we're not enabling a q that has its TXD bit set. */ HALASSERT((OS_REG_READ(ah, AR_Q_TXD) & (1 << q)) == 0); OS_REG_WRITE(ah, AR_Q_TXE, 1 << q); return AH_TRUE;}/* * Return the number of pending frames or 0 if the specified * queue is stopped. */uint32_tar5212NumTxPending(struct ath_hal *ah, u_int q){ uint32_t npend; HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); npend = OS_REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; if (npend == 0) { /* * Pending frame count (PFC) can momentarily go to zero * while TXE remains asserted. In other words a PFC of * zero is not sufficient to say that the queue has stopped. */ if (OS_REG_READ(ah, AR_Q_TXE) & (1 << q)) npend = 1; /* arbitrarily return 1 */ } return npend;}/* * Stop transmit on the specified queue */HAL_BOOLar5212StopTxDma(struct ath_hal *ah, u_int q){ u_int i; u_int wait; HALASSERT(q < AH_PRIVATE(ah)->ah_caps.halTotalQueues); HALASSERT(AH5212(ah)->ah_txq[q].tqi_type != HAL_TX_QUEUE_INACTIVE); OS_REG_WRITE(ah, AR_Q_TXD, 1 << q); for (i = 1000; i != 0; i--) { if (ar5212NumTxPending(ah, q) == 0) break; OS_DELAY(100); /* XXX get actual value */ }#ifdef AH_DEBUG if (i == 0) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: queue %u DMA did not stop in 100 msec\n", __func__, q); HALDEBUG(ah, HAL_DEBUG_ANY, "%s: QSTS 0x%x Q_TXE 0x%x Q_TXD 0x%x Q_CBR 0x%x\n", __func__, OS_REG_READ(ah, AR_QSTS(q)), OS_REG_READ(ah, AR_Q_TXE), OS_REG_READ(ah, AR_Q_TXD), OS_REG_READ(ah, AR_QCBRCFG(q))); HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Q_MISC 0x%x Q_RDYTIMECFG 0x%x Q_RDYTIMESHDN 0x%x\n", __func__, OS_REG_READ(ah, AR_QMISC(q)), OS_REG_READ(ah, AR_QRDYTIMECFG(q)), OS_REG_READ(ah, AR_Q_RDYTIMESHDN)); }#endif /* AH_DEBUG */ /* 2413+ and up can kill packets at the PCU level */ if (ar5212NumTxPending(ah, q) && (IS_2413(ah) || IS_5413(ah) || IS_2425(ah) || IS_2417(ah))) { uint32_t tsfLow, j; HALDEBUG(ah, HAL_DEBUG_TXQUEUE, "%s: Num of pending TX Frames %d on Q %d\n", __func__, ar5212NumTxPending(ah, q), q); /* Kill last PCU Tx Frame */ /* TODO - save off and restore current values of Q1/Q2? */ for (j = 0; j < 2; j++) { tsfLow = OS_REG_READ(ah, AR_TSF_L32); OS_REG_WRITE(ah, AR_QUIET2, SM(100, AR_QUIET2_QUIET_PER) | SM(10, AR_QUIET2_QUIET_DUR)); OS_REG_WRITE(ah, AR_QUIET1, AR_QUIET1_QUIET_ENABLE | SM(tsfLow >> 10, AR_QUIET1_NEXT_QUIET)); if ((OS_REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) { break; } HALDEBUG(ah, HAL_DEBUG_ANY, "%s: TSF moved while trying to set quiet time " "TSF: 0x%08x\n", __func__, tsfLow); HALASSERT(j < 1); /* TSF shouldn't count twice or reg access is taking forever */ } OS_REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE); /* Allow the quiet mechanism to do its work */ OS_DELAY(200); OS_REG_CLR_BIT(ah, AR_QUIET1, AR_QUIET1_QUIET_ENABLE); /* Give at least 1 millisec more to wait */ wait = 100; /* Verify all transmit is dead */ while (ar5212NumTxPending(ah, q)) { if ((--wait) == 0) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Failed to stop Tx DMA in %d msec after killing last frame\n", __func__, wait); break; } OS_DELAY(10); } OS_REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_CHAN_IDLE); } OS_REG_WRITE(ah, AR_Q_TXD, 0); return (i != 0);}/* * Descriptor Access Functions */#define VALID_PKT_TYPES \ ((1<<HAL_PKT_TYPE_NORMAL)|(1<<HAL_PKT_TYPE_ATIM)|\ (1<<HAL_PKT_TYPE_PSPOLL)|(1<<HAL_PKT_TYPE_PROBE_RESP)|\ (1<<HAL_PKT_TYPE_BEACON))#define isValidPktType(_t) ((1<<(_t)) & VALID_PKT_TYPES)#define VALID_TX_RATES \ ((1<<0x0b)|(1<<0x0f)|(1<<0x0a)|(1<<0x0e)|(1<<0x09)|(1<<0x0d)|\ (1<<0x08)|(1<<0x0c)|(1<<0x1b)|(1<<0x1a)|(1<<0x1e)|(1<<0x19)|\ (1<<0x1d)|(1<<0x18)|(1<<0x1c))#define isValidTxRate(_r) ((1<<(_r)) & VALID_TX_RATES)HAL_BOOLar5212SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds, u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int txPower, u_int txRate0, u_int txTries0, u_int keyIx, u_int antMode, u_int flags, u_int rtsctsRate, u_int rtsctsDuration, u_int compicvLen, u_int compivLen, u_int comp){#define RTSCTS (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA) struct ar5212_desc *ads = AR5212DESC(ds); struct ath_hal_5212 *ahp = AH5212(ah); (void) hdrLen; HALASSERT(txTries0 != 0); HALASSERT(isValidPktType(type)); HALASSERT(isValidTxRate(txRate0)); HALASSERT((flags & RTSCTS) != RTSCTS); /* XXX validate antMode */ txPower = (txPower + ahp->ah_txPowerIndexOffset ); if(txPower > 63) txPower=63; ads->ds_ctl0 = (pktLen & AR_FrameLen) | (txPower << AR_XmitPower_S) | (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0) | (flags & HAL_TXDESC_CLRDMASK ? AR_ClearDestMask : 0) | SM(antMode, AR_AntModeXmit) | (flags & HAL_TXDESC_INTREQ ? AR_TxInterReq : 0) ; ads->ds_ctl1 = (type << AR_FrmType_S) | (flags & HAL_TXDESC_NOACK ? AR_NoAck : 0) | (comp << AR_CompProc_S) | (compicvLen << AR_CompICVLen_S) | (compivLen << AR_CompIVLen_S) ; ads->ds_ctl2 = SM(txTries0, AR_XmitDataTries0) | (flags & HAL_TXDESC_DURENA ? AR_DurUpdateEna : 0) ; ads->ds_ctl3 = (txRate0 << AR_XmitRate0_S) ; if (keyIx != HAL_TXKEYIX_INVALID) { /* XXX validate key index */ ads->ds_ctl1 |= SM(keyIx, AR_DestIdx); ads->ds_ctl0 |= AR_DestIdxValid; } if (flags & RTSCTS) { if (!isValidTxRate(rtsctsRate)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid rts/cts rate 0x%x\n", __func__, rtsctsRate); return AH_FALSE; } /* XXX validate rtsctsDuration */ ads->ds_ctl0 |= (flags & HAL_TXDESC_CTSENA ? AR_CTSEnable : 0) | (flags & HAL_TXDESC_RTSENA ? AR_RTSCTSEnable : 0) ; ads->ds_ctl2 |= SM(rtsctsDuration, AR_RTSCTSDuration); ads->ds_ctl3 |= (rtsctsRate << AR_RTSCTSRate_S); } return AH_TRUE;#undef RTSCTS}HAL_BOOLar5212SetupXTxDesc(struct ath_hal *ah, struct ath_desc *ds, u_int txRate1, u_int txTries1, u_int txRate2, u_int txTries2, u_int txRate3, u_int txTries3){ struct ar5212_desc *ads = AR5212DESC(ds); if (txTries1) { HALASSERT(isValidTxRate(txRate1)); ads->ds_ctl2 |= SM(txTries1, AR_XmitDataTries1) | AR_DurUpdateEna ; ads->ds_ctl3 |= (txRate1 << AR_XmitRate1_S); } if (txTries2) { HALASSERT(isValidTxRate(txRate2)); ads->ds_ctl2 |= SM(txTries2, AR_XmitDataTries2) | AR_DurUpdateEna ; ads->ds_ctl3 |= (txRate2 << AR_XmitRate2_S); } if (txTries3) { HALASSERT(isValidTxRate(txRate3)); ads->ds_ctl2 |= SM(txTries3, AR_XmitDataTries3) | AR_DurUpdateEna ; ads->ds_ctl3 |= (txRate3 << AR_XmitRate3_S); } return AH_TRUE;}voidar5212IntrReqTxDesc(struct ath_hal *ah, struct ath_desc *ds){ struct ar5212_desc *ads = AR5212DESC(ds);#ifdef AH_NEED_DESC_SWAP ads->ds_ctl0 |= __bswap32(AR_TxInterReq);#else ads->ds_ctl0 |= AR_TxInterReq;#endif}HAL_BOOLar5212FillTxDesc(struct ath_hal *ah, struct ath_desc *ds, u_int segLen, HAL_BOOL firstSeg, HAL_BOOL lastSeg, const struct ath_desc *ds0){ struct ar5212_desc *ads = AR5212DESC(ds); HALASSERT((segLen &~ AR_BufLen) == 0); if (firstSeg) { /* * First descriptor, don't clobber xmit control data * setup by ar5212SetupTxDesc. */ ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_More); } else if (lastSeg) { /* !firstSeg && lastSeg */ /* * Last descriptor in a multi-descriptor frame, * copy the multi-rate transmit parameters from * the first frame for processing on completion. */ ads->ds_ctl0 = 0; ads->ds_ctl1 = segLen;#ifdef AH_NEED_DESC_SWAP ads->ds_ctl2 = __bswap32(AR5212DESC_CONST(ds0)->ds_ctl2); ads->ds_ctl3 = __bswap32(AR5212DESC_CONST(ds0)->ds_ctl3);#else ads->ds_ctl2 = AR5212DESC_CONST(ds0)->ds_ctl2; ads->ds_ctl3 = AR5212DESC_CONST(ds0)->ds_ctl3;#endif } else { /* !firstSeg && !lastSeg */ /* * Intermediate descriptor in a multi-descriptor frame. */ ads->ds_ctl0 = 0; ads->ds_ctl1 = segLen | AR_More; ads->ds_ctl2 = 0; ads->ds_ctl3 = 0; } ads->ds_txstatus0 = ads->ds_txstatus1 = 0; return AH_TRUE;}#ifdef AH_NEED_DESC_SWAP/* Swap transmit descriptor */static __inline voidar5212SwapTxDesc(struct ath_desc *ds){ ds->ds_data = __bswap32(ds->ds_data); ds->ds_ctl0 = __bswap32(ds->ds_ctl0); ds->ds_ctl1 = __bswap32(ds->ds_ctl1); ds->ds_hw[0] = __bswap32(ds->ds_hw[0]); ds->ds_hw[1] = __bswap32(ds->ds_hw[1]); ds->ds_hw[2] = __bswap32(ds->ds_hw[2]); ds->ds_hw[3] = __bswap32(ds->ds_hw[3]);}#endif/* * Processing of HW TX descriptor. */HAL_STATUSar5212ProcTxDesc(struct ath_hal *ah, struct ath_desc *ds, struct ath_tx_status *ts){ struct ar5212_desc *ads = AR5212DESC(ds);#ifdef AH_NEED_DESC_SWAP if ((ads->ds_txstatus1 & __bswap32(AR_Done)) == 0) return HAL_EINPROGRESS; ar5212SwapTxDesc(ds);#else if ((ads->ds_txstatus1 & AR_Done) == 0) return HAL_EINPROGRESS;#endif /* Update software copies of the HW status */ ts->ts_seqnum = MS(ads->ds_txstatus1, AR_SeqNum); ts->ts_tstamp = MS(ads->ds_txstatus0, AR_SendTimestamp); ts->ts_status = 0; if ((ads->ds_txstatus0 & AR_FrmXmitOK) == 0) { if (ads->ds_txstatus0 & AR_ExcessiveRetries) ts->ts_status |= HAL_TXERR_XRETRY; if (ads->ds_txstatus0 & AR_Filtered) ts->ts_status |= HAL_TXERR_FILT; if (ads->ds_txstatus0 & AR_FIFOUnderrun) ts->ts_status |= HAL_TXERR_FIFO; } /* * Extract the transmit rate used and mark the rate as * ``alternate'' if it wasn't the series 0 rate. */ ts->ts_finaltsi = MS(ads->ds_txstatus1, AR_FinalTSIndex); switch (ts->ts_finaltsi) { case 0: ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate0); break; case 1: ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate1) | HAL_TXSTAT_ALTRATE; break; case 2: ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate2) | HAL_TXSTAT_ALTRATE; break; case 3: ts->ts_rate = MS(ads->ds_ctl3, AR_XmitRate3) | HAL_TXSTAT_ALTRATE; break; } ts->ts_rssi = MS(ads->ds_txstatus1, AR_AckSigStrength); ts->ts_shortretry = MS(ads->ds_txstatus0, AR_RTSFailCnt); ts->ts_longretry = MS(ads->ds_txstatus0, AR_DataFailCnt); /* * The retry count has the number of un-acked tries for the * final series used. When doing multi-rate retry we must * fixup the retry count by adding in the try counts for * each series that was fully-processed. Beware that this * takes values from the try counts in the final descriptor. * These are not required by the hardware. We assume they * are placed there by the driver as otherwise we have no * access and the driver can't do the calculation because it * doesn't know the descriptor format. */ switch (ts->ts_finaltsi) { case 3: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries2); case 2: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries1); case 1: ts->ts_longretry += MS(ads->ds_ctl2, AR_XmitDataTries0); } ts->ts_virtcol = MS(ads->ds_txstatus0, AR_VirtCollCnt); ts->ts_antenna = (ads->ds_txstatus1 & AR_XmitAtenna ? 2 : 1); return HAL_OK;}/* * Determine which tx queues need interrupt servicing. */voidar5212GetTxIntrQueue(struct ath_hal *ah, uint32_t *txqs){ struct ath_hal_5212 *ahp = AH5212(ah); *txqs &= ahp->ah_intrTxqs; ahp->ah_intrTxqs &= ~(*txqs);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -