1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /**
8 * @brief File containing API definitions for the
9 * FMAC IF Layer of the Wi-Fi driver.
10 */
11
12 #include "host_rpu_umac_if.h"
13 #include "common/fmac_api_common.h"
14 #include "common/fmac_util.h"
15 #include "common/fmac_cmd_common.h"
16 #include "util.h"
17
18 struct nrf_wifi_proc {
19 const enum RPU_PROC_TYPE type;
20 const char *name;
21 bool is_patch_present;
22 };
23
24 struct nrf_wifi_proc wifi_proc[] = {
25 {RPU_PROC_TYPE_MCU_LMAC, "LMAC", true},
26 {RPU_PROC_TYPE_MCU_UMAC, "UMAC", true},
27 };
28
nrf_wifi_patch_version_compat(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,const unsigned int version)29 static int nrf_wifi_patch_version_compat(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
30 const unsigned int version)
31 {
32 unsigned int family, major, minor, patch;
33
34 family = (version >> 24) & 0xff;
35 major = (version >> 16) & 0xff;
36 minor = (version >> 8) & 0xff;
37 patch = (version >> 0) & 0xff;
38
39 if (family != RPU_FAMILY) {
40 nrf_wifi_osal_log_err("Incompatible RPU version: %d, expected: %d",
41 family, RPU_FAMILY);
42 return -1;
43 }
44
45 if (major != RPU_MAJOR_VERSION) {
46 nrf_wifi_osal_log_err("Incompatible RPU major version: %d, expected: %d",
47 major, RPU_MAJOR_VERSION);
48 return -1;
49 }
50
51 /* TODO: Allow minor version to be different */
52 if (minor != RPU_MINOR_VERSION) {
53 nrf_wifi_osal_log_err("Incompatible RPU minor version: %d, expected: %d",
54 minor, RPU_MINOR_VERSION);
55 return -1;
56 }
57
58 /* TODO: Allow patch version to be different */
59 if (patch != RPU_PATCH_VERSION) {
60 nrf_wifi_osal_log_err("Incompatible RPU patch version: %d, expected: %d",
61 patch, RPU_PATCH_VERSION);
62 return -1;
63 }
64
65 return 0;
66 }
67
nrf_wifi_patch_feature_flags_compat(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,const unsigned int feature_flags)68 static int nrf_wifi_patch_feature_flags_compat(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
69 const unsigned int feature_flags)
70 {
71 if (fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_RT) {
72 if (!(feature_flags & NRF70_FEAT_RADIO_TEST)) {
73 nrf_wifi_osal_log_err("Radio test feature flag not set");
74 return -1;
75 }
76 } else if (fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_SYS) {
77 #ifdef NRF70_SCAN_ONLY
78 if (!(feature_flags & NRF70_FEAT_SCAN_ONLY)) {
79 nrf_wifi_osal_log_err("Scan only feature flag not set");
80 return -1;
81 }
82 #elif defined(NRF70_SYSTEM_MODE)
83 if (!(feature_flags & NRF70_FEAT_SYSTEM_MODE)) {
84 nrf_wifi_osal_log_err("System mode feature flag not set");
85 return -1;
86 }
87 #elif defined(NRF70_SYSTEM_WITH_RAW_MODES)
88 if (!(feature_flags & NRF70_FEAT_SYSTEM_WITH_RAW_MODES)) {
89 nrf_wifi_osal_log_err("System with raw modes feature flag not set");
90 return -1;
91 }
92 #else
93 nrf_wifi_osal_log_err("Invalid feature flags: 0x%x or build configuration",
94 feature_flags);
95 #endif
96 } else if (fmac_dev_ctx->op_mode == NRF_WIFI_OP_MODE_OFF_RAW_TX) {
97 if (!(feature_flags & NRF70_FEAT_OFFLOADED_RAW_TX)) {
98 nrf_wifi_osal_log_err("Offloaded raw tx feature flag not set");
99 return -1;
100 }
101 } else {
102 nrf_wifi_osal_log_err("Invalid op_mode: %d", fmac_dev_ctx->op_mode);
103 return -1;
104 }
105
106 return 0;
107 }
108
109
nrf_wifi_fmac_deinit(struct nrf_wifi_fmac_priv * fpriv)110 void nrf_wifi_fmac_deinit(struct nrf_wifi_fmac_priv *fpriv)
111 {
112 nrf_wifi_hal_deinit(fpriv->hpriv);
113
114 nrf_wifi_osal_mem_free(fpriv);
115 }
116
117
nrf_wifi_fmac_dev_rem(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx)118 void nrf_wifi_fmac_dev_rem(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
119 {
120 nrf_wifi_hal_dev_rem(fmac_dev_ctx->hal_dev_ctx);
121
122 nrf_wifi_osal_mem_free(fmac_dev_ctx);
123 }
124
125
nrf_wifi_validate_fw_header(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,struct nrf70_fw_image_info * info)126 enum nrf_wifi_status nrf_wifi_validate_fw_header(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
127 struct nrf70_fw_image_info *info)
128 {
129
130 nrf_wifi_osal_log_dbg("Signature: 0x%x", info->signature);
131 nrf_wifi_osal_log_dbg("num_images: %d", info->num_images);
132 nrf_wifi_osal_log_dbg("version: 0x%x", info->version);
133 nrf_wifi_osal_log_dbg("feature_flags: %d", info->feature_flags);
134
135 if (info->signature != NRF_WIFI_PATCH_SIGNATURE) {
136 nrf_wifi_osal_log_err("Invalid patch signature: 0x%x, expected: 0x%x",
137 info->signature, NRF_WIFI_PATCH_SIGNATURE);
138 return NRF_WIFI_STATUS_FAIL;
139 }
140
141 if (info->num_images != NRF_WIFI_PATCH_NUM_IMAGES) {
142 nrf_wifi_osal_log_err("Invalid number of images, expected %d, got %d",
143 NRF_WIFI_PATCH_NUM_IMAGES, info->num_images);
144 return NRF_WIFI_STATUS_FAIL;
145 }
146
147 if (nrf_wifi_patch_version_compat(fmac_dev_ctx, info->version) != 0) {
148 nrf_wifi_osal_log_err("Incompatible patch");
149 return NRF_WIFI_STATUS_FAIL;
150 }
151
152 if (nrf_wifi_patch_feature_flags_compat(fmac_dev_ctx, info->feature_flags) != 0) {
153 nrf_wifi_osal_log_err("Incompatible feature flags");
154 return NRF_WIFI_STATUS_FAIL;
155 }
156
157 return NRF_WIFI_STATUS_SUCCESS;
158 }
159
nrf_wifi_fmac_fw_parse(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,const void * fw_data,unsigned int fw_size,struct nrf_wifi_fmac_fw_info * fw_info)160 enum nrf_wifi_status nrf_wifi_fmac_fw_parse(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
161 const void *fw_data,
162 unsigned int fw_size,
163 struct nrf_wifi_fmac_fw_info *fw_info)
164 {
165 struct nrf70_fw_image_info *info = (struct nrf70_fw_image_info *)fw_data;
166 unsigned int offset;
167 unsigned int image_id;
168
169 if (!fw_data || !fw_size || !fw_info) {
170 nrf_wifi_osal_log_err("Invalid parameters");
171 return NRF_WIFI_STATUS_FAIL;
172 }
173
174 if (fw_size < sizeof(struct nrf70_fw_image_info)) {
175 nrf_wifi_osal_log_err("Invalid fw_size: %d, minimum size: %d",
176 fw_size, sizeof(struct nrf70_fw_image_info));
177 return NRF_WIFI_STATUS_FAIL;
178 }
179
180
181 if (nrf_wifi_validate_fw_header(fmac_dev_ctx, info) != NRF_WIFI_STATUS_SUCCESS) {
182 nrf_wifi_osal_log_err("Invalid fw header");
183 return NRF_WIFI_STATUS_FAIL;
184 }
185
186 offset = sizeof(struct nrf70_fw_image_info);
187
188 nrf_wifi_osal_log_dbg("====");
189 for (image_id = 0; image_id < info->num_images; image_id++) {
190 struct nrf70_fw_image *image =
191 (struct nrf70_fw_image *)((char *)fw_data + offset);
192 const void *data = (char *)fw_data + offset + sizeof(struct nrf70_fw_image);
193
194 if (offset + sizeof(struct nrf70_fw_image) + image->len > fw_size) {
195 nrf_wifi_osal_log_err("Invalid fw_size: %d for image[%d] len: %d",
196 fw_size, image_id, image->len);
197 return NRF_WIFI_STATUS_FAIL;
198 }
199
200 nrf_wifi_osal_log_dbg("image[%d] type: %d", image_id, image->type);
201 nrf_wifi_osal_log_dbg("image[%d] len: %d", image_id, image->len);
202 nrf_wifi_osal_log_dbg("====");
203
204 switch (image_id) {
205 case NRF70_IMAGE_LMAC_PRI:
206 fw_info->lmac_patch_pri.data = data;
207 fw_info->lmac_patch_pri.size = image->len;
208 break;
209 case NRF70_IMAGE_LMAC_SEC:
210 fw_info->lmac_patch_sec.data = data;
211 fw_info->lmac_patch_sec.size = image->len;
212 break;
213 case NRF70_IMAGE_UMAC_PRI:
214 fw_info->umac_patch_pri.data = data;
215 fw_info->umac_patch_pri.size = image->len;
216 break;
217 case NRF70_IMAGE_UMAC_SEC:
218 fw_info->umac_patch_sec.data = data;
219 fw_info->umac_patch_sec.size = image->len;
220 break;
221 default:
222 nrf_wifi_osal_log_err("Invalid image id: %d", image_id);
223 break;
224 }
225
226 offset += sizeof(struct nrf70_fw_image) + image->len;
227 }
228
229 return NRF_WIFI_STATUS_SUCCESS;
230 }
231
nrf_wifi_fmac_fw_reset(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx)232 enum nrf_wifi_status nrf_wifi_fmac_fw_reset(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
233 {
234 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
235 int i = 0;
236
237 for (i = 0; i < ARRAY_SIZE(wifi_proc); i++) {
238 status = nrf_wifi_hal_proc_reset(fmac_dev_ctx->hal_dev_ctx,
239 wifi_proc[i].type);
240
241 if (status != NRF_WIFI_STATUS_SUCCESS) {
242 nrf_wifi_osal_log_err("%s: %s processor reset failed\n",
243 __func__, wifi_proc[i].name);
244 return NRF_WIFI_STATUS_FAIL;
245 }
246 }
247
248 return NRF_WIFI_STATUS_SUCCESS;
249 }
250
nrf_wifi_fmac_fw_boot(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx)251 enum nrf_wifi_status nrf_wifi_fmac_fw_boot(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
252 {
253 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
254 int i = 0;
255
256 for (i = 0; i < ARRAY_SIZE(wifi_proc); i++) {
257 status = nrf_wifi_hal_fw_patch_boot(fmac_dev_ctx->hal_dev_ctx,
258 wifi_proc[i].type,
259 wifi_proc[i].is_patch_present);
260
261 if (status != NRF_WIFI_STATUS_SUCCESS) {
262 nrf_wifi_osal_log_err("%s: %s processor ROM boot failed\n",
263 __func__, wifi_proc[i].name);
264 return NRF_WIFI_STATUS_FAIL;
265 }
266
267 status = nrf_wifi_hal_fw_chk_boot(fmac_dev_ctx->hal_dev_ctx,
268 wifi_proc[i].type);
269
270 if (status != NRF_WIFI_STATUS_SUCCESS) {
271 nrf_wifi_osal_log_err("%s: %s processor ROM boot check failed\n",
272 __func__, wifi_proc[i].name);
273 return NRF_WIFI_STATUS_FAIL;
274 }
275 }
276
277 return NRF_WIFI_STATUS_SUCCESS;
278 }
279
280
nrf_wifi_fmac_fw_chunk_load(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,enum RPU_PROC_TYPE rpu_proc,struct nrf_wifi_fmac_fw_chunk_info * fw_chunk)281 enum nrf_wifi_status nrf_wifi_fmac_fw_chunk_load(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
282 enum RPU_PROC_TYPE rpu_proc,
283 struct nrf_wifi_fmac_fw_chunk_info *fw_chunk)
284 {
285 return hal_fw_patch_chunk_load(fmac_dev_ctx->hal_dev_ctx,
286 rpu_proc,
287 fw_chunk->dest_addr,
288 fw_chunk->data,
289 fw_chunk->size);
290 }
291
nrf_wifi_fmac_fw_load(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,struct nrf_wifi_fmac_fw_info * fmac_fw)292 enum nrf_wifi_status nrf_wifi_fmac_fw_load(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
293 struct nrf_wifi_fmac_fw_info *fmac_fw)
294 {
295 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
296
297 status = nrf_wifi_fmac_fw_reset(fmac_dev_ctx);
298 if (status != NRF_WIFI_STATUS_SUCCESS) {
299 nrf_wifi_osal_log_err("%s: FW reset failed\n",
300 __func__);
301 goto out;
302 }
303
304 /* Load the UMAC patches if available */
305 if (fmac_fw->umac_patch_pri.data && fmac_fw->umac_patch_pri.size &&
306 fmac_fw->umac_patch_sec.data && fmac_fw->umac_patch_sec.size) {
307 status = nrf_wifi_hal_fw_patch_load(fmac_dev_ctx->hal_dev_ctx,
308 RPU_PROC_TYPE_MCU_UMAC,
309 fmac_fw->umac_patch_pri.data,
310 fmac_fw->umac_patch_pri.size,
311 fmac_fw->umac_patch_sec.data,
312 fmac_fw->umac_patch_sec.size);
313
314 if (status != NRF_WIFI_STATUS_SUCCESS) {
315 nrf_wifi_osal_log_err("%s: UMAC patch load failed\n",
316 __func__);
317 goto out;
318 } else {
319 nrf_wifi_osal_log_dbg("%s: UMAC patches loaded\n",
320 __func__);
321 }
322 } else {
323 wifi_proc[1].is_patch_present = false;
324 }
325
326 /* Load the LMAC patches if available */
327 if (fmac_fw->lmac_patch_pri.data && fmac_fw->lmac_patch_pri.size &&
328 fmac_fw->lmac_patch_sec.data && fmac_fw->lmac_patch_sec.size) {
329 status = nrf_wifi_hal_fw_patch_load(fmac_dev_ctx->hal_dev_ctx,
330 RPU_PROC_TYPE_MCU_LMAC,
331 fmac_fw->lmac_patch_pri.data,
332 fmac_fw->lmac_patch_pri.size,
333 fmac_fw->lmac_patch_sec.data,
334 fmac_fw->lmac_patch_sec.size);
335
336 if (status != NRF_WIFI_STATUS_SUCCESS) {
337 nrf_wifi_osal_log_err("%s: LMAC patch load failed\n",
338 __func__);
339 goto out;
340 } else {
341 nrf_wifi_osal_log_dbg("%s: LMAC patches loaded\n",
342 __func__);
343 }
344 } else {
345 wifi_proc[0].is_patch_present = false;
346 }
347
348 status = nrf_wifi_fmac_fw_boot(fmac_dev_ctx);
349 if (status != NRF_WIFI_STATUS_SUCCESS) {
350 nrf_wifi_osal_log_err("%s: FW boot failed\n",
351 __func__);
352 goto out;
353 }
354
355 fmac_dev_ctx->fw_boot_done = true;
356
357 out:
358 return status;
359 }
360
361
nrf_wifi_fmac_ver_get(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,unsigned int * fw_ver)362 enum nrf_wifi_status nrf_wifi_fmac_ver_get(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
363 unsigned int *fw_ver)
364 {
365 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
366
367 status = hal_rpu_mem_read(fmac_dev_ctx->hal_dev_ctx,
368 fw_ver,
369 RPU_MEM_UMAC_VER,
370 sizeof(*fw_ver));
371
372 if (status != NRF_WIFI_STATUS_SUCCESS) {
373 nrf_wifi_osal_log_err("%s: Unable to read UMAC ver",
374 __func__);
375 goto out;
376 }
377
378 out:
379 return status;
380 }
381
382
nrf_wifi_fmac_otp_mac_addr_get(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,unsigned char vif_idx,unsigned char * mac_addr)383 enum nrf_wifi_status nrf_wifi_fmac_otp_mac_addr_get(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
384 unsigned char vif_idx,
385 unsigned char *mac_addr)
386 {
387 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
388 struct nrf_wifi_fmac_otp_info otp_info;
389 unsigned char *otp_mac_addr = NULL;
390 unsigned int otp_mac_addr_flag_mask = 0;
391
392 if (!fmac_dev_ctx || !mac_addr || (vif_idx >= MAX_NUM_VIFS)) {
393 nrf_wifi_osal_log_err("%s: Invalid parameters",
394 __func__);
395 goto out;
396 }
397
398 nrf_wifi_osal_mem_set(&otp_info,
399 0xFF,
400 sizeof(otp_info));
401
402 status = nrf_wifi_hal_otp_info_get(fmac_dev_ctx->hal_dev_ctx,
403 &otp_info.info,
404 &otp_info.flags);
405
406 if (status != NRF_WIFI_STATUS_SUCCESS) {
407 nrf_wifi_osal_log_err("%s: Fetching of RPU OTP information failed",
408 __func__);
409 goto out;
410 }
411
412 if (vif_idx == 0) {
413 otp_mac_addr = (unsigned char *)otp_info.info.mac_address0;
414 otp_mac_addr_flag_mask = (~MAC0_ADDR_FLAG_MASK);
415
416 } else if (vif_idx == 1) {
417 otp_mac_addr = (unsigned char *)otp_info.info.mac_address1;
418 otp_mac_addr_flag_mask = (~MAC1_ADDR_FLAG_MASK);
419 }
420
421 /* Check if a valid MAC address has been programmed in the OTP */
422
423 if (otp_info.flags & otp_mac_addr_flag_mask) {
424 nrf_wifi_osal_log_info("%s: MAC addr not programmed in OTP",
425 __func__);
426
427 } else {
428 nrf_wifi_osal_mem_cpy(mac_addr,
429 otp_mac_addr,
430 NRF_WIFI_ETH_ADDR_LEN);
431
432 if (!nrf_wifi_utils_is_mac_addr_valid((const char *)mac_addr)) {
433 nrf_wifi_osal_log_info("%s: Invalid OTP MA: %02X%02X%02X%02X%02X%02X",
434 __func__,
435 (*(mac_addr + 0)),
436 (*(mac_addr + 1)),
437 (*(mac_addr + 2)),
438 (*(mac_addr + 3)),
439 (*(mac_addr + 4)),
440 (*(mac_addr + 5)));
441
442 }
443 }
444 out:
445 return status;
446 }
447
nrf_wifi_fmac_get_reg(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,struct nrf_wifi_fmac_reg_info * reg_info)448 enum nrf_wifi_status nrf_wifi_fmac_get_reg(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
449 struct nrf_wifi_fmac_reg_info *reg_info)
450 {
451 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
452 struct nrf_wifi_umac_cmd_get_reg *get_reg_cmd = NULL;
453 unsigned int count = 0;
454
455 if (!fmac_dev_ctx || !reg_info) {
456 nrf_wifi_osal_log_err("%s: Invalid parameters",
457 __func__);
458 goto err;
459 }
460
461 nrf_wifi_osal_log_dbg("%s: Get regulatory information", __func__);
462
463 get_reg_cmd = nrf_wifi_osal_mem_zalloc(sizeof(*get_reg_cmd));
464
465 if (!get_reg_cmd) {
466 nrf_wifi_osal_log_err("%s: Unable to allocate memory",
467 __func__);
468 goto err;
469 }
470
471 get_reg_cmd->umac_hdr.cmd_evnt = NRF_WIFI_UMAC_CMD_GET_REG;
472 get_reg_cmd->umac_hdr.ids.valid_fields = 0;
473
474 fmac_dev_ctx->alpha2_valid = false;
475 fmac_dev_ctx->reg_chan_info = reg_info->reg_chan_info;
476
477 status = umac_cmd_cfg(fmac_dev_ctx,
478 get_reg_cmd,
479 sizeof(*get_reg_cmd));
480
481 if (status != NRF_WIFI_STATUS_SUCCESS) {
482 nrf_wifi_osal_log_err("%s: Failed to get regulatory information", __func__);
483 goto err;
484 }
485
486 do {
487 nrf_wifi_osal_sleep_ms(100);
488 } while (count++ < 100 && !fmac_dev_ctx->alpha2_valid);
489
490 if (!fmac_dev_ctx->alpha2_valid) {
491 nrf_wifi_osal_log_err("%s: Failed to get regulatory information",
492 __func__);
493 goto err;
494 }
495
496 nrf_wifi_osal_mem_cpy(reg_info->alpha2,
497 fmac_dev_ctx->alpha2,
498 sizeof(reg_info->alpha2));
499
500 reg_info->reg_chan_count = fmac_dev_ctx->reg_chan_count;
501
502 status = NRF_WIFI_STATUS_SUCCESS;
503 err:
504 if (get_reg_cmd) {
505 nrf_wifi_osal_mem_free(get_reg_cmd);
506 }
507 return status;
508 }
509
nrf_wifi_fmac_stats_reset(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx)510 enum nrf_wifi_status nrf_wifi_fmac_stats_reset(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx)
511 {
512 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
513 unsigned char count = 0;
514
515 status = umac_cmd_prog_stats_reset(fmac_dev_ctx);
516 if (status != NRF_WIFI_STATUS_SUCCESS) {
517 goto out;
518 }
519
520 do {
521 nrf_wifi_osal_sleep_ms(1);
522 } while ((fmac_dev_ctx->stats_req == true) &&
523 (count++ < NRF_WIFI_FMAC_STATS_RECV_TIMEOUT));
524
525 if (count == NRF_WIFI_FMAC_STATS_RECV_TIMEOUT) {
526 nrf_wifi_osal_log_err("%s: Timed out",
527 __func__);
528 goto out;
529 }
530
531 status = NRF_WIFI_STATUS_SUCCESS;
532
533 out:
534 return status;
535 }
536
537
nrf_wifi_fmac_conf_srcoex(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,void * cmd,unsigned int cmd_len)538 enum nrf_wifi_status nrf_wifi_fmac_conf_srcoex(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
539 void *cmd, unsigned int cmd_len)
540 {
541 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
542
543 status = umac_cmd_srcoex(fmac_dev_ctx, cmd, cmd_len);
544
545 return status;
546 }
547
nrf_wifi_fmac_set_reg(struct nrf_wifi_fmac_dev_ctx * fmac_dev_ctx,struct nrf_wifi_fmac_reg_info * reg_info)548 enum nrf_wifi_status nrf_wifi_fmac_set_reg(struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx,
549 struct nrf_wifi_fmac_reg_info *reg_info)
550 {
551 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
552 struct nrf_wifi_cmd_req_set_reg *set_reg_cmd = NULL;
553 unsigned int count = 0, max_count = NRF_WIFI_FMAC_REG_SET_TIMEOUT_MS / 20;
554 enum nrf_wifi_reg_initiator exp_initiator = NRF_WIFI_REGDOM_SET_BY_USER;
555 enum nrf_wifi_reg_type exp_reg_type = NRF_WIFI_REGDOM_TYPE_COUNTRY;
556 char exp_alpha2[NRF_WIFI_COUNTRY_CODE_LEN] = {0};
557 struct nrf_wifi_fmac_reg_info cur_reg_info = {0};
558 struct nrf_wifi_event_regulatory_change *reg_change = NULL;
559
560 if (!fmac_dev_ctx || !reg_info) {
561 nrf_wifi_osal_log_err("%s: Invalid parameters",
562 __func__);
563 goto out;
564 }
565
566 nrf_wifi_osal_log_dbg("%s: Setting regulatory information: %c%c", __func__,
567 reg_info->alpha2[0],
568 reg_info->alpha2[1]);
569
570 /* No change event from UMAC for same regd */
571 status = nrf_wifi_fmac_get_reg(fmac_dev_ctx, &cur_reg_info);
572 if (status != NRF_WIFI_STATUS_SUCCESS) {
573 nrf_wifi_osal_log_err("%s: Failed to get current regulatory information",
574 __func__);
575 goto out;
576 }
577
578 if (nrf_wifi_osal_mem_cmp(cur_reg_info.alpha2,
579 reg_info->alpha2,
580 NRF_WIFI_COUNTRY_CODE_LEN) == 0) {
581 nrf_wifi_osal_log_dbg("%s: Regulatory domain already set to %c%c",
582 __func__,
583 reg_info->alpha2[0],
584 reg_info->alpha2[1]);
585 status = NRF_WIFI_STATUS_SUCCESS;
586 goto out;
587 }
588
589 set_reg_cmd = nrf_wifi_osal_mem_zalloc(sizeof(*set_reg_cmd));
590
591 if (!set_reg_cmd) {
592 nrf_wifi_osal_log_err("%s: Unable to allocate memory",
593 __func__);
594 goto out;
595 }
596
597 set_reg_cmd->umac_hdr.cmd_evnt = NRF_WIFI_UMAC_CMD_REQ_SET_REG;
598 set_reg_cmd->umac_hdr.ids.valid_fields = 0;
599
600 nrf_wifi_osal_mem_cpy(set_reg_cmd->nrf_wifi_alpha2,
601 reg_info->alpha2,
602 NRF_WIFI_COUNTRY_CODE_LEN);
603
604 exp_alpha2[0] = reg_info->alpha2[0];
605 exp_alpha2[1] = reg_info->alpha2[1];
606
607 if (reg_info->alpha2[0] == '0' && reg_info->alpha2[1] == '0') {
608 exp_reg_type = NRF_WIFI_REGDOM_TYPE_WORLD;
609 }
610
611 set_reg_cmd->valid_fields = NRF_WIFI_CMD_REQ_SET_REG_ALPHA2_VALID;
612
613 /* New feature in rev B patch */
614 if (reg_info->force) {
615 set_reg_cmd->valid_fields |= NRF_WIFI_CMD_REQ_SET_REG_USER_REG_FORCE;
616 }
617
618 fmac_dev_ctx->reg_set_status = false;
619 fmac_dev_ctx->waiting_for_reg_event = true;
620
621 status = umac_cmd_cfg(fmac_dev_ctx,
622 set_reg_cmd,
623 sizeof(*set_reg_cmd));
624 if (status != NRF_WIFI_STATUS_SUCCESS) {
625 nrf_wifi_osal_log_err("%s: Failed to set regulatory information",
626 __func__);
627 goto out;
628 }
629
630 fmac_dev_ctx->reg_set_status = false;
631 nrf_wifi_osal_log_dbg("%s: Waiting for regulatory domain change event", __func__);
632 while (!fmac_dev_ctx->reg_set_status && count++ <= max_count) {
633 nrf_wifi_osal_sleep_ms(100);
634 }
635
636 if (!fmac_dev_ctx->reg_set_status) {
637 nrf_wifi_osal_log_err("%s: Failed to set regulatory information",
638 __func__);
639 status = NRF_WIFI_STATUS_FAIL;
640 goto out;
641 }
642
643 fmac_dev_ctx->waiting_for_reg_event = false;
644 reg_change = fmac_dev_ctx->reg_change;
645
646 if (reg_change->intr != exp_initiator) {
647 nrf_wifi_osal_log_err("%s: Non-user initiated reg domain change: exp: %d, got: %d",
648 __func__,
649 exp_initiator,
650 reg_change->intr);
651 status = NRF_WIFI_STATUS_FAIL;
652 goto out;
653 }
654
655 if (reg_change->regulatory_type != exp_reg_type) {
656 nrf_wifi_osal_log_err("%s: Unexpected reg domain change: exp: %d, got: %d",
657 __func__,
658 exp_reg_type,
659 reg_change->regulatory_type);
660 status = NRF_WIFI_STATUS_FAIL;
661 goto out;
662 }
663
664 if ((reg_change->regulatory_type == NRF_WIFI_REGDOM_TYPE_COUNTRY) &&
665 nrf_wifi_osal_mem_cmp(reg_change->nrf_wifi_alpha2,
666 exp_alpha2,
667 NRF_WIFI_COUNTRY_CODE_LEN) != 0) {
668 nrf_wifi_osal_log_err("%s: Unexpected alpha2 reg domain change: "
669 "exp: %c%c, got: %c%c",
670 __func__,
671 exp_alpha2[0],
672 exp_alpha2[1],
673 reg_change->nrf_wifi_alpha2[0],
674 reg_change->nrf_wifi_alpha2[1]);
675 status = NRF_WIFI_STATUS_FAIL;
676 goto out;
677 }
678
679 out:
680 if (set_reg_cmd) {
681 nrf_wifi_osal_mem_free(set_reg_cmd);
682 }
683
684 if (reg_change) {
685 nrf_wifi_osal_mem_free(reg_change);
686 fmac_dev_ctx->reg_change = NULL;
687 }
688
689 return status;
690 }