129 lines
4 KiB
Diff
129 lines
4 KiB
Diff
|
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;
|