Skip to content

Commit

Permalink
ath9k_hw: clean up EEPROM endian handling on AR9003
Browse files Browse the repository at this point in the history
Remove the double swapping of the descriptor data structure, instead
keep it little-endian (native format of the eeprom data), and byteswap
on access.
This allows sparse to verify endian access to the eeprom struct.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Felix Fietkau authored and John W. Linville committed May 12, 2010
1 parent 9bff0bc commit ffdc4cb
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 103 deletions.
174 changes: 76 additions & 98 deletions drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,17 @@
#define AR_SWITCH_TABLE_ALL (0xfff)
#define AR_SWITCH_TABLE_ALL_S (0)

#define LE16(x) __constant_cpu_to_le16(x)
#define LE32(x) __constant_cpu_to_le32(x)

static const struct ar9300_eeprom ar9300_default = {
.eepromVersion = 2,
.templateVersion = 2,
.macAddr = {1, 2, 3, 4, 5, 6},
.custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
.baseEepHeader = {
.regDmn = {0, 0x1f},
.regDmn = { LE16(0), LE16(0x1f) },
.txrxMask = 0x77, /* 4 bits tx and 4 bits rx */
.opCapFlags = {
.opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A,
Expand Down Expand Up @@ -76,15 +79,15 @@ static const struct ar9300_eeprom ar9300_default = {
.modalHeader2G = {
/* ar9300_modal_eep_header 2g */
/* 4 idle,t1,t2,b(4 bits per setting) */
.antCtrlCommon = 0x110,
.antCtrlCommon = LE32(0x110),
/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
.antCtrlCommon2 = 0x22222,
.antCtrlCommon2 = LE32(0x22222),

/*
* antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
* rx1, rx12, b (2 bits each)
*/
.antCtrlChain = {0x150, 0x150, 0x150},
.antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },

/*
* xatten1DB[AR9300_MAX_CHAINS]; 3 xatten1_db
Expand Down Expand Up @@ -287,12 +290,12 @@ static const struct ar9300_eeprom ar9300_default = {
},
.modalHeader5G = {
/* 4 idle,t1,t2,b (4 bits per setting) */
.antCtrlCommon = 0x110,
.antCtrlCommon = LE32(0x110),
/* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
.antCtrlCommon2 = 0x22222,
.antCtrlCommon2 = LE32(0x22222),
/* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
.antCtrlChain = {
0x000, 0x000, 0x000,
LE16(0x000), LE16(0x000), LE16(0x000),
},
/* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
.xatten1DB = {0, 0, 0},
Expand Down Expand Up @@ -620,9 +623,9 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
case EEP_MAC_MSW:
return eep->macAddr[4] << 8 | eep->macAddr[5];
case EEP_REG_0:
return pBase->regDmn[0];
return le16_to_cpu(pBase->regDmn[0]);
case EEP_REG_1:
return pBase->regDmn[1];
return le16_to_cpu(pBase->regDmn[1]);
case EEP_OP_CAP:
return pBase->deviceCap;
case EEP_OP_MODE:
Expand All @@ -640,93 +643,80 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
/* Bit 4 is internal regulator flag */
return (pBase->featureEnable & 0x10) >> 4;
case EEP_SWREG:
return pBase->swreg;
return le32_to_cpu(pBase->swreg);
default:
return 0;
}
}

#ifdef __BIG_ENDIAN
static void ar9300_swap_eeprom(struct ar9300_eeprom *eep)
static bool ar9300_eeprom_read_byte(struct ath_common *common, int address,
u8 *buffer)
{
u32 dword;
u16 word;
int i;

word = swab16(eep->baseEepHeader.regDmn[0]);
eep->baseEepHeader.regDmn[0] = word;

word = swab16(eep->baseEepHeader.regDmn[1]);
eep->baseEepHeader.regDmn[1] = word;

dword = swab32(eep->baseEepHeader.swreg);
eep->baseEepHeader.swreg = dword;
u16 val;

dword = swab32(eep->modalHeader2G.antCtrlCommon);
eep->modalHeader2G.antCtrlCommon = dword;
if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val)))
return false;

dword = swab32(eep->modalHeader2G.antCtrlCommon2);
eep->modalHeader2G.antCtrlCommon2 = dword;
*buffer = (val >> (8 * (address % 2))) & 0xff;
return true;
}

dword = swab32(eep->modalHeader5G.antCtrlCommon);
eep->modalHeader5G.antCtrlCommon = dword;
static bool ar9300_eeprom_read_word(struct ath_common *common, int address,
u8 *buffer)
{
u16 val;

dword = swab32(eep->modalHeader5G.antCtrlCommon2);
eep->modalHeader5G.antCtrlCommon2 = dword;
if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val)))
return false;

for (i = 0; i < AR9300_MAX_CHAINS; i++) {
word = swab16(eep->modalHeader2G.antCtrlChain[i]);
eep->modalHeader2G.antCtrlChain[i] = word;
buffer[0] = val >> 8;
buffer[1] = val & 0xff;

word = swab16(eep->modalHeader5G.antCtrlChain[i]);
eep->modalHeader5G.antCtrlChain[i] = word;
}
return true;
}
#endif

static bool ar9300_hw_read_eeprom(struct ath_hw *ah,
long address, u8 *buffer, int many)
static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer,
int count)
{
int i;
u8 value[2];
unsigned long eepAddr;
unsigned long byteAddr;
u16 *svalue;
struct ath_common *common = ath9k_hw_common(ah);
int i;

if ((address < 0) || ((address + many) > AR9300_EEPROM_SIZE - 1)) {
if ((address < 0) || ((address + count) / 2 > AR9300_EEPROM_SIZE - 1)) {
ath_print(common, ATH_DBG_EEPROM,
"eeprom address not in range\n");
return false;
}

for (i = 0; i < many; i++) {
eepAddr = (u16) (address + i) / 2;
byteAddr = (u16) (address + i) % 2;
svalue = (u16 *) value;
if (!ath9k_hw_nvram_read(common, eepAddr, svalue)) {
ath_print(common, ATH_DBG_EEPROM,
"unable to read eeprom region\n");
return false;
}
*svalue = le16_to_cpu(*svalue);
buffer[i] = value[byteAddr];
/*
* Since we're reading the bytes in reverse order from a little-endian
* word stream, an even address means we only use the lower half of
* the 16-bit word at that address
*/
if (address % 2 == 0) {
if (!ar9300_eeprom_read_byte(common, address--, buffer++))
goto error;

count--;
}

return true;
}
for (i = 0; i < count / 2; i++) {
if (!ar9300_eeprom_read_word(common, address, buffer))
goto error;

static bool ar9300_read_eeprom(struct ath_hw *ah,
int address, u8 *buffer, int many)
{
int it;
address -= 2;
buffer += 2;
}

if (count % 2)
if (!ar9300_eeprom_read_byte(common, address, buffer))
goto error;

for (it = 0; it < many; it++)
if (!ar9300_hw_read_eeprom(ah,
(address - it),
(buffer + it), 1))
return false;
return true;

error:
ath_print(common, ATH_DBG_EEPROM,
"unable to read eeprom region at offset %d\n", address);
return false;
}

static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference,
Expand Down Expand Up @@ -927,30 +917,13 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
*/
static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah)
{
u8 *mptr = NULL;
int mdata_size;
u8 *mptr = (u8 *) &ah->eeprom.ar9300_eep;

mptr = (u8 *) &ah->eeprom.ar9300_eep;
mdata_size = sizeof(struct ar9300_eeprom);
if (ar9300_eeprom_restore_internal(ah, mptr,
sizeof(struct ar9300_eeprom)) < 0)
return false;

if (mptr && mdata_size > 0) {
/* At this point, mptr points to the eeprom data structure
* in it's "default" state. If this is big endian, swap the
* data structures back to "little endian"
*/
/* First swap, default to Little Endian */
#ifdef __BIG_ENDIAN
ar9300_swap_eeprom((struct ar9300_eeprom *)mptr);
#endif
if (ar9300_eeprom_restore_internal(ah, mptr, mdata_size) >= 0)
return true;

/* Second Swap, back to Big Endian */
#ifdef __BIG_ENDIAN
ar9300_swap_eeprom((struct ar9300_eeprom *)mptr);
#endif
}
return false;
return true;
}

/* XXX: review hardware docs */
Expand Down Expand Up @@ -998,37 +971,42 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
{
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
__le32 val;

if (is2ghz)
return eep->modalHeader2G.antCtrlCommon;
val = eep->modalHeader2G.antCtrlCommon;
else
return eep->modalHeader5G.antCtrlCommon;
val = eep->modalHeader5G.antCtrlCommon;
return le32_to_cpu(val);
}

static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz)
{
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
__le32 val;

if (is2ghz)
return eep->modalHeader2G.antCtrlCommon2;
val = eep->modalHeader2G.antCtrlCommon2;
else
return eep->modalHeader5G.antCtrlCommon2;
val = eep->modalHeader5G.antCtrlCommon2;
return le32_to_cpu(val);
}

static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
int chain,
bool is2ghz)
{
struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
__le16 val = 0;

if (chain >= 0 && chain < AR9300_MAX_CHAINS) {
if (is2ghz)
return eep->modalHeader2G.antCtrlChain[chain];
val = eep->modalHeader2G.antCtrlChain[chain];
else
return eep->modalHeader5G.antCtrlChain[chain];
val = eep->modalHeader5G.antCtrlChain[chain];
}

return 0;
return le16_to_cpu(val);
}

static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
Expand Down
10 changes: 5 additions & 5 deletions drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ enum CompressAlgorithm {
};

struct ar9300_base_eep_hdr {
u16 regDmn[2];
__le16 regDmn[2];
/* 4 bits tx and 4 bits rx */
u8 txrxMask;
struct eepFlags opCapFlags;
Expand Down Expand Up @@ -199,16 +199,16 @@ struct ar9300_base_eep_hdr {
u8 rxBandSelectGpio;
u8 txrxgain;
/* SW controlled internal regulator fields */
u32 swreg;
__le32 swreg;
} __packed;

struct ar9300_modal_eep_header {
/* 4 idle, t1, t2, b (4 bits per setting) */
u32 antCtrlCommon;
__le32 antCtrlCommon;
/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
u32 antCtrlCommon2;
__le32 antCtrlCommon2;
/* 6 idle, t, r, rx1, rx12, b (2 bits each) */
u16 antCtrlChain[AR9300_MAX_CHAINS];
__le16 antCtrlChain[AR9300_MAX_CHAINS];
/* 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
u8 xatten1DB[AR9300_MAX_CHAINS];
/* 3 xatten1_margin for merlin (0xa20c/b20c 16:12 */
Expand Down

0 comments on commit ffdc4cb

Please sign in to comment.