From c26858bb0297c537bb9b6581c8416630e5541436 Mon Sep 17 00:00:00 2001 From: Sergey Ryazanov Date: Mon, 19 Sep 2022 19:24:14 +0300 Subject: [PATCH] eep9300: RAW EEPROM/OTP reading support Add support for RAW EEPROM and OTP contents loading if it is requested by the caller. It assumes complete contents ignoring, including I/O byteswapping check bypassing and decompression avoidance. A WNIC can contain two data sources: EEPROM and OTP, with EEPROM being tried first in the common case. So the EEPROM RAW reading code has been augmented with empty/missed EEPROM checks to skip the EEPROM and automatically continue with OTP memory as the data souce. The user can still explicitly specify which memory should be read using the appropriate utiltiy command: saveraweep or saverawotp. The change was runtime tested with QCA9565 based card. The card contains data only in the OTP memory, but the EEPROM reading should be reliable as well. Refs: gh-4 --- eep_9300.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/eep_9300.c b/eep_9300.c index 9367816..8184dca 100644 --- a/eep_9300.c +++ b/eep_9300.c @@ -272,6 +272,40 @@ static bool eep_9300_load_blob(struct atheepmgr *aem) return true; } +/** + * Special handler for RAW EEPROM data loading + */ +static bool eep_9300_load_raw_eeprom(struct atheepmgr *aem) +{ + const int eepsz = 0x1000; /* Max EEPROM read length in words */ + int i; + + if (aem->verbose) + printf("RAW EEPROM read [0x0000...0x%04x] words\n", eepsz - 1); + if (ar9300_eep2buf(aem, eepsz) != 0) + return false; + + /* Check for unsoldered EEPROM */ + for (i = 0; i < aem->eep_len; ++i) + if (aem->eep_buf[i] != 0x0000) + break; + if (i == aem->eep_len) { + fprintf(stderr, "EEPROM contains only 0x0000 words and looks unsoldered, ignoring.\n"); + return false; + } + + /* Check for empty EEPROM */ + for (i = 0; i < aem->eep_len; ++i) + if (aem->eep_buf[i] != 0xffff) + break; + if (i == aem->eep_len) { + fprintf(stderr, "EEPROM contains only 0xffff words and looks empty, ignoring.\n"); + return false; + } + + return true; +} + /* * Read the configuration data from the eeprom uncompress it if necessary. */ @@ -284,6 +318,9 @@ static bool eep_9300_load_eeprom(struct atheepmgr *aem, bool raw) emp->buf_is_be = 0; /* EEPROM is always in Little-endians */ aem->eep_len = 0; /* Reset internal buffer contents */ + if (raw) /* RAW reading is a bit special case */ + return eep_9300_load_raw_eeprom(aem); + /* Check byteswaping requirements */ if (!EEP_READ(AR5416_EEPROM_MAGIC_OFFSET, &magic)) { fprintf(stderr, "EEPROM magic read failed\n"); @@ -331,6 +368,25 @@ static bool eep_9300_load_eeprom(struct atheepmgr *aem, bool raw) return true; } +/** + * Special handler for RAW OTP data loading + */ +static bool eep_9300_load_raw_otp(struct atheepmgr *aem) +{ + const int otpsz = 0x400; /* Max OTP read length in bytes */ + + if (aem->verbose) + printf("RAW OTP read [0x0000...0x%04x] bytes\n", otpsz - 1); + if (ar9300_otp2buf(aem, otpsz) != 0) + return false; + + /* NB: OTP loading is called in last order, so do not check for + * OTP memory emptiness and return the buffer as-is. + */ + + return true; +} + /* * Read the configuration data from the OTP memory uncompress it if necessary. */ @@ -342,6 +398,9 @@ static bool eep_9300_load_otp(struct atheepmgr *aem, bool raw) emp->buf_is_be = aem->host_is_be; /* OTP utilize native-endians */ aem->eep_len = 0; /* Reset internal buffer contents */ + if (raw) /* RAW reading is a bit special case */ + return eep_9300_load_raw_otp(aem); + cptr = AR9300_BASE_ADDR; if (aem->verbose) printf("Trying OTP access at Address 0x%04x\n", cptr); @@ -822,6 +881,7 @@ static bool eep_9300_update_eeprom(struct atheepmgr *aem, int param, const struct eepmap eepmap_9300 = { .name = "9300", .desc = "EEPROM map for modern .11n chips (AR93xx/AR94xx/AR95xx/etc.)", + .features = EEPMAP_F_RAW_EEP | EEPMAP_F_RAW_OTP, .chip_regs = { .srev = 0x4020, },