diff --git a/src/jaguar3/HalJaguar3.cpp b/src/jaguar3/HalJaguar3.cpp index d299c2e..0e76fb1 100644 --- a/src/jaguar3/HalJaguar3.cpp +++ b/src/jaguar3/HalJaguar3.cpp @@ -601,12 +601,6 @@ void HalJaguar3::config_pa_bias_8822e() { pg2a & 0xf, pg2b & 0xf, pg5a & 0xf, pg5b & 0xf); } -/* Decode the packed (extended-header) EFUSE into a logical map, up to (and - * including the block holding) logical offset `upto`. Shared by read_efuse_rfe_type - * and read_efuse_txpwr_base_8822e. `map` must be zero-init'd by the caller (this - * fills 0xFF for gaps). Standard Realtek section format: header (or header+ext) - * gives a logical block offset + 4-bit word-enable; each enabled 2-byte word - * follows. */ bool HalJaguar3::probe_efuse_map(uint8_t *map, size_t len) { /* 8822E OTP reads are not reliable after TX/coex bring-up (by design — see * cache_efuse_8822e); probing there would flag healthy units. 8822C only. */ @@ -614,11 +608,31 @@ bool HalJaguar3::probe_efuse_map(uint8_t *map, size_t len) { return false; if (map == nullptr || len != sizeof(_efuse_cache)) return false; - read_efuse_logical_map(map, len, 0xFA); + read_efuse_logical_map(map, len); return true; } -void HalJaguar3::read_efuse_logical_map(uint8_t *map, size_t len, uint16_t upto) { +/* Decode the packed (extended-header) EFUSE into a logical map. Shared by + * read_efuse_rfe_type and read_efuse_txpwr_base_8822e. `map` must be zero-init'd + * by the caller (this fills 0xFF for gaps). Standard Realtek section format: + * header (or header+ext) gives a logical block offset + 4-bit word-enable; each + * enabled 2-byte word follows. + * + * The walk decodes the whole programmed area. Sections are not in ascending base + * order, so it must not stop at any requested offset — measured on an RTL8822CU, + * the third section on the chip jumps to base 0x100: + * + * phys 0x00 hdr=0x00 -> base 0x000 + * phys 0x09 hdr=0x10 -> base 0x008 + * phys 0x12 hdr=0x0F ext=48 -> base 0x100 + * phys 0x2C hdr=0x4F ext=5D -> base 0x150 + * + * A walk bounded by the byte the caller asked for ends after those first three + * sections for anything below 0x100 — including EEPROM_RFE_OPTION at logical + * 0xCA — and returns a map that is 0xFF almost everywhere. On that adapter it + * made read_efuse_rfe_type() return 0 while the kernel driver reads 0x03 from + * the same chip, i.e. BB/RFE config chosen from an unprogrammed default. */ +void HalJaguar3::read_efuse_logical_map(uint8_t *map, size_t len) { constexpr uint16_t kPhysMax = 1024; /* EFUSE_REAL_CONTENT_LEN_8822C */ for (size_t i = 0; i < len; ++i) map[i] = 0xFF; @@ -631,6 +645,15 @@ void HalJaguar3::read_efuse_logical_map(uint8_t *map, size_t len, uint16_t upto) if (eu) efuse_pwr_cut_8822e(true); auto rd = [this, eu](uint16_t a) -> uint8_t { + /* A section straddling the end of the physical area would otherwise run + * `phys` past kPhysMax: the loop head checks it once per section, but a + * header + ext + four data words advance it up to ten more bytes. That + * matters because efuse_OneByteRead masks the address to 10 bits, so a + * read at 1024 aliases to 0 and would silently decode the START of the + * EFUSE into whatever logical base the truncated section named. 0xFF is + * what both walks already treat as end-of-map / skip. */ + if (a >= kPhysMax) + return 0xFF; if (eu) return efuse_phys_read_8822e(a); uint8_t d = 0xFF; @@ -704,15 +727,13 @@ void HalJaguar3::read_efuse_logical_map(uint8_t *map, size_t len, uint16_t upto) map[idx] = d; } } - if (base > upto + 8) - break; /* past the byte we need */ } } void HalJaguar3::cache_efuse_8822e() { if (_variant != ChipVariant::C8822E) return; - read_efuse_logical_map(_efuse_cache, sizeof(_efuse_cache), 0xFA); + read_efuse_logical_map(_efuse_cache, sizeof(_efuse_cache)); _efuse_cache_valid = true; _logger->info("Jaguar3(8822e): efuse decoded (0x22={:x} 0x4c={:x} 0xca={:x})", _efuse_cache[0x22], _efuse_cache[0x4c], _efuse_cache[0xca]); @@ -725,7 +746,7 @@ uint8_t HalJaguar3::read_efuse_rfe_type() { rfe = _efuse_cache[kRfeLogicalOff]; } else { uint8_t map[0x100 + 0x40]; /* enough to cover block holding 0xCA */ - read_efuse_logical_map(map, sizeof(map), kRfeLogicalOff); + read_efuse_logical_map(map, sizeof(map)); rfe = map[kRfeLogicalOff]; } return (rfe == 0xFF) ? 0 : rfe; @@ -762,7 +783,7 @@ void HalJaguar3::read_efuse_txpwr_base_8822e(uint8_t channel, uint8_t &base_a, if (_efuse_cache_valid) { map = _efuse_cache; /* decoded early where OTP access is reliable */ } else { - read_efuse_logical_map(local, sizeof(local), k5gB + 14); + read_efuse_logical_map(local, sizeof(local)); map = local; } int g = chnl_group_5g(channel); diff --git a/src/jaguar3/HalJaguar3.h b/src/jaguar3/HalJaguar3.h index 840624e..d1fa7a4 100644 --- a/src/jaguar3/HalJaguar3.h +++ b/src/jaguar3/HalJaguar3.h @@ -194,9 +194,12 @@ class HalJaguar3 { private: - /* Decode the packed extended-header EFUSE into a logical map up to (the block - * holding) offset `upto`. Backs read_efuse_rfe_type + read_efuse_txpwr_base. */ - void read_efuse_logical_map(uint8_t *map, size_t len, uint16_t upto); + /* Decode the packed extended-header EFUSE into a logical map. Backs + * read_efuse_rfe_type + read_efuse_txpwr_base. Walks the whole programmed + * area — sections are NOT ordered by logical base, so stopping once a + * requested offset is passed would drop later sections that backfill lower + * offsets (see the .cpp for the measured case). */ + void read_efuse_logical_map(uint8_t *map, size_t len); /* One-shot decode of the logical EFUSE into _efuse_cache during rtw_hal_init, * where OTP access is reliable. RFE + per-channel TX-power base are then served