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