1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @brief File containing API definitions for the Offloaded raw TX feature.
9 */
10
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/drivers/wifi/nrf_wifi/off_raw_tx/off_raw_tx_api.h>
16 #include <off_raw_tx.h>
17 #include <fmac_api.h>
18
19 #define DT_DRV_COMPAT nordic_wlan
20 LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
21
22 struct nrf_wifi_off_raw_tx_drv_priv off_raw_tx_drv_priv;
23 extern const struct nrf_wifi_osal_ops nrf_wifi_os_zep_ops;
24
25 static const int valid_data_rates[] = { 1, 2, 55, 11, 6, 9, 12, 18, 24, 36, 48, 54,
26 0, 1, 2, 3, 4, 5, 6, 7, -1 };
27
28 /* DTS uses 1dBm as the unit for TX power, while the RPU uses 0.25dBm */
29 #define MAX_TX_PWR(label) DT_PROP(DT_NODELABEL(nrf70), label) * 4
configure_tx_pwr_settings(struct nrf_wifi_tx_pwr_ctrl_params * ctrl_params,struct nrf_wifi_tx_pwr_ceil_params * ceil_params)30 static void configure_tx_pwr_settings(struct nrf_wifi_tx_pwr_ctrl_params *ctrl_params,
31 struct nrf_wifi_tx_pwr_ceil_params *ceil_params)
32 {
33 ctrl_params->ant_gain_2g = CONFIG_NRF70_ANT_GAIN_2G;
34 ctrl_params->ant_gain_5g_band1 = CONFIG_NRF70_ANT_GAIN_5G_BAND1;
35 ctrl_params->ant_gain_5g_band2 = CONFIG_NRF70_ANT_GAIN_5G_BAND2;
36 ctrl_params->ant_gain_5g_band3 = CONFIG_NRF70_ANT_GAIN_5G_BAND3;
37 ctrl_params->band_edge_2g_lo_dss = CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_DSSS;
38 ctrl_params->band_edge_2g_lo_ht = CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HT;
39 ctrl_params->band_edge_2g_lo_he = CONFIG_NRF70_BAND_2G_LOWER_EDGE_BACKOFF_HE;
40 ctrl_params->band_edge_2g_hi_dsss = CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_DSSS;
41 ctrl_params->band_edge_2g_hi_ht = CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HT;
42 ctrl_params->band_edge_2g_hi_he = CONFIG_NRF70_BAND_2G_UPPER_EDGE_BACKOFF_HE;
43 ctrl_params->band_edge_5g_unii_1_lo_ht =
44 CONFIG_NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HT;
45 ctrl_params->band_edge_5g_unii_1_lo_he =
46 CONFIG_NRF70_BAND_UNII_1_LOWER_EDGE_BACKOFF_HE;
47 ctrl_params->band_edge_5g_unii_1_hi_ht =
48 CONFIG_NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HT;
49 ctrl_params->band_edge_5g_unii_1_hi_he =
50 CONFIG_NRF70_BAND_UNII_1_UPPER_EDGE_BACKOFF_HE;
51 ctrl_params->band_edge_5g_unii_2a_lo_ht =
52 CONFIG_NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HT;
53 ctrl_params->band_edge_5g_unii_2a_lo_he =
54 CONFIG_NRF70_BAND_UNII_2A_LOWER_EDGE_BACKOFF_HE;
55 ctrl_params->band_edge_5g_unii_2a_hi_ht =
56 CONFIG_NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HT;
57 ctrl_params->band_edge_5g_unii_2a_hi_he =
58 CONFIG_NRF70_BAND_UNII_2A_UPPER_EDGE_BACKOFF_HE;
59 ctrl_params->band_edge_5g_unii_2c_lo_ht =
60 CONFIG_NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HT;
61 ctrl_params->band_edge_5g_unii_2c_lo_he =
62 CONFIG_NRF70_BAND_UNII_2C_LOWER_EDGE_BACKOFF_HE;
63 ctrl_params->band_edge_5g_unii_2c_hi_ht =
64 CONFIG_NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HT;
65 ctrl_params->band_edge_5g_unii_2c_hi_he =
66 CONFIG_NRF70_BAND_UNII_2C_UPPER_EDGE_BACKOFF_HE;
67 ctrl_params->band_edge_5g_unii_3_lo_ht =
68 CONFIG_NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HT;
69 ctrl_params->band_edge_5g_unii_3_lo_he =
70 CONFIG_NRF70_BAND_UNII_3_LOWER_EDGE_BACKOFF_HE;
71 ctrl_params->band_edge_5g_unii_3_hi_ht =
72 CONFIG_NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HT;
73 ctrl_params->band_edge_5g_unii_3_hi_he =
74 CONFIG_NRF70_BAND_UNII_3_UPPER_EDGE_BACKOFF_HE;
75 ctrl_params->band_edge_5g_unii_4_lo_ht =
76 CONFIG_NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HT;
77 ctrl_params->band_edge_5g_unii_4_lo_he =
78 CONFIG_NRF70_BAND_UNII_4_LOWER_EDGE_BACKOFF_HE;
79 ctrl_params->band_edge_5g_unii_4_hi_ht =
80 CONFIG_NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HT;
81 ctrl_params->band_edge_5g_unii_4_hi_he =
82 CONFIG_NRF70_BAND_UNII_4_UPPER_EDGE_BACKOFF_HE;
83 ceil_params->max_pwr_2g_dsss = MAX_TX_PWR(wifi_max_tx_pwr_2g_dsss);
84 ceil_params->max_pwr_2g_mcs7 = MAX_TX_PWR(wifi_max_tx_pwr_2g_mcs7);
85 ceil_params->max_pwr_2g_mcs0 = MAX_TX_PWR(wifi_max_tx_pwr_2g_mcs0);
86 #ifndef CONFIG_NRF70_2_4G_ONLY
87 ceil_params->max_pwr_5g_low_mcs7 = MAX_TX_PWR(wifi_max_tx_pwr_5g_low_mcs7);
88 ceil_params->max_pwr_5g_mid_mcs7 = MAX_TX_PWR(wifi_max_tx_pwr_5g_mid_mcs7);
89 ceil_params->max_pwr_5g_high_mcs7 = MAX_TX_PWR(wifi_max_tx_pwr_5g_high_mcs7);
90 ceil_params->max_pwr_5g_low_mcs0 = MAX_TX_PWR(wifi_max_tx_pwr_5g_low_mcs0);
91 ceil_params->max_pwr_5g_mid_mcs0 = MAX_TX_PWR(wifi_max_tx_pwr_5g_mid_mcs0);
92 ceil_params->max_pwr_5g_high_mcs0 = MAX_TX_PWR(wifi_max_tx_pwr_5g_high_mcs0);
93 #endif /* CONFIG_NRF70_2_4G_ONLY */
94 }
95
configure_board_dep_params(struct nrf_wifi_board_params * board_params)96 static void configure_board_dep_params(struct nrf_wifi_board_params *board_params)
97 {
98 board_params->pcb_loss_2g = CONFIG_NRF70_PCB_LOSS_2G;
99 #ifndef CONFIG_NRF70_2_4G_ONLY
100 board_params->pcb_loss_5g_band1 = CONFIG_NRF70_PCB_LOSS_5G_BAND1;
101 board_params->pcb_loss_5g_band2 = CONFIG_NRF70_PCB_LOSS_5G_BAND2;
102 board_params->pcb_loss_5g_band3 = CONFIG_NRF70_PCB_LOSS_5G_BAND3;
103 #endif /* CONFIG_NRF70_2_4G_ONLY */
104 }
105
106 #ifdef CONFIG_WIFI_FIXED_MAC_ADDRESS_ENABLED
bytes_from_str(uint8_t * buf,int buf_len,const char * src)107 static int bytes_from_str(uint8_t *buf, int buf_len, const char *src)
108 {
109 size_t i;
110 size_t src_len = strlen(src);
111 char *endptr;
112
113 for (i = 0U; i < src_len; i++) {
114 if (!isxdigit((unsigned char)src[i]) &&
115 src[i] != ':') {
116 return -EINVAL;
117 }
118 }
119
120 (void)memset(buf, 0, buf_len);
121
122 for (i = 0U; i < (size_t)buf_len; i++) {
123 buf[i] = (uint8_t)strtol(src, &endptr, 16);
124 src = ++endptr;
125 }
126
127 return 0;
128 }
129 #endif /* CONFIG_WIFI_FIXED_MAC_ADDRESS_ENABLED */
130
nrf70_off_raw_tx_init(uint8_t * mac_addr,unsigned char * country_code)131 int nrf70_off_raw_tx_init(uint8_t *mac_addr, unsigned char *country_code)
132 {
133 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
134 struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
135 void *rpu_ctx = NULL;
136 struct nrf_wifi_tx_pwr_ctrl_params ctrl_params;
137 struct nrf_wifi_tx_pwr_ceil_params ceil_params;
138 struct nrf_wifi_board_params board_params;
139 unsigned int fw_ver = 0;
140 k_spinlock_key_t key;
141
142 /* The OSAL layer needs to be initialized before any other initialization
143 * so that other layers (like FW IF,HW IF etc) have access to OS ops
144 */
145 nrf_wifi_osal_init(&nrf_wifi_os_zep_ops);
146
147 key = k_spin_lock(&off_raw_tx_drv_priv.lock);
148
149 off_raw_tx_drv_priv.fmac_priv = nrf_wifi_fmac_off_raw_tx_init();
150
151 if (off_raw_tx_drv_priv.fmac_priv == NULL) {
152 LOG_ERR("%s: Failed to initialize nRF70 driver",
153 __func__);
154 goto err;
155 }
156
157 rpu_ctx_zep = &off_raw_tx_drv_priv.rpu_ctx_zep;
158
159 rpu_ctx_zep->drv_priv_zep = &off_raw_tx_drv_priv;
160
161 rpu_ctx = nrf_wifi_fmac_dev_add(off_raw_tx_drv_priv.fmac_priv,
162 rpu_ctx_zep);
163 if (!rpu_ctx) {
164 LOG_ERR("%s: Failed to add nRF70 device", __func__);
165 rpu_ctx_zep = NULL;
166 goto err;
167 }
168
169 rpu_ctx_zep->rpu_ctx = rpu_ctx;
170
171 status = nrf_wifi_fw_load(rpu_ctx);
172 if (status != NRF_WIFI_STATUS_SUCCESS) {
173 LOG_ERR("%s: Failed to load the nRF70 firmware patch", __func__);
174 goto err;
175 }
176
177 status = nrf_wifi_fmac_ver_get(rpu_ctx,
178 &fw_ver);
179 if (status != NRF_WIFI_STATUS_SUCCESS) {
180 LOG_ERR("%s: Failed to read the nRF70 firmware version", __func__);
181 goto err;
182 }
183
184 LOG_DBG("nRF70 firmware (v%d.%d.%d.%d) booted successfully",
185 NRF_WIFI_UMAC_VER(fw_ver),
186 NRF_WIFI_UMAC_VER_MAJ(fw_ver),
187 NRF_WIFI_UMAC_VER_MIN(fw_ver),
188 NRF_WIFI_UMAC_VER_EXTRA(fw_ver));
189
190 memset(&ctrl_params, 0, sizeof(ctrl_params));
191 memset(&ceil_params, 0, sizeof(ceil_params));
192
193 configure_tx_pwr_settings(&ctrl_params,
194 &ceil_params);
195
196 memset(&board_params, 0, sizeof(board_params));
197
198 configure_board_dep_params(&board_params);
199
200 status = nrf_wifi_fmac_off_raw_tx_dev_init(rpu_ctx_zep->rpu_ctx,
201 #ifdef CONFIG_NRF_WIFI_LOW_POWER
202 HW_SLEEP_ENABLE,
203 #endif /* CONFIG_NRF_WIFI_LOW_POWER */
204 NRF_WIFI_DEF_PHY_CALIB,
205 CONFIG_NRF_WIFI_OP_BAND,
206 IS_ENABLED(CONFIG_NRF_WIFI_BEAMFORMING),
207 &ctrl_params,
208 &ceil_params,
209 &board_params,
210 country_code);
211 if (status != NRF_WIFI_STATUS_SUCCESS) {
212 LOG_ERR("%s: nRF70 firmware initialization failed", __func__);
213 goto err;
214 }
215
216 if (mac_addr) {
217 memcpy(rpu_ctx_zep->mac_addr, mac_addr, 6);
218 } else {
219 #ifdef CONFIG_WIFI_FIXED_MAC_ADDRESS_ENABLED
220 int ret = -1;
221
222 ret = bytes_from_str(rpu_ctx_zep->mac_addr,
223 6,
224 CONFIG_WIFI_FIXED_MAC_ADDRESS);
225 if (ret < 0) {
226 LOG_ERR("%s: Failed to parse MAC address: %s",
227 __func__,
228 CONFIG_WIFI_FIXED_MAC_ADDRESS);
229 goto err;
230 }
231 #elif CONFIG_WIFI_OTP_MAC_ADDRESS
232 status = nrf_wifi_fmac_otp_mac_addr_get(off_raw_tx_drv_priv.rpu_ctx_zep.rpu_ctx,
233 0,
234 rpu_ctx_zep->mac_addr);
235 if (status != NRF_WIFI_STATUS_SUCCESS) {
236 LOG_ERR("%s: Fetching of MAC address from OTP failed",
237 __func__);
238 goto err;
239 }
240 #endif /* CONFIG_WIFI_FIXED_MAC_ADDRESS_ENABLED */
241
242 if (!nrf_wifi_utils_is_mac_addr_valid(rpu_ctx_zep->mac_addr)) {
243 LOG_ERR("%s: Invalid MAC address: %02X:%02X:%02X:%02X:%02X:%02X",
244 __func__,
245 rpu_ctx_zep->mac_addr[0],
246 rpu_ctx_zep->mac_addr[1],
247 rpu_ctx_zep->mac_addr[2],
248 rpu_ctx_zep->mac_addr[3],
249 rpu_ctx_zep->mac_addr[4],
250 rpu_ctx_zep->mac_addr[5]);
251 goto err;
252 }
253 }
254
255 k_spin_unlock(&off_raw_tx_drv_priv.lock, key);
256
257 return 0;
258 err:
259 if (rpu_ctx) {
260 nrf_wifi_fmac_off_raw_tx_dev_rem(rpu_ctx);
261 rpu_ctx_zep->rpu_ctx = NULL;
262 }
263
264 k_spin_unlock(&off_raw_tx_drv_priv.lock, key);
265 nrf70_off_raw_tx_deinit();
266 return -1;
267 }
268
269
nrf70_off_raw_tx_deinit(void)270 void nrf70_off_raw_tx_deinit(void)
271 {
272 k_spinlock_key_t key;
273
274 key = k_spin_lock(&off_raw_tx_drv_priv.lock);
275
276 if (!off_raw_tx_drv_priv.fmac_priv) {
277 k_spin_unlock(&off_raw_tx_drv_priv.lock, key);
278 return;
279 }
280
281 nrf_wifi_fmac_off_raw_tx_deinit(off_raw_tx_drv_priv.fmac_priv);
282 nrf_wifi_osal_deinit();
283
284 k_spin_unlock(&off_raw_tx_drv_priv.lock, key);
285 }
286
validate_rate(enum nrf_wifi_off_raw_tx_tput_mode tput_mode,enum nrf_wifi_off_raw_tx_rate rate)287 static bool validate_rate(enum nrf_wifi_off_raw_tx_tput_mode tput_mode,
288 enum nrf_wifi_off_raw_tx_rate rate)
289 {
290 if (tput_mode == TPUT_MODE_LEGACY) {
291 if (rate > RATE_54M) {
292 return false;
293 }
294 } else {
295 if (rate <= RATE_54M) {
296 return false;
297 }
298 }
299
300 return true;
301 }
302
nrf70_off_raw_tx_conf_update(struct nrf_wifi_off_raw_tx_conf * conf)303 int nrf70_off_raw_tx_conf_update(struct nrf_wifi_off_raw_tx_conf *conf)
304 {
305 int ret = -1;
306 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
307 struct nrf_wifi_offload_ctrl_params *off_ctrl_params = NULL;
308 struct nrf_wifi_offload_tx_ctrl *off_tx_params = NULL;
309 struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
310 k_spinlock_key_t key;
311
312 if (!conf) {
313 LOG_ERR("%s: Config params is NULL", __func__);
314 goto out;
315 }
316
317 off_ctrl_params = nrf_wifi_osal_mem_zalloc(sizeof(*off_ctrl_params));
318 if (!off_ctrl_params) {
319 LOG_ERR("%s: Failed to allocate memory for off_ctrl_params", __func__);
320 goto out;
321 }
322
323 key = k_spin_lock(&off_raw_tx_drv_priv.lock);
324
325 fmac_dev_ctx = off_raw_tx_drv_priv.rpu_ctx_zep.rpu_ctx;
326
327 if (!fmac_dev_ctx) {
328 LOG_ERR("%s: FMAC device context is NULL", __func__);
329 goto out;
330 }
331
332 off_tx_params = nrf_wifi_osal_mem_zalloc(sizeof(*off_tx_params));
333 if (!off_tx_params) {
334 LOG_ERR("%s Failed to allocate memory for off_tx_params: ", __func__);
335 goto out;
336 }
337
338 if (!validate_rate(conf->tput_mode, conf->rate)) {
339 LOG_ERR("%s Invalid rate. Throughput mode: %d, rate: %d\n", __func__,
340 conf->tput_mode, conf->rate);
341 goto out;
342 }
343
344 off_ctrl_params->channel_no = conf->chan;
345 off_ctrl_params->period_in_us = conf->period_us;
346 off_ctrl_params->tx_pwr = conf->tx_pwr;
347 off_tx_params->he_gi_type = conf->he_gi;
348 off_tx_params->he_ltf = conf->he_ltf;
349 off_tx_params->pkt_ram_ptr = RPU_MEM_PKT_BASE;
350 off_tx_params->pkt_length = conf->pkt_len;
351 off_tx_params->rate_flags = conf->tput_mode;
352 off_tx_params->rate = valid_data_rates[conf->rate];
353 off_tx_params->rate_preamble_type = conf->short_preamble;
354 off_tx_params->rate_retries = conf->num_retries;
355
356 status = hal_rpu_mem_write(fmac_dev_ctx->hal_dev_ctx,
357 RPU_MEM_PKT_BASE,
358 conf->pkt,
359 conf->pkt_len);
360 if (status != NRF_WIFI_STATUS_SUCCESS) {
361 LOG_ERR("%s: hal_rpu_mem_write failed", __func__);
362 goto out;
363 }
364
365 status = nrf_wifi_fmac_off_raw_tx_conf(fmac_dev_ctx,
366 off_ctrl_params,
367 off_tx_params);
368 if (status != NRF_WIFI_STATUS_SUCCESS) {
369 LOG_ERR("%s: nRF70 offloaded raw TX configuration failed",
370 __func__);
371 goto out;
372 }
373
374 ret = 0;
375 out:
376 nrf_wifi_osal_mem_free(off_ctrl_params);
377 nrf_wifi_osal_mem_free(off_tx_params);
378 k_spin_unlock(&off_raw_tx_drv_priv.lock, key);
379 return ret;
380 }
381
382
nrf70_off_raw_tx_start(struct nrf_wifi_off_raw_tx_conf * conf)383 int nrf70_off_raw_tx_start(struct nrf_wifi_off_raw_tx_conf *conf)
384 {
385 int ret = -1;
386 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
387 k_spinlock_key_t key;
388
389 status = nrf70_off_raw_tx_conf_update(conf);
390 if (status != NRF_WIFI_STATUS_SUCCESS) {
391 LOG_ERR("%s: nRF70 offloaded raw TX configuration failed",
392 __func__);
393 goto out;
394 }
395
396 key = k_spin_lock(&off_raw_tx_drv_priv.lock);
397 if (!off_raw_tx_drv_priv.rpu_ctx_zep.rpu_ctx) {
398 LOG_ERR("%s: FMAC device context is NULL", __func__);
399 goto out;
400 }
401
402 status = nrf_wifi_fmac_off_raw_tx_start(off_raw_tx_drv_priv.rpu_ctx_zep.rpu_ctx);
403 if (status != NRF_WIFI_STATUS_SUCCESS) {
404 LOG_ERR("%s: nRF70 offloaded raw TX start failed",
405 __func__);
406 goto out;
407 }
408
409 ret = 0;
410 out:
411 k_spin_unlock(&off_raw_tx_drv_priv.lock, key);
412 return ret;
413 }
414
415
nrf70_off_raw_tx_stop(void)416 int nrf70_off_raw_tx_stop(void)
417 {
418 int ret = -1;
419 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
420 k_spinlock_key_t key;
421
422 key = k_spin_lock(&off_raw_tx_drv_priv.lock);
423
424 if (!off_raw_tx_drv_priv.rpu_ctx_zep.rpu_ctx) {
425 LOG_ERR("%s: FMAC device context is NULL", __func__);
426 goto out;
427 }
428
429 status = nrf_wifi_fmac_off_raw_tx_stop(off_raw_tx_drv_priv.rpu_ctx_zep.rpu_ctx);
430 if (status != NRF_WIFI_STATUS_SUCCESS) {
431 LOG_ERR("%s: nRF70 offloaded raw TX stop failed",
432 __func__);
433 goto out;
434 }
435
436 ret = 0;
437 out:
438 k_spin_unlock(&off_raw_tx_drv_priv.lock, key);
439 return ret;
440 }
441
442
nrf70_off_raw_tx_mac_addr_get(uint8_t * mac_addr)443 int nrf70_off_raw_tx_mac_addr_get(uint8_t *mac_addr)
444 {
445 if (!mac_addr) {
446 LOG_ERR("%s: Invalid param", __func__);
447 return -EINVAL;
448 }
449
450 memcpy(mac_addr, off_raw_tx_drv_priv.rpu_ctx_zep.mac_addr, 6);
451 return 0;
452 }
453
nrf70_off_raw_tx_stats(struct nrf_wifi_off_raw_tx_stats * off_raw_tx_stats)454 int nrf70_off_raw_tx_stats(struct nrf_wifi_off_raw_tx_stats *off_raw_tx_stats)
455 {
456 int ret = -1;
457 enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
458 struct rpu_op_stats stats;
459 k_spinlock_key_t key;
460
461 memset(&stats, 0, sizeof(struct rpu_op_stats));
462
463 key = k_spin_lock(&off_raw_tx_drv_priv.lock);
464
465 if (!off_raw_tx_drv_priv.rpu_ctx_zep.rpu_ctx) {
466 LOG_ERR("%s: FMAC device context is NULL", __func__);
467 goto out;
468 }
469
470 status = nrf_wifi_fmac_stats_get(off_raw_tx_drv_priv.rpu_ctx_zep.rpu_ctx, 0, &stats);
471 if (status != NRF_WIFI_STATUS_SUCCESS) {
472 LOG_ERR("%s: nRF70 offloaded raw TX stats failed",
473 __func__);
474 goto out;
475 }
476
477 off_raw_tx_stats->off_raw_tx_pkt_sent = stats.fw.offloaded_raw_tx.offload_raw_tx_cnt;
478
479 ret = 0;
480 out:
481 k_spin_unlock(&off_raw_tx_drv_priv.lock, key);
482 return ret;
483 }
484