diff options
author | Sugnan Prabhu S <sugnan.prabhu.s@intel.com> | 2021-07-30 20:12:22 +0530 |
---|---|---|
committer | Tim Wawrzynczak <twawrzynczak@chromium.org> | 2021-09-02 22:53:26 +0000 |
commit | fcb4f2d77e4d0c09bf8e433d724ef0ea272df815 (patch) | |
tree | 012d0334a5d7918798dd7aad6139e4356b9faea9 /src/vendorcode/google | |
parent | 93ca873f209daef0e6a53b6f16e40be3ddb82ee1 (diff) |
wifi: Add support for new revisions of SAR table entries
Existing SAR infrastructure supports only revision 0 of the SAR tables.
This patch modifies it to extend support for intel wifi 6 and wifi 6e
configurations as per the connectivity document:
559910_Intel_Connectivity_Platforms_BIOS_Guidelines_Rev6_4.pdf
The SAR table and WGDS configuration block sizes were static in the
legacy SAR file format. Following is the format of the new binary file.
+------------------------------------------------------------+
| Field | Size | Description |
+------------------------------------------------------------+
| Marker | 4 bytes | "$SAR" |
+------------------------------------------------------------+
| Version | 1 byte | Current version = 1 |
+------------------------------------------------------------+
| SAR table | 2 bytes | Offset of SAR table from start of |
| offset | | the header |
+------------------------------------------------------------+
| WGDS | 2 bytes | Offset of WGDS table from start of |
| offset | | the header |
+------------------------------------------------------------+
| Data | n bytes | Data for the different tables |
+------------------------------------------------------------+
This change supports both the legacy and the new format of SAR file
BUG=b:193665559
TEST=Checked the SSDT entries for WRDS, EWRD and WGDS with different
binaries generated by setting different versions in the config.star
Change-Id: I08c3f321938eba04e8bcff4d87cb215422715bb2
Signed-off-by: Sugnan Prabhu S <sugnan.prabhu.s@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/56750
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Diffstat (limited to 'src/vendorcode/google')
-rw-r--r-- | src/vendorcode/google/chromeos/sar.c | 244 |
1 files changed, 203 insertions, 41 deletions
diff --git a/src/vendorcode/google/chromeos/sar.c b/src/vendorcode/google/chromeos/sar.c index a38ffe270b..d6cb021412 100644 --- a/src/vendorcode/google/chromeos/sar.c +++ b/src/vendorcode/google/chromeos/sar.c @@ -9,79 +9,241 @@ #include <string.h> #include <types.h> +#define LEGACY_BYTES_PER_GEO_OFFSET 6 +#define LEGACY_BYTES_PER_SAR_LIMIT 10 +#define LEGACY_NUM_SAR_LIMITS 4 +#define LEGACY_SAR_BIN_SIZE 81 +#define LEGACY_SAR_WGDS_BIN_SIZE 119 +#define LEGACY_SAR_NUM_WGDS_GROUPS 3 + +static uint8_t *wifi_hextostr(const char *sar_str, size_t str_len, size_t *sar_bin_len, + bool legacy_hex_format) +{ + uint8_t *sar_bin = NULL; + size_t bin_len; + + if (!legacy_hex_format) { + sar_bin = malloc(str_len); + if (!sar_bin) { + printk(BIOS_ERR, "ERROR: Failed to allocate space for SAR binary!\n"); + return NULL; + } + + memcpy(sar_bin, sar_str, str_len); + *sar_bin_len = str_len; + } else { + bin_len = ((str_len - 1) / 2); + sar_bin = malloc(bin_len); + if (!sar_bin) { + printk(BIOS_ERR, "ERROR: Failed to allocate space for SAR binary!\n"); + return NULL; + } + + if (hexstrtobin(sar_str, (uint8_t *)sar_bin, bin_len) != bin_len) { + printk(BIOS_ERR, "ERROR: sar_limits contains non-hex value!\n"); + free(sar_bin); + return NULL; + } + + *sar_bin_len = bin_len; + } + + return sar_bin; +} + +static int sar_table_size(const struct sar_profile *sar) +{ + if (sar == NULL) + return 0; + + return (sizeof(struct sar_profile) + ((1 + sar->dsar_set_count) * sar->chains_count * + sar->subbands_count)); +} + +static int wgds_table_size(const struct geo_profile *geo) +{ + if (geo == NULL) + return 0; + + return sizeof(struct geo_profile) + (geo->chains_count * geo->bands_count); +} + +static bool valid_legacy_length(size_t bin_len) +{ + if (bin_len == LEGACY_SAR_WGDS_BIN_SIZE) + return true; + + if (bin_len == LEGACY_SAR_BIN_SIZE && !CONFIG(GEO_SAR_ENABLE)) + return true; + + return false; +} + +static int sar_header_size(void) +{ + return (MAX_PROFILE_COUNT * sizeof(uint16_t)) + sizeof(struct sar_header); +} + +static int fill_wifi_sar_limits(union wifi_sar_limits *sar_limits, const uint8_t *sar_bin, + size_t sar_bin_size) +{ + struct sar_header *header; + size_t i = 0, expected_sar_bin_size; + size_t header_size = sar_header_size(); + + if (sar_bin_size < header_size) { + printk(BIOS_ERR, "ERROR: Invalid SAR format!\n"); + return -1; + } + + header = (struct sar_header *)sar_bin; + + if (header->version != SAR_FILE_REVISION) { + printk(BIOS_ERR, "ERROR: Invalid SAR file version: %d!\n", header->version); + return -1; + } + + for (i = 0; i < MAX_PROFILE_COUNT; i++) { + if (header->offsets[i] > sar_bin_size) { + printk(BIOS_ERR, "ERROR: Offset is outside the file size!\n"); + return -1; + } + + if (header->offsets[i]) + sar_limits->profile[i] = (void *) (sar_bin + header->offsets[i]); + } + + expected_sar_bin_size = header_size; + expected_sar_bin_size += sar_table_size(sar_limits->sar); + expected_sar_bin_size += wgds_table_size(sar_limits->wgds); + + if (sar_bin_size != expected_sar_bin_size) { + printk(BIOS_ERR, "ERROR: Invalid SAR size, expected: %ld, obtained: %ld\n", + expected_sar_bin_size, sar_bin_size); + return -1; + } + + return 0; +} + +static int fill_wifi_sar_limits_legacy(union wifi_sar_limits *sar_limits, + const uint8_t *sar_bin, size_t sar_bin_size) +{ + uint8_t *new_sar_bin; + size_t size = sar_bin_size + sizeof(struct sar_profile); + + if (CONFIG(GEO_SAR_ENABLE)) + size += sizeof(struct geo_profile); + + new_sar_bin = malloc(size); + if (!new_sar_bin) { + printk(BIOS_ERR, "ERROR: Failed to allocate space for SAR binary!\n"); + return -1; + } + + sar_limits->sar = (struct sar_profile *) new_sar_bin; + sar_limits->sar->revision = 0; + sar_limits->sar->dsar_set_count = CONFIG_DSAR_SET_NUM; + sar_limits->sar->chains_count = SAR_REV0_CHAINS_COUNT; + sar_limits->sar->subbands_count = SAR_REV0_SUBBANDS_COUNT; + memcpy(&sar_limits->sar->sar_table, sar_bin, + LEGACY_BYTES_PER_SAR_LIMIT * LEGACY_NUM_SAR_LIMITS); + + if (!CONFIG(GEO_SAR_ENABLE)) + return 0; + + sar_limits->wgds = (struct geo_profile *)(new_sar_bin + + sar_table_size(sar_limits->sar)); + sar_limits->wgds->revision = 0; + sar_limits->wgds->chains_count = LEGACY_SAR_NUM_WGDS_GROUPS; + sar_limits->wgds->bands_count = LEGACY_BYTES_PER_GEO_OFFSET; + memcpy(&sar_limits->wgds->wgds_table, + sar_bin + LEGACY_BYTES_PER_SAR_LIMIT * LEGACY_NUM_SAR_LIMITS + REVISION_SIZE, + LEGACY_BYTES_PER_GEO_OFFSET * LEGACY_SAR_NUM_WGDS_GROUPS); + + return 0; +} + /* * Retrieve WiFi SAR limits data from CBFS and decode it - * WiFi SAR data is expected in the format: [<WRDD><EWRD>][WGDS] + * Legacy WiFi SAR data is expected in the format: [<WRDD><EWRD>][WGDS] * * [<WRDD><EWRD>] = NUM_SAR_LIMITS * BYTES_PER_SAR_LIMIT bytes. - * [WGDS]=[WGDS_VERSION][WGDS_DATA] + * [WGDS]=[WGDS_REVISION][WGDS_DATA] + * + * Current SAR configuration data is expected in the format: + * "$SAR" Marker + * Version + * Offset count + * Offsets + * [SAR_REVISION,DSAR_SET_COUNT,CHAINS_COUNT,SUBBANDS_COUNT <WRDD>[EWRD]] + * [WGDS_REVISION,CHAINS_COUNT,SUBBANDS_COUNT<WGDS_DATA>] + * + * The configuration data will always have the revision added in the file for each of the + * block, based on the revision number and validity, size of the specific block will be + * calculated. * - * For [WGDS_VERSION] 0x00, * [WGDS_DATA] = [GROUP#0][GROUP#1][GROUP#2] * * [GROUP#<i>] = - * [2.4Ghz – Max Allowed][2.4Ghz – Chain A Offset] - * [2.4Ghz – Chain B Offset][5Ghz – Max Allowed] - * [5Ghz – Chain A Offset][5Ghz – Chain B Offset] + * Supported by Revision 0, 1 and 2 + * [2.4Ghz - Max Allowed][2.4Ghz - Chain A Offset][2.4Ghz - Chain B Offset] + * [5Ghz - Max Allowed][5Ghz - Chain A Offset][5Ghz - Chain B Offset] + * Supported by Revision 1 and 2 + * [6Ghz - Max Allowed][6Ghz - Chain A Offset][6Ghz - Chain B Offset] * * [GROUP#0] is for FCC * [GROUP#1] is for Europe/Japan * [GROUP#2] is for ROW -*/ -int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits) + */ +int get_wifi_sar_limits(union wifi_sar_limits *sar_limits) { const char *filename; - size_t sar_str_len, sar_bin_len; + size_t sar_bin_len, sar_str_len; + uint8_t *sar_bin; char *sar_str; int ret = -1; + bool legacy_hex_format = false; filename = get_wifi_sar_cbfs_filename(); if (filename == NULL) { - printk(BIOS_DEBUG, "Filename missing for CBFS SAR file!\n"); + printk(BIOS_ERR, "ERROR: Filename missing for CBFS SAR file!\n"); return ret; } - /* - * If GEO_SAR_ENABLE is not selected, SAR file does not contain - * delta table settings. - */ - if (CONFIG(GEO_SAR_ENABLE)) - sar_bin_len = sizeof(struct wifi_sar_limits); - else - sar_bin_len = sizeof(struct wifi_sar_limits) - - sizeof(struct wifi_sar_delta_table); - - /* - * Each hex digit is represented as a character in CBFS SAR file. Thus, - * the SAR file is double the size of its binary buffer equivalent. - * Hence, the buffer size allocated for SAR file is: - * `2 * sar_bin_len + 1` - * 1 additional byte is allocated to store the terminating '\0'. - */ - sar_str_len = 2 * sar_bin_len + 1; - sar_str = malloc(sar_str_len); - + sar_str = cbfs_map(filename, &sar_str_len); if (!sar_str) { - printk(BIOS_ERR, "Failed to allocate space for SAR string!\n"); + printk(BIOS_ERR, "ERROR: Failed to get the %s file size!\n", filename); return ret; } - printk(BIOS_DEBUG, "Checking CBFS for default SAR values\n"); + if (strncmp(sar_str, SAR_STR_PREFIX, SAR_STR_PREFIX_SIZE) == 0) { + legacy_hex_format = false; + } else if (valid_legacy_length(sar_str_len)) { + legacy_hex_format = true; + } else { + printk(BIOS_ERR, "ERROR: Invalid SAR format!\n"); + goto error; + } - if (cbfs_load(filename, sar_str, sar_str_len) != sar_str_len) { - printk(BIOS_ERR, "%s has bad len in CBFS\n", filename); - goto done; + sar_bin = wifi_hextostr(sar_str, sar_str_len, &sar_bin_len, legacy_hex_format); + if (sar_bin == NULL) { + printk(BIOS_ERR, "ERROR: Failed to parse SAR file %s\n", filename); + goto error; } memset(sar_limits, 0, sizeof(*sar_limits)); - if (hexstrtobin(sar_str, (uint8_t *)sar_limits, sar_bin_len) != sar_bin_len) { - printk(BIOS_ERR, "Error: wifi_sar contains non-hex value!\n"); - goto done; + if (legacy_hex_format) { + ret = fill_wifi_sar_limits_legacy(sar_limits, sar_bin, sar_bin_len); + free(sar_bin); + } else { + ret = fill_wifi_sar_limits(sar_limits, sar_bin, sar_bin_len); + if (ret < 0) + free(sar_bin); } - ret = 0; -done: - free(sar_str); +error: + cbfs_unmap(sar_str); return ret; } |