diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mvm.c b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mvm.c index bb872bec7c..e9a04e6073 100644 --- a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mvm.c +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mvm.c @@ -83,3 +83,91 @@ int rb_iwl_mvm_rate_to_mcs(int signal) if (signal > -80) return 3; return 1; } + +/* ------------------------------------------------------------------ */ +/* TLV type IDs — Linux 7.1 fw/file.h enum iwl_ucode_tlv_type */ +/* ------------------------------------------------------------------ */ +#define RB_IWL_UCODE_TLV_ENABLED_CAPABILITIES 30 +#define RB_IWL_UCODE_TLV_N_SCAN_CHANNELS 31 +#define RB_IWL_UCODE_TLV_FW_VERSION 36 + +int rb_iwl_mvm_parse_firmware(const uint8_t *data, size_t len, + struct rb_iwl_fw_metadata *out) +{ + const uint8_t *p, *end; + uint32_t magic; + + if (!data || !out || len < RB_IWL_TLV_HDR_SIZE) + return -1; + + memset(out, 0, sizeof(*out)); + + magic = (uint32_t)data[0] | ((uint32_t)data[1] << 8) | + ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24); + if (magic != RB_IWL_TLV_UCODE_MAGIC) + return -1; + + out->version = (uint32_t)data[4] | ((uint32_t)data[5] << 8) | + ((uint32_t)data[6] << 16) | ((uint32_t)data[7] << 24); + out->build = (uint32_t)data[8] | ((uint32_t)data[9] << 8) | + ((uint32_t)data[10] << 16) | ((uint32_t)data[11] << 24); + out->api = (uint8_t)((out->version >> 8) & 0xFFU); + + p = data + RB_IWL_TLV_HDR_SIZE; + end = data + len; + + while (p + 8 <= end) { + uint32_t tlv_type, tlv_len; + const uint8_t *tlv_data; + + tlv_type = (uint32_t)p[0] | ((uint32_t)p[1] << 8) | + ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); + tlv_len = (uint32_t)p[4] | ((uint32_t)p[5] << 8) | + ((uint32_t)p[6] << 16) | ((uint32_t)p[7] << 24); + p += 8; + + if (p + tlv_len > end) + break; + + tlv_data = p; + p += tlv_len; + + /* TLV entries are 4-byte aligned per Intel firmware spec */ + if (tlv_len & 3) + p += 4 - (tlv_len & 3); + + switch (tlv_type) { + case RB_IWL_UCODE_TLV_ENABLED_CAPABILITIES: + if (tlv_len >= 4) + out->capabilities = (uint32_t)tlv_data[0] | + ((uint32_t)tlv_data[1] << 8) | + ((uint32_t)tlv_data[2] << 16) | + ((uint32_t)tlv_data[3] << 24); + break; + + case RB_IWL_UCODE_TLV_N_SCAN_CHANNELS: + if (tlv_len >= 4) + out->n_scan_channels = (uint32_t)tlv_data[0] | + ((uint32_t)tlv_data[1] << 8) | + ((uint32_t)tlv_data[2] << 16) | + ((uint32_t)tlv_data[3] << 24); + break; + + case RB_IWL_UCODE_TLV_FW_VERSION: + if (tlv_len > 0) { + size_t copy = tlv_len; + if (copy >= RB_IWL_FW_VER_HUMAN_READABLE_SZ) + copy = RB_IWL_FW_VER_HUMAN_READABLE_SZ - 1; + memcpy(out->version_str, tlv_data, copy); + out->version_str[copy] = '\0'; + } + break; + + default: + break; + } + } + + out->parsed = 1; + return 0; +} diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mvm.h b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mvm.h index 3a9281144a..a9118638ca 100644 --- a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mvm.h +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_mvm.h @@ -165,4 +165,42 @@ void rb_iwl_mvm_extract_signal(const uint8_t *desc_data, */ int rb_iwl_mvm_rate_to_mcs(int signal); +/* ------------------------------------------------------------------ */ +/* Firmware TLV parser — Linux 7.1 fw/file.h. */ +/* ------------------------------------------------------------------ */ + +#define RB_IWL_TLV_UCODE_MAGIC 0x0A4F5749 /* "IWO\x0a" — Red Bear firmware */ +#define RB_IWL_TLV_HDR_SIZE 12 /* magic(4) + version(4) + build(4) */ +#define RB_IWL_FW_VER_HUMAN_READABLE_SZ 64 + +/* Linux 7.1 iwl_ucode_tlv — type/length/data format */ +struct rb_iwl_ucode_tlv { + uint32_t type; + uint32_t length; + uint8_t data[]; +}; + +/* Extracted firmware metadata */ +struct rb_iwl_fw_metadata { + uint32_t version; + uint32_t build; + uint8_t api; + char version_str[RB_IWL_FW_VER_HUMAN_READABLE_SZ]; + uint32_t capabilities; /* from IWL_UCODE_TLV_ENABLED_CAPABILITIES */ + uint32_t n_scan_channels; /* from IWL_UCODE_TLV_N_SCAN_CHANNELS */ + int parsed; /* 1 if TLV parsing succeeded */ +}; + +/* + * rb_iwl_mvm_parse_firmware — walk TLV sections in the firmware blob + * and extract metadata (capabilities, version string, scan channels). + * + * Cross-referenced with Linux 7.1 iwl_req_fw_callback() in iwl-drv.c + * and iwl_parse_tlv_firmware(). + * + * Returns: 0 on success, negative on error. + */ +int rb_iwl_mvm_parse_firmware(const uint8_t *data, size_t len, + struct rb_iwl_fw_metadata *out); + #endif /* RB_IWLWIFI_MVM_H */ diff --git a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_port.c b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_port.c index e4fcb8a9c7..10b81174af 100644 --- a/local/recipes/drivers/redbear-iwlwifi/source/src/linux_port.c +++ b/local/recipes/drivers/redbear-iwlwifi/source/src/linux_port.c @@ -31,10 +31,12 @@ // Known gaps vs Linux 7.1 iwlwifi (drivers/net/wireless/intel/iwlwifi/): // - Mini-MVM present (linux_mvm.c) but not a full port of iwl-mvm.c (~5200 lines). -// Provides RX descriptor parsing, signal extraction, notification dispatch. +// Provides RX descriptor parsing, signal extraction, notification dispatch, +// and firmware TLV metadata (capabilities, version string). // Missing: Minstrel rate adaptation, thermal management, WoWLAN, debug hooks. -// - No firmware TLV/NVM parser — only magic number check. -// See Linux 7.1 iwl-nvm-parse.c. +// - Firmware TLV parser present — extracts ENABLED_CAPABILITIES, N_SCAN_CHANNELS, +// and FW_VERSION from the Intel firmware blob. +// Missing: full NVM section parsing (MAC address, calibration, regulatory). // - No power management (PS mode, WoWLAN, thermal throttling). // - PCI device ID table: 37 entries. Linux 7.1 has ~500+ across all families. // - Scan uses active+dwell schedule but no UMAC scan engine integration. @@ -272,6 +274,7 @@ struct iwl_trans_pcie { struct ieee80211_bss_conf bss_conf; struct rb_iwl_fw_blob_info fw_info; struct rb_iwl_fw_blob_info pnvm_info; + struct rb_iwl_fw_metadata fw_meta; struct rb_iwl_key keys[4]; char fw_name_storage[RB_IWL_MAX_FW_NAME]; char pnvm_name_storage[RB_IWL_MAX_FW_NAME]; @@ -974,8 +977,17 @@ static int rb_iwlwifi_do_prepare(struct iwl_trans_pcie *trans, const char *ucode return rc; rc = rb_iwlwifi_parse_fw_blob(fw, &trans->fw_info); - if (!rc) + if (!rc) { rb_iwlwifi_update_fw_info(&trans->fw_info, fw); + if (rb_iwl_mvm_parse_firmware(fw->data, fw->size, &trans->fw_meta) == 0) { + pr_info("prepare: firmware %s v%d.%d (build %u), caps=0x%x\n", + trans->fw_meta.version_str[0] ? trans->fw_meta.version_str : "(unknown)", + (trans->fw_meta.version >> 16) & 0xFF, + (trans->fw_meta.version >> 8) & 0xFF, + trans->fw_meta.build, + trans->fw_meta.capabilities); + } + } release_firmware(fw); if (rc) return rc;