/* * Initialize the Valid Rate Index from valid entries in Rate Table */ static A_UINT8 rcSibInitValidRates(const RATE_TABLE_11N *pRateTable, TX_RATE_CTRL *pRc, A_UINT32 capflag, PHY_STATE_CTRL *pPhyStateCtrl) { A_UINT8 i, hi = 0; A_UINT8 singleStream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1; A_UINT8 valid; for (i = 0; i < pRateTable->rateCount; i++) { if (singleStream) { valid = pRateTable->info[i].validSingleStream; } else { valid = pRateTable->info[i].valid; } if (valid == TRUE) { A_UINT32 phy = pRateTable->info[i].phy; if (!rcIsValidPhyRate(phy, capflag, FALSE)) continue; pPhyStateCtrl->validPhyRateIndex[phy][pPhyStateCtrl->validPhyRateCount[phy]] = i; pPhyStateCtrl->validPhyRateCount[phy] += 1; rcSetValidTxMask(pRc, i, TRUE); hi = A_MAX(hi, i); } } return hi; }
/* * 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); }
/* * 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 atheros_softc *asc, struct atheros_node *pSib, int keepState, struct ieee80211_rateset *pRateSet, enum ieee80211_phymode curmode) { #define N(a) (sizeof(a)/sizeof(a[0])) const RATE_TABLE *pRateTable; struct TxRateCtrl_s *pRc = &pSib->txRateCtrl; A_UINT8 i, j, hi = 0, count; A_INT8 k; int rateCount, numInfo; HAL_BOOL bFoundDot11Rate_11, bFoundDot11Rate_22; pRateTable = asc->hwRateTable[curmode]; /* Initial rate table size. Will change depending on the working rate set */ pRc->rateTableSize = MAX_TX_RATE_TBL; numInfo = N(pRateTable->info); /* Initialize thresholds according to the global rate table */ for (i = 0 ; (i < pRc->rateTableSize) && (!keepState) && (i < pRateTable->rateCount); i++) { if (i < numInfo) { pRc->state[i].rssiThres = pRateTable->info[i].rssiAckValidMin; } pRc->state[i].per = 0; #if ATH_SUPPORT_VOWEXT /* for RCA */ pRc->state[i].maxAggrSize = MAX_AGGR_LIMIT; #endif } /* 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 the rate is: * 1. not valid, or * 2. this is an uapsd node but the rate is not an uapsd rate * skip it. */ if (pRateTable->info[i].valid != TRUE) { continue; } #ifdef ATH_SUPPORT_UAPSD_RATE_CONTROL if ((pSib->uapsd) && (pRateTable->info[i].validUAPSD != TRUE)) { continue; } #endif /* ATH_SUPPORT_UAPSD_RATE_CONTROL */ pRc->validRateIndex[count] = i; /* * Copy the static rate series for the correspondig rate * from static rate table to TxRateCtrl_s. */ OS_MEMCPY(pRc->validRateSeries[count], &(pRateTable->info[i].normalSched), MAX_SCHED_TBL); 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_UINT64 mask; bFoundDot11Rate_11 = FALSE; bFoundDot11Rate_22 = FALSE; for(k = 0; k < pRateSet->rs_nrates; k++) { // Look for 5.5 mbps if((pRateSet->rs_rates[k] & 0x7F) == 11) { bFoundDot11Rate_11 = TRUE; } // Look for 11 mbps if((pRateSet->rs_rates[k] & 0x7F) == 22) { bFoundDot11Rate_22 = TRUE; } } /* * Use intersection of working rates and valid rates. * if working rates has 6 OFDM and does not have 5.5 and 11 CCKM, use 6. * if working rates has 9 OFDM and does not has 11 CCKM, use 9. */ 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)) { #ifdef ATH_SUPPORT_UAPSD_RATE_CONTROL /* * If this is an uapsd node but the rate is not an uapsd rate * skip it. */ if ((pSib->uapsd) && (pRateTable->info[j].validUAPSD != TRUE)) { continue; } #endif /* ATH_SUPPORT_UAPSD_RATE_CONTROL */ if(pRateTable->info[j].valid == TRUE) { rcSetValidTxMask(pRc, j, TRUE); hi = A_MAX(hi, j); pSib->rixMap[j] = i; } else { //To keep rate monotonicity if(pRateTable->info[j].phy == WLAN_PHY_OFDM && ((((pRateSet->rs_rates[i] & 0x7F) == 12) && (!bFoundDot11Rate_11) && (!bFoundDot11Rate_22)) || (((pRateSet->rs_rates[i] & 0x7F) == 18) && !bFoundDot11Rate_22))) { 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 & ((A_UINT64)1 << i)) { pRc->validRateIndex[count] = i; /* * Copy the static rate series for the correspondig rate * from static rate table to TxRateCtrl_s. */ OS_MEMCPY(pRc->validRateSeries[count], &(pRateTable->info[i].normalSched), MAX_SCHED_TBL); count ++; if (pRateTable->info[i].phy == WLAN_PHY_TURBO) { turboCount ++; } } } pRc->maxValidRate = count; pRc->maxValidTurboRate = turboCount; } /* * Modify the static rate series in TxRateCtrl_s with respect to intersection * rate table. */ for(i = 0 ; i < pRc->maxValidRate; i ++) { k = i; for (j = 5; j < MAX_SCHED_TBL; j ++) { if(j % 8 == 0) { k = i; j = j + 4; continue; } for (; k >= 0; k --) { if(pRc->validRateSeries[i][j] == pRateTable->info[k].rateCode) { break; } } if (k == -1) { pRc->validRateSeries[i][j] = pRc->validRateSeries[i][j-1]; } } } pRc->rateTableSize = hi + 1; pRc->rateMax = A_MIN(hi, pRateTable->initialRateMax); ASSERT(pRc->rateTableSize <= MAX_TX_RATE_TBL); #undef N }
/* * 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); }