cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

eeprom.c (17891B)


      1/*
      2 * Copyright (c) 2008-2011 Atheros Communications Inc.
      3 *
      4 * Permission to use, copy, modify, and/or distribute this software for any
      5 * purpose with or without fee is hereby granted, provided that the above
      6 * copyright notice and this permission notice appear in all copies.
      7 *
      8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15 */
     16
     17#include "hw.h"
     18#include <linux/ath9k_platform.h>
     19
     20void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
     21{
     22        REG_WRITE(ah, reg, val);
     23
     24        if (ah->config.analog_shiftreg)
     25		udelay(100);
     26}
     27
     28void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
     29			       u32 shift, u32 val)
     30{
     31	REG_RMW(ah, reg, ((val << shift) & mask), mask);
     32
     33	if (ah->config.analog_shiftreg)
     34		udelay(100);
     35}
     36
     37int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
     38			     int16_t targetLeft, int16_t targetRight)
     39{
     40	int16_t rv;
     41
     42	if (srcRight == srcLeft) {
     43		rv = targetLeft;
     44	} else {
     45		rv = (int16_t) (((target - srcLeft) * targetRight +
     46				 (srcRight - target) * targetLeft) /
     47				(srcRight - srcLeft));
     48	}
     49	return rv;
     50}
     51
     52bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
     53				    u16 *indexL, u16 *indexR)
     54{
     55	u16 i;
     56
     57	if (target <= pList[0]) {
     58		*indexL = *indexR = 0;
     59		return true;
     60	}
     61	if (target >= pList[listSize - 1]) {
     62		*indexL = *indexR = (u16) (listSize - 1);
     63		return true;
     64	}
     65
     66	for (i = 0; i < listSize - 1; i++) {
     67		if (pList[i] == target) {
     68			*indexL = *indexR = i;
     69			return true;
     70		}
     71		if (target < pList[i + 1]) {
     72			*indexL = i;
     73			*indexR = (u16) (i + 1);
     74			return false;
     75		}
     76	}
     77	return false;
     78}
     79
     80void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
     81				  int eep_start_loc, int size)
     82{
     83	int i = 0, j, addr;
     84	u32 addrdata[8];
     85	u32 data[8];
     86
     87	for (addr = 0; addr < size; addr++) {
     88		addrdata[i] = AR5416_EEPROM_OFFSET +
     89			((addr + eep_start_loc) << AR5416_EEPROM_S);
     90		i++;
     91		if (i == 8) {
     92			REG_READ_MULTI(ah, addrdata, data, i);
     93
     94			for (j = 0; j < i; j++) {
     95				*eep_data = data[j];
     96				eep_data++;
     97			}
     98			i = 0;
     99		}
    100	}
    101
    102	if (i != 0) {
    103		REG_READ_MULTI(ah, addrdata, data, i);
    104
    105		for (j = 0; j < i; j++) {
    106			*eep_data = data[j];
    107			eep_data++;
    108		}
    109	}
    110}
    111
    112static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size,
    113				      off_t offset, u16 *data)
    114{
    115	if (offset >= blob_size)
    116		return false;
    117
    118	*data =  blob[offset];
    119	return true;
    120}
    121
    122static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata,
    123				      off_t offset, u16 *data)
    124{
    125	return ath9k_hw_nvram_read_array(pdata->eeprom_data,
    126					 ARRAY_SIZE(pdata->eeprom_data),
    127					 offset, data);
    128}
    129
    130static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob,
    131					 off_t offset, u16 *data)
    132{
    133	return ath9k_hw_nvram_read_array((u16 *) eeprom_blob->data,
    134					 eeprom_blob->size / sizeof(u16),
    135					 offset, data);
    136}
    137
    138static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset,
    139				      u16 *data)
    140{
    141	return ath9k_hw_nvram_read_array(ah->nvmem_blob,
    142					 ah->nvmem_blob_len / sizeof(u16),
    143					 offset, data);
    144}
    145
    146bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
    147{
    148	struct ath_common *common = ath9k_hw_common(ah);
    149	struct ath9k_platform_data *pdata = ah->dev->platform_data;
    150	bool ret;
    151
    152	if (ah->nvmem_blob)
    153		ret = ath9k_hw_nvram_read_nvmem(ah, off, data);
    154	else if (ah->eeprom_blob)
    155		ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
    156	else if (pdata && !pdata->use_eeprom)
    157		ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
    158	else
    159		ret = common->bus_ops->eeprom_read(common, off, data);
    160
    161	if (!ret)
    162		ath_dbg(common, EEPROM,
    163			"unable to read eeprom region at offset %u\n", off);
    164
    165	return ret;
    166}
    167
    168int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
    169{
    170	u16 magic;
    171	u16 *eepdata;
    172	int i;
    173	bool needs_byteswap = false;
    174	struct ath_common *common = ath9k_hw_common(ah);
    175
    176	if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
    177		ath_err(common, "Reading Magic # failed\n");
    178		return -EIO;
    179	}
    180
    181	if (swab16(magic) == AR5416_EEPROM_MAGIC) {
    182		needs_byteswap = true;
    183		ath_dbg(common, EEPROM,
    184			"EEPROM needs byte-swapping to correct endianness.\n");
    185	} else if (magic != AR5416_EEPROM_MAGIC) {
    186		if (ath9k_hw_use_flash(ah)) {
    187			ath_dbg(common, EEPROM,
    188				"Ignoring invalid EEPROM magic (0x%04x).\n",
    189				magic);
    190		} else {
    191			ath_err(common,
    192				"Invalid EEPROM magic (0x%04x).\n", magic);
    193			return -EINVAL;
    194		}
    195	}
    196
    197	if (needs_byteswap) {
    198		if (ah->ah_flags & AH_NO_EEP_SWAP) {
    199			ath_info(common,
    200				 "Ignoring endianness difference in EEPROM magic bytes.\n");
    201		} else {
    202			eepdata = (u16 *)(&ah->eeprom);
    203
    204			for (i = 0; i < size; i++)
    205				eepdata[i] = swab16(eepdata[i]);
    206		}
    207	}
    208
    209	if (ah->eep_ops->get_eepmisc(ah) & AR5416_EEPMISC_BIG_ENDIAN) {
    210		*swap_needed = true;
    211		ath_dbg(common, EEPROM,
    212			"Big Endian EEPROM detected according to EEPMISC register.\n");
    213	} else {
    214		*swap_needed = false;
    215	}
    216
    217	return 0;
    218}
    219
    220bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
    221{
    222	u32 i, sum = 0;
    223	u16 *eepdata = (u16 *)(&ah->eeprom);
    224	struct ath_common *common = ath9k_hw_common(ah);
    225
    226	for (i = 0; i < size; i++)
    227		sum ^= eepdata[i];
    228
    229	if (sum != 0xffff) {
    230		ath_err(common, "Bad EEPROM checksum 0x%x\n", sum);
    231		return false;
    232	}
    233
    234	return true;
    235}
    236
    237bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
    238{
    239	struct ath_common *common = ath9k_hw_common(ah);
    240
    241	if (ah->eep_ops->get_eeprom_ver(ah) != version ||
    242	    ah->eep_ops->get_eeprom_rev(ah) < minrev) {
    243		ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
    244			ah->eep_ops->get_eeprom_ver(ah),
    245			ah->eep_ops->get_eeprom_rev(ah));
    246		return false;
    247	}
    248
    249	return true;
    250}
    251
    252void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
    253			     u8 *pVpdList, u16 numIntercepts,
    254			     u8 *pRetVpdList)
    255{
    256	u16 i, k;
    257	u8 currPwr = pwrMin;
    258	u16 idxL = 0, idxR = 0;
    259
    260	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
    261		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
    262					       numIntercepts, &(idxL),
    263					       &(idxR));
    264		if (idxR < 1)
    265			idxR = 1;
    266		if (idxL == numIntercepts - 1)
    267			idxL = (u16) (numIntercepts - 2);
    268		if (pPwrList[idxL] == pPwrList[idxR])
    269			k = pVpdList[idxL];
    270		else
    271			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
    272				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
    273				  (pPwrList[idxR] - pPwrList[idxL]));
    274		pRetVpdList[i] = (u8) k;
    275		currPwr += 2;
    276	}
    277}
    278
    279void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
    280				       struct ath9k_channel *chan,
    281				       struct cal_target_power_leg *powInfo,
    282				       u16 numChannels,
    283				       struct cal_target_power_leg *pNewPower,
    284				       u16 numRates, bool isExtTarget)
    285{
    286	struct chan_centers centers;
    287	u16 clo, chi;
    288	int i;
    289	int matchIndex = -1, lowIndex = -1;
    290	u16 freq;
    291
    292	ath9k_hw_get_channel_centers(ah, chan, &centers);
    293	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
    294
    295	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
    296				       IS_CHAN_2GHZ(chan))) {
    297		matchIndex = 0;
    298	} else {
    299		for (i = 0; (i < numChannels) &&
    300			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
    301			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
    302						       IS_CHAN_2GHZ(chan))) {
    303				matchIndex = i;
    304				break;
    305			} else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
    306						IS_CHAN_2GHZ(chan)) && i > 0 &&
    307				   freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
    308						IS_CHAN_2GHZ(chan))) {
    309				lowIndex = i - 1;
    310				break;
    311			}
    312		}
    313		if ((matchIndex == -1) && (lowIndex == -1))
    314			matchIndex = i - 1;
    315	}
    316
    317	if (matchIndex != -1) {
    318		*pNewPower = powInfo[matchIndex];
    319	} else {
    320		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
    321					 IS_CHAN_2GHZ(chan));
    322		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
    323					 IS_CHAN_2GHZ(chan));
    324
    325		for (i = 0; i < numRates; i++) {
    326			pNewPower->tPow2x[i] =
    327				(u8)ath9k_hw_interpolate(freq, clo, chi,
    328						powInfo[lowIndex].tPow2x[i],
    329						powInfo[lowIndex + 1].tPow2x[i]);
    330		}
    331	}
    332}
    333
    334void ath9k_hw_get_target_powers(struct ath_hw *ah,
    335				struct ath9k_channel *chan,
    336				struct cal_target_power_ht *powInfo,
    337				u16 numChannels,
    338				struct cal_target_power_ht *pNewPower,
    339				u16 numRates, bool isHt40Target)
    340{
    341	struct chan_centers centers;
    342	u16 clo, chi;
    343	int i;
    344	int matchIndex = -1, lowIndex = -1;
    345	u16 freq;
    346
    347	ath9k_hw_get_channel_centers(ah, chan, &centers);
    348	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
    349
    350	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
    351		matchIndex = 0;
    352	} else {
    353		for (i = 0; (i < numChannels) &&
    354			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
    355			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
    356						       IS_CHAN_2GHZ(chan))) {
    357				matchIndex = i;
    358				break;
    359			} else
    360				if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
    361						IS_CHAN_2GHZ(chan)) && i > 0 &&
    362				    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
    363						IS_CHAN_2GHZ(chan))) {
    364					lowIndex = i - 1;
    365					break;
    366				}
    367		}
    368		if ((matchIndex == -1) && (lowIndex == -1))
    369			matchIndex = i - 1;
    370	}
    371
    372	if (matchIndex != -1) {
    373		*pNewPower = powInfo[matchIndex];
    374	} else {
    375		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
    376					 IS_CHAN_2GHZ(chan));
    377		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
    378					 IS_CHAN_2GHZ(chan));
    379
    380		for (i = 0; i < numRates; i++) {
    381			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
    382						clo, chi,
    383						powInfo[lowIndex].tPow2x[i],
    384						powInfo[lowIndex + 1].tPow2x[i]);
    385		}
    386	}
    387}
    388
    389u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
    390				bool is2GHz, int num_band_edges)
    391{
    392	u16 twiceMaxEdgePower = MAX_RATE_POWER;
    393	int i;
    394
    395	for (i = 0; (i < num_band_edges) &&
    396		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
    397		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
    398			twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
    399			break;
    400		} else if ((i > 0) &&
    401			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
    402						      is2GHz))) {
    403			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
    404					       is2GHz) < freq &&
    405			    CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
    406				twiceMaxEdgePower =
    407					CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
    408			}
    409			break;
    410		}
    411	}
    412
    413	return twiceMaxEdgePower;
    414}
    415
    416u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
    417			      u8 antenna_reduction)
    418{
    419	u16 reduction = antenna_reduction;
    420
    421	/*
    422	 * Reduce scaled Power by number of chains active
    423	 * to get the per chain tx power level.
    424	 */
    425	switch (ar5416_get_ntxchains(ah->txchainmask)) {
    426	case 1:
    427		break;
    428	case 2:
    429		reduction += POWER_CORRECTION_FOR_TWO_CHAIN;
    430		break;
    431	case 3:
    432		reduction += POWER_CORRECTION_FOR_THREE_CHAIN;
    433		break;
    434	}
    435
    436	if (power_limit > reduction)
    437		power_limit -= reduction;
    438	else
    439		power_limit = 0;
    440
    441	return min_t(u16, power_limit, MAX_RATE_POWER);
    442}
    443
    444void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
    445{
    446	struct ath_common *common = ath9k_hw_common(ah);
    447	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
    448
    449	switch (ar5416_get_ntxchains(ah->txchainmask)) {
    450	case 1:
    451		break;
    452	case 2:
    453		regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN;
    454		break;
    455	case 3:
    456		regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN;
    457		break;
    458	default:
    459		ath_dbg(common, EEPROM, "Invalid chainmask configuration\n");
    460		break;
    461	}
    462}
    463
    464void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
    465				struct ath9k_channel *chan,
    466				void *pRawDataSet,
    467				u8 *bChans, u16 availPiers,
    468				u16 tPdGainOverlap,
    469				u16 *pPdGainBoundaries, u8 *pPDADCValues,
    470				u16 numXpdGains)
    471{
    472	int i, j, k;
    473	int16_t ss;
    474	u16 idxL = 0, idxR = 0, numPiers;
    475	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
    476		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
    477	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
    478		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
    479	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
    480		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
    481
    482	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
    483	u8 minPwrT4[AR5416_NUM_PD_GAINS];
    484	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
    485	int16_t vpdStep;
    486	int16_t tmpVal;
    487	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
    488	bool match;
    489	int16_t minDelta = 0;
    490	struct chan_centers centers;
    491	int pdgain_boundary_default;
    492	struct cal_data_per_freq *data_def = pRawDataSet;
    493	struct cal_data_per_freq_4k *data_4k = pRawDataSet;
    494	struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
    495	bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
    496	int intercepts;
    497
    498	if (AR_SREV_9287(ah))
    499		intercepts = AR9287_PD_GAIN_ICEPTS;
    500	else
    501		intercepts = AR5416_PD_GAIN_ICEPTS;
    502
    503	memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
    504	ath9k_hw_get_channel_centers(ah, chan, &centers);
    505
    506	for (numPiers = 0; numPiers < availPiers; numPiers++) {
    507		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
    508			break;
    509	}
    510
    511	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
    512							     IS_CHAN_2GHZ(chan)),
    513					       bChans, numPiers, &idxL, &idxR);
    514
    515	if (match) {
    516		if (AR_SREV_9287(ah)) {
    517			for (i = 0; i < numXpdGains; i++) {
    518				minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
    519				maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1];
    520				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
    521						data_9287[idxL].pwrPdg[i],
    522						data_9287[idxL].vpdPdg[i],
    523						intercepts,
    524						vpdTableI[i]);
    525			}
    526		} else if (eeprom_4k) {
    527			for (i = 0; i < numXpdGains; i++) {
    528				minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
    529				maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1];
    530				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
    531						data_4k[idxL].pwrPdg[i],
    532						data_4k[idxL].vpdPdg[i],
    533						intercepts,
    534						vpdTableI[i]);
    535			}
    536		} else {
    537			for (i = 0; i < numXpdGains; i++) {
    538				minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
    539				maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1];
    540				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
    541						data_def[idxL].pwrPdg[i],
    542						data_def[idxL].vpdPdg[i],
    543						intercepts,
    544						vpdTableI[i]);
    545			}
    546		}
    547	} else {
    548		for (i = 0; i < numXpdGains; i++) {
    549			if (AR_SREV_9287(ah)) {
    550				pVpdL = data_9287[idxL].vpdPdg[i];
    551				pPwrL = data_9287[idxL].pwrPdg[i];
    552				pVpdR = data_9287[idxR].vpdPdg[i];
    553				pPwrR = data_9287[idxR].pwrPdg[i];
    554			} else if (eeprom_4k) {
    555				pVpdL = data_4k[idxL].vpdPdg[i];
    556				pPwrL = data_4k[idxL].pwrPdg[i];
    557				pVpdR = data_4k[idxR].vpdPdg[i];
    558				pPwrR = data_4k[idxR].pwrPdg[i];
    559			} else {
    560				pVpdL = data_def[idxL].vpdPdg[i];
    561				pPwrL = data_def[idxL].pwrPdg[i];
    562				pVpdR = data_def[idxR].vpdPdg[i];
    563				pPwrR = data_def[idxR].pwrPdg[i];
    564			}
    565
    566			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
    567
    568			maxPwrT4[i] =
    569				min(pPwrL[intercepts - 1],
    570				    pPwrR[intercepts - 1]);
    571
    572
    573			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
    574						pPwrL, pVpdL,
    575						intercepts,
    576						vpdTableL[i]);
    577			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
    578						pPwrR, pVpdR,
    579						intercepts,
    580						vpdTableR[i]);
    581
    582			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
    583				vpdTableI[i][j] =
    584					(u8)(ath9k_hw_interpolate((u16)
    585					     FREQ2FBIN(centers.
    586						       synth_center,
    587						       IS_CHAN_2GHZ
    588						       (chan)),
    589					     bChans[idxL], bChans[idxR],
    590					     vpdTableL[i][j], vpdTableR[i][j]));
    591			}
    592		}
    593	}
    594
    595	k = 0;
    596
    597	for (i = 0; i < numXpdGains; i++) {
    598		if (i == (numXpdGains - 1))
    599			pPdGainBoundaries[i] =
    600				(u16)(maxPwrT4[i] / 2);
    601		else
    602			pPdGainBoundaries[i] =
    603				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
    604
    605		pPdGainBoundaries[i] =
    606			min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
    607
    608		minDelta = 0;
    609
    610		if (i == 0) {
    611			if (AR_SREV_9280_20_OR_LATER(ah))
    612				ss = (int16_t)(0 - (minPwrT4[i] / 2));
    613			else
    614				ss = 0;
    615		} else {
    616			ss = (int16_t)((pPdGainBoundaries[i - 1] -
    617					(minPwrT4[i] / 2)) -
    618				       tPdGainOverlap + 1 + minDelta);
    619		}
    620		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
    621		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
    622
    623		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
    624			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
    625			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
    626			ss++;
    627		}
    628
    629		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
    630		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
    631				(minPwrT4[i] / 2));
    632		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
    633			tgtIndex : sizeCurrVpdTable;
    634
    635		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
    636			pPDADCValues[k++] = vpdTableI[i][ss++];
    637		}
    638
    639		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
    640				    vpdTableI[i][sizeCurrVpdTable - 2]);
    641		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
    642
    643		if (tgtIndex >= maxIndex) {
    644			while ((ss <= tgtIndex) &&
    645			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
    646				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
    647						    (ss - maxIndex + 1) * vpdStep));
    648				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
    649							 255 : tmpVal);
    650				ss++;
    651			}
    652		}
    653	}
    654
    655	if (eeprom_4k)
    656		pdgain_boundary_default = 58;
    657	else
    658		pdgain_boundary_default = pPdGainBoundaries[i - 1];
    659
    660	while (i < AR5416_PD_GAINS_IN_MASK) {
    661		pPdGainBoundaries[i] = pdgain_boundary_default;
    662		i++;
    663	}
    664
    665	while (k < AR5416_NUM_PDADC_VALUES) {
    666		pPDADCValues[k] = pPDADCValues[k - 1];
    667		k++;
    668	}
    669}
    670
    671int ath9k_hw_eeprom_init(struct ath_hw *ah)
    672{
    673	if (AR_SREV_9300_20_OR_LATER(ah))
    674		ah->eep_ops = &eep_ar9300_ops;
    675	else if (AR_SREV_9287(ah)) {
    676		ah->eep_ops = &eep_ar9287_ops;
    677	} else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
    678		ah->eep_ops = &eep_4k_ops;
    679	} else {
    680		ah->eep_ops = &eep_def_ops;
    681	}
    682
    683	if (!ah->eep_ops->fill_eeprom(ah))
    684		return -EIO;
    685
    686	return ah->eep_ops->check_eeprom(ah);
    687}