123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- From 1f796f9265c10384a274ac330f671ef4ac6d56e5 Mon Sep 17 00:00:00 2001
- From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
- Date: Mon, 3 Oct 2016 00:29:12 +0200
- Subject: [v2 PATCH 6/7] 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#L351
- Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
- ---
- drivers/net/wireless/ath/ath9k/eeprom.c | 57 ++++++++++++++++++++++++---------
- 1 file changed, 41 insertions(+), 16 deletions(-)
- --- a/drivers/net/wireless/ath/ath9k/eeprom.c
- +++ b/drivers/net/wireless/ath/ath9k/eeprom.c
- @@ -155,11 +155,19 @@ bool ath9k_hw_nvram_read(struct ath_hw *
- 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)
- {
- u16 magic;
- u16 *eepdata;
- + u8 eepmisc;
- int i;
- + bool needs_byteswap = false;
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
- @@ -167,36 +175,53 @@ int ath9k_hw_nvram_swap_data(struct ath_
- return -EIO;
- }
-
- - *swap_needed = false;
- if (swab16(magic) == AR5416_EEPROM_MAGIC) {
- + needs_byteswap = true;
- + ath_dbg(common, EEPROM,
- + "EEPROM needs byte-swapping to correct endianness.\n");
- + } else if (magic != AR5416_EEPROM_MAGIC) {
- + if (ath9k_hw_use_flash(ah)) {
- + ath_dbg(common, EEPROM,
- + "Ignoring invalid EEPROM magic (0x%04x).\n",
- + magic);
- + } else {
- + ath_err(common,
- + "Invalid EEPROM magic (0x%04x).\n", magic);
- + 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 {
- - *swap_needed = true;
- - }
- - } else if (magic != AR5416_EEPROM_MAGIC) {
- - if (ath9k_hw_use_flash(ah))
- - return 0;
- + eepdata = (u16 *)(&ah->eeprom);
-
- - ath_err(common,
- - "Invalid EEPROM Magic (0x%04x).\n", magic);
- - return -EINVAL;
- + for (i = 0; i < size; i++)
- + eepdata[i] = swab16(eepdata[i]);
- + }
- }
-
- - eepdata = (u16 *)(&ah->eeprom);
- -
- - if (*swap_needed) {
- - ath_dbg(common, EEPROM,
- - "EEPROM Endianness is not native.. Changing.\n");
- + *swap_needed = false;
-
- - for (i = 0; i < size; i++)
- - eepdata[i] = swab16(eepdata[i]);
- + 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;
- }
-
- +#undef EXPECTED_EEPMISC_VAL
- +
- bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
- {
- u32 i, sum = 0;
|