⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ar5212_xmit.c

📁 Atheros wifi driver source code
💻 C
📖 第 1 页 / 共 3 页
字号:
			| (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 + -