mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
83d6f1f15f
Code that was added back in 2.6.38 has an obvious overflow
when accessing a static array, and at the time it was added
only a code comment was put in front of it as a reminder
to have it reviewed properly.
This has not happened, but gcc-6 now points to the specific
overflow:
drivers/net/wireless/ath/ath9k/eeprom.c: In function 'ath9k_hw_get_gain_boundaries_pdadcs':
drivers/net/wireless/ath/ath9k/eeprom.c:483:44: error: array subscript is above array bounds [-Werror=array-bounds]
maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
~~~~~~~~~~~~~~~~~~~~~~~~~^~~
It turns out that the correct array length exists in the local
'intercepts' variable of this function, so we can just use that
instead of hardcoding '4', so this patch changes all three
instances to use that variable. The other two instances were
already correct, but it's more consistent this way.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Fixes: 940cd2c12e
("ath9k_hw: merge the ar9287 version of ath9k_hw_get_gain_boundaries_pdadcs")
Signed-off-by: David S. Miller <davem@davemloft.net>
655 lines
16 KiB
C
655 lines
16 KiB
C
/*
|
|
* Copyright (c) 2008-2011 Atheros Communications Inc.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "hw.h"
|
|
|
|
void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
|
|
{
|
|
REG_WRITE(ah, reg, val);
|
|
|
|
if (ah->config.analog_shiftreg)
|
|
udelay(100);
|
|
}
|
|
|
|
void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
|
|
u32 shift, u32 val)
|
|
{
|
|
REG_RMW(ah, reg, ((val << shift) & mask), mask);
|
|
|
|
if (ah->config.analog_shiftreg)
|
|
udelay(100);
|
|
}
|
|
|
|
int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
|
|
int16_t targetLeft, int16_t targetRight)
|
|
{
|
|
int16_t rv;
|
|
|
|
if (srcRight == srcLeft) {
|
|
rv = targetLeft;
|
|
} else {
|
|
rv = (int16_t) (((target - srcLeft) * targetRight +
|
|
(srcRight - target) * targetLeft) /
|
|
(srcRight - srcLeft));
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
|
|
u16 *indexL, u16 *indexR)
|
|
{
|
|
u16 i;
|
|
|
|
if (target <= pList[0]) {
|
|
*indexL = *indexR = 0;
|
|
return true;
|
|
}
|
|
if (target >= pList[listSize - 1]) {
|
|
*indexL = *indexR = (u16) (listSize - 1);
|
|
return true;
|
|
}
|
|
|
|
for (i = 0; i < listSize - 1; i++) {
|
|
if (pList[i] == target) {
|
|
*indexL = *indexR = i;
|
|
return true;
|
|
}
|
|
if (target < pList[i + 1]) {
|
|
*indexL = i;
|
|
*indexR = (u16) (i + 1);
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
|
|
int eep_start_loc, int size)
|
|
{
|
|
int i = 0, j, addr;
|
|
u32 addrdata[8];
|
|
u32 data[8];
|
|
|
|
for (addr = 0; addr < size; addr++) {
|
|
addrdata[i] = AR5416_EEPROM_OFFSET +
|
|
((addr + eep_start_loc) << AR5416_EEPROM_S);
|
|
i++;
|
|
if (i == 8) {
|
|
REG_READ_MULTI(ah, addrdata, data, i);
|
|
|
|
for (j = 0; j < i; j++) {
|
|
*eep_data = data[j];
|
|
eep_data++;
|
|
}
|
|
i = 0;
|
|
}
|
|
}
|
|
|
|
if (i != 0) {
|
|
REG_READ_MULTI(ah, addrdata, data, i);
|
|
|
|
for (j = 0; j < i; j++) {
|
|
*eep_data = data[j];
|
|
eep_data++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off,
|
|
u16 *data)
|
|
{
|
|
u16 *blob_data;
|
|
|
|
if (off * sizeof(u16) > ah->eeprom_blob->size)
|
|
return false;
|
|
|
|
blob_data = (u16 *)ah->eeprom_blob->data;
|
|
*data = blob_data[off];
|
|
return true;
|
|
}
|
|
|
|
bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
|
|
{
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
bool ret;
|
|
|
|
if (ah->eeprom_blob)
|
|
ret = ath9k_hw_nvram_read_blob(ah, off, data);
|
|
else
|
|
ret = common->bus_ops->eeprom_read(common, off, data);
|
|
|
|
if (!ret)
|
|
ath_dbg(common, EEPROM,
|
|
"unable to read eeprom region at offset %u\n", off);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
|
|
{
|
|
u16 magic;
|
|
u16 *eepdata;
|
|
int i;
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
|
|
if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
|
|
ath_err(common, "Reading Magic # failed\n");
|
|
return -EIO;
|
|
}
|
|
|
|
*swap_needed = false;
|
|
if (swab16(magic) == AR5416_EEPROM_MAGIC) {
|
|
if (ah->ah_flags & AH_NO_EEP_SWAP) {
|
|
ath_info(common,
|
|
"Ignoring endianness difference in EEPROM magic bytes.\n");
|
|
} else {
|
|
*swap_needed = true;
|
|
}
|
|
} else if (magic != AR5416_EEPROM_MAGIC) {
|
|
if (ath9k_hw_use_flash(ah))
|
|
return 0;
|
|
|
|
ath_err(common,
|
|
"Invalid EEPROM Magic (0x%04x).\n", magic);
|
|
return -EINVAL;
|
|
}
|
|
|
|
eepdata = (u16 *)(&ah->eeprom);
|
|
|
|
if (*swap_needed) {
|
|
ath_dbg(common, EEPROM,
|
|
"EEPROM Endianness is not native.. Changing.\n");
|
|
|
|
for (i = 0; i < size; i++)
|
|
eepdata[i] = swab16(eepdata[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
|
|
{
|
|
u32 i, sum = 0;
|
|
u16 *eepdata = (u16 *)(&ah->eeprom);
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
|
|
for (i = 0; i < size; i++)
|
|
sum ^= eepdata[i];
|
|
|
|
if (sum != 0xffff) {
|
|
ath_err(common, "Bad EEPROM checksum 0x%x\n", sum);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
|
|
{
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
|
|
if (ah->eep_ops->get_eeprom_ver(ah) != version ||
|
|
ah->eep_ops->get_eeprom_rev(ah) < minrev) {
|
|
ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
|
|
ah->eep_ops->get_eeprom_ver(ah),
|
|
ah->eep_ops->get_eeprom_rev(ah));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
|
|
u8 *pVpdList, u16 numIntercepts,
|
|
u8 *pRetVpdList)
|
|
{
|
|
u16 i, k;
|
|
u8 currPwr = pwrMin;
|
|
u16 idxL = 0, idxR = 0;
|
|
|
|
for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
|
|
ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
|
|
numIntercepts, &(idxL),
|
|
&(idxR));
|
|
if (idxR < 1)
|
|
idxR = 1;
|
|
if (idxL == numIntercepts - 1)
|
|
idxL = (u16) (numIntercepts - 2);
|
|
if (pPwrList[idxL] == pPwrList[idxR])
|
|
k = pVpdList[idxL];
|
|
else
|
|
k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
|
|
(pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
|
|
(pPwrList[idxR] - pPwrList[idxL]));
|
|
pRetVpdList[i] = (u8) k;
|
|
currPwr += 2;
|
|
}
|
|
}
|
|
|
|
void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
|
|
struct ath9k_channel *chan,
|
|
struct cal_target_power_leg *powInfo,
|
|
u16 numChannels,
|
|
struct cal_target_power_leg *pNewPower,
|
|
u16 numRates, bool isExtTarget)
|
|
{
|
|
struct chan_centers centers;
|
|
u16 clo, chi;
|
|
int i;
|
|
int matchIndex = -1, lowIndex = -1;
|
|
u16 freq;
|
|
|
|
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
|
freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
|
|
|
|
if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
|
|
IS_CHAN_2GHZ(chan))) {
|
|
matchIndex = 0;
|
|
} else {
|
|
for (i = 0; (i < numChannels) &&
|
|
(powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
|
|
if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
|
|
IS_CHAN_2GHZ(chan))) {
|
|
matchIndex = i;
|
|
break;
|
|
} else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
|
|
IS_CHAN_2GHZ(chan)) && i > 0 &&
|
|
freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
|
|
IS_CHAN_2GHZ(chan))) {
|
|
lowIndex = i - 1;
|
|
break;
|
|
}
|
|
}
|
|
if ((matchIndex == -1) && (lowIndex == -1))
|
|
matchIndex = i - 1;
|
|
}
|
|
|
|
if (matchIndex != -1) {
|
|
*pNewPower = powInfo[matchIndex];
|
|
} else {
|
|
clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
|
|
IS_CHAN_2GHZ(chan));
|
|
chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
|
|
IS_CHAN_2GHZ(chan));
|
|
|
|
for (i = 0; i < numRates; i++) {
|
|
pNewPower->tPow2x[i] =
|
|
(u8)ath9k_hw_interpolate(freq, clo, chi,
|
|
powInfo[lowIndex].tPow2x[i],
|
|
powInfo[lowIndex + 1].tPow2x[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ath9k_hw_get_target_powers(struct ath_hw *ah,
|
|
struct ath9k_channel *chan,
|
|
struct cal_target_power_ht *powInfo,
|
|
u16 numChannels,
|
|
struct cal_target_power_ht *pNewPower,
|
|
u16 numRates, bool isHt40Target)
|
|
{
|
|
struct chan_centers centers;
|
|
u16 clo, chi;
|
|
int i;
|
|
int matchIndex = -1, lowIndex = -1;
|
|
u16 freq;
|
|
|
|
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
|
freq = isHt40Target ? centers.synth_center : centers.ctl_center;
|
|
|
|
if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
|
|
matchIndex = 0;
|
|
} else {
|
|
for (i = 0; (i < numChannels) &&
|
|
(powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
|
|
if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
|
|
IS_CHAN_2GHZ(chan))) {
|
|
matchIndex = i;
|
|
break;
|
|
} else
|
|
if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
|
|
IS_CHAN_2GHZ(chan)) && i > 0 &&
|
|
freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
|
|
IS_CHAN_2GHZ(chan))) {
|
|
lowIndex = i - 1;
|
|
break;
|
|
}
|
|
}
|
|
if ((matchIndex == -1) && (lowIndex == -1))
|
|
matchIndex = i - 1;
|
|
}
|
|
|
|
if (matchIndex != -1) {
|
|
*pNewPower = powInfo[matchIndex];
|
|
} else {
|
|
clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
|
|
IS_CHAN_2GHZ(chan));
|
|
chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
|
|
IS_CHAN_2GHZ(chan));
|
|
|
|
for (i = 0; i < numRates; i++) {
|
|
pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
|
|
clo, chi,
|
|
powInfo[lowIndex].tPow2x[i],
|
|
powInfo[lowIndex + 1].tPow2x[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
|
|
bool is2GHz, int num_band_edges)
|
|
{
|
|
u16 twiceMaxEdgePower = MAX_RATE_POWER;
|
|
int i;
|
|
|
|
for (i = 0; (i < num_band_edges) &&
|
|
(pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
|
|
if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
|
|
twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
|
|
break;
|
|
} else if ((i > 0) &&
|
|
(freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
|
|
is2GHz))) {
|
|
if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
|
|
is2GHz) < freq &&
|
|
CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
|
|
twiceMaxEdgePower =
|
|
CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return twiceMaxEdgePower;
|
|
}
|
|
|
|
u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
|
|
u8 antenna_reduction)
|
|
{
|
|
u16 reduction = antenna_reduction;
|
|
|
|
/*
|
|
* Reduce scaled Power by number of chains active
|
|
* to get the per chain tx power level.
|
|
*/
|
|
switch (ar5416_get_ntxchains(ah->txchainmask)) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
reduction += POWER_CORRECTION_FOR_TWO_CHAIN;
|
|
break;
|
|
case 3:
|
|
reduction += POWER_CORRECTION_FOR_THREE_CHAIN;
|
|
break;
|
|
}
|
|
|
|
if (power_limit > reduction)
|
|
power_limit -= reduction;
|
|
else
|
|
power_limit = 0;
|
|
|
|
return power_limit;
|
|
}
|
|
|
|
void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
|
|
{
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
|
|
|
|
switch (ar5416_get_ntxchains(ah->txchainmask)) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN;
|
|
break;
|
|
case 3:
|
|
regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN;
|
|
break;
|
|
default:
|
|
ath_dbg(common, EEPROM, "Invalid chainmask configuration\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
|
|
struct ath9k_channel *chan,
|
|
void *pRawDataSet,
|
|
u8 *bChans, u16 availPiers,
|
|
u16 tPdGainOverlap,
|
|
u16 *pPdGainBoundaries, u8 *pPDADCValues,
|
|
u16 numXpdGains)
|
|
{
|
|
int i, j, k;
|
|
int16_t ss;
|
|
u16 idxL = 0, idxR = 0, numPiers;
|
|
static u8 vpdTableL[AR5416_NUM_PD_GAINS]
|
|
[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
|
|
static u8 vpdTableR[AR5416_NUM_PD_GAINS]
|
|
[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
|
|
static u8 vpdTableI[AR5416_NUM_PD_GAINS]
|
|
[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
|
|
|
|
u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
|
|
u8 minPwrT4[AR5416_NUM_PD_GAINS];
|
|
u8 maxPwrT4[AR5416_NUM_PD_GAINS];
|
|
int16_t vpdStep;
|
|
int16_t tmpVal;
|
|
u16 sizeCurrVpdTable, maxIndex, tgtIndex;
|
|
bool match;
|
|
int16_t minDelta = 0;
|
|
struct chan_centers centers;
|
|
int pdgain_boundary_default;
|
|
struct cal_data_per_freq *data_def = pRawDataSet;
|
|
struct cal_data_per_freq_4k *data_4k = pRawDataSet;
|
|
struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
|
|
bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
|
|
int intercepts;
|
|
|
|
if (AR_SREV_9287(ah))
|
|
intercepts = AR9287_PD_GAIN_ICEPTS;
|
|
else
|
|
intercepts = AR5416_PD_GAIN_ICEPTS;
|
|
|
|
memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
|
|
ath9k_hw_get_channel_centers(ah, chan, ¢ers);
|
|
|
|
for (numPiers = 0; numPiers < availPiers; numPiers++) {
|
|
if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
|
|
break;
|
|
}
|
|
|
|
match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
|
|
IS_CHAN_2GHZ(chan)),
|
|
bChans, numPiers, &idxL, &idxR);
|
|
|
|
if (match) {
|
|
if (AR_SREV_9287(ah)) {
|
|
for (i = 0; i < numXpdGains; i++) {
|
|
minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
|
|
maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1];
|
|
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
|
|
data_9287[idxL].pwrPdg[i],
|
|
data_9287[idxL].vpdPdg[i],
|
|
intercepts,
|
|
vpdTableI[i]);
|
|
}
|
|
} else if (eeprom_4k) {
|
|
for (i = 0; i < numXpdGains; i++) {
|
|
minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
|
|
maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1];
|
|
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
|
|
data_4k[idxL].pwrPdg[i],
|
|
data_4k[idxL].vpdPdg[i],
|
|
intercepts,
|
|
vpdTableI[i]);
|
|
}
|
|
} else {
|
|
for (i = 0; i < numXpdGains; i++) {
|
|
minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
|
|
maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1];
|
|
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
|
|
data_def[idxL].pwrPdg[i],
|
|
data_def[idxL].vpdPdg[i],
|
|
intercepts,
|
|
vpdTableI[i]);
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < numXpdGains; i++) {
|
|
if (AR_SREV_9287(ah)) {
|
|
pVpdL = data_9287[idxL].vpdPdg[i];
|
|
pPwrL = data_9287[idxL].pwrPdg[i];
|
|
pVpdR = data_9287[idxR].vpdPdg[i];
|
|
pPwrR = data_9287[idxR].pwrPdg[i];
|
|
} else if (eeprom_4k) {
|
|
pVpdL = data_4k[idxL].vpdPdg[i];
|
|
pPwrL = data_4k[idxL].pwrPdg[i];
|
|
pVpdR = data_4k[idxR].vpdPdg[i];
|
|
pPwrR = data_4k[idxR].pwrPdg[i];
|
|
} else {
|
|
pVpdL = data_def[idxL].vpdPdg[i];
|
|
pPwrL = data_def[idxL].pwrPdg[i];
|
|
pVpdR = data_def[idxR].vpdPdg[i];
|
|
pPwrR = data_def[idxR].pwrPdg[i];
|
|
}
|
|
|
|
minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
|
|
|
|
maxPwrT4[i] =
|
|
min(pPwrL[intercepts - 1],
|
|
pPwrR[intercepts - 1]);
|
|
|
|
|
|
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
|
|
pPwrL, pVpdL,
|
|
intercepts,
|
|
vpdTableL[i]);
|
|
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
|
|
pPwrR, pVpdR,
|
|
intercepts,
|
|
vpdTableR[i]);
|
|
|
|
for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
|
|
vpdTableI[i][j] =
|
|
(u8)(ath9k_hw_interpolate((u16)
|
|
FREQ2FBIN(centers.
|
|
synth_center,
|
|
IS_CHAN_2GHZ
|
|
(chan)),
|
|
bChans[idxL], bChans[idxR],
|
|
vpdTableL[i][j], vpdTableR[i][j]));
|
|
}
|
|
}
|
|
}
|
|
|
|
k = 0;
|
|
|
|
for (i = 0; i < numXpdGains; i++) {
|
|
if (i == (numXpdGains - 1))
|
|
pPdGainBoundaries[i] =
|
|
(u16)(maxPwrT4[i] / 2);
|
|
else
|
|
pPdGainBoundaries[i] =
|
|
(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
|
|
|
|
pPdGainBoundaries[i] =
|
|
min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
|
|
|
|
minDelta = 0;
|
|
|
|
if (i == 0) {
|
|
if (AR_SREV_9280_20_OR_LATER(ah))
|
|
ss = (int16_t)(0 - (minPwrT4[i] / 2));
|
|
else
|
|
ss = 0;
|
|
} else {
|
|
ss = (int16_t)((pPdGainBoundaries[i - 1] -
|
|
(minPwrT4[i] / 2)) -
|
|
tPdGainOverlap + 1 + minDelta);
|
|
}
|
|
vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
|
|
vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
|
|
|
|
while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
|
|
tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
|
|
pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
|
|
ss++;
|
|
}
|
|
|
|
sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
|
|
tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
|
|
(minPwrT4[i] / 2));
|
|
maxIndex = (tgtIndex < sizeCurrVpdTable) ?
|
|
tgtIndex : sizeCurrVpdTable;
|
|
|
|
while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
|
|
pPDADCValues[k++] = vpdTableI[i][ss++];
|
|
}
|
|
|
|
vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
|
|
vpdTableI[i][sizeCurrVpdTable - 2]);
|
|
vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
|
|
|
|
if (tgtIndex >= maxIndex) {
|
|
while ((ss <= tgtIndex) &&
|
|
(k < (AR5416_NUM_PDADC_VALUES - 1))) {
|
|
tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
|
|
(ss - maxIndex + 1) * vpdStep));
|
|
pPDADCValues[k++] = (u8)((tmpVal > 255) ?
|
|
255 : tmpVal);
|
|
ss++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (eeprom_4k)
|
|
pdgain_boundary_default = 58;
|
|
else
|
|
pdgain_boundary_default = pPdGainBoundaries[i - 1];
|
|
|
|
while (i < AR5416_PD_GAINS_IN_MASK) {
|
|
pPdGainBoundaries[i] = pdgain_boundary_default;
|
|
i++;
|
|
}
|
|
|
|
while (k < AR5416_NUM_PDADC_VALUES) {
|
|
pPDADCValues[k] = pPDADCValues[k - 1];
|
|
k++;
|
|
}
|
|
}
|
|
|
|
int ath9k_hw_eeprom_init(struct ath_hw *ah)
|
|
{
|
|
int status;
|
|
|
|
if (AR_SREV_9300_20_OR_LATER(ah))
|
|
ah->eep_ops = &eep_ar9300_ops;
|
|
else if (AR_SREV_9287(ah)) {
|
|
ah->eep_ops = &eep_ar9287_ops;
|
|
} else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
|
|
ah->eep_ops = &eep_4k_ops;
|
|
} else {
|
|
ah->eep_ops = &eep_def_ops;
|
|
}
|
|
|
|
if (!ah->eep_ops->fill_eeprom(ah))
|
|
return -EIO;
|
|
|
|
status = ah->eep_ops->check_eeprom(ah);
|
|
|
|
return status;
|
|
}
|