drivers/wifi: Remove unnecessary data structure copy
[coreboot2.git] / src / vendorcode / google / chromeos / sar.c
blob50c59d5ed032213a94aff8036287cbb330d80237
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <cbfs.h>
4 #include <console/console.h>
5 #include <drivers/vpd/vpd.h>
6 #include <fw_config.h>
7 #include <lib.h>
8 #include <sar.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <types.h>
14 #define LEGACY_BYTES_PER_GEO_OFFSET 6
15 #define LEGACY_BYTES_PER_SAR_LIMIT 10
16 #define LEGACY_NUM_SAR_LIMITS 4
17 #define LEGACY_SAR_BIN_SIZE 81
18 #define LEGACY_SAR_WGDS_BIN_SIZE 119
19 #define LEGACY_SAR_NUM_WGDS_GROUPS 3
21 static uint8_t *wifi_hextostr(const char *sar_str, size_t str_len, size_t *sar_bin_len,
22 bool legacy_hex_format)
24 uint8_t *sar_bin = NULL;
25 size_t bin_len;
27 if (!legacy_hex_format) {
28 sar_bin = malloc(str_len);
29 if (!sar_bin) {
30 printk(BIOS_ERR, "Failed to allocate space for SAR binary!\n");
31 return NULL;
34 memcpy(sar_bin, sar_str, str_len);
35 *sar_bin_len = str_len;
36 } else {
37 bin_len = ((str_len - 1) / 2);
38 sar_bin = malloc(bin_len);
39 if (!sar_bin) {
40 printk(BIOS_ERR, "Failed to allocate space for SAR binary!\n");
41 return NULL;
44 if (hexstrtobin(sar_str, (uint8_t *)sar_bin, bin_len) != bin_len) {
45 printk(BIOS_ERR, "sar_limits contains non-hex value!\n");
46 free(sar_bin);
47 return NULL;
50 *sar_bin_len = bin_len;
53 return sar_bin;
56 static int sar_table_size(const struct sar_profile *sar)
58 if (sar == NULL)
59 return 0;
61 return (sizeof(struct sar_profile) + ((1 + sar->dsar_set_count) * sar->chains_count *
62 sar->subbands_count));
65 static int wgds_table_size(const struct geo_profile *geo)
67 if (geo == NULL)
68 return 0;
70 return sizeof(struct geo_profile) + (geo->chains_count * geo->bands_count);
73 static int gain_table_size(const struct gain_profile *gain)
75 if (gain == NULL)
76 return 0;
78 return sizeof(struct gain_profile) + (gain->chains_count * gain->bands_count);
81 static int sar_avg_table_size(const struct avg_profile *sar_avg)
83 if (sar_avg == NULL)
84 return 0;
86 return sizeof(struct avg_profile);
89 static int dsm_table_size(const struct dsm_profile *dsm)
91 if (dsm == NULL)
92 return 0;
94 return sizeof(struct dsm_profile);
97 static int bsar_table_size(const struct bsar_profile *bsar)
99 if (bsar == NULL)
100 return 0;
102 return sizeof(struct bsar_profile);
105 static int wbem_table_size(const struct wbem_profile *wbem)
107 if (wbem == NULL)
108 return 0;
110 return sizeof(struct wbem_profile);
113 static bool valid_legacy_length(size_t bin_len)
115 if (bin_len == LEGACY_SAR_WGDS_BIN_SIZE)
116 return true;
118 if (bin_len == LEGACY_SAR_BIN_SIZE && !CONFIG(GEO_SAR_ENABLE))
119 return true;
121 return false;
124 static int sar_header_size(void)
126 return (MAX_PROFILE_COUNT * sizeof(uint16_t)) + sizeof(struct sar_header);
129 static int fill_wifi_sar_limits(union wifi_sar_limits *sar_limits, const uint8_t *sar_bin,
130 size_t sar_bin_size)
132 struct sar_header *header;
133 size_t i = 0, expected_sar_bin_size;
134 size_t header_size = sar_header_size();
136 if (sar_bin_size < header_size) {
137 printk(BIOS_ERR, "Invalid SAR format!\n");
138 return -1;
141 header = (struct sar_header *)sar_bin;
143 if (header->version != SAR_FILE_REVISION) {
144 printk(BIOS_ERR, "Invalid SAR file version: %d!\n", header->version);
145 return -1;
148 for (i = 0; i < MAX_PROFILE_COUNT; i++) {
149 if (header->offsets[i] > sar_bin_size) {
150 printk(BIOS_ERR, "Offset is outside the file size!\n");
151 return -1;
154 if (header->offsets[i])
155 sar_limits->profile[i] = (void *) (sar_bin + header->offsets[i]);
158 expected_sar_bin_size = header_size;
159 expected_sar_bin_size += sar_table_size(sar_limits->sar);
160 expected_sar_bin_size += wgds_table_size(sar_limits->wgds);
161 expected_sar_bin_size += gain_table_size(sar_limits->ppag);
162 expected_sar_bin_size += sar_avg_table_size(sar_limits->wtas);
163 expected_sar_bin_size += dsm_table_size(sar_limits->dsm);
164 expected_sar_bin_size += bsar_table_size(sar_limits->bsar);
165 expected_sar_bin_size += wbem_table_size(sar_limits->wbem);
167 if (sar_bin_size != expected_sar_bin_size) {
168 printk(BIOS_ERR, "Invalid SAR size, expected: %zu, obtained: %zu\n",
169 expected_sar_bin_size, sar_bin_size);
170 return -1;
173 return 0;
176 static int fill_wifi_sar_limits_legacy(union wifi_sar_limits *sar_limits,
177 const uint8_t *sar_bin, size_t sar_bin_size)
179 uint8_t *new_sar_bin;
180 size_t size = sar_bin_size + sizeof(struct sar_profile);
182 if (CONFIG(GEO_SAR_ENABLE))
183 size += sizeof(struct geo_profile);
185 new_sar_bin = malloc(size);
186 if (!new_sar_bin) {
187 printk(BIOS_ERR, "Failed to allocate space for SAR binary!\n");
188 return -1;
191 sar_limits->sar = (struct sar_profile *) new_sar_bin;
192 sar_limits->sar->revision = 0;
193 sar_limits->sar->dsar_set_count = CONFIG_DSAR_SET_NUM;
194 sar_limits->sar->chains_count = SAR_REV0_CHAINS_COUNT;
195 sar_limits->sar->subbands_count = SAR_REV0_SUBBANDS_COUNT;
196 memcpy(&sar_limits->sar->sar_table, sar_bin,
197 LEGACY_BYTES_PER_SAR_LIMIT * LEGACY_NUM_SAR_LIMITS);
199 if (!CONFIG(GEO_SAR_ENABLE))
200 return 0;
202 sar_limits->wgds = (struct geo_profile *)(new_sar_bin +
203 sar_table_size(sar_limits->sar));
204 sar_limits->wgds->revision = 0;
205 sar_limits->wgds->chains_count = LEGACY_SAR_NUM_WGDS_GROUPS;
206 sar_limits->wgds->bands_count = LEGACY_BYTES_PER_GEO_OFFSET;
207 memcpy(&sar_limits->wgds->wgds_table,
208 sar_bin + LEGACY_BYTES_PER_SAR_LIMIT * LEGACY_NUM_SAR_LIMITS + REVISION_SIZE,
209 LEGACY_BYTES_PER_GEO_OFFSET * LEGACY_SAR_NUM_WGDS_GROUPS);
211 return 0;
215 * Retrieve WiFi SAR limits data from CBFS and decode it
216 * Legacy WiFi SAR data is expected in the format: [<WRDD><EWRD>][WGDS]
218 * [<WRDD><EWRD>] = NUM_SAR_LIMITS * BYTES_PER_SAR_LIMIT bytes.
219 * [WGDS]=[WGDS_REVISION][WGDS_DATA]
221 * Current SAR configuration data is expected in the format:
222 * "$SAR" Marker
223 * Version
224 * Offset count
225 * Offsets
226 * [SAR_REVISION,DSAR_SET_COUNT,CHAINS_COUNT,SUBBANDS_COUNT <WRDD>[EWRD]]
227 * [WGDS_REVISION,CHAINS_COUNT,SUBBANDS_COUNT<WGDS_DATA>]
228 * [PPAG_REVISION,MODE,CHAINS_COUNT,SUBBANDS_COUNT<PPAG_DATA>]
229 * [WTAS_REVISION, WTAS_DATA]
230 * [DSM_RETURN_VALUES]
231 * [BSAR_REVISION,IPML,LB,BR,EDR2,EDR3,LE,LE2,LE_LR]
232 * [WBEM_REVISION, WBEM_DATA]
234 * The configuration data will always have the revision added in the file for each of the
235 * block, based on the revision number and validity, size of the specific block will be
236 * calculated.
238 * [WGDS_DATA] = [GROUP#0][GROUP#1][GROUP#2]
240 * [GROUP#<i>] =
241 * Supported by Revision 0, 1 and 2
242 * [2.4Ghz - Max Allowed][2.4Ghz - Chain A Offset][2.4Ghz - Chain B Offset]
243 * [5Ghz - Max Allowed][5Ghz - Chain A Offset][5Ghz - Chain B Offset]
244 * Supported by Revision 1 and 2
245 * [6Ghz - Max Allowed][6Ghz - Chain A Offset][6Ghz - Chain B Offset]
247 * [GROUP#0] is for FCC
248 * [GROUP#1] is for Europe/Japan
249 * [GROUP#2] is for ROW
251 * [PPAG_DATA] = [ANT_gain Table Chain A] [ANT_gain Table Chain A]
253 * [ANT_gain Table] =
254 * Supported by Revision 0, 1 and 2
255 * [Antenna gain used for 2400MHz frequency]
256 * [Antenna gain used for 5150-5350MHz frequency]
257 * [Antenna gain used for 5350-5470MHz frequency]
258 * [Antenna gain used for 5470-5725MHz frequency]
259 * [Antenna gain used for 5725-5945MHz frequency]
260 * Supported by Revision 1 and 2
261 * [Antenna gain used for 5945-6165MHz frequency]
262 * [Antenna gain used for 6165-6405MHz frequency]
263 * [Antenna gain used for 6405-6525MHz frequency]
264 * [Antenna gain used for 6525-6705MHz frequency]
265 * [Antenna gain used for 6705-6865MHz frequency]
266 * [Antenna gain used for 6865-7105MHz frequency]
268 * [WTAS_DATA] =
269 * [Enable/disable the TAS feature]
270 * [Number of blocked countries that are not approved by the OEM to support this feature]
271 * [deny_list_entry_<1-16>: ISO country code to block]
272 * [WBEM_DATA] =
273 * [Enable or disable 320MHZ Bandwidth for Japan, SouthKorea]
275 int get_wifi_sar_limits(union wifi_sar_limits *sar_limits)
277 const char *filename;
278 size_t sar_bin_len, sar_str_len;
279 uint8_t *sar_bin;
280 char *sar_str;
281 int ret = -1;
282 bool legacy_hex_format = false;
284 filename = get_wifi_sar_cbfs_filename();
285 if (filename == NULL) {
286 printk(BIOS_ERR, "Filename missing for CBFS SAR file!\n");
287 return ret;
290 sar_str = cbfs_map(filename, &sar_str_len);
291 if (!sar_str) {
292 printk(BIOS_ERR, "Failed to get the %s file size!\n", filename);
293 return ret;
296 if (strncmp(sar_str, SAR_STR_PREFIX, SAR_STR_PREFIX_SIZE) == 0) {
297 legacy_hex_format = false;
298 } else if (valid_legacy_length(sar_str_len)) {
299 legacy_hex_format = true;
300 } else {
301 printk(BIOS_ERR, "Invalid SAR format!\n");
302 goto error;
305 sar_bin = wifi_hextostr(sar_str, sar_str_len, &sar_bin_len, legacy_hex_format);
306 if (sar_bin == NULL) {
307 printk(BIOS_ERR, "Failed to parse SAR file %s\n", filename);
308 goto error;
311 memset(sar_limits, 0, sizeof(*sar_limits));
312 if (legacy_hex_format) {
313 ret = fill_wifi_sar_limits_legacy(sar_limits, sar_bin, sar_bin_len);
314 free(sar_bin);
315 } else {
316 ret = fill_wifi_sar_limits(sar_limits, sar_bin, sar_bin_len);
317 if (ret < 0)
318 free(sar_bin);
321 error:
322 cbfs_unmap(sar_str);
323 return ret;
326 __weak
327 const char *get_wifi_sar_cbfs_filename(void)
329 return WIFI_SAR_CBFS_DEFAULT_FILENAME;
332 char *get_wifi_sar_fw_config_filename(const struct fw_config_field *field)
334 uint64_t sar_id = fw_config_get_field(field);
335 if (sar_id == UNDEFINED_FW_CONFIG) {
336 printk(BIOS_WARNING, "fw_config unprovisioned, set sar filename to NULL\n");
337 return NULL;
339 static char filename[20];
340 printk(BIOS_INFO, "Use wifi_sar_%lld.hex.\n", sar_id);
341 if (snprintf(filename, sizeof(filename), "wifi_sar_%lld.hex", sar_id) < 0) {
342 printk(BIOS_ERR, "Error occurred with snprintf, set sar filename to NULL\n");
343 return NULL;
345 return filename;