static A_BOOL rcIsValidPhyRate(A_UINT32 phy, A_UINT32 capflag, A_BOOL ignoreCW) { if (WLAN_RC_PHY_HT(phy) && !(capflag & WLAN_RC_HT_FLAG)) { return FALSE; } if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) { return FALSE; } if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_HT40_SGI_FLAG)) { return FALSE; } if (!ignoreCW && WLAN_RC_PHY_HT(phy)) { if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) { return FALSE; } if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG)) { return FALSE; } } return TRUE; }
/* * 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 ssize_t read_file_rcstat(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; char *buf; unsigned int len = 0, max; int i = 0; ssize_t retval; if (sc->cur_rate_table == NULL) return 0; max = 80 + sc->cur_rate_table->rate_cnt * 1024; buf = kmalloc(max + 1, GFP_KERNEL); if (buf == NULL) return 0; buf[max] = 0; len += sprintf(buf, "%6s %6s %6s " "%10s %10s %10s %10s\n", "HT", "MCS", "Rate", "Success", "Retries", "XRetries", "PER"); for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) { u32 ratekbps = sc->cur_rate_table->info[i].ratekbps; struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i]; char mcs[5]; char htmode[5]; int used_mcs = 0, used_htmode = 0; if (WLAN_RC_PHY_HT(sc->cur_rate_table->info[i].phy)) { used_mcs = snprintf(mcs, 5, "%d", sc->cur_rate_table->info[i].ratecode); if (WLAN_RC_PHY_40(sc->cur_rate_table->info[i].phy)) used_htmode = snprintf(htmode, 5, "HT40"); else if (WLAN_RC_PHY_20(sc->cur_rate_table->info[i].phy)) used_htmode = snprintf(htmode, 5, "HT20"); else used_htmode = snprintf(htmode, 5, "????"); } mcs[used_mcs] = '\0'; htmode[used_htmode] = '\0'; len += snprintf(buf + len, max - len, "%6s %6s %3u.%d: " "%10u %10u %10u %10u\n", htmode, mcs, ratekbps / 1000, (ratekbps % 1000) / 100, stats->success, stats->retries, stats->xretries, stats->per); } retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); kfree(buf); return retval; }