static A_UINT8 
rcRateGetIndex(struct ath_softc_tgt *sc, struct ath_node_target *an,        
               const RATE_TABLE_11N *pRateTable , 
               A_UINT8 rix, A_UINT16 stepDown, A_UINT16 minRate)
{
	A_UINT32                j;
	A_UINT8                 nextIndex;
	struct atheros_node     *pSib = ATH_NODE_ATHEROS(an);
	TX_RATE_CTRL            *pRc = (TX_RATE_CTRL *)(pSib);
    
	if (minRate) {
		for (j = RATE_TABLE_11N_SIZE; j > 0; j-- ) {
			if (rcGetNextLowerValidTxRate(pRateTable, pRc, rix, &nextIndex)) {
				rix = nextIndex;
			} else {
				break;
			}
		}
	} else {
		for (j = stepDown; j > 0; j-- ) {
			if (rcGetNextLowerValidTxRate(pRateTable, pRc, rix, &nextIndex)) {
				rix = nextIndex;
			} else {
				break;
			}
		}
	}

	return rix;
}
static void
ath_rate_newassoc_11n(struct ath_softc_tgt *sc, struct ath_node_target *an, int isnew, 
		      unsigned int capflag, struct ieee80211_rate *rs)
{
	struct ieee80211vap  *vap = an->ni.ni_vap;
    
	if (isnew) {
		struct atheros_node *oan = ATH_NODE_ATHEROS(an);

		oan->htcap = ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) |
			((capflag & ATH_RC_HT40_SGI_FLAG) ? WLAN_RC_HT40_SGI_FLAG : 0) | 
			((capflag & ATH_RC_HT_FLAG)  ? WLAN_RC_HT_FLAG : 0) |
			((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0) |
			((capflag & ATH_RC_WEP_TKIP_FLAG) ? WLAN_RC_WEP_TKIP_FLAG : 0);    
    
#ifdef MAGPIE_MERLIN
		/* Rx STBC is a 2-bit mask. Needs to convert from ath definition to wlan definition. */
        
		oan->htcap |= (((capflag & ATH_RC_RX_STBC_FLAG) >> ATH_RC_RX_STBC_FLAG_S)
			       << WLAN_RC_STBC_FLAG_S);
                       
		/* If only one chain is enabled, do not do stbc. */
		if (sc->sc_txstbcsupport) {
			oan->stbc = (capflag & ATH_RC_RX_STBC_FLAG) >> ATH_RC_RX_STBC_FLAG_S;
		} else {
void
ath_rate_findrate(struct ath_softc_tgt *sc,
                  struct ath_node_target *an,
                  int shortPreamble,
                  size_t frameLen,
                  int numTries,
                  int numRates,
                  int stepDnInc,
                  unsigned int rcflag,
                  struct ath_rc_series series[],
                  int *isProbe)
{
	struct ieee80211vap *vap = an->ni.ni_vap;
	struct atheros_node *oan = ATH_NODE_ATHEROS(an);
	struct atheros_softc *asc = (struct atheros_softc *) sc->sc_rc;
	RATE_TABLE *pRateTable = (RATE_TABLE *)asc->hwRateTable[sc->sc_curmode];
	u_int32_t *retrySched;

	*isProbe = 0;

	if (!numRates || !numTries) {
		return;
	}

	ath_rate_findrate_11n(sc, an, frameLen, numTries, numRates, stepDnInc,
			      rcflag, series, isProbe);
}
Пример #4
0
/*
 * Update rate-control state on station associate/reassociate.
 */
static int
ath_rate_newassoc_11n(struct ath_softc *sc, struct ath_node *an, int isnew,
                      unsigned int capflag,
                      struct ieee80211_rateset *negotiated_rates,
                      struct ieee80211_rateset *negotiated_htrates)
{
    struct atheros_node    *oan = ATH_NODE_ATHEROS(an);

    if (isnew) {
        u_int32_t node_maxRate = (u_int32_t) (-1);
        MAX_RATES maxRates;
        
        OS_MEMZERO(&maxRates, sizeof(maxRates));

        /* FIX ME:XXXX Looks like this not used at all.    */
        oan->htcap =
                    ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) |
                    ((capflag & ATH_RC_TS_FLAG) ? WLAN_RC_TS_FLAG : 0) |
                    ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) |
                    ((capflag & ATH_RC_HT_FLAG)  ? WLAN_RC_HT_FLAG : 0) |
#ifdef ATH_SUPPORT_TxBF
                    ((capflag & ATH_RC_TXBF_FLAG) ? WLAN_RC_TxBF_FLAG:0)|     
#endif
                    ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0);

        /* Rx STBC is a 2-bit mask. Needs to convert from ath definition to wlan definition. */
        oan->htcap |= (((capflag & ATH_RC_RX_STBC_FLAG) >> ATH_RC_RX_STBC_FLAG_S)
                       << WLAN_RC_STBC_FLAG_S);

        /* Enable stbc only for more than one tx chain */
        if (sc->sc_txstbcsupport && (sc->sc_tx_chainmask != 1)) {
            oan->stbc = (capflag & ATH_RC_RX_STBC_FLAG) >> ATH_RC_RX_STBC_FLAG_S;
        } else {
Пример #5
0
/*
 *  This routine is called to initialize the rate control parameters
 *  in the SIB. It is called initially during system initialization
 *  or when a station is associated with the AP.
 */
void
rcSibInit(struct ath_softc *sc, struct ath_node *an)
{
    struct atheros_node	*pSib	    = ATH_NODE_ATHEROS(an);
    struct TxRateCtrl_s *pRc        = &pSib->txRateCtrl;

#if 0
    /* NB: caller assumed to zero state */
    A_MEM_ZERO((char *)pSib, sizeof(*pSib));
#endif
    pRc->rssiDownTime = A_MS_TICKGET();
}
static void
ath_rate_findrate_11n(struct ath_softc_tgt *sc,
		      struct ath_node_target *an,
		      size_t frameLen,
		      int numTries,
		      int numRates,
		      int stepDnInc,
		      unsigned int rcflag,
		      struct ath_rc_series series[],
		      int *isProbe)
{
	struct ieee80211vap  *vap = an->ni.ni_vap;
	struct atheros_node *oan = ATH_NODE_ATHEROS(an);

	*isProbe = 0;
	if (!numRates || !numTries) {
		return;
	}

	rcRateFind_11n(sc, an, numTries, numRates, stepDnInc, rcflag, series, isProbe);
}
/*
 * This routine is called by the Tx interrupt service routine to give
 * the status of previous frames.
 */
void rcUpdate_11n(struct ath_softc_tgt *sc, struct ath_node_target *an,
		  A_UINT8 curTxAnt, 
		  int finalTSIdx, int Xretries,
		  struct ath_rc_series rcs[], int nFrames, 
		  int nBad, int long_retry)
{
	A_UINT32 series = 0;
	A_UINT32 rix;
	struct atheros_softc *asc = (struct atheros_softc*)sc->sc_rc;
	RATE_TABLE_11N *pRateTable = (RATE_TABLE_11N *)asc->hwRateTable[sc->sc_curmode];
	struct atheros_node *pSib = ATH_NODE_ATHEROS(an);
	TX_RATE_CTRL *pRc = (TX_RATE_CTRL *)(pSib);
	A_UINT8 flags;

	if (!an) {
		adf_os_assert(0);
		return;
	}

	ASSERT (rcs[0].tries != 0);

	/*
	 * If the first rate is not the final index, there are intermediate rate failures
	 * to be processed.
	 */
	if (finalTSIdx != 0) {

		/* Process intermediate rates that failed.*/
		for (series = 0; series < finalTSIdx ; series++) {
			if (rcs[series].tries != 0) {
				flags = rcs[series].flags;
				/* If HT40 and we have switched mode from 40 to 20 => don't update */
				if ((flags & ATH_RC_CW40_FLAG) && 
				    (pRc->rcPhyMode != (flags & ATH_RC_CW40_FLAG))) {
					return;
				}
				if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_HT40_SGI_FLAG)) {
					rix = pRateTable->info[rcs[series].rix].htIndex;
				} else if (flags & ATH_RC_HT40_SGI_FLAG) {
					rix = pRateTable->info[rcs[series].rix].sgiIndex;
				} else if (flags & ATH_RC_CW40_FLAG) {
					rix = pRateTable->info[rcs[series].rix].cw40Index;
				} else {
					rix = pRateTable->info[rcs[series].rix].baseIndex;
				}

				/* FIXME:XXXX, too many args! */
				rcUpdate_ht(sc, an, rix, Xretries? 1 : 2, rcs[series].tries, 
					    curTxAnt, nFrames, nFrames);
			}
		}
	} else {
		/*
		 * Handle the special case of MIMO PS burst, where the second aggregate is sent
		 *  out with only one rate and one try. Treating it as an excessive retry penalizes
		 * the rate inordinately.
		 */
		if (rcs[0].tries == 1 && Xretries == 1) {
			Xretries = 2;
		}
	}

	flags = rcs[series].flags;
	/* If HT40 and we have switched mode from 40 to 20 => don't update */
	if ((flags & ATH_RC_CW40_FLAG) && 
	    (pRc->rcPhyMode != (flags & ATH_RC_CW40_FLAG))) {
		return;
	}
	if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_HT40_SGI_FLAG)) {
		rix = pRateTable->info[rcs[series].rix].htIndex;
	} else if (flags & ATH_RC_HT40_SGI_FLAG) {
		rix = pRateTable->info[rcs[series].rix].sgiIndex;
	} else if (flags & ATH_RC_CW40_FLAG) {
		rix = pRateTable->info[rcs[series].rix].cw40Index;
	} else {
		rix = pRateTable->info[rcs[series].rix].baseIndex;
	}

	/* FIXME:XXXX, too many args! */
	rcUpdate_ht(sc, an, rix, Xretries, long_retry, curTxAnt, 
		    nFrames, nBad);
}
static void
rcUpdate_ht(struct ath_softc_tgt *sc, struct ath_node_target *an, int txRate, 
            A_BOOL Xretries, int retries, A_UINT8 curTxAnt, 
            A_UINT16 nFrames, A_UINT16 nBad)
{
	TX_RATE_CTRL *pRc;
	A_UINT32 nowMsec = A_MS_TICKGET();
	A_BOOL stateChange = FALSE;
	A_UINT8 lastPer;
	int rate,count;
	struct atheros_node *pSib = ATH_NODE_ATHEROS(an);
	struct atheros_softc *asc = (struct atheros_softc*)sc->sc_rc;
	RATE_TABLE_11N *pRateTable = (RATE_TABLE_11N *)asc->hwRateTable[sc->sc_curmode];
	u_int32_t txRateKbps;

	static A_UINT32 nRetry2PerLookup[10] = {
		100 * 0 / 1,    // 0
		100 * 1 / 4,    // 25
		100 * 1 / 2,    // 50
		100 * 3 / 4,    // 75
		100 * 4 / 5,    // 80
		100 * 5 / 6,    // 83.3
		100 * 6 / 7,    // 85.7
		100 * 7 / 8,    // 87.5
		100 * 8 / 9,    // 88.8
		100 * 9 / 10    // 90
	};

	if (!pSib)
		return;

	pRc = (TX_RATE_CTRL *)(pSib);

	ASSERT(retries >= 0 && retries < MAX_TX_RETRIES);
	ASSERT(txRate >= 0);
    
	if (txRate < 0) {
		return;
	}

	lastPer = pRc->state[txRate].per;

	if (Xretries) {
		/* Update the PER. */
		if (Xretries == 1) {
			pRc->state[txRate].per += 30;
			if (pRc->state[txRate].per > 100) {
				pRc->state[txRate].per = 100;
			}
		} else {
			/* Xretries == 2 */

			count = sizeof(nRetry2PerLookup) / sizeof(nRetry2PerLookup[0]);
			if (retries >= count) {
				retries = count - 1;
			}

			/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
			pRc->state[txRate].per = (A_UINT8)(pRc->state[txRate].per - 
						   (pRc->state[txRate].per / 8) + ((100) / 8));
		}

		/* Xretries == 1 or 2 */

		if (pRc->probeRate == txRate)
			pRc->probeRate = 0;
	} else {
		/* Xretries == 0 */

		/*
		 * Update the PER.  Make sure it doesn't index out of array's bounds.
		 */
		count = sizeof(nRetry2PerLookup) / sizeof(nRetry2PerLookup[0]);
		if (retries >= count) {
			retries = count - 1;
		}

		if (nBad) {
			/* new_PER = 7/8*old_PER + 1/8*(currentPER)  */
			/*
			 * Assuming that nFrames is not 0.  The current PER
			 * from the retries is 100 * retries / (retries+1),
			 * since the first retries attempts failed, and the
			 * next one worked.  For the one that worked, nBad
			 * subframes out of nFrames wored, so the PER for
			 * that part is 100 * nBad / nFrames, and it contributes
			 * 100 * nBad / (nFrames * (retries+1)) to the above
			 * PER.  The expression below is a simplified version
			 * of the sum of these two terms.
			 */
			if (nFrames > 0)
				pRc->state[txRate].per = (A_UINT8)(pRc->state[txRate].per - 
					   (pRc->state[txRate].per / 8) + 
					   ((100*(retries*nFrames + nBad)/(nFrames*(retries+1))) / 8));
		} else {
			/* new_PER = 7/8*old_PER + 1/8*(currentPER) */

			pRc->state[txRate].per = (A_UINT8)(pRc->state[txRate].per - 
				   (pRc->state[txRate].per / 8) + (nRetry2PerLookup[retries] / 8));
		}

		/*
		 * If we got at most one retry then increase the max rate if
		 * this was a probe.  Otherwise, ignore the probe.
		 */

		if (pRc->probeRate && pRc->probeRate == txRate) {
			if (retries > 0 || 2 * nBad > nFrames) {
				/*
				 * Since we probed with just a single attempt,
				 * any retries means the probe failed.  Also,
				 * if the attempt worked, but more than half
				 * the subframes were bad then also consider
				 * the probe a failure.
				 */
				pRc->probeRate = 0;
			} else {
				pRc->rateMaxPhy = pRc->probeRate;

				if (pRc->state[pRc->probeRate].per > 30) {
					pRc->state[pRc->probeRate].per = 20;
				}

				pRc->probeRate = 0;

				/*
				 * Since this probe succeeded, we allow the next probe
				 * twice as soon.  This allows the maxRate to move up
				 * faster if the probes are succesful.
				 */
				pRc->probeTime = nowMsec - pRateTable->probeInterval / 2;
			}
		}

		if (retries > 0) {
			/*
			 * Don't update anything.  We don't know if this was because
			 * of collisions or poor signal.
			 *
			 * Later: if rssiAck is close to pRc->state[txRate].rssiThres
			 * and we see lots of retries, then we could increase
			 * pRc->state[txRate].rssiThres.
			 */
			pRc->hwMaxRetryPktCnt = 0;
		} else {
			/*
			 * It worked with no retries.  First ignore bogus (small)
			 * rssiAck values.
			 */
			if (txRate == pRc->rateMaxPhy && pRc->hwMaxRetryPktCnt < 255) {
				pRc->hwMaxRetryPktCnt++;
			}

		}
	}

	/* For all cases */

	ASSERT((pRc->rateMaxPhy >= 0 && pRc->rateMaxPhy <= pRc->rateTableSize && 
		pRc->rateMaxPhy != INVALID_RATE_MAX));
    
	/*
	 * If this rate looks bad (high PER) then stop using it for
	 * a while (except if we are probing).
	 */
	if (pRc->state[txRate].per >= 55 && txRate > 0 &&
	    pRateTable->info[txRate].rateKbps <= 
            pRateTable->info[pRc->rateMaxPhy].rateKbps)
	{
		rcGetNextLowerValidTxRate(pRateTable, pRc, (A_UINT8) txRate, 
					  &pRc->rateMaxPhy);

		/* Don't probe for a little while. */
		pRc->probeTime = nowMsec;
	}

	/* Make sure the rates below this have lower PER */
	/* Monotonicity is kept only for rates below the current rate. */
	if (pRc->state[txRate].per < lastPer) {
		for (rate = txRate - 1; rate >= 0; rate--) {
			if (pRateTable->info[rate].phy != pRateTable->info[txRate].phy) {
				break;
			}

			if (pRc->state[rate].per > pRc->state[rate+1].per) {
				pRc->state[rate].per = pRc->state[rate+1].per;
			}
		}
	}

	/* Maintain monotonicity for rates above the current rate*/
	for (rate = txRate; rate < pRc->rateTableSize - 1; rate++) {
		if (pRc->state[rate+1].per < pRc->state[rate].per) {
			pRc->state[rate+1].per = pRc->state[rate].per;
		}
	}

	/* Every so often, we reduce the thresholds and PER (different for CCK and OFDM). */
	if (nowMsec - pRc->perDownTime >= pRateTable->rssiReduceInterval) {
		for (rate = 0; rate < pRc->rateTableSize; rate++) {
			pRc->state[rate].per = 7*pRc->state[rate].per/8;
		}

		pRc->perDownTime = nowMsec;
	}
}
void rcRateFind_11n(struct ath_softc_tgt *sc, struct ath_node_target *an, 
		    int numTries, int numRates, int stepDnInc,
		    unsigned int rcflag, struct ath_rc_series series[], int *isProbe)
{
	A_UINT8 i = 0; 
	A_UINT8 tryPerRate  = 0;
	struct atheros_softc *asc = (struct atheros_softc*)sc->sc_rc;
	RATE_TABLE_11N *pRateTable = (RATE_TABLE_11N *)asc->hwRateTable[sc->sc_curmode];
	struct atheros_node *asn = ATH_NODE_ATHEROS(an);
	A_UINT8 rix, nrix;
	A_UINT8 dot11Rate;
	A_UINT8 rateCode;
	WLAN_PHY phy;

	rix = rcRateFind_ht(sc, asn, pRateTable, (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, 
			    isProbe);
	nrix = rix;

	if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*isProbe)) {
		/* set one try for probe rates. For the probes don't enable rts */
		rcRateSetseries(pRateTable, &series[i++], 1, nrix,
				FALSE, asc->tx_chainmask, asn->stbc);
          
		/*
		 * Get the next tried/allowed rate. No RTS for the next series
		 * after the probe rate
		 */
		nrix = rcRateGetIndex( sc, an, pRateTable, nrix, 1, FALSE);
	}

	tryPerRate = (numTries/numRates);

	/* Set the choosen rate. No RTS for first series entry. */
	rcRateSetseries(pRateTable, &series[i++], tryPerRate,
			nrix, FALSE, asc->tx_chainmask, asn->stbc);

	/* Fill in the other rates for multirate retry */
	for (; i < numRates; i++) {
		A_UINT8 tryNum;
		A_UINT8 minRate;

		tryNum  = ((i + 1) == numRates) ? numTries - (tryPerRate * i) : tryPerRate ;
		minRate = (((i + 1) == numRates) && (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;

		nrix = rcRateGetIndex(sc, an, pRateTable, nrix, stepDnInc, minRate);

		/* All other rates in the series have RTS enabled */
		rcRateSetseries(pRateTable, &series[i], tryNum,
				nrix, TRUE, asc->tx_chainmask, asn->stbc);
	}

	/*
	 * BUG 26545:
	 * Change rate series to enable aggregation when operating at lower MCS rates. 
	 * When first rate in series is MCS2 in HT40 @ 2.4GHz, series should look like:
	 *    {MCS2, MCS1, MCS0, MCS0}.
	 * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should look like:
	 *    {MCS3, MCS2, MCS1, MCS1}
	 * So, set fourth rate in series to be same as third one for above conditions.
	 */
	if (sc->sc_curmode == IEEE80211_MODE_11NG) {
		dot11Rate = pRateTable->info[rix].dot11Rate;
		phy = pRateTable->info[rix].phy;
		if (i == 4 &&
		    ((dot11Rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || 
		     (dot11Rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) 
		{
			series[3].rix = series[2].rix;
			series[3].flags = series[2].flags;
			series[3].max4msframelen = series[2].max4msframelen;
		}
	}

	/*
	 * 2009/02/06
	 * AP91 Kite: NetGear OTA location-4 downlink.
	 *            Enable RTS/CTS at MCS 3-0 for downlink throughput.
	 */
	if (sc->sc_curmode == IEEE80211_MODE_11NG) {
		dot11Rate = pRateTable->info[rix].dot11Rate;
		if (dot11Rate <= 3 ) {
			series[0].flags |= ATH_RC_RTSCTS_FLAG;         
		}
	}
}
/* 
 * Initialize the Valid Rate Index from Rate Set 
 */
static A_UINT8
rcSibSetValidRates(const RATE_TABLE_11N *pRateTable,
		   TX_RATE_CTRL *pRc, 
                   struct ieee80211_rateset *pRateSet,
		   A_UINT32 capflag,
		   struct ath_node_target *an,
		   PHY_STATE_CTRL *pPhyStateCtrl)
{
	A_UINT8 i, j, hi = 0;
	A_UINT8 singleStream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1;
	A_UINT32 valid;
	struct atheros_node *pSib = ATH_NODE_ATHEROS(an);
       
	/* Use intersection of working rates and valid rates */
	for (i = 0; i < pRateSet->rs_nrates; i++) {
		for (j = 0; j < pRateTable->rateCount; j++) {
			A_UINT32 phy = pRateTable->info[j].phy;

#ifdef MAGPIE_MERLIN
			if (pSib->stbc) {
				valid = pRateTable->info[j].validSTBC;
			} else if (singleStream) {
#else
			if (singleStream) {
#endif            
				valid = pRateTable->info[j].validSingleStream;
			} else {
				valid = pRateTable->info[j].valid;
			}
        
			/*
			 * We allow a rate only if its valid and the capflag matches one of
			 * the validity (TRUE/TRUE_20/TRUE_40) flags
			 */

			if (((pRateSet->rs_rates[i] & 0x7F) == 
			     (pRateTable->info[j].dot11Rate & 0x7F))
			    && ((valid & WLAN_RC_CAP_MODE(capflag)) == 
				WLAN_RC_CAP_MODE(capflag)) && !WLAN_RC_PHY_HT(phy)) {
				if (!rcIsValidPhyRate(phy, capflag, FALSE)) 
					continue;

				pPhyStateCtrl->validPhyRateIndex[phy][pPhyStateCtrl->validPhyRateCount[phy]] = j;
				pPhyStateCtrl->validPhyRateCount[phy] += 1;

				rcSetValidTxMask(pRc, j, TRUE);
				hi = A_MAX(hi, j);
			}
		}
	}
  
	return hi;
}

static A_UINT8
rcSibSetValidHtRates(const RATE_TABLE_11N *pRateTable,
		     TX_RATE_CTRL *pRc, 
                     A_UINT8 *pMcsSet,
		     A_UINT32 capflag,
		     struct ath_node_target *an,
		     PHY_STATE_CTRL *pPhyStateCtrl)
{
	A_UINT8 i, j, hi = 0;
	A_UINT8 singleStream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1;
	A_UINT8 valid;
	struct atheros_node *pSib = ATH_NODE_ATHEROS(an);
    
	/* Use intersection of working rates and valid rates */
	for (i = 0; i <  ((struct ieee80211_rateset *)pMcsSet)->rs_nrates; i++) {
		for (j = 0; j < pRateTable->rateCount; j++) {
			A_UINT32 phy = pRateTable->info[j].phy;

#ifdef MAGPIE_MERLIN
			if (pSib->stbc) {
				valid = pRateTable->info[j].validSTBC;
			} else if (singleStream) {
#else
			if (singleStream) {
#endif
				valid = pRateTable->info[j].validSingleStream;
			} else {
				valid = pRateTable->info[j].valid;
			}
                           
			if (((((struct ieee80211_rateset *)pMcsSet)->rs_rates[i] & 0x7F) 
			     != (pRateTable->info[j].dot11Rate & 0x7F)) 
			    || !WLAN_RC_PHY_HT(phy) 
			    || !WLAN_RC_PHY_HT_VALID(valid, capflag)
			    || ((pRateTable->info[j].dot11Rate == 15) && 
				(valid & TRUE_20) && 
				(capflag & WLAN_RC_WEP_TKIP_FLAG)) )
			{
				continue;
			}
    
			if (!rcIsValidPhyRate(phy, capflag, FALSE)) 
				continue;
    
			pPhyStateCtrl->validPhyRateIndex[phy][pPhyStateCtrl->validPhyRateCount[phy]] = j;
			pPhyStateCtrl->validPhyRateCount[phy] += 1;

			rcSetValidTxMask(pRc, j, TRUE);
			hi = A_MAX(hi, j);
		}
	}

	return hi;
}

/*
 *  Update the SIB's rate control information
 *
 *  This should be called when the supported rates change
 *  (e.g. SME operation, wireless mode change)
 *
 *  It will determine which rates are valid for use.
 */
static void
rcSibUpdate_ht(struct ath_softc_tgt *sc, struct ath_node_target *an,
	       A_UINT32 capflag, A_BOOL keepState, struct ieee80211_rate  *pRateSet)
{
	RATE_TABLE_11N *pRateTable = 0;
	struct atheros_node *pSib = ATH_NODE_ATHEROS(an);
	struct atheros_softc *asc = (struct atheros_softc*)sc->sc_rc;
	A_UINT8 *phtMcs = (A_UINT8*)&pRateSet->htrates;
	TX_RATE_CTRL *pRc = (TX_RATE_CTRL *)(pSib);
	PHY_STATE_CTRL mPhyCtrlState;  

	A_UINT8 i, j, k, hi = 0, htHi = 0;

	pRateTable = (RATE_TABLE_11N*)asc->hwRateTable[sc->sc_curmode];

	/* Initial rate table size. Will change depending on the working rate set */
	pRc->rateTableSize = MAX_TX_RATE_TBL;

	/* Initialize thresholds according to the global rate table */
	for (i = 0 ; (i < pRc->rateTableSize) && (!keepState); i++) {
		pRc->state[i].per       = 0;
	}

	/* Determine the valid rates */
	rcInitValidTxMask(pRc);

	for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
		for (j = 0; j < MAX_TX_RATE_PHY; j++) {
			mPhyCtrlState.validPhyRateIndex[i][j] = 0;
		}   
		mPhyCtrlState.validPhyRateCount[i] = 0;
	}

	pRc->rcPhyMode = (capflag & WLAN_RC_40_FLAG);

	if (pRateSet == NULL || !pRateSet->rates.rs_nrates) {
		/* No working rate, just initialize valid rates */
		hi = rcSibInitValidRates(pRateTable, pRc, capflag, &mPhyCtrlState);
	} else {
		/* Use intersection of working rates and valid rates */
		hi = rcSibSetValidRates(pRateTable, pRc, &(pRateSet->rates),
					capflag, an, &mPhyCtrlState);

		if (capflag & WLAN_RC_HT_FLAG) {
			htHi = rcSibSetValidHtRates(pRateTable, pRc, phtMcs,
						    capflag, an, &mPhyCtrlState);
		}

		hi = A_MAX(hi, htHi);
	}

	pRc->rateTableSize = hi + 1;
	pRc->rateMaxPhy    = 0;
    
	ASSERT(pRc->rateTableSize <= MAX_TX_RATE_TBL);

	for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
		for (j = 0; j < mPhyCtrlState.validPhyRateCount[i]; j++) {
			pRc->validRateIndex[k++] = mPhyCtrlState.validPhyRateIndex[i][j];
		}   

		if (!rcIsValidPhyRate(i, pRateTable->initialRateMax, TRUE) ||
		    !mPhyCtrlState.validPhyRateCount[i]) 
			continue;

		pRc->rateMaxPhy = mPhyCtrlState.validPhyRateIndex[i][j-1];	
	}
    
	ASSERT(pRc->rateTableSize <= MAX_TX_RATE_TBL);
	ASSERT(k <= MAX_TX_RATE_TBL);

	pRc->rateMaxPhy = pRc->validRateIndex[k-4];
	pRc->maxValidRate = k;

	rcSortValidRates(pRateTable, pRc);
}
Пример #11
0
static void
ath_rate_findrate_11n(struct ath_softc *sc,
                      struct ath_node *an,
                      size_t frameLen,
                      int numTries,
                      int numRates,
                      unsigned int rcflag,
                      u_int8_t ac,
                      struct ath_rc_series series[],
                      int *isProbe,
                      int isretry
                      )
{
    struct atheros_node    *oan = ATH_NODE_ATHEROS(an);
    struct ath_vap         *avp = oan->avp->athdev_vap;

    if (!numRates || !numTries) {
        return;
    }

    if (avp->av_config.av_fixed_rateset == IEEE80211_FIXED_RATE_NONE) {
#if ATH_SUPPORT_IQUE
        oan->rcFunc[ac].rcFind(sc, an, ac, numTries, numRates, rcflag, series, isProbe, isretry);
#else
        rcRateFind_11n(sc, an, ac, numTries, numRates, rcflag, series, isProbe, isretry);
#endif
    } else {
        /* Fixed rate */
        int idx;
        A_UINT16 flags;
        A_UINT32 rix;
        struct atheros_softc *asc = oan->asc;
        RATE_TABLE_11N *pRateTable = (RATE_TABLE_11N *)asc->hwRateTable[sc->sc_curmode];

        for (idx = 0; idx < 4; idx++) {
            unsigned int    mcs;
            unsigned int    maxRateCode;

            series[idx].tries =
                IEEE80211_RATE_IDX_ENTRY(avp->av_config.av_fixed_retryset, idx);

            mcs = IEEE80211_RATE_IDX_ENTRY(avp->av_config.av_fixed_rateset, idx);
 #ifdef ATH_SUPPORT_TxBF          
                //swap rate at sounding frame
            if ((sc->sc_txbfsounding) && (VALID_TXBF_RATE(mcs, oan->usedNss))){
                const u_int8_t  *sounding_swap_table;
                if ((sc->sc_curmode == WIRELESS_MODE_11NA_HT20) 
                    ||(sc->sc_curmode == WIRELESS_MODE_11NA_HT40PLUS) 
                    ||(sc->sc_curmode == WIRELESS_MODE_11NA_HT40MINUS))
                {    //A_band
                    if (series[0].flags & ATH_RC_CW40_FLAG ){
                        // 40M 
                        sounding_swap_table = sounding_swap_table_A_40;
                    } else {
                        sounding_swap_table = sounding_swap_table_A_20;
                    }
                } else {
                    // g band table
                    if (series[0].flags & ATH_RC_CW40_FLAG ){
                        // 40M 
                        sounding_swap_table = sounding_swap_table_G_40;
                    } else {
                        sounding_swap_table = sounding_swap_table_G_20; 
                    }
                }
                // swap rate
                mcs = sounding_swap_table[(mcs & SWAP_RATE)];       
            }
#endif

            if (idx == 3 && (mcs & 0xf0) == 0x70)
                mcs = (mcs & ~0xf0)|0x80;

            if (!(mcs & 0x80)) {
                flags = 0;
            } else {
                int i, j, SGIenable = 0;
                WLAN_PHY SGIphy = WLAN_RC_PHY_MAX;
                u_int8_t sgi_phy_options[2 /* 20 MHz vs. 40 MHz */][3 /* single, double, triple stream*/] = {
                {
                    WLAN_RC_PHY_HT_20_SS_HGI,
                    WLAN_RC_PHY_HT_20_DS_HGI,
                    WLAN_RC_PHY_HT_20_TS_HGI,
                }, {
                    WLAN_RC_PHY_HT_40_SS_HGI,
                    WLAN_RC_PHY_HT_40_DS_HGI,
                    WLAN_RC_PHY_HT_40_TS_HGI,
                }};
                
                /* enable short GI according to rate table*/

                i = (oan->htcap & WLAN_RC_40_FLAG) ? 1 : 0;
                j = (oan->htcap & WLAN_RC_TS_FLAG) ? 2 :
                    (oan->htcap & WLAN_RC_DS_FLAG) ? 1 : 0;
                SGIphy = sgi_phy_options[i][j];

                /* enable SGI according to phy state of current mcs rate*/                 
                for ( i = 0; i< pRateTable->rateCount; i++){
                    if ((mcs == pRateTable->info[i].rateCode)
                        &&  (pRateTable->info[i].phy == SGIphy)){
                        SGIenable = 1; //enable SGI
                        break;
                    }
                }
 
               flags = ((oan->htcap & WLAN_RC_DS_FLAG) ? ATH_RC_DS_FLAG : 0) |
                        ((oan->htcap & WLAN_RC_TS_FLAG) ? ATH_RC_TS_FLAG : 0) |
                        ((oan->htcap & WLAN_RC_40_FLAG) ? ATH_RC_CW40_FLAG : 0) |
                        (((SGIenable)&&(oan->htcap & WLAN_RC_SGI_FLAG))? ATH_RC_SGI_FLAG : 0); //EV 89300: checking short GI according to rate table

                if (oan->stbc) {
                    /* For now, only single stream STBC is supported */
                    if (mcs >= 0x80 && mcs <= 0x87)
                        flags |= ATH_RC_TX_STBC_FLAG;
                }
#ifdef ATH_SUPPORT_TxBF
                rix = sc->sc_rixmap[mcs];
                if (oan->txbf && VALID_TXBF_RATE(mcs, oan->usedNss) &&
                    !(asc->sc_txbf_disable_flag[rix][sc->sc_tx_numchains - 1])) {
                    flags |= ATH_RC_TXBF_FLAG;
                    flags &= ~(ATH_RC_TX_STBC_FLAG);                    
                }
                if (sc->sc_txbfsounding) {
                    flags &=~(ATH_RC_SGI_FLAG);     //disable SGI at sounding
                    flags |= ATH_RC_SOUNDING_FLAG;
                }
#endif
            }
   
            series[idx].rix = sc->sc_rixmap[mcs];
            /* Rate count cannot be zero */
            KASSERT(pRateTable->rateCount,("Rate count cannot be zero"));
            /*
             * Check if the fixed rate is valid for this mode.
             * If invalid then set the rate index to max rate code index
             */
            maxRateCode = pRateTable->info[pRateTable->rateCount-1].rateCode;
            if(series[idx].rix == 0xFF) {
                printk("\nThe curmode =%d and max rate code in this mode=%x your want to set=%x\n",sc->sc_curmode,maxRateCode,mcs);
                printk("Your Rate code is invalid for this mode. Setting the max rate");
                mcs = maxRateCode;
                series[idx].rix = sc->sc_rixmap[mcs];
            }

            if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG)) {
                rix = pRateTable->info[series[idx].rix].htIndex;
            } else if (flags & ATH_RC_SGI_FLAG) {
                rix = pRateTable->info[series[idx].rix].sgiIndex;
            } else if (flags & ATH_RC_CW40_FLAG) {
                rix = pRateTable->info[series[idx].rix].cw40Index;
            } else {
                rix = pRateTable->info[series[idx].rix].baseIndex;
            }
            series[idx].max4msframelen = pRateTable->info[rix].max4msframelen;
            series[idx].flags = flags;
        }
    }
}
Пример #12
0
/*
 * Return current transmit rate.
 */
u_int32_t
ath_rate_node_gettxrate(struct ath_node *an)
{
    struct atheros_node *oan = ATH_NODE_ATHEROS(an);
    return oan->lastRateKbps;
}
Пример #13
0
void
ath_rate_tx_complete_11n(struct ath_softc *sc,
                         struct ath_node *an,
                         struct ath_tx_status *ts,
                         struct ath_rc_series rcs[],
                         u_int8_t ac,
                         int nframes,
                         int nbad,
                         int rts_retry_limit)
#endif
{
    int    finalTSIdx = ts->ts_rateindex;
    int    tx_status = 0, is_underrun = 0;
    struct atheros_node    *oan = ATH_NODE_ATHEROS(an);
    struct ath_vap         *avp = oan->avp->athdev_vap;

#ifdef ATH_SUPPORT_TxBF
    if (rcs[0].flags & ATH_RC_SOUNDING_FLAG) {
      /* indicate sounding sent*/ 
      ts->ts_txbfstatus |= TxBF_STATUS_Sounding_Complete;
    }
    if (oan->lastTxmcs0cnt > MCS0_80_PERCENT ){
        /* clear TxBF HW status to avoid trigger sounding*/
        ts->ts_txbfstatus &= ~(AR_TxBF_Valid_HW_Status);
    }
#endif

    if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE)
            || ts->ts_status & HAL_TXERR_FILT) {
        return;
    }

#ifdef ATH_CHAINMASK_SELECT
    if (ts->ts_rssi > 0) {
        ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi,
                             ts->ts_rssi);
    }
#endif

    /*
     * If underrun error is seen assume it as an excessive retry only if prefetch
     * trigger level have reached the max (0x3f for 5416)
     * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY times. This
     * affects how ratectrl updates PER for the failed rate.
     */
    if ((HAL_IS_TX_UNDERRUN(ts)) &&
        (ath_hal_gettxtriglevel(sc->sc_ah) >= sc->sc_rc->txTrigLevelMax)) {
        tx_status = 1;
        is_underrun = 1;
    }

    if (ts->ts_status & (HAL_TXERR_XRETRY |HAL_TXERR_FIFO))
    {
        tx_status = 1;
    }

    RcUpdate_TxBF_STATS(sc, rcs, ts);

#ifdef ATH_SUPPORT_VOWEXT
#if ATH_SUPPORT_IQUE
    oan->rcFunc[ac].rcUpdate(sc, an, ts->ts_rssi, ac,
                        finalTSIdx, tx_status, rcs, nframes , nbad,
                        (is_underrun) ? ATH_11N_TXMAXTRY:ts->ts_longretry,
                        0 ,
                        nHeadFail, nTailFail);
#else
    rcUpdate_11n(sc, an, ts->ts_rssi , ac,
                    finalTSIdx, tx_status, rcs, nframes , nbad,
                    (is_underrun) ? ATH_11N_TXMAXTRY:ts->ts_longretry,
                    0 ,
                    nHeadFail, nTailFail);
#endif
#else
#if ATH_SUPPORT_IQUE
    oan->rcFunc[ac].rcUpdate(sc, an, ts->ts_rssi, ac,
                        finalTSIdx, tx_status, rcs, nframes , nbad,
                        (is_underrun) ? ATH_11N_TXMAXTRY:ts->ts_longretry,
                        0 );
#else
    rcUpdate_11n(sc, an, ts->ts_rssi , ac,
                    finalTSIdx, tx_status, rcs, nframes , nbad,
                    (is_underrun) ? ATH_11N_TXMAXTRY:ts->ts_longretry,
                    0 );
#endif

#ifdef ATH_SUPPORT_TxBF
    if (oan->txbf_sounding_request){
        ts->ts_txbfstatus |= TxBF_STATUS_Sounding_Request;
        oan->txbf_sounding_request = 0;
    } else {
        ts->ts_txbfstatus &= ~(TxBF_STATUS_Sounding_Request);
    }
#endif
#endif
}
Пример #14
0
int ath_ald_collect_ni_data(ath_dev_t dev, ath_node_t an, ath_ald_t ald_data, ath_ni_ald_t ald_ni_data)
{
    u_int32_t ccf;
    u_int32_t myCcf = 0;
    u_int32_t aggrAverage = 0;
    struct ath_softc *sc = ATH_DEV_TO_SC(dev);
    struct atheros_softc  *asc = (struct atheros_softc*)sc->sc_rc;
    struct ath_node *ant = ATH_NODE(an);
    struct atheros_node *pSib;
    TX_RATE_CTRL *pRc;
    const RATE_TABLE_11N  *pRateTable = (const RATE_TABLE_11N *)asc->hwRateTable[sc->sc_curmode];

    //an = ATH_NODE(ATH_NODE_NET80211(ni)->an_sta);
    pSib = ATH_NODE_ATHEROS(ant);
    pRc = (TX_RATE_CTRL *)(pSib);

    ald_ni_data->ald_lastper = pRc->state[pRc->lastRateIndex].per;

    if(pRc->TxRateCount != 0) {
        ald_ni_data->ald_avgtxrate = pRc->TxRateInMbps / pRc->TxRateCount;
        ald_ni_data->ald_avgmax4msaggr = pRc->Max4msFrameLen / (pRc->TxRateCount * ald_data->msdu_size);
    }
    
    pRc->TxRateInMbps = 0;
    pRc->Max4msFrameLen = 0;
    pRc->TxRateCount = 0;

    if (ald_ni_data->ald_avgmax4msaggr > 32)
        ald_ni_data->ald_avgmax4msaggr = 32;

    if(sc->sc_ald.sc_ald_txairtime != 0){
        //ccf = (ald_data->msdu_size/(sc->sc_ald.sc_ald_txairtime/ald_ni_data->ald_pktnum))*8;
        ccf = ald_ni_data->ald_avgtxrate;
        myCcf = sc->sc_ald.sc_ald_pktlen*8/sc->sc_ald.sc_ald_txairtime;
        aggrAverage = sc->sc_ald.sc_ald_pktnum/sc->sc_ald.sc_ald_counter;
    }
    else {
        if(ald_ni_data->ald_avgtxrate) {
            ccf = ald_ni_data->ald_avgtxrate;
            aggrAverage = ald_ni_data->ald_avgmax4msaggr/2;
        }
        else {
            ccf = pRateTable->info[INIT_RATE_MAX_40-4].rateKbps/1000;
            aggrAverage = MAX_AGGR_LIMIT/2;
        }
    }
    if (sc->sc_ald.sc_ald_counter) {
        ald_data->ald_txbuf_used = sc->sc_ald.sc_ald_bfused/sc->sc_ald.sc_ald_counter;
    } else {
        ald_data->ald_txbuf_used = 0;
    }
    ald_data->ald_curThroughput = sc->sc_ald.sc_ald_pktnum * ald_data->msdu_size * 8 / 1000000;
    if (ald_data->ald_curThroughput < 1) {
        aggrAverage = MAX_AGGR_LIMIT/2;
    }
    
    if (ccf != 0) {
        ald_ni_data->ald_capacity = ccf;
        ald_ni_data->ald_aggr = aggrAverage;
        ald_ni_data->ald_phyerr = ald_data->phyerr_rate;
        if (ald_data->msdu_size < DEFAULT_MSDU_SIZE) {
            ald_ni_data->ald_msdusize = ALD_MSDU_SIZE;
        } else {
            ald_ni_data->ald_msdusize = ald_data->msdu_size;
        }
    }
    sc->sc_ald.sc_ald_txairtime = 0;
    sc->sc_ald.sc_ald_pktnum = 0;
    sc->sc_ald.sc_ald_pktlen = 0;
    sc->sc_ald.sc_ald_bfused = 0;
    sc->sc_ald.sc_ald_counter = 0;
    ald_ni_data->ald_txrate = 0;
    ald_ni_data->ald_max4msframelen = 0;
    ald_ni_data->ald_txcount = 0;
    ald_ni_data->ald_avgtxrate = 0;
    ald_ni_data->ald_avgmax4msaggr = 0;
    return 0;
}
Пример #15
0
/*
 *  Update the SIB's rate control information
 *
 *  This should be called when the supported rates change
 *  (e.g. SME operation, wireless mode change)
 *
 *  It will determine which rates are valid for use.
 */
void
rcSibUpdate(struct ath_softc *sc, struct ath_node *an, A_BOOL keepState)
{
    struct atheros_node	*pSib	    = ATH_NODE_ATHEROS(an);
    struct atheros_softc *asc	    = (struct atheros_softc *) sc->sc_rc;
    const RATE_TABLE    *pRateTable = asc->hwRateTable[sc->sc_curmode];
    struct ieee80211_rateset *pRateSet = &an->an_node.ni_rates;
    struct TxRateCtrl_s *pRc        = &pSib->txRateCtrl;
    A_UINT8             i, j, hi = 0,count;
    int                 rateCount;

    /* Initial rate table size. Will change depending on the working rate set */
    pRc->rateTableSize = MAX_TX_RATE_TBL;

    /* Initialize thresholds according to the global rate table */
    for (i = 0 ; (i < pRc->rateTableSize) && (!keepState); i++) {
        pRc->state[i].rssiThres = pRateTable->info[i].rssiAckValidMin;
        pRc->state[i].per       = 0;
    }

    /* Determine the valid rates */
    rcInitValidTxMask(pRc);
    rateCount = pRateTable->rateCount;
#ifdef notyet
    if (wlanIs5211Channel14(pSib)) {
        rateCount = 2;
    }
#endif

    count = 0;
    if (!pRateSet->rs_nrates) {
        /* No working rate, use valid rates */
        for (i = 0; i < rateCount; i++) {
            if (pRateTable->info[i].valid == TRUE) {
                pRc->validRateIndex[count] = i;
                count ++;
                rcSetValidTxMask(pRc, i, TRUE);
                hi = A_MAX(hi, i);
		pSib->rixMap[i] = 0;
            }
        }

        pRc->maxValidRate = count;
        pRc->maxValidTurboRate = pRateTable->numTurboRates;
    } else {
        A_UINT8  turboCount;
        A_UINT32 mask;

        /* Use intersection of working rates and valid rates */
        turboCount = 0;
        for (i = 0; i < pRateSet->rs_nrates; i++) {
            for (j = 0; j < rateCount; j++) {
                if (((pRateSet->rs_rates[i] & 0x7F) == (pRateTable->info[j].dot11Rate & 0x7F)) &&
                    (pRateTable->info[j].valid == TRUE))
                {
                    rcSetValidTxMask(pRc, j, TRUE);
                    hi = A_MAX(hi, j);
		    pSib->rixMap[j] = i;
                }
            }
        }

        /* Get actually valid rate index, previous we get it from rate table,
         * now get rate table which include all working rate, so we need make
         * sure our valid rate table align with working rate */
        mask = pRc->validTxRateMask;
        for (i = 0; i < pRc->rateTableSize; i ++) {
            if (mask & (1 << i)) {
                pRc->validRateIndex[count] = i;
                count ++;
                if (pRateTable->info[i].phy == WLAN_PHY_TURBO) {
                    turboCount ++;
                }
            }
        }

        pRc->maxValidRate = count;
        pRc->maxValidTurboRate = turboCount;
    }

    pRc->rateTableSize = hi + 1;
    pRc->rateMax = A_MIN(hi, pRateTable->initialRateMax);

    ASSERT(pRc->rateTableSize <= MAX_TX_RATE_TBL);
}