Setup needed tables for TPC on AR5416->AR9287 chips.
* Add ah_ratesArray[] to the ar5416 HAL state - this stores the maximum values permissable per rate. * Since different chip EEPROM formats store this value in a different place, store the HT40 power detector increment value in the ar5416 HAL state. * Modify the target power setup code to store the maximum values in the ar5416 HAL state rather than using a local variable. * Add ar5416RateToRateTable() - to convert a hardware rate code to the ratesArray enum / index. * Add ar5416GetTxRatePower() - which goes through the gymnastics required to correctly calculate the target TX power: + Add the power detector increment for ht40; + Take the power offset into account for AR9280 and later; + Offset the TX power correctly when doing open-loop TX power control; + Enforce the per-rate maximum value allowable. Note - setting a TPC value of 0x0 in the TX descriptor on (at least) the AR9160 resulted in the TX power being very high indeed. This didn't happen on the AR9220. I'm guessing it's a chip bug that was fixed at some point. So for now, just assume the AR5416/AR5418 and AR9130 are also suspect and clamp the minimum value here at 1. Tested: * AR5416, AR9160, AR9220 hostap, verified using (2GHz) spectrum analyser * Looked at target TX power in TX descriptor (using athalq) as well as TX power on the spectrum analyser. TODO: * The TX descriptor code sets the target TX power to 0 for AR9285 chips. I'm not yet sure why. Disable this for TPC and ensure that the TPC TX power is set. * AR9280, AR9285, AR9227, AR9287 testing! * 5GHz testing! Quirks: * The per-packet TPC code is only exercised when the tpc sysctl is set to 1. (dev.ath.X.tpc=1.) This needs to be done before you bring the interface up. * When TPC is enabled, setting the TX power doesn't end up with a call through to the HAL to update the maximum TX power. So ensure that you set the TPC sysctl before you bring the interface up and configure a lower TX power or the hardware will be clamped by the lower TX power (at least until the next channel change.) Thanks to Qualcomm Atheros for all the hardware, and Sam Leffler for use of his spectrum analyser to verify the TX channel power.
This commit is contained in:
parent
8b470f6f71
commit
91046e9c5f
@ -132,7 +132,12 @@ struct ath_hal_5416 {
|
||||
struct ar5416NfLimits nf_2g;
|
||||
struct ar5416NfLimits nf_5g;
|
||||
|
||||
/*
|
||||
* TX power configuration related structures
|
||||
*/
|
||||
int initPDADC;
|
||||
int ah_ht40PowerIncForPdadc;
|
||||
int16_t ah_ratesArray[Ar5416RateSize];
|
||||
|
||||
int ah_need_an_top2_fixup; /* merlin or later chips that may need this workaround */
|
||||
|
||||
|
@ -1005,6 +1005,14 @@ ar5416WriteTxPowerRateRegisters(struct ath_hal *ah,
|
||||
| POW_SM(ratesArray[rateDupCck], 0)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set max power to 30 dBm and, optionally,
|
||||
* enable TPC in tx descriptors.
|
||||
*/
|
||||
OS_REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER |
|
||||
(AH5212(ah)->ah_tpcEnabled ? AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE : 0));
|
||||
#undef POW_SM
|
||||
}
|
||||
|
||||
|
||||
@ -1019,12 +1027,11 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
const struct ieee80211_channel *chan, uint16_t *rfXpdGain)
|
||||
{
|
||||
#define N(a) (sizeof (a) / sizeof (a[0]))
|
||||
#define POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
|
||||
|
||||
MODAL_EEP_HEADER *pModal;
|
||||
struct ath_hal_5212 *ahp = AH5212(ah);
|
||||
int16_t ratesArray[Ar5416RateSize];
|
||||
int16_t txPowerIndexOffset = 0;
|
||||
uint8_t ht40PowerIncForPdadc = 2;
|
||||
int i;
|
||||
|
||||
uint16_t cfgCtl;
|
||||
@ -1037,8 +1044,13 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
|
||||
HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
|
||||
|
||||
/*
|
||||
* Default to 2, is overridden based on the EEPROM version / value.
|
||||
*/
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc = 2;
|
||||
|
||||
/* Setup info for the actual eeprom */
|
||||
OS_MEMZERO(ratesArray, sizeof(ratesArray));
|
||||
OS_MEMZERO(AH5416(ah)->ah_ratesArray, sizeof(AH5416(ah)->ah_ratesArray));
|
||||
cfgCtl = ath_hal_getctl(ah, chan);
|
||||
powerLimit = chan->ic_maxregpower * 2;
|
||||
twiceAntennaReduction = chan->ic_maxantgain;
|
||||
@ -1048,11 +1060,12 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
__func__,chan->ic_freq, cfgCtl );
|
||||
|
||||
if (IS_EEP_MINOR_V2(ah)) {
|
||||
ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
|
||||
}
|
||||
|
||||
if (!ar5416SetPowerPerRateTable(ah, pEepData, chan,
|
||||
&ratesArray[0],cfgCtl,
|
||||
&AH5416(ah)->ah_ratesArray[0],
|
||||
cfgCtl,
|
||||
twiceAntennaReduction,
|
||||
twiceMaxRegulatoryPower, powerLimit)) {
|
||||
HALDEBUG(ah, HAL_DEBUG_ANY,
|
||||
@ -1066,14 +1079,15 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
return AH_FALSE;
|
||||
}
|
||||
|
||||
maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]);
|
||||
maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb],
|
||||
AH5416(ah)->ah_ratesArray[rateHt20_0]);
|
||||
|
||||
if (IEEE80211_IS_CHAN_2GHZ(chan)) {
|
||||
maxPower = AH_MAX(maxPower, ratesArray[rate1l]);
|
||||
maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rate1l]);
|
||||
}
|
||||
|
||||
if (IEEE80211_IS_CHAN_HT40(chan)) {
|
||||
maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]);
|
||||
maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rateHt40_0]);
|
||||
}
|
||||
|
||||
ahp->ah_tx6PowerInHalfDbm = maxPower;
|
||||
@ -1084,10 +1098,11 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
* txPowerIndexOffset is set by the SetPowerTable() call -
|
||||
* adjust the rate table (0 offset if rates EEPROM not loaded)
|
||||
*/
|
||||
for (i = 0; i < N(ratesArray); i++) {
|
||||
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
|
||||
if (ratesArray[i] > AR5416_MAX_RATE_POWER)
|
||||
ratesArray[i] = AR5416_MAX_RATE_POWER;
|
||||
for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
|
||||
AH5416(ah)->ah_ratesArray[i] =
|
||||
(int16_t)(txPowerIndexOffset + AH5416(ah)->ah_ratesArray[i]);
|
||||
if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
|
||||
AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
|
||||
}
|
||||
|
||||
#ifdef AH_EEPROM_DUMP
|
||||
@ -1098,7 +1113,7 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
* this debugging; the values won't necessarily be what's being
|
||||
* programmed into the hardware.
|
||||
*/
|
||||
ar5416PrintPowerPerRate(ah, ratesArray);
|
||||
ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -1114,16 +1129,16 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
&pwr_table_offset);
|
||||
/* Underflow power gets clamped at raw value 0 */
|
||||
/* Overflow power gets camped at AR5416_MAX_RATE_POWER */
|
||||
for (i = 0; i < N(ratesArray); i++) {
|
||||
for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
|
||||
/*
|
||||
* + pwr_table_offset is in dBm
|
||||
* + ratesArray is in 1/2 dBm
|
||||
*/
|
||||
ratesArray[i] -= (pwr_table_offset * 2);
|
||||
if (ratesArray[i] < 0)
|
||||
ratesArray[i] = 0;
|
||||
else if (ratesArray[i] > AR5416_MAX_RATE_POWER)
|
||||
ratesArray[i] = AR5416_MAX_RATE_POWER;
|
||||
AH5416(ah)->ah_ratesArray[i] -= (pwr_table_offset * 2);
|
||||
if (AH5416(ah)->ah_ratesArray[i] < 0)
|
||||
AH5416(ah)->ah_ratesArray[i] = 0;
|
||||
else if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
|
||||
AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1150,9 +1165,9 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
int cck_ofdm_delta = 2;
|
||||
int i;
|
||||
for (i = 0; i < N(adj); i++) {
|
||||
ratesArray[adj[i]] -= cck_ofdm_delta;
|
||||
if (ratesArray[adj[i]] < 0)
|
||||
ratesArray[adj[i]] = 0;
|
||||
AH5416(ah)->ah_ratesArray[adj[i]] -= cck_ofdm_delta;
|
||||
if (AH5416(ah)->ah_ratesArray[adj[i]] < 0)
|
||||
AH5416(ah)->ah_ratesArray[adj[i]] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1164,18 +1179,20 @@ ar5416SetTransmitPower(struct ath_hal *ah,
|
||||
* XXX handle overflow/too high power level?
|
||||
*/
|
||||
if (IEEE80211_IS_CHAN_HT40(chan)) {
|
||||
ratesArray[rateHt40_0] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_1] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_2] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_3] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_4] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_5] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_6] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_7] += ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_0] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_1] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_2] += AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_3] += AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_4] += AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_5] += AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_6] += AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_7] += AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
}
|
||||
|
||||
/* Write the TX power rate registers */
|
||||
ar5416WriteTxPowerRateRegisters(ah, chan, ratesArray);
|
||||
ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray);
|
||||
|
||||
/* Write the Power subtraction for dynamic chain changing, for per-packet powertx */
|
||||
OS_REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
|
||||
|
@ -155,6 +155,169 @@ ar5416StopTxDma(struct ath_hal *ah, u_int q)
|
||||
/* NB: accept HT rates */
|
||||
#define isValidTxRate(_r) ((1<<((_r) & 0x7f)) & VALID_TX_RATES)
|
||||
|
||||
static inline int
|
||||
ar5416RateToRateTable(struct ath_hal *ah, uint8_t rate, HAL_BOOL is_ht40)
|
||||
{
|
||||
|
||||
/*
|
||||
* Handle the non-MCS rates
|
||||
*/
|
||||
switch (rate) {
|
||||
case /* 1 Mb */ 0x1b:
|
||||
case /* 1 MbS*/ 0x1b | 0x4:
|
||||
return (AH5416(ah)->ah_ratesArray[rate1l]);
|
||||
case /* 2 Mb */ 0x1a:
|
||||
return (AH5416(ah)->ah_ratesArray[rate2l]);
|
||||
case /* 2 MbS*/ 0x1a | 0x4:
|
||||
return (AH5416(ah)->ah_ratesArray[rate2s]);
|
||||
case /* 5.5 Mb */ 0x19:
|
||||
return (AH5416(ah)->ah_ratesArray[rate5_5l]);
|
||||
case /* 5.5 MbS*/ 0x19 | 0x4:
|
||||
return (AH5416(ah)->ah_ratesArray[rate5_5s]);
|
||||
case /* 11 Mb */ 0x18:
|
||||
return (AH5416(ah)->ah_ratesArray[rate11l]);
|
||||
case /* 11 MbS*/ 0x18 | 0x4:
|
||||
return (AH5416(ah)->ah_ratesArray[rate11s]);
|
||||
}
|
||||
|
||||
/* OFDM rates */
|
||||
switch (rate) {
|
||||
case /* 6 Mb */ 0x0b:
|
||||
return (AH5416(ah)->ah_ratesArray[rate6mb]);
|
||||
case /* 9 Mb */ 0x0f:
|
||||
return (AH5416(ah)->ah_ratesArray[rate9mb]);
|
||||
case /* 12 Mb */ 0x0a:
|
||||
return (AH5416(ah)->ah_ratesArray[rate12mb]);
|
||||
case /* 18 Mb */ 0x0e:
|
||||
return (AH5416(ah)->ah_ratesArray[rate18mb]);
|
||||
case /* 24 Mb */ 0x09:
|
||||
return (AH5416(ah)->ah_ratesArray[rate24mb]);
|
||||
case /* 36 Mb */ 0x0d:
|
||||
return (AH5416(ah)->ah_ratesArray[rate36mb]);
|
||||
case /* 48 Mb */ 0x08:
|
||||
return (AH5416(ah)->ah_ratesArray[rate48mb]);
|
||||
case /* 54 Mb */ 0x0c:
|
||||
return (AH5416(ah)->ah_ratesArray[rate54mb]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle HT20/HT40 - we only have to do MCS0-7;
|
||||
* there's no stream differences.
|
||||
*/
|
||||
if ((rate & 0x80) && is_ht40) {
|
||||
return (AH5416(ah)->ah_ratesArray[rateHt40_0 + (rate & 0x7)]);
|
||||
} else if (rate & 0x80) {
|
||||
return (AH5416(ah)->ah_ratesArray[rateHt20_0 + (rate & 0x7)]);
|
||||
}
|
||||
|
||||
/* XXX default (eg XR, bad bad person!) */
|
||||
return (AH5416(ah)->ah_ratesArray[rate6mb]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the TX power to be used for the given rate/chains/TX power.
|
||||
*
|
||||
* There are a bunch of tweaks to make to a given TX power based on
|
||||
* the current configuration, so...
|
||||
*/
|
||||
static uint16_t
|
||||
ar5416GetTxRatePower(struct ath_hal *ah, uint8_t rate, uint8_t tx_chainmask,
|
||||
uint16_t txPower, HAL_BOOL is_ht40)
|
||||
{
|
||||
int n_txpower, max_txpower;
|
||||
const int cck_ofdm_delta = 2;
|
||||
#define EEP_MINOR(_ah) \
|
||||
(AH_PRIVATE(_ah)->ah_eeversion & AR5416_EEP_VER_MINOR_MASK)
|
||||
#define IS_EEP_MINOR_V2(_ah) (EEP_MINOR(_ah) >= AR5416_EEP_MINOR_VER_2)
|
||||
|
||||
/* Take a copy ; we may underflow and thus need to clamp things */
|
||||
n_txpower = txPower;
|
||||
|
||||
/* HT40? Need to adjust the TX power by this */
|
||||
if (is_ht40)
|
||||
n_txpower += AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
|
||||
/*
|
||||
* Merlin? Offset the target TX power offset - it defaults to
|
||||
* starting at -5.0dBm, but that can change!
|
||||
*
|
||||
* Kiwi/Kite? Always -5.0dBm offset.
|
||||
*/
|
||||
if (AR_SREV_KIWI_10_OR_LATER(ah)) {
|
||||
n_txpower -= (AR5416_PWR_TABLE_OFFSET_DB * 2);
|
||||
} else if (AR_SREV_MERLIN_20_OR_LATER(ah)) {
|
||||
int8_t pwr_table_offset = 0;
|
||||
/* This is in dBm, convert to 1/2 dBm */
|
||||
(void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET,
|
||||
&pwr_table_offset);
|
||||
n_txpower -= (pwr_table_offset * 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* If Open-loop TX power control is used, the CCK rates need
|
||||
* to be offset by that.
|
||||
*
|
||||
* Rates: 2S, 2L, 1S, 1L, 5.5S, 5.5L
|
||||
*
|
||||
* XXX Odd, we don't have a PHY table entry for long preamble
|
||||
* 1mbit CCK?
|
||||
*/
|
||||
if (AR_SREV_MERLIN_20_OR_LATER(ah) &&
|
||||
ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) {
|
||||
|
||||
if (rate == 0x19 || rate == 0x1a || rate == 0x1b ||
|
||||
rate == (0x19 | 0x04) || rate == (0x1a | 0x04) ||
|
||||
rate == (0x1b | 0x04)) {
|
||||
n_txpower -= cck_ofdm_delta;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We're now offset by the same amount that the static maximum
|
||||
* PHY power tables are. So, clamp the value based on that rate.
|
||||
*/
|
||||
max_txpower = ar5416RateToRateTable(ah, rate, is_ht40);
|
||||
#if 0
|
||||
ath_hal_printf(ah, "%s: n_txpower = %d, max_txpower = %d, "
|
||||
"rate = 0x%x , is_ht40 = %d\n",
|
||||
__func__,
|
||||
n_txpower,
|
||||
max_txpower,
|
||||
rate,
|
||||
is_ht40);
|
||||
#endif
|
||||
n_txpower = MIN(max_txpower, n_txpower);
|
||||
|
||||
/*
|
||||
* We don't have to offset the TX power for two or three
|
||||
* chain operation here - it's done by the AR_PHY_POWER_TX_SUB
|
||||
* register setting via the EEPROM.
|
||||
*
|
||||
* So for vendors that programmed the maximum target power assuming
|
||||
* that 2/3 chains are always on, things will just plain work.
|
||||
* (They won't reach that target power if only one chain is on, but
|
||||
* that's a different problem.)
|
||||
*/
|
||||
|
||||
/* Over/underflow? Adjust */
|
||||
if (n_txpower < 0)
|
||||
n_txpower = 0;
|
||||
else if (n_txpower > 63)
|
||||
n_txpower = 63;
|
||||
|
||||
/*
|
||||
* For some odd reason the AR9160 with txpower=0 results in a
|
||||
* much higher (max?) TX power. So, if it's a chipset before
|
||||
* AR9220/AR9280, just clamp the minimum value at 1.
|
||||
*/
|
||||
if ((! AR_SREV_MERLIN_10_OR_LATER(ah)) && (n_txpower == 0))
|
||||
n_txpower = 1;
|
||||
|
||||
return (n_txpower);
|
||||
#undef EEP_MINOR
|
||||
#undef IS_EEP_MINOR_V2
|
||||
}
|
||||
|
||||
HAL_BOOL
|
||||
ar5416SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
u_int pktLen,
|
||||
@ -187,6 +350,16 @@ ar5416SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
if (txPower > 63)
|
||||
txPower = 63;
|
||||
|
||||
/*
|
||||
* XXX For now, just assume that this isn't a HT40 frame.
|
||||
*/
|
||||
if (AH5212(ah)->ah_tpcEnabled) {
|
||||
txPower = ar5416GetTxRatePower(ah, txRate0,
|
||||
ahp->ah_tx_chainmask,
|
||||
txPower,
|
||||
AH_FALSE);
|
||||
}
|
||||
|
||||
ads->ds_ctl0 = (pktLen & AR_FrameLen)
|
||||
| (txPower << AR_XmitPower_S)
|
||||
| (flags & HAL_TXDESC_VEOL ? AR_VEOL : 0)
|
||||
@ -238,6 +411,8 @@ ar5416SetupTxDesc(struct ath_hal *ah, struct ath_desc *ds,
|
||||
* Set the TX antenna to 0 for Kite
|
||||
* To preserve existing behaviour, also set the TPC bits to 0;
|
||||
* when TPC is enabled these should be filled in appropriately.
|
||||
*
|
||||
* XXX TODO: when doing TPC, set the TX power up appropriately?
|
||||
*/
|
||||
if (AR_SREV_KITE(ah)) {
|
||||
ads->ds_ctl8 = SM(0, AR_AntCtl0);
|
||||
@ -744,6 +919,48 @@ ar5416Set11nRateScenario(struct ath_hal *ah, struct ath_desc *ds,
|
||||
| set11nRateFlags(series, 2)
|
||||
| set11nRateFlags(series, 3)
|
||||
| SM(rtsctsRate, AR_RTSCTSRate);
|
||||
|
||||
/*
|
||||
* Doing per-packet TPC - update the TX power for the first
|
||||
* field; program in the other series.
|
||||
*/
|
||||
if (AH5212(ah)->ah_tpcEnabled) {
|
||||
uint32_t ds_ctl0;
|
||||
uint16_t txPower;
|
||||
|
||||
/* Modify the tx power field for rate 0 */
|
||||
txPower = ar5416GetTxRatePower(ah, series[0].Rate,
|
||||
series[0].ChSel,
|
||||
series[0].tx_power_cap,
|
||||
!! (series[0].RateFlags & HAL_RATESERIES_2040));
|
||||
ds_ctl0 = ads->ds_ctl0 & ~AR_XmitPower;
|
||||
ds_ctl0 |= (txPower << AR_XmitPower_S);
|
||||
ads->ds_ctl0 = ds_ctl0;
|
||||
|
||||
/*
|
||||
* Override the whole descriptor field for each TX power.
|
||||
*
|
||||
* This will need changing if we ever support antenna control
|
||||
* programming.
|
||||
*/
|
||||
txPower = ar5416GetTxRatePower(ah, series[1].Rate,
|
||||
series[1].ChSel,
|
||||
series[1].tx_power_cap,
|
||||
!! (series[1].RateFlags & HAL_RATESERIES_2040));
|
||||
ads->ds_ctl9 = SM(0, AR_AntCtl1) | SM(txPower, AR_XmitPower1);
|
||||
|
||||
txPower = ar5416GetTxRatePower(ah, series[2].Rate,
|
||||
series[2].ChSel,
|
||||
series[2].tx_power_cap,
|
||||
!! (series[2].RateFlags & HAL_RATESERIES_2040));
|
||||
ads->ds_ctl10 = SM(0, AR_AntCtl2) | SM(txPower, AR_XmitPower2);
|
||||
|
||||
txPower = ar5416GetTxRatePower(ah, series[3].Rate,
|
||||
series[3].ChSel,
|
||||
series[3].tx_power_cap,
|
||||
!! (series[3].RateFlags & HAL_RATESERIES_2040));
|
||||
ads->ds_ctl11 = SM(0, AR_AntCtl3) | SM(txPower, AR_XmitPower3);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -76,9 +76,7 @@ ar9285SetTransmitPower(struct ath_hal *ah,
|
||||
|
||||
MODAL_EEP4K_HEADER *pModal;
|
||||
struct ath_hal_5212 *ahp = AH5212(ah);
|
||||
int16_t ratesArray[Ar5416RateSize];
|
||||
int16_t txPowerIndexOffset = 0;
|
||||
uint8_t ht40PowerIncForPdadc = 2;
|
||||
int i;
|
||||
|
||||
uint16_t cfgCtl;
|
||||
@ -91,8 +89,10 @@ ar9285SetTransmitPower(struct ath_hal *ah,
|
||||
|
||||
HALASSERT(AH_PRIVATE(ah)->ah_eeversion >= AR_EEPROM_VER14_1);
|
||||
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc = 2;
|
||||
|
||||
/* Setup info for the actual eeprom */
|
||||
OS_MEMZERO(ratesArray, sizeof(ratesArray));
|
||||
OS_MEMZERO(AH5416(ah)->ah_ratesArray, sizeof(AH5416(ah)->ah_ratesArray));
|
||||
cfgCtl = ath_hal_getctl(ah, chan);
|
||||
powerLimit = chan->ic_maxregpower * 2;
|
||||
twiceAntennaReduction = chan->ic_maxantgain;
|
||||
@ -102,11 +102,11 @@ ar9285SetTransmitPower(struct ath_hal *ah,
|
||||
__func__,chan->ic_freq, cfgCtl );
|
||||
|
||||
if (IS_EEP_MINOR_V2(ah)) {
|
||||
ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
|
||||
}
|
||||
|
||||
if (!ar9285SetPowerPerRateTable(ah, pEepData, chan,
|
||||
&ratesArray[0],cfgCtl,
|
||||
&AH5416(ah)->ah_ratesArray[0],cfgCtl,
|
||||
twiceAntennaReduction,
|
||||
twiceMaxRegulatoryPower, powerLimit)) {
|
||||
HALDEBUG(ah, HAL_DEBUG_ANY,
|
||||
@ -120,11 +120,12 @@ ar9285SetTransmitPower(struct ath_hal *ah,
|
||||
return AH_FALSE;
|
||||
}
|
||||
|
||||
maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]);
|
||||
maxPower = AH_MAX(maxPower, ratesArray[rate1l]);
|
||||
maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb],
|
||||
AH5416(ah)->ah_ratesArray[rateHt20_0]);
|
||||
maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rate1l]);
|
||||
|
||||
if (IEEE80211_IS_CHAN_HT40(chan)) {
|
||||
maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]);
|
||||
maxPower = AH_MAX(maxPower, AH5416(ah)->ah_ratesArray[rateHt40_0]);
|
||||
}
|
||||
|
||||
ahp->ah_tx6PowerInHalfDbm = maxPower;
|
||||
@ -135,18 +136,18 @@ ar9285SetTransmitPower(struct ath_hal *ah,
|
||||
* txPowerIndexOffset is set by the SetPowerTable() call -
|
||||
* adjust the rate table (0 offset if rates EEPROM not loaded)
|
||||
*/
|
||||
for (i = 0; i < N(ratesArray); i++) {
|
||||
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
|
||||
for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
|
||||
AH5416(ah)->ah_ratesArray[i] = (int16_t)(txPowerIndexOffset + AH5416(ah)->ah_ratesArray[i]);
|
||||
/* -5 dBm offset for Merlin and later; this includes Kite */
|
||||
ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
|
||||
if (ratesArray[i] > AR5416_MAX_RATE_POWER)
|
||||
ratesArray[i] = AR5416_MAX_RATE_POWER;
|
||||
if (ratesArray[i] < 0)
|
||||
ratesArray[i] = 0;
|
||||
AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
|
||||
if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
|
||||
AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
|
||||
if (AH5416(ah)->ah_ratesArray[i] < 0)
|
||||
AH5416(ah)->ah_ratesArray[i] = 0;
|
||||
}
|
||||
|
||||
#ifdef AH_EEPROM_DUMP
|
||||
ar5416PrintPowerPerRate(ah, ratesArray);
|
||||
ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -157,18 +158,26 @@ ar9285SetTransmitPower(struct ath_hal *ah,
|
||||
* XXX handle overflow/too high power level?
|
||||
*/
|
||||
if (IEEE80211_IS_CHAN_HT40(chan)) {
|
||||
ratesArray[rateHt40_0] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_1] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_2] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_3] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_4] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_5] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_6] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_7] += ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_0] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_1] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_2] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_3] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_4] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_5] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_6] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_7] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
}
|
||||
|
||||
/* Write the TX power rate registers */
|
||||
ar5416WriteTxPowerRateRegisters(ah, chan, ratesArray);
|
||||
ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray);
|
||||
|
||||
return AH_TRUE;
|
||||
#undef POW_SM
|
||||
|
@ -333,9 +333,7 @@ ar9287SetTransmitPower(struct ath_hal *ah,
|
||||
|
||||
const struct modal_eep_ar9287_header *pModal;
|
||||
struct ath_hal_5212 *ahp = AH5212(ah);
|
||||
int16_t ratesArray[Ar5416RateSize];
|
||||
int16_t txPowerIndexOffset = 0;
|
||||
uint8_t ht40PowerIncForPdadc = 2;
|
||||
int i;
|
||||
|
||||
uint16_t cfgCtl;
|
||||
@ -346,8 +344,11 @@ ar9287SetTransmitPower(struct ath_hal *ah,
|
||||
HAL_EEPROM_9287 *ee = AH_PRIVATE(ah)->ah_eeprom;
|
||||
struct ar9287_eeprom *pEepData = &ee->ee_base;
|
||||
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc = 2;
|
||||
|
||||
/* Setup info for the actual eeprom */
|
||||
OS_MEMZERO(ratesArray, sizeof(ratesArray));
|
||||
OS_MEMZERO(AH5416(ah)->ah_ratesArray,
|
||||
sizeof(AH5416(ah)->ah_ratesArray));
|
||||
cfgCtl = ath_hal_getctl(ah, chan);
|
||||
powerLimit = chan->ic_maxregpower * 2;
|
||||
twiceAntennaReduction = chan->ic_maxantgain;
|
||||
@ -358,11 +359,12 @@ ar9287SetTransmitPower(struct ath_hal *ah,
|
||||
__func__,chan->ic_freq, cfgCtl );
|
||||
|
||||
/* XXX Assume Minor is v2 or later */
|
||||
ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
|
||||
|
||||
/* Fetch per-rate power table for the given channel */
|
||||
if (! ar9287SetPowerPerRateTable(ah, pEepData, chan,
|
||||
&ratesArray[0],cfgCtl,
|
||||
&AH5416(ah)->ah_ratesArray[0],
|
||||
cfgCtl,
|
||||
twiceAntennaReduction,
|
||||
twiceMaxRegulatoryPower, powerLimit)) {
|
||||
HALDEBUG(ah, HAL_DEBUG_ANY,
|
||||
@ -374,11 +376,14 @@ ar9287SetTransmitPower(struct ath_hal *ah,
|
||||
ar9287SetPowerCalTable(ah, chan, &txPowerIndexOffset);
|
||||
|
||||
/* Calculate maximum power level */
|
||||
maxPower = AH_MAX(ratesArray[rate6mb], ratesArray[rateHt20_0]);
|
||||
maxPower = AH_MAX(maxPower, ratesArray[rate1l]);
|
||||
maxPower = AH_MAX(AH5416(ah)->ah_ratesArray[rate6mb],
|
||||
AH5416(ah)->ah_ratesArray[rateHt20_0]);
|
||||
maxPower = AH_MAX(maxPower,
|
||||
AH5416(ah)->ah_ratesArray[rate1l]);
|
||||
|
||||
if (IEEE80211_IS_CHAN_HT40(chan))
|
||||
maxPower = AH_MAX(maxPower, ratesArray[rateHt40_0]);
|
||||
maxPower = AH_MAX(maxPower,
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_0]);
|
||||
|
||||
ahp->ah_tx6PowerInHalfDbm = maxPower;
|
||||
AH_PRIVATE(ah)->ah_maxPowerLevel = maxPower;
|
||||
@ -389,18 +394,20 @@ ar9287SetTransmitPower(struct ath_hal *ah,
|
||||
* adjust the rate table (0 offset if rates EEPROM not loaded)
|
||||
*/
|
||||
/* XXX what about the pwrTableOffset? */
|
||||
for (i = 0; i < N(ratesArray); i++) {
|
||||
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
|
||||
for (i = 0; i < N(AH5416(ah)->ah_ratesArray); i++) {
|
||||
AH5416(ah)->ah_ratesArray[i] =
|
||||
(int16_t)(txPowerIndexOffset +
|
||||
AH5416(ah)->ah_ratesArray[i]);
|
||||
/* -5 dBm offset for Merlin and later; this includes Kiwi */
|
||||
ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
|
||||
if (ratesArray[i] > AR5416_MAX_RATE_POWER)
|
||||
ratesArray[i] = AR5416_MAX_RATE_POWER;
|
||||
if (ratesArray[i] < 0)
|
||||
ratesArray[i] = 0;
|
||||
AH5416(ah)->ah_ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
|
||||
if (AH5416(ah)->ah_ratesArray[i] > AR5416_MAX_RATE_POWER)
|
||||
AH5416(ah)->ah_ratesArray[i] = AR5416_MAX_RATE_POWER;
|
||||
if (AH5416(ah)->ah_ratesArray[i] < 0)
|
||||
AH5416(ah)->ah_ratesArray[i] = 0;
|
||||
}
|
||||
|
||||
#ifdef AH_EEPROM_DUMP
|
||||
ar5416PrintPowerPerRate(ah, ratesArray);
|
||||
ar5416PrintPowerPerRate(ah, AH5416(ah)->ah_ratesArray);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -411,18 +418,26 @@ ar9287SetTransmitPower(struct ath_hal *ah,
|
||||
* XXX handle overflow/too high power level?
|
||||
*/
|
||||
if (IEEE80211_IS_CHAN_HT40(chan)) {
|
||||
ratesArray[rateHt40_0] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_1] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_2] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_3] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_4] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_5] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_6] += ht40PowerIncForPdadc;
|
||||
ratesArray[rateHt40_7] += ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_0] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_1] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_2] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_3] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_4] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_5] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_6] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
AH5416(ah)->ah_ratesArray[rateHt40_7] +=
|
||||
AH5416(ah)->ah_ht40PowerIncForPdadc;
|
||||
}
|
||||
|
||||
/* Write the TX power rate registers */
|
||||
ar5416WriteTxPowerRateRegisters(ah, chan, ratesArray);
|
||||
ar5416WriteTxPowerRateRegisters(ah, chan, AH5416(ah)->ah_ratesArray);
|
||||
|
||||
return AH_TRUE;
|
||||
#undef POW_SM
|
||||
|
Loading…
Reference in New Issue
Block a user