📄 ar5212_xmit.c
字号:
| (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); break; default: /* NB: silence compiler */ break; }#ifndef AH_DISABLE_WME /* * Yes, this is a hack and not the right way to do it, but * it does get the lockout bits and backoff set for the * high-pri WME queues for testing. We need to either extend * the meaning of queueInfo->mode, or create something like * queueInfo->dcumode. */ if (qi->tqi_intFlags & HAL_TXQ_USE_LOCKOUT_BKOFF_DIS) { OS_REG_WRITE(ah, AR_DMISC(q), OS_REG_READ(ah, AR_DMISC(q)) | SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, AR_D_MISC_ARB_LOCKOUT_CNTRL)| AR_D_MISC_POST_FR_BKOFF_DIS); }#endif /* Setup compression scratchpad buffer */ /* * XXX: calling this asynchronously to queue operation can * cause unexpected behavior!!! */ if (qi->tqi_physCompBuf) { HALASSERT((type == HAL_TX_QUEUE_DATA || type == HAL_TX_QUEUE_UAPSD)); OS_REG_WRITE(ah, AR_Q_CBBS, (80 + 2*q)); OS_REG_WRITE(ah, AR_Q_CBBA, qi->tqi_physCompBuf); OS_REG_WRITE(ah, AR_Q_CBC, HAL_COMP_BUF_MAX_SIZE/1024); OS_REG_WRITE(ah, AR_Q0_MISC + 4*q, OS_REG_READ(ah, AR_Q0_MISC + 4*q) | AR_Q_MISC_QCU_COMP_EN); } /* * Always update the secondary interrupt mask registers - this * could be a new queue getting enabled in a running system or * hw getting re-initialized during a reset! * * Since we don't differentiate between tx interrupts corresponding * to individual queues - secondary tx mask regs are always unmasked; * tx interrupts are enabled/disabled for all queues collectively * using the primary mask reg */ if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) ahp->ah_txOkInterruptMask |= 1 << q; else ahp->ah_txOkInterruptMask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) ahp->ah_txErrInterruptMask |= 1 << q; else ahp->ah_txErrInterruptMask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) ahp->ah_txDescInterruptMask |= 1 << q; else ahp->ah_txDescInterruptMask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) ahp->ah_txEolInterruptMask |= 1 << q; else ahp->ah_txEolInterruptMask &= ~(1 << q); if (qi->tqi_qflags & TXQ_FLAG_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 */u_int32_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, u_int32_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); HALDEBUGn(ah, 2, "%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);#if 0 /* XXX - Disable timebomb. Don't need this anymore I think */#ifdef AH_SUPPORT_DFS if (AH5212(ah)->ah_dfsDisabled & HAL_DFS_DISABLE) { u_int32_t val; val = OS_REG_READ(ah, AR_Q_TXE); val &= ~(1 << q); OS_REG_WRITE(ah, AR_Q_TXE, val); return AH_FALSE; }#endif#endif 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. */u_int32_tar5212NumTxPending(struct ath_hal *ah, u_int q){ u_int32_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 */ }#ifdef DEBUG if (npend && (AH5212(ah)->ah_txq[q].tqi_type == HAL_TX_QUEUE_CAB)) { if (OS_REG_READ(ah, AR_Q_RDYTIMESHDN) & (1 << q)) { isrPrintf("RTSD on CAB queue\n"); /* Clear the ReadyTime shutdown status bits */ OS_REG_WRITE(ah, AR_Q_RDYTIMESHDN, 1 << q); } }#endif return npend;}/* * Stop transmit on the specified queue */HAL_BOOLar5212StopTxDma(struct ath_hal *ah, u_int q){ u_int i; u_int pktsOnQueue = ((IS_2413(ah) || IS_5413(ah)) ? 1 : 0); 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, "%s: queue %u DMA did not stop in 100 msec\n", __func__, q); HALDEBUG(ah, "%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, "%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))) { u_int32_t tsfLow, j; HALDEBUG(ah, "%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, "%s: TSF have 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) {#ifdef AH_DEBUG HALDEBUG(ah, "%s: Failed to stop Tx DMA in %d msec after killing last frame\n", __func__, wait);#endif 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);}/* Set the Interrupt Req and VEOL for the frame *//* Note: caller must ensure (_ds) is not NULL */#define AR5212_SET_INT_VEOL_IN_TXDESC(_ds, _value) do { \ u_int8_t moreData = ((_ds)->ds_ctl1 & AR_More); \ struct ar5212_desc *currds = (_ds); \ while (currds && moreData) { \ currds->ds_ctl0 = (_value) ? \ (currds->ds_ctl0 | (AR_TxInterReq)) \ : (currds->ds_ctl0 & ~(AR_TxInterReq)); \ currds++; \ if (currds) { \ moreData = (currds->ds_ctl1 & AR_More); \ } \ } \ HALASSERT(currds); \ /* Set the Last Desc interrupt Req and VEOL bit */ \ currds->ds_ctl0 = (_value) ? \ (currds->ds_ctl0 | (AR_TxInterReq | AR_VEOL)) \ : (currds->ds_ctl0 & ~(AR_TxInterReq | AR_VEOL)); \} while(0)HAL_BOOLar5212UpdateCTSForBursting(struct ath_hal *ah, struct ath_desc *ds, struct ath_desc *prevds, struct ath_desc *prevdsWithCTS, struct ath_desc *gatingds, u_int32_t txOpLimit /* in us */, u_int32_t ctsDuration){ struct ath_hal_5212 *ahp = AH5212(ah); struct ar5212_desc *ads = AR5212DESC(ds); struct ar5212_desc *aprevds = AR5212DESC(prevds); struct ar5212_desc *aprevdsWithCTS = AR5212DESC(prevdsWithCTS); struct ar5212_desc *agatingds = AR5212DESC(gatingds); u_int32_t aprevRTSCTSDur = 0; u_int32_t decCTSdur = 0; u_int8_t doneBit = 1; u_int8_t disableRTSCTS = 0; u_int8_t aprevRTSEnable = 0; u_int32_t adsRTSCTSDur = 0; u_int32_t adsRTSCTSRate = 0; u_int32_t adsRTSCTSEnable = 0; HALASSERT(ads); if (txOpLimit) { /* Check if previous RTS/CTS has been sent yet. */ /* If not, record its RTS/CTS duration */ HAL_INT omask; /* * Disable interrupts while futzing with the live queue. */ omask = ar5212SetInterrupts(ah, ahp->ah_maskReg &~ HAL_INT_GLOBAL); if (agatingds) { doneBit = (agatingds->ds_txstatus1 & AR_Done); aprevRTSCTSDur = MS(aprevdsWithCTS->ds_ctl2, AR_RTSCTSDuration); aprevRTSEnable = (aprevdsWithCTS->ds_ctl0 & AR_RTSCTSEnable); } /* Record current frame's RTS/CTS properties: */ /* duration, rate, enable */ adsRTSCTSRate = MS(ads->ds_ctl3, AR_RTSCTSRate); adsRTSCTSDur = MS(ads->ds_ctl2, AR_RTSCTSDuration); adsRTSCTSEnable = (ads->ds_ctl0 & (AR_RTSCTSEnable | AR_CTSEnable)); /* If the previous CTS packet has been sent, exit early */ if (!doneBit && adsRTSCTSEnable) { /* Account for extra RTS duration that covers the CTS packet */ if (aprevRTSEnable) { decCTSdur = ctsDuration; } /* * If the previous CTS packet's CTS duration can be extended to cover * the current packet while not exceeding the TxOpLimit, * extend this CTS duration and disable CTS * on the current packet ---> burst extention */ if ((aprevRTSCTSDur + adsRTSCTSDur - decCTSdur) <= txOpLimit) { aprevRTSCTSDur += (adsRTSCTSDur - decCTSdur); if (aprevdsWithCTS) { aprevdsWithCTS->ds_ctl2 = (aprevdsWithCTS->ds_ctl2 & ~AR_RTSCTSDuration) | SM(aprevRTSCTSDur, AR_RTSCTSDuration); if (!(agatingds->ds_txstatus1 & AR_Done)) { disableRTSCTS = 1; } } if (disableRTSCTS) { ads->ds_ctl0 = (ads->ds_ctl0 & ~(AR_RTSCTSEnable | AR_CTSEnable)); ads->ds_ctl2 = (ads->ds_ctl2 & ~AR_RTSCTSDuration); } } } AR5212_SET_INT_VEOL_IN_TXDESC(ads, 1); if (disableRTSCTS && aprevds) { AR5212_SET_INT_VEOL_IN_TXDESC(aprevds, 0); } /* re-enable chip interrupts */ ar5212SetInterrupts(ah, omask); } return disableRTSCTS;}/* * 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)|\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -