1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @brief File containing WiFi management operation implementations
9  * for the Zephyr OS.
10  */
11 
12 #include <stdlib.h>
13 
14 #include <zephyr/kernel.h>
15 #include <zephyr/logging/log.h>
16 
17 #include "util.h"
18 #include "system/fmac_api.h"
19 #include "system/fmac_tx.h"
20 #include "common/fmac_util.h"
21 #include "fmac_main.h"
22 #include "wifi_mgmt.h"
23 
24 LOG_MODULE_DECLARE(wifi_nrf, CONFIG_WIFI_NRF70_LOG_LEVEL);
25 
26 extern struct nrf_wifi_drv_priv_zep rpu_drv_priv_zep;
27 
nrf_wifi_set_power_save(const struct device * dev,struct wifi_ps_params * params)28 int nrf_wifi_set_power_save(const struct device *dev,
29 			    struct wifi_ps_params *params)
30 {
31 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
32 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
33 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
34 	int ret = -1;
35 	unsigned int uapsd_queue = UAPSD_Q_MIN; /* Legacy mode */
36 
37 	if (!dev || !params) {
38 		LOG_ERR("%s: dev or params is NULL", __func__);
39 		return ret;
40 	}
41 
42 	vif_ctx_zep = dev->data;
43 
44 	if (!vif_ctx_zep) {
45 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
46 		return ret;
47 	}
48 
49 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
50 
51 	if (!rpu_ctx_zep) {
52 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
53 		return ret;
54 	}
55 
56 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
57 	if (!rpu_ctx_zep->rpu_ctx) {
58 		LOG_DBG("%s: RPU context not initialized", __func__);
59 		goto out;
60 	}
61 
62 	switch (params->type) {
63 	case WIFI_PS_PARAM_LISTEN_INTERVAL:
64 		if ((params->listen_interval <
65 		     NRF_WIFI_LISTEN_INTERVAL_MIN) ||
66 		    (params->listen_interval >
67 		     WIFI_LISTEN_INTERVAL_MAX)) {
68 			params->fail_reason =
69 				WIFI_PS_PARAM_LISTEN_INTERVAL_RANGE_INVALID;
70 			return -EINVAL;
71 		}
72 		status = nrf_wifi_sys_fmac_set_listen_interval(
73 						rpu_ctx_zep->rpu_ctx,
74 						vif_ctx_zep->vif_idx,
75 						params->listen_interval);
76 	break;
77 	case  WIFI_PS_PARAM_TIMEOUT:
78 		if ((vif_ctx_zep->if_type != NRF_WIFI_IFTYPE_STATION)
79 #ifdef CONFIG_NRF70_RAW_DATA_TX
80 		    && (vif_ctx_zep->if_type != NRF_WIFI_STA_TX_INJECTOR)
81 #endif /* CONFIG_NRF70_RAW_DATA_TX */
82 #ifdef CONFIG_NRF70_PROMISC_DATA_RX
83 		    && (vif_ctx_zep->if_type != NRF_WIFI_STA_PROMISC_TX_INJECTOR)
84 #endif /* CONFIG_NRF70_PROMISC_DATA_RX */
85 		   ) {
86 			LOG_ERR("%s: Operation supported only in STA enabled mode",
87 				__func__);
88 			params->fail_reason =
89 				WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
90 			goto out;
91 		}
92 
93 		status = nrf_wifi_sys_fmac_set_power_save_timeout(
94 							rpu_ctx_zep->rpu_ctx,
95 							vif_ctx_zep->vif_idx,
96 							params->timeout_ms);
97 	break;
98 	case WIFI_PS_PARAM_MODE:
99 		if (params->mode == WIFI_PS_MODE_WMM) {
100 			uapsd_queue = UAPSD_Q_MAX; /* WMM mode */
101 		}
102 
103 		status = nrf_wifi_sys_fmac_set_uapsd_queue(rpu_ctx_zep->rpu_ctx,
104 						       vif_ctx_zep->vif_idx,
105 						       uapsd_queue);
106 	break;
107 	case  WIFI_PS_PARAM_STATE:
108 		status = nrf_wifi_sys_fmac_set_power_save(rpu_ctx_zep->rpu_ctx,
109 						      vif_ctx_zep->vif_idx,
110 						      params->enabled);
111 	break;
112 	case WIFI_PS_PARAM_WAKEUP_MODE:
113 		status = nrf_wifi_sys_fmac_set_ps_wakeup_mode(
114 							rpu_ctx_zep->rpu_ctx,
115 							vif_ctx_zep->vif_idx,
116 							params->wakeup_mode);
117 	break;
118 	case WIFI_PS_PARAM_EXIT_STRATEGY:
119 		unsigned int exit_strategy;
120 
121 		if (params->exit_strategy == WIFI_PS_EXIT_EVERY_TIM) {
122 			exit_strategy = EVERY_TIM;
123 		} else if (params->exit_strategy == WIFI_PS_EXIT_CUSTOM_ALGO) {
124 			exit_strategy = INT_PS;
125 		} else {
126 			params->fail_reason =
127 				WIFI_PS_PARAM_FAIL_INVALID_EXIT_STRATEGY;
128 			return -EINVAL;
129 		}
130 
131 		status = nrf_wifi_sys_fmac_set_ps_exit_strategy(
132 							rpu_ctx_zep->rpu_ctx,
133 							vif_ctx_zep->vif_idx,
134 							exit_strategy);
135 	break;
136 	default:
137 		params->fail_reason =
138 			WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
139 		return -ENOTSUP;
140 	}
141 
142 	if (status != NRF_WIFI_STATUS_SUCCESS) {
143 		LOG_ERR("%s: Confiuring PS param %d failed",
144 			__func__, params->type);
145 		params->fail_reason =
146 			WIFI_PS_PARAM_FAIL_CMD_EXEC_FAIL;
147 		goto out;
148 	}
149 
150 
151 	ret = 0;
152 out:
153 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
154 	return ret;
155 }
156 
nrf_wifi_get_power_save_config(const struct device * dev,struct wifi_ps_config * ps_config)157 int nrf_wifi_get_power_save_config(const struct device *dev,
158 				   struct wifi_ps_config *ps_config)
159 {
160 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
161 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
162 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
163 	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
164 	int ret = -1;
165 	int count = 0;
166 
167 	if (!dev || !ps_config) {
168 		return ret;
169 	}
170 
171 	vif_ctx_zep = dev->data;
172 
173 	if (!vif_ctx_zep) {
174 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
175 		return ret;
176 	}
177 
178 	if ((vif_ctx_zep->if_type != NRF_WIFI_IFTYPE_STATION)
179 #ifdef CONFIG_NRF70_RAW_DATA_TX
180 	    && (vif_ctx_zep->if_type != NRF_WIFI_STA_TX_INJECTOR)
181 #endif /* CONFIG_NRF70_RAW_DATA_TX */
182 #ifdef CONFIG_NRF70_PROMISC_DATA_RX
183 	    && (vif_ctx_zep->if_type != NRF_WIFI_STA_PROMISC_TX_INJECTOR)
184 #endif /* CONFIG_NRF70_PROMISC_DATA_RX */
185 	    ) {
186 		LOG_ERR("%s: Operation supported only in STA enabled mode",
187 			__func__);
188 		return ret;
189 	}
190 
191 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
192 	if (!rpu_ctx_zep) {
193 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
194 		return ret;
195 	}
196 
197 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
198 	if (!rpu_ctx_zep->rpu_ctx) {
199 		LOG_DBG("%s: RPU context not initialized", __func__);
200 		goto out;
201 	}
202 
203 	fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
204 
205 	if (!rpu_ctx_zep) {
206 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
207 		goto out;
208 	}
209 
210 	vif_ctx_zep->ps_info = ps_config;
211 
212 	vif_ctx_zep->ps_config_info_evnt = false;
213 
214 	status = nrf_wifi_sys_fmac_get_power_save_info(rpu_ctx_zep->rpu_ctx,
215 						   vif_ctx_zep->vif_idx);
216 
217 	if (status != NRF_WIFI_STATUS_SUCCESS) {
218 		LOG_ERR("%s: nrf_wifi_sys_fmac_get_power_save_info failed",
219 			__func__);
220 		goto out;
221 	}
222 
223 	do {
224 		nrf_wifi_osal_sleep_ms(1);
225 		 count++;
226 	} while ((vif_ctx_zep->ps_config_info_evnt == false) &&
227 		 (count < NRF_WIFI_FMAC_PS_CONF_EVNT_RECV_TIMEOUT));
228 
229 	if (count == NRF_WIFI_FMAC_PS_CONF_EVNT_RECV_TIMEOUT) {
230 		nrf_wifi_osal_log_err("%s: Timed out",
231 				      __func__);
232 		goto out;
233 	}
234 
235 	ret = 0;
236 out:
237 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
238 	return ret;
239 }
240 
241 /* TWT interval conversion helpers: User <-> Protocol */
nrf_wifi_twt_us_to_float(uint32_t twt_interval)242 static struct twt_interval_float nrf_wifi_twt_us_to_float(uint32_t twt_interval)
243 {
244 	double mantissa = 0.0;
245 	int exponent = 0;
246 	struct twt_interval_float twt_interval_fp;
247 
248 	double twt_interval_ms = twt_interval / 1000.0;
249 
250 	mantissa = frexp(twt_interval_ms, &exponent);
251 	/* Ceiling and conversion to milli seconds */
252 	twt_interval_fp.mantissa = ceil(mantissa * 1000);
253 	twt_interval_fp.exponent = exponent;
254 
255 	return twt_interval_fp;
256 }
257 
nrf_wifi_twt_float_to_us(struct twt_interval_float twt_interval_fp)258 static uint64_t nrf_wifi_twt_float_to_us(struct twt_interval_float twt_interval_fp)
259 {
260 	/* Conversion to micro-seconds */
261 	return floor(ldexp(twt_interval_fp.mantissa, twt_interval_fp.exponent) / (1000)) *
262 			     1000;
263 }
264 
twt_wifi_mgmt_to_rpu_neg_type(enum wifi_twt_negotiation_type neg_type)265 static unsigned char twt_wifi_mgmt_to_rpu_neg_type(enum wifi_twt_negotiation_type neg_type)
266 {
267 	unsigned char rpu_neg_type = 0;
268 
269 	switch (neg_type) {
270 	case WIFI_TWT_INDIVIDUAL:
271 		rpu_neg_type = NRF_WIFI_TWT_NEGOTIATION_TYPE_INDIVIDUAL;
272 		break;
273 	case WIFI_TWT_BROADCAST:
274 		rpu_neg_type = NRF_WIFI_TWT_NEGOTIATION_TYPE_BROADCAST;
275 		break;
276 	default:
277 		LOG_ERR("%s: Invalid negotiation type: %d",
278 			__func__, neg_type);
279 		break;
280 	}
281 
282 	return rpu_neg_type;
283 }
284 
twt_rpu_to_wifi_mgmt_neg_type(unsigned char neg_type)285 static enum wifi_twt_negotiation_type twt_rpu_to_wifi_mgmt_neg_type(unsigned char neg_type)
286 {
287 	enum wifi_twt_negotiation_type wifi_neg_type = WIFI_TWT_INDIVIDUAL;
288 
289 	switch (neg_type) {
290 	case NRF_WIFI_TWT_NEGOTIATION_TYPE_INDIVIDUAL:
291 		wifi_neg_type = WIFI_TWT_INDIVIDUAL;
292 		break;
293 	case NRF_WIFI_TWT_NEGOTIATION_TYPE_BROADCAST:
294 		wifi_neg_type = WIFI_TWT_BROADCAST;
295 		break;
296 	default:
297 		LOG_ERR("%s: Invalid negotiation type: %d",
298 			__func__, neg_type);
299 		break;
300 	}
301 
302 	return wifi_neg_type;
303 }
304 
305 /* Though setup_cmd enums have 1-1 mapping but due to data type different need these */
twt_rpu_to_wifi_mgmt_setup_cmd(signed int setup_cmd)306 static enum wifi_twt_setup_cmd twt_rpu_to_wifi_mgmt_setup_cmd(signed int setup_cmd)
307 {
308 	enum wifi_twt_setup_cmd wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST;
309 
310 	switch (setup_cmd) {
311 	case NRF_WIFI_REQUEST_TWT:
312 		wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REQUEST;
313 		break;
314 	case NRF_WIFI_SUGGEST_TWT:
315 		wifi_setup_cmd = WIFI_TWT_SETUP_CMD_SUGGEST;
316 		break;
317 	case NRF_WIFI_DEMAND_TWT:
318 		wifi_setup_cmd = WIFI_TWT_SETUP_CMD_DEMAND;
319 		break;
320 	case NRF_WIFI_GROUPING_TWT:
321 		wifi_setup_cmd = WIFI_TWT_SETUP_CMD_GROUPING;
322 		break;
323 	case NRF_WIFI_ACCEPT_TWT:
324 		wifi_setup_cmd = WIFI_TWT_SETUP_CMD_ACCEPT;
325 		break;
326 	case NRF_WIFI_ALTERNATE_TWT:
327 		wifi_setup_cmd = WIFI_TWT_SETUP_CMD_ALTERNATE;
328 		break;
329 	case NRF_WIFI_DICTATE_TWT:
330 		wifi_setup_cmd = WIFI_TWT_SETUP_CMD_DICTATE;
331 		break;
332 	case NRF_WIFI_REJECT_TWT:
333 		wifi_setup_cmd = WIFI_TWT_SETUP_CMD_REJECT;
334 		break;
335 	default:
336 		LOG_ERR("%s: Invalid setup command: %d",
337 			__func__, setup_cmd);
338 		break;
339 	}
340 
341 	return wifi_setup_cmd;
342 }
343 
twt_wifi_mgmt_to_rpu_setup_cmd(enum wifi_twt_setup_cmd setup_cmd)344 static signed int twt_wifi_mgmt_to_rpu_setup_cmd(enum wifi_twt_setup_cmd setup_cmd)
345 {
346 	signed int rpu_setup_cmd = NRF_WIFI_REQUEST_TWT;
347 
348 	switch (setup_cmd) {
349 	case WIFI_TWT_SETUP_CMD_REQUEST:
350 		rpu_setup_cmd = NRF_WIFI_REQUEST_TWT;
351 		break;
352 	case WIFI_TWT_SETUP_CMD_SUGGEST:
353 		rpu_setup_cmd = NRF_WIFI_SUGGEST_TWT;
354 		break;
355 	case WIFI_TWT_SETUP_CMD_DEMAND:
356 		rpu_setup_cmd = NRF_WIFI_DEMAND_TWT;
357 		break;
358 	case WIFI_TWT_SETUP_CMD_GROUPING:
359 		rpu_setup_cmd = NRF_WIFI_GROUPING_TWT;
360 		break;
361 	case WIFI_TWT_SETUP_CMD_ACCEPT:
362 		rpu_setup_cmd = NRF_WIFI_ACCEPT_TWT;
363 		break;
364 	case WIFI_TWT_SETUP_CMD_ALTERNATE:
365 		rpu_setup_cmd = NRF_WIFI_ALTERNATE_TWT;
366 		break;
367 	case WIFI_TWT_SETUP_CMD_DICTATE:
368 		rpu_setup_cmd = NRF_WIFI_DICTATE_TWT;
369 		break;
370 	case WIFI_TWT_SETUP_CMD_REJECT:
371 		rpu_setup_cmd = NRF_WIFI_REJECT_TWT;
372 		break;
373 	default:
374 		LOG_ERR("%s: Invalid setup command: %d",
375 			__func__, setup_cmd);
376 		break;
377 	}
378 
379 	return rpu_setup_cmd;
380 }
381 
nrf_wifi_event_proc_get_power_save_info(void * vif_ctx,struct nrf_wifi_umac_event_power_save_info * ps_info,unsigned int event_len)382 void nrf_wifi_event_proc_get_power_save_info(void *vif_ctx,
383 					     struct nrf_wifi_umac_event_power_save_info *ps_info,
384 					     unsigned int event_len)
385 {
386 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
387 
388 	if (!vif_ctx || !ps_info) {
389 		return;
390 	}
391 
392 	vif_ctx_zep = vif_ctx;
393 
394 	vif_ctx_zep->ps_info->ps_params.mode = ps_info->ps_mode;
395 	vif_ctx_zep->ps_info->ps_params.enabled = ps_info->enabled;
396 	vif_ctx_zep->ps_info->num_twt_flows = ps_info->num_twt_flows;
397 	vif_ctx_zep->ps_info->ps_params.timeout_ms = ps_info->ps_timeout;
398 	vif_ctx_zep->ps_info->ps_params.listen_interval = ps_info->listen_interval;
399 	vif_ctx_zep->ps_info->ps_params.wakeup_mode = ps_info->extended_ps;
400 	if (ps_info->ps_exit_strategy == EVERY_TIM) {
401 		vif_ctx_zep->ps_info->ps_params.exit_strategy = WIFI_PS_EXIT_EVERY_TIM;
402 	} else if (ps_info->ps_exit_strategy == INT_PS) {
403 		vif_ctx_zep->ps_info->ps_params.exit_strategy = WIFI_PS_EXIT_CUSTOM_ALGO;
404 	}
405 
406 	for (int i = 0; i < ps_info->num_twt_flows; i++) {
407 		struct twt_interval_float twt_interval_fp;
408 		struct wifi_twt_flow_info *twt_zep = &vif_ctx_zep->ps_info->twt_flows[i];
409 		struct nrf_wifi_umac_config_twt_info *twt_rpu = &ps_info->twt_flow_info[i];
410 
411 		memset(twt_zep, 0, sizeof(struct wifi_twt_flow_info));
412 
413 		twt_zep->flow_id = twt_rpu->twt_flow_id;
414 		twt_zep->implicit = twt_rpu->is_implicit ? 1 : 0;
415 		twt_zep->trigger = twt_rpu->ap_trigger_frame ? 1 : 0;
416 		twt_zep->announce = twt_rpu->twt_flow_type == NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED;
417 		twt_zep->negotiation_type = twt_rpu_to_wifi_mgmt_neg_type(twt_rpu->neg_type);
418 		twt_zep->dialog_token = twt_rpu->dialog_token;
419 		twt_interval_fp.mantissa = twt_rpu->twt_target_wake_interval_mantissa;
420 		twt_interval_fp.exponent = twt_rpu->twt_target_wake_interval_exponent;
421 		twt_zep->twt_interval = nrf_wifi_twt_float_to_us(twt_interval_fp);
422 		twt_zep->twt_wake_interval = twt_rpu->nominal_min_twt_wake_duration;
423 	}
424 
425 	vif_ctx_zep->ps_config_info_evnt = true;
426 }
427 
nrf_wifi_twt_update_internal_state(struct nrf_wifi_vif_ctx_zep * vif_ctx_zep,bool setup,unsigned char flow_id)428 static void nrf_wifi_twt_update_internal_state(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep,
429 	bool setup, unsigned char flow_id)
430 {
431 	if (setup) {
432 		vif_ctx_zep->twt_flows_map |= BIT(flow_id);
433 		vif_ctx_zep->twt_flow_in_progress_map &= ~BIT(flow_id);
434 	} else {
435 		vif_ctx_zep->twt_flows_map &= ~BIT(flow_id);
436 	}
437 }
438 
nrf_wifi_twt_teardown_flows(struct nrf_wifi_vif_ctx_zep * vif_ctx_zep,unsigned char start_flow_id,unsigned char end_flow_id)439 int nrf_wifi_twt_teardown_flows(struct nrf_wifi_vif_ctx_zep *vif_ctx_zep,
440 		unsigned char start_flow_id, unsigned char end_flow_id)
441 {
442 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
443 	struct nrf_wifi_umac_config_twt_info twt_info = {0};
444 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
445 	int ret = 0;
446 	struct wifi_twt_params twt_params = {0};
447 
448 	if (!vif_ctx_zep) {
449 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
450 		return ret;
451 	}
452 
453 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
454 
455 	if (!rpu_ctx_zep) {
456 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
457 		return ret;
458 	}
459 
460 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
461 	if (!rpu_ctx_zep->rpu_ctx) {
462 		LOG_DBG("%s: RPU context not initialized", __func__);
463 		goto out;
464 	}
465 
466 	for (int flow_id = start_flow_id; flow_id < end_flow_id; flow_id++) {
467 		if (!(vif_ctx_zep->twt_flows_map & BIT(flow_id))) {
468 			continue;
469 		}
470 		twt_info.twt_flow_id = flow_id;
471 		status = nrf_wifi_sys_fmac_twt_teardown(rpu_ctx_zep->rpu_ctx,
472 						vif_ctx_zep->vif_idx,
473 						&twt_info);
474 		if (status != NRF_WIFI_STATUS_SUCCESS) {
475 			LOG_ERR("%s: TWT teardown for flow id %d failed",
476 				__func__, flow_id);
477 			ret = -1;
478 			continue;
479 		}
480 		/* UMAC doesn't send TWT teardown event for host initiated teardown */
481 		nrf_wifi_twt_update_internal_state(vif_ctx_zep, false, flow_id);
482 		/* TODO: Remove this once UMAC sends the status */
483 		twt_params.operation = WIFI_TWT_TEARDOWN;
484 		twt_params.flow_id = flow_id;
485 		twt_params.teardown_status = WIFI_TWT_TEARDOWN_SUCCESS;
486 		wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params);
487 	}
488 
489 out:
490 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
491 	return ret;
492 }
493 
nrf_wifi_set_twt(const struct device * dev,struct wifi_twt_params * twt_params)494 int nrf_wifi_set_twt(const struct device *dev,
495 		     struct wifi_twt_params *twt_params)
496 {
497 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
498 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
499 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
500 	struct nrf_wifi_umac_config_twt_info twt_info = {0};
501 	int ret = -1;
502 
503 	if (!dev || !twt_params) {
504 		LOG_ERR("%s: dev or twt_params is NULL", __func__);
505 		return ret;
506 	}
507 
508 	vif_ctx_zep = dev->data;
509 
510 	if (!vif_ctx_zep) {
511 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
512 		return ret;
513 	}
514 
515 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
516 
517 	if (!rpu_ctx_zep) {
518 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
519 		return ret;
520 	}
521 
522 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
523 	if (!rpu_ctx_zep->rpu_ctx) {
524 		LOG_DBG("%s: RPU context not initialized", __func__);
525 		goto out;
526 	}
527 
528 	if (!(twt_params->operation == WIFI_TWT_TEARDOWN && twt_params->teardown.teardown_all) &&
529 		twt_params->flow_id >= WIFI_MAX_TWT_FLOWS) {
530 		LOG_ERR("%s: Invalid flow id: %d",
531 			__func__, twt_params->flow_id);
532 		twt_params->fail_reason = WIFI_TWT_FAIL_INVALID_FLOW_ID;
533 		goto out;
534 	}
535 
536 	switch (twt_params->operation) {
537 	case WIFI_TWT_SETUP:
538 		if (vif_ctx_zep->twt_flow_in_progress_map & BIT(twt_params->flow_id)) {
539 			twt_params->fail_reason = WIFI_TWT_FAIL_OPERATION_IN_PROGRESS;
540 			goto out;
541 		}
542 
543 		if (twt_params->setup_cmd == WIFI_TWT_SETUP_CMD_REQUEST) {
544 			if (vif_ctx_zep->twt_flows_map & BIT(twt_params->flow_id)) {
545 				twt_params->fail_reason = WIFI_TWT_FAIL_FLOW_ALREADY_EXISTS;
546 				goto out;
547 			}
548 		}
549 
550 		struct twt_interval_float twt_interval_fp =
551 			nrf_wifi_twt_us_to_float(twt_params->setup.twt_interval);
552 
553 		twt_info.twt_flow_id = twt_params->flow_id;
554 		twt_info.neg_type = twt_wifi_mgmt_to_rpu_neg_type(twt_params->negotiation_type);
555 		twt_info.setup_cmd = twt_wifi_mgmt_to_rpu_setup_cmd(twt_params->setup_cmd);
556 		twt_info.ap_trigger_frame = twt_params->setup.trigger;
557 		twt_info.is_implicit = twt_params->setup.implicit;
558 		if (twt_params->setup.announce) {
559 			twt_info.twt_flow_type = NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED;
560 		} else {
561 			twt_info.twt_flow_type = NRF_WIFI_TWT_FLOW_TYPE_UNANNOUNCED;
562 		}
563 
564 		twt_info.nominal_min_twt_wake_duration =
565 				twt_params->setup.twt_wake_interval;
566 		twt_info.twt_target_wake_interval_mantissa = twt_interval_fp.mantissa;
567 		twt_info.twt_target_wake_interval_exponent = twt_interval_fp.exponent;
568 
569 		twt_info.dialog_token = twt_params->dialog_token;
570 		twt_info.twt_wake_ahead_duration = twt_params->setup.twt_wake_ahead_duration;
571 
572 		status = nrf_wifi_sys_fmac_twt_setup(rpu_ctx_zep->rpu_ctx,
573 					   vif_ctx_zep->vif_idx,
574 					   &twt_info);
575 
576 		break;
577 	case WIFI_TWT_TEARDOWN:
578 		unsigned char start_flow_id = 0;
579 		unsigned char end_flow_id = WIFI_MAX_TWT_FLOWS;
580 
581 		if (!twt_params->teardown.teardown_all) {
582 			if (!(vif_ctx_zep->twt_flows_map & BIT(twt_params->flow_id))) {
583 				twt_params->fail_reason = WIFI_TWT_FAIL_INVALID_FLOW_ID;
584 				goto out;
585 			}
586 			start_flow_id = twt_params->flow_id;
587 			end_flow_id = twt_params->flow_id + 1;
588 			twt_info.twt_flow_id = twt_params->flow_id;
589 		}
590 
591 		status = nrf_wifi_twt_teardown_flows(vif_ctx_zep,
592 						     start_flow_id,
593 						     end_flow_id);
594 		if (status != NRF_WIFI_STATUS_SUCCESS) {
595 			LOG_ERR("%s: TWT teardown failed: start_flow_id: %d, end_flow_id: %d",
596 				__func__, start_flow_id, end_flow_id);
597 			goto out;
598 		}
599 		break;
600 
601 	default:
602 		LOG_ERR("Unknown TWT operation");
603 		status = NRF_WIFI_STATUS_FAIL;
604 		break;
605 	}
606 
607 	if (status != NRF_WIFI_STATUS_SUCCESS) {
608 		LOG_ERR("%s: Failed", __func__);
609 		goto out;
610 	}
611 
612 	ret = 0;
613 out:
614 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
615 	return ret;
616 }
617 
nrf_wifi_event_proc_twt_setup_zep(void * vif_ctx,struct nrf_wifi_umac_cmd_config_twt * twt_setup_info,unsigned int event_len)618 void nrf_wifi_event_proc_twt_setup_zep(void *vif_ctx,
619 				       struct nrf_wifi_umac_cmd_config_twt *twt_setup_info,
620 				       unsigned int event_len)
621 {
622 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
623 	struct wifi_twt_params twt_params = { 0 };
624 	struct twt_interval_float twt_interval_fp = { 0 };
625 
626 	if (!vif_ctx || !twt_setup_info) {
627 		return;
628 	}
629 
630 	vif_ctx_zep = vif_ctx;
631 
632 	twt_params.operation = WIFI_TWT_SETUP;
633 	twt_params.flow_id = twt_setup_info->info.twt_flow_id;
634 	twt_params.negotiation_type = twt_rpu_to_wifi_mgmt_neg_type(twt_setup_info->info.neg_type);
635 	twt_params.setup_cmd = twt_rpu_to_wifi_mgmt_setup_cmd(twt_setup_info->info.setup_cmd);
636 	twt_params.setup.trigger = twt_setup_info->info.ap_trigger_frame ? 1 : 0;
637 	twt_params.setup.implicit = twt_setup_info->info.is_implicit ? 1 : 0;
638 	twt_params.setup.announce =
639 		twt_setup_info->info.twt_flow_type == NRF_WIFI_TWT_FLOW_TYPE_ANNOUNCED;
640 	twt_params.setup.twt_wake_interval =
641 			twt_setup_info->info.nominal_min_twt_wake_duration;
642 	twt_interval_fp.mantissa = twt_setup_info->info.twt_target_wake_interval_mantissa;
643 	twt_interval_fp.exponent = twt_setup_info->info.twt_target_wake_interval_exponent;
644 	twt_params.setup.twt_interval = nrf_wifi_twt_float_to_us(twt_interval_fp);
645 	twt_params.dialog_token = twt_setup_info->info.dialog_token;
646 	twt_params.resp_status = twt_setup_info->info.twt_resp_status;
647 
648 	if ((twt_setup_info->info.twt_resp_status == 0) ||
649 	    (twt_setup_info->info.neg_type == NRF_WIFI_ACCEPT_TWT)) {
650 		nrf_wifi_twt_update_internal_state(vif_ctx_zep, true, twt_params.flow_id);
651 	}
652 
653 	wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params);
654 }
655 
656 
nrf_wifi_event_proc_twt_teardown_zep(void * vif_ctx,struct nrf_wifi_umac_cmd_teardown_twt * twt_teardown_info,unsigned int event_len)657 void nrf_wifi_event_proc_twt_teardown_zep(void *vif_ctx,
658 					  struct nrf_wifi_umac_cmd_teardown_twt *twt_teardown_info,
659 					  unsigned int event_len)
660 {
661 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
662 	struct wifi_twt_params twt_params = {0};
663 
664 	if (!vif_ctx || !twt_teardown_info) {
665 		return;
666 	}
667 
668 	vif_ctx_zep = vif_ctx;
669 
670 	twt_params.operation = WIFI_TWT_TEARDOWN;
671 	twt_params.flow_id = twt_teardown_info->info.twt_flow_id;
672 	/* TODO: ADD reason code in the twt_params structure */
673 	nrf_wifi_twt_update_internal_state(vif_ctx_zep, false, twt_params.flow_id);
674 
675 	wifi_mgmt_raise_twt_event(vif_ctx_zep->zep_net_if_ctx, &twt_params);
676 }
677 
nrf_wifi_event_proc_twt_sleep_zep(void * vif_ctx,struct nrf_wifi_umac_event_twt_sleep * sleep_evnt,unsigned int event_len)678 void nrf_wifi_event_proc_twt_sleep_zep(void *vif_ctx,
679 					struct nrf_wifi_umac_event_twt_sleep *sleep_evnt,
680 					unsigned int event_len)
681 {
682 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
683 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
684 	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
685 	struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL;
686 	struct nrf_wifi_sys_fmac_priv *sys_fpriv = NULL;
687 #ifdef CONFIG_NRF70_DATA_TX
688 	int desc = 0;
689 	int ac = 0;
690 #endif
691 	vif_ctx_zep = vif_ctx;
692 
693 	if (!vif_ctx_zep) {
694 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
695 		return;
696 	}
697 
698 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
699 	if (!rpu_ctx_zep) {
700 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
701 		return;
702 	}
703 
704 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
705 	if (!rpu_ctx_zep->rpu_ctx) {
706 		LOG_DBG("%s: RPU context not initialized", __func__);
707 		goto out;
708 	}
709 
710 	fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
711 	sys_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
712 	sys_fpriv = wifi_fmac_priv(fmac_dev_ctx->fpriv);
713 
714 	if (!sleep_evnt) {
715 		LOG_ERR("%s: sleep_evnt is NULL", __func__);
716 		return;
717 	}
718 
719 	switch (sleep_evnt->info.type) {
720 	case TWT_BLOCK_TX:
721 		nrf_wifi_osal_spinlock_take(sys_dev_ctx->tx_config.tx_lock);
722 
723 		sys_dev_ctx->twt_sleep_status = NRF_WIFI_FMAC_TWT_STATE_SLEEP;
724 
725 		wifi_mgmt_raise_twt_sleep_state(vif_ctx_zep->zep_net_if_ctx,
726 						WIFI_TWT_STATE_SLEEP);
727 		nrf_wifi_osal_spinlock_rel(sys_dev_ctx->tx_config.tx_lock);
728 	break;
729 	case TWT_UNBLOCK_TX:
730 		nrf_wifi_osal_spinlock_take(sys_dev_ctx->tx_config.tx_lock);
731 		sys_dev_ctx->twt_sleep_status = NRF_WIFI_FMAC_TWT_STATE_AWAKE;
732 		wifi_mgmt_raise_twt_sleep_state(vif_ctx_zep->zep_net_if_ctx,
733 						WIFI_TWT_STATE_AWAKE);
734 #ifdef CONFIG_NRF70_DATA_TX
735 		for (ac = NRF_WIFI_FMAC_AC_BE;
736 		     ac <= NRF_WIFI_FMAC_AC_MAX; ++ac) {
737 			desc = tx_desc_get(fmac_dev_ctx, ac);
738 			if (desc < sys_fpriv->num_tx_tokens) {
739 				tx_pending_process(fmac_dev_ctx, desc, ac);
740 			}
741 		}
742 #endif
743 		nrf_wifi_osal_spinlock_rel(sys_dev_ctx->tx_config.tx_lock);
744 	break;
745 	default:
746 	break;
747 	}
748 out:
749 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
750 }
751 
752 #ifdef CONFIG_NRF70_SYSTEM_WITH_RAW_MODES
nrf_wifi_mode(const struct device * dev,struct wifi_mode_info * mode)753 int nrf_wifi_mode(const struct device *dev,
754 		  struct wifi_mode_info *mode)
755 {
756 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
757 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
758 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
759 	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
760 	struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL;
761 	int ret = -1;
762 
763 	if (!dev || !mode) {
764 		LOG_ERR("%s: illegal input parameters", __func__);
765 		return ret;
766 	}
767 
768 	vif_ctx_zep = dev->data;
769 	if (!vif_ctx_zep) {
770 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
771 		return ret;
772 	}
773 
774 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
775 	if (!rpu_ctx_zep) {
776 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
777 		return ret;
778 	}
779 
780 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
781 	if (!rpu_ctx_zep->rpu_ctx) {
782 		LOG_DBG("%s: RPU context not initialized", __func__);
783 		goto out;
784 	}
785 
786 	fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
787 	sys_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
788 
789 	if (!device_is_ready(dev)) {
790 		LOG_ERR("%s: Device %s is not ready",
791 			__func__, dev->name);
792 		goto out;
793 	}
794 
795 	if (mode->oper == WIFI_MGMT_SET) {
796 		status = nrf_wifi_check_mode_validity(mode->mode);
797 		if (status != NRF_WIFI_STATUS_SUCCESS) {
798 			LOG_ERR("%s: mode setting is not valid", __func__);
799 			goto out;
800 		}
801 
802 		if (vif_ctx_zep->authorized && (mode->mode == NRF_WIFI_MONITOR_MODE)) {
803 			LOG_ERR("%s: Cannot set monitor mode when station is connected",
804 				__func__);
805 			goto out;
806 		}
807 
808 		/**
809 		 * Send the driver vif_idx instead of upper layer sent if_index.
810 		 * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep
811 		 * context maps the correct network interface index to current driver
812 		 * interface index.
813 		 */
814 		status = nrf_wifi_sys_fmac_set_mode(rpu_ctx_zep->rpu_ctx,
815 						    vif_ctx_zep->vif_idx,
816 						    mode->mode);
817 		if (status != NRF_WIFI_STATUS_SUCCESS) {
818 			LOG_ERR("%s: mode set operation failed", __func__);
819 			goto out;
820 		}
821 
822 	} else {
823 		mode->mode = sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode;
824 		/**
825 		 * This is a work-around to handle current UMAC mode handling.
826 		 * This might be removed in future versions when UMAC has more space.
827 		 */
828 #ifdef CONFIG_NRF70_RAW_DATA_TX
829 		if (sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->txinjection_mode == true) {
830 			mode->mode ^= NRF_WIFI_TX_INJECTION_MODE;
831 		}
832 #endif /* CONFIG_NRF70_RAW_DATA_TX */
833 #ifdef CONFIG_NRF70_PROMISC_DATA_RX
834 		if (sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->promisc_mode == true) {
835 			mode->mode ^= NRF_WIFI_PROMISCUOUS_MODE;
836 		}
837 #endif /* CONFIG_NRF70_PROMISC_DATA_RX */
838 	}
839 	ret = 0;
840 out:
841 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
842 	return ret;
843 }
844 #endif /* CONFIG_NRF70_SYSTEM_WITH_RAW_MODES */
845 
846 #if defined(CONFIG_NRF70_RAW_DATA_TX) || defined(CONFIG_NRF70_RAW_DATA_RX)
nrf_wifi_channel(const struct device * dev,struct wifi_channel_info * channel)847 int nrf_wifi_channel(const struct device *dev,
848 		     struct wifi_channel_info *channel)
849 {
850 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
851 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
852 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
853 	struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL;
854 	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
855 	int ret = -1;
856 
857 	if (!dev || !channel) {
858 		LOG_ERR("%s: illegal input parameters", __func__);
859 		return ret;
860 	}
861 
862 	vif_ctx_zep = dev->data;
863 	if (!vif_ctx_zep) {
864 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
865 		return ret;
866 	}
867 
868 	if (vif_ctx_zep->authorized) {
869 		LOG_ERR("%s: Cannot change channel when in station connected mode", __func__);
870 		return ret;
871 	}
872 
873 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
874 	if (!rpu_ctx_zep) {
875 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
876 		return ret;
877 	}
878 
879 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
880 	if (!rpu_ctx_zep->rpu_ctx) {
881 		LOG_DBG("%s: RPU context not initialized", __func__);
882 		goto out;
883 	}
884 
885 	fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
886 	sys_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
887 
888 	if (channel->oper == WIFI_MGMT_SET) {
889 		/**
890 		 * Send the driver vif_idx instead of upper layer sent if_index.
891 		 * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep
892 		 * context maps the correct network interface index to current driver
893 		 * interface index.
894 		 */
895 		status = nrf_wifi_sys_fmac_set_channel(rpu_ctx_zep->rpu_ctx,
896 						       vif_ctx_zep->vif_idx,
897 						       channel->channel);
898 
899 		if (status != NRF_WIFI_STATUS_SUCCESS) {
900 			LOG_ERR("%s: set channel failed", __func__);
901 			goto out;
902 		}
903 	} else {
904 		channel->channel = sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->channel;
905 	}
906 	ret = 0;
907 out:
908 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
909 	return ret;
910 }
911 #endif /* CONFIG_NRF70_RAW_DATA_TX || CONFIG_NRF70_RAW_DATA_RX */
912 
913 #if defined(CONFIG_NRF70_RAW_DATA_RX) || defined(CONFIG_NRF70_PROMISC_DATA_RX)
nrf_wifi_filter(const struct device * dev,struct wifi_filter_info * filter)914 int nrf_wifi_filter(const struct device *dev,
915 		    struct wifi_filter_info *filter)
916 {
917 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
918 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
919 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
920 	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
921 	struct nrf_wifi_sys_fmac_dev_ctx *sys_dev_ctx = NULL;
922 	int ret = -1;
923 
924 	if (!dev || !filter) {
925 		LOG_ERR("%s: Illegal input parameters", __func__);
926 		goto out;
927 	}
928 
929 	vif_ctx_zep = dev->data;
930 	if (!vif_ctx_zep) {
931 		LOG_ERR("%s: vif_ctx_zep is NULL\n", __func__);
932 		goto out;
933 	}
934 
935 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
936 	fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
937 	sys_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
938 
939 	if (filter->oper == WIFI_MGMT_SET) {
940 		/**
941 		 * If promiscuous mode is enabled, filter settings
942 		 * cannot be plumbed to the lower layers as that might
943 		 * affect connectivity. Save the filter settings in the
944 		 * driver and filter packet type on packet receive by
945 		 * checking the 802.11 header in the packet
946 		 */
947 		if (((sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode) &
948 		    (NRF_WIFI_PROMISCUOUS_MODE)) == NRF_WIFI_PROMISCUOUS_MODE) {
949 			sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter =
950 				filter->filter;
951 			ret = 0;
952 			goto out;
953 		}
954 
955 		/**
956 		 * In case a user sets data + management + ctrl bits
957 		 * or all the filter bits. Map it to bit 0 set to
958 		 * enable "all" packet filter bit setting.
959 		 * In case only filter packet size is configured and filter
960 		 * setting is sent as zero, set the filter value to
961 		 * previously configured value.
962 		 */
963 		if (filter->filter == WIFI_MGMT_DATA_CTRL_FILTER_SETTING
964 		    || filter->filter == WIFI_ALL_FILTER_SETTING) {
965 			filter->filter = 1;
966 		} else if (filter->filter == 0) {
967 			filter->filter =
968 				sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter;
969 		}
970 
971 		/**
972 		 * Send the driver vif_idx instead of upper layer sent if_index.
973 		 * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep
974 		 * context maps the correct network interface index to current driver
975 		 * interface index
976 		 */
977 		status = nrf_wifi_sys_fmac_set_packet_filter(rpu_ctx_zep->rpu_ctx,
978 							     filter->filter,
979 							     vif_ctx_zep->vif_idx,
980 							     filter->buffer_size);
981 		if (status != NRF_WIFI_STATUS_SUCCESS) {
982 			LOG_ERR("%s: Set filter operation failed\n", __func__);
983 			goto out;
984 		}
985 	} else {
986 		filter->filter = sys_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter;
987 	}
988 	ret = 0;
989 out:
990 	return ret;
991 }
992 #endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
993 
nrf_wifi_set_rts_threshold(const struct device * dev,unsigned int rts_threshold)994 int nrf_wifi_set_rts_threshold(const struct device *dev,
995 			       unsigned int rts_threshold)
996 {
997 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
998 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
999 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
1000 	struct nrf_wifi_umac_set_wiphy_info wiphy_info;
1001 	int ret = -1;
1002 
1003 	if (!dev) {
1004 		LOG_ERR("%s: dev is NULL", __func__);
1005 		return ret;
1006 	}
1007 
1008 	vif_ctx_zep = dev->data;
1009 
1010 	if (!vif_ctx_zep) {
1011 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
1012 		return ret;
1013 	}
1014 
1015 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
1016 
1017 	if (!rpu_ctx_zep) {
1018 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
1019 		return ret;
1020 	}
1021 
1022 
1023 	if (!rpu_ctx_zep->rpu_ctx) {
1024 		LOG_ERR("%s: RPU context not initialized", __func__);
1025 		return ret;
1026 	}
1027 
1028 	if ((int)rts_threshold < -1) {
1029 		/* 0 or any positive value is passed to f/w.
1030 		 * For RTS off, -1 is passed to f/w.
1031 		 * All other negative values considered as invalid.
1032 		 */
1033 		LOG_ERR("%s: Invalid threshold value : %d", __func__, (int)rts_threshold);
1034 		return ret;
1035 	}
1036 
1037 	memset(&wiphy_info, 0, sizeof(struct nrf_wifi_umac_set_wiphy_info));
1038 
1039 	wiphy_info.rts_threshold = (int)rts_threshold;
1040 
1041 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
1042 
1043 	status = nrf_wifi_sys_fmac_set_wiphy_params(rpu_ctx_zep->rpu_ctx,
1044 						vif_ctx_zep->vif_idx,
1045 						&wiphy_info);
1046 
1047 	if (status != NRF_WIFI_STATUS_SUCCESS) {
1048 		LOG_ERR("%s: Configuring rts threshold failed\n", __func__);
1049 		goto out;
1050 	}
1051 
1052 	vif_ctx_zep->rts_threshold_value = (int)rts_threshold;
1053 
1054 	ret = 0;
1055 out:
1056 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
1057 
1058 	return ret;
1059 }
1060 
nrf_wifi_get_rts_threshold(const struct device * dev,unsigned int * rts_threshold)1061 int nrf_wifi_get_rts_threshold(const struct device *dev,
1062 			       unsigned int *rts_threshold)
1063 {
1064 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
1065 	int ret = -1;
1066 
1067 	if (!dev) {
1068 		LOG_ERR("%s: dev is NULL", __func__);
1069 		return ret;
1070 	}
1071 
1072 	vif_ctx_zep = dev->data;
1073 	if (!vif_ctx_zep) {
1074 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
1075 		return ret;
1076 	}
1077 
1078 	*rts_threshold = vif_ctx_zep->rts_threshold_value;
1079 	ret = 0;
1080 
1081 	return ret;
1082 }
1083