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); }
/* * 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 {
/* * 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); }
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; } } }
/* * 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; }
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 }
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; }
/* * 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); }