int wlc_stf_ant_txant_validate(struct wlc_info *wlc, s8 val) { int bcmerror = BCME_OK; /* when there is only 1 tx_streams, don't allow to change the txant */ if (WLCISNPHY(wlc->band) && (wlc->stf->txstreams == 1)) return ((val == wlc->stf->txant) ? bcmerror : BCME_RANGE); switch (val) { case -1: val = ANT_TX_DEF; break; case 0: val = ANT_TX_FORCE_0; break; case 1: val = ANT_TX_FORCE_1; break; case 3: val = ANT_TX_LAST_RX; break; default: bcmerror = BCME_RANGE; break; } if (bcmerror == BCME_OK) wlc->stf->txant = (s8) val; return bcmerror; }
u16 wlc_stf_d11hdrs_phyctl_txant(struct wlc_info *wlc, ratespec_t rspec) { u16 phytxant = wlc->stf->phytxant; u16 mask = PHY_TXC_ANT_MASK; /* for non-siso rates or default setting, use the available chains */ if (WLCISNPHY(wlc->band)) { ASSERT(wlc->stf->txchain != 0); phytxant = _wlc_stf_phytxchain_sel(wlc, rspec); mask = PHY_TXC_HTANT_MASK; } phytxant |= phytxant & mask; return phytxant; }
void wlc_stf_phy_chain_calc(struct wlc_info *wlc) { /* get available rx/tx chains */ wlc->stf->hw_txchain = (u8) getintvar(wlc->pub->vars, "txchain"); wlc->stf->hw_rxchain = (u8) getintvar(wlc->pub->vars, "rxchain"); /* these parameter are intended to be used for all PHY types */ if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) { if (WLCISNPHY(wlc->band)) { wlc->stf->hw_txchain = TXCHAIN_DEF_NPHY; } else { wlc->stf->hw_txchain = TXCHAIN_DEF; } } wlc->stf->txchain = wlc->stf->hw_txchain; wlc->stf->txstreams = (u8) WLC_BITSCNT(wlc->stf->hw_txchain); if (wlc->stf->hw_rxchain == 0 || wlc->stf->hw_rxchain == 0xf) { if (WLCISNPHY(wlc->band)) { wlc->stf->hw_rxchain = RXCHAIN_DEF_NPHY; } else { wlc->stf->hw_rxchain = RXCHAIN_DEF; } } wlc->stf->rxchain = wlc->stf->hw_rxchain; wlc->stf->rxstreams = (u8) WLC_BITSCNT(wlc->stf->hw_rxchain); /* initialize the txcore table */ bcopy(txcore_default, wlc->stf->txcore, sizeof(wlc->stf->txcore)); /* default spatial_policy */ wlc->stf->spatial_policy = MIN_SPATIAL_EXPANSION; wlc_stf_spatial_policy_set(wlc, MIN_SPATIAL_EXPANSION); }
/* * Centralized txant update function. call it whenever wlc->stf->txant and/or wlc->stf->txchain * change * * Antennas are controlled by ucode indirectly, which drives PHY or GPIO to * achieve various tx/rx antenna selection schemes * * legacy phy, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 means auto(last rx) * for NREV<3, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 means last rx and * do tx-antenna selection for SISO transmissions * for NREV=3, bit 6 and bit _8_ means antenna 0 and 1 respectively, bit6+bit7 means last rx and * do tx-antenna selection for SISO transmissions * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7 means both cores active */ static void _wlc_stf_phy_txant_upd(struct wlc_info *wlc) { s8 txant; txant = (s8) wlc->stf->txant; ASSERT(txant == ANT_TX_FORCE_0 || txant == ANT_TX_FORCE_1 || txant == ANT_TX_LAST_RX); if (WLC_PHY_11N_CAP(wlc->band)) { if (txant == ANT_TX_FORCE_0) { wlc->stf->phytxant = PHY_TXC_ANT_0; } else if (txant == ANT_TX_FORCE_1) { wlc->stf->phytxant = PHY_TXC_ANT_1; if (WLCISNPHY(wlc->band) && NREV_GE(wlc->band->phyrev, 3) && NREV_LT(wlc->band->phyrev, 7)) { wlc->stf->phytxant = PHY_TXC_ANT_2; } } else { if (WLCISLCNPHY(wlc->band) || WLCISSSLPNPHY(wlc->band)) wlc->stf->phytxant = PHY_TXC_LCNPHY_ANT_LAST; else { /* keep this assert to catch out of sync wlc->stf->txcore */ ASSERT(wlc->stf->txchain > 0); wlc->stf->phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT; } } } else { if (txant == ANT_TX_FORCE_0) wlc->stf->phytxant = PHY_TXC_OLD_ANT_0; else if (txant == ANT_TX_FORCE_1) wlc->stf->phytxant = PHY_TXC_OLD_ANT_1; else wlc->stf->phytxant = PHY_TXC_OLD_ANT_LAST; } wlc_bmac_txant_set(wlc->hw, wlc->stf->phytxant); }
int wlc_stf_attach(struct wlc_info *wlc) { wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_SISO; wlc->bandstate[BAND_5G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD; if (WLCISNPHY(wlc->band) && (wlc_phy_txpower_hw_ctrl_get(wlc->band->pi) != PHY_TPC_HW_ON)) wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD; wlc_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); wlc_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); wlc_stf_stbc_rx_ht_update(wlc, HT_CAP_RX_STBC_NO); wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF; wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF; if (WLC_STBC_CAP_PHY(wlc)) { wlc->stf->ss_algosel_auto = true; wlc->stf->ss_algo_channel = (u16) -1; /* Init the default value */ } return 0; }
/* * Validate the chanspec for this locale, for 40MHZ we need to also check that the sidebands * are valid 20MZH channels in this locale and they are also a legal HT combination */ static bool wlc_valid_chanspec_ext(wlc_cm_info_t *wlc_cm, chanspec_t chspec, bool dualband) { struct wlc_info *wlc = wlc_cm->wlc; u8 channel = CHSPEC_CHANNEL(chspec); /* check the chanspec */ if (wf_chspec_malformed(chspec)) { WL_ERROR("wl%d: malformed chanspec 0x%x\n", wlc->pub->unit, chspec); ASSERT(0); return false; } if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) != CHSPEC_WLCBANDUNIT(chspec)) return false; /* Check a 20Mhz channel */ if (CHSPEC_IS20(chspec)) { if (dualband) return VALID_CHANNEL20_DB(wlc_cm->wlc, channel); else return VALID_CHANNEL20(wlc_cm->wlc, channel); } #ifdef SUPPORT_40MHZ /* We know we are now checking a 40MHZ channel, so we should only be here * for NPHYS */ if (WLCISNPHY(wlc->band) || WLCISSSLPNPHY(wlc->band)) { u8 upper_sideband = 0, idx; u8 num_ch20_entries = sizeof(chan20_info) / sizeof(struct chan20_info); if (!VALID_40CHANSPEC_IN_BAND(wlc, CHSPEC_WLCBANDUNIT(chspec))) return false; if (dualband) { if (!VALID_CHANNEL20_DB(wlc, LOWER_20_SB(channel)) || !VALID_CHANNEL20_DB(wlc, UPPER_20_SB(channel))) return false; } else { if (!VALID_CHANNEL20(wlc, LOWER_20_SB(channel)) || !VALID_CHANNEL20(wlc, UPPER_20_SB(channel))) return false; } /* find the lower sideband info in the sideband array */ for (idx = 0; idx < num_ch20_entries; idx++) { if (chan20_info[idx].sb == LOWER_20_SB(channel)) upper_sideband = chan20_info[idx].adj_sbs; } /* check that the lower sideband allows an upper sideband */ if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) == (CH_UPPER_SB | CH_EWA_VALID)) return true; return false; } #endif /* 40 MHZ */ return false; }