Commit 68fbe792 authored by Martin Blumenstingl's avatar Martin Blumenstingl Committed by Kalle Valo

ath9k: Make the EEPROM swapping check use the eepmisc register

There are two ways of swapping the EEPROM data in the ath9k driver:
1) swab16 based on the first two EEPROM "magic" bytes (same for all
   EEPROM formats)
2) field and EEPROM format specific swab16/swab32 (different for
   eeprom_def, eeprom_4k and eeprom_9287)

The result of the first check was used to also enable the second swap.
This behavior seems incorrect, since the data may only be byte-swapped
(afterwards the data could be in the correct endianness).
Thus we introduce a separate check based on the "eepmisc" register
(which is part of the EEPROM data). When bit 0 is set, then the EEPROM
format specific values are in "big endian". This is also done by the
FreeBSD kernel, see [0] for example.

This allows us to parse EEPROMs with the "correct" magic bytes but
swapped EEPROM format specific values. These EEPROMs (mostly found in
lantiq and broadcom based big endian MIPS based devices) only worked
due to platform specific "hacks" which swapped the EEPROM so the
magic was inverted, which also enabled the format specific swapping.
With this patch the old behavior is still supported, but neither
recommended nor needed anymore.

[0]
https://github.com/freebsd/freebsd/blob/50719b56d9ce8d7d4beb53b16e9edb2e9a4a7a18/sys/dev/ath/ath_hal/ah_eeprom_9287.c#L351Signed-off-by: default avatarMartin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 9bff7428
...@@ -155,11 +155,19 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) ...@@ -155,11 +155,19 @@ bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
return ret; return ret;
} }
#ifdef __BIG_ENDIAN
#define EXPECTED_EEPMISC_ENDIAN AR5416_EEPMISC_BIG_ENDIAN
#else
#define EXPECTED_EEPMISC_ENDIAN 0
#endif
int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size) int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
{ {
u16 magic; u16 magic;
u16 *eepdata; u16 *eepdata;
u8 eepmisc;
int i; int i;
bool needs_byteswap = false;
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
...@@ -167,36 +175,53 @@ int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size) ...@@ -167,36 +175,53 @@ int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
return -EIO; return -EIO;
} }
*swap_needed = false;
if (swab16(magic) == AR5416_EEPROM_MAGIC) { if (swab16(magic) == AR5416_EEPROM_MAGIC) {
if (ah->ah_flags & AH_NO_EEP_SWAP) { needs_byteswap = true;
ath_info(common, ath_dbg(common, EEPROM,
"Ignoring endianness difference in EEPROM magic bytes.\n"); "EEPROM needs byte-swapping to correct endianness.\n");
} else {
*swap_needed = true;
}
} else if (magic != AR5416_EEPROM_MAGIC) { } else if (magic != AR5416_EEPROM_MAGIC) {
if (ath9k_hw_use_flash(ah)) if (ath9k_hw_use_flash(ah)) {
return 0; ath_dbg(common, EEPROM,
"Ignoring invalid EEPROM magic (0x%04x).\n",
magic);
} else {
ath_err(common, ath_err(common,
"Invalid EEPROM Magic (0x%04x).\n", magic); "Invalid EEPROM magic (0x%04x).\n", magic);
return -EINVAL; return -EINVAL;
} }
}
if (needs_byteswap) {
if (ah->ah_flags & AH_NO_EEP_SWAP) {
ath_info(common,
"Ignoring endianness difference in EEPROM magic bytes.\n");
} else {
eepdata = (u16 *)(&ah->eeprom); eepdata = (u16 *)(&ah->eeprom);
if (*swap_needed) {
ath_dbg(common, EEPROM,
"EEPROM Endianness is not native.. Changing.\n");
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
eepdata[i] = swab16(eepdata[i]); eepdata[i] = swab16(eepdata[i]);
} }
}
*swap_needed = false;
eepmisc = ah->eep_ops->get_eepmisc(ah);
if ((eepmisc & AR5416_EEPMISC_BIG_ENDIAN) != EXPECTED_EEPMISC_ENDIAN) {
if (ah->ah_flags & AH_NO_EEP_SWAP) {
ath_info(common,
"Ignoring endianness difference in eepmisc register.\n");
} else {
*swap_needed = true;
ath_dbg(common, EEPROM,
"EEPROM needs swapping according to the eepmisc register.\n");
}
}
return 0; return 0;
} }
#undef EXPECTED_EEPMISC_VAL
bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size) bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
{ {
u32 i, sum = 0; u32 i, sum = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment