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 "fmac_api.h"
19 #include "fmac_tx.h"
20 #include "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_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_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_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_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_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_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_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_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_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_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_fmac_dev_ctx_def *def_dev_ctx = NULL;
686 	struct nrf_wifi_fmac_priv_def *def_priv = 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 	def_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
712 	def_priv = 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(def_dev_ctx->tx_config.tx_lock);
722 
723 		def_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(def_dev_ctx->tx_config.tx_lock);
728 	break;
729 	case TWT_UNBLOCK_TX:
730 		nrf_wifi_osal_spinlock_take(def_dev_ctx->tx_config.tx_lock);
731 		def_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 < def_priv->num_tx_tokens) {
739 				tx_pending_process(fmac_dev_ctx, desc, ac);
740 			}
741 		}
742 #endif
743 		nrf_wifi_osal_spinlock_rel(def_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_fmac_dev_ctx_def *def_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 	def_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_fmac_set_mode(rpu_ctx_zep->rpu_ctx,
815 						vif_ctx_zep->vif_idx, mode->mode);
816 		if (status != NRF_WIFI_STATUS_SUCCESS) {
817 			LOG_ERR("%s: mode set operation failed", __func__);
818 			goto out;
819 		}
820 
821 	} else {
822 		mode->mode = def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode;
823 		/**
824 		 * This is a work-around to handle current UMAC mode handling.
825 		 * This might be removed in future versions when UMAC has more space.
826 		 */
827 #ifdef CONFIG_NRF70_RAW_DATA_TX
828 		if (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->txinjection_mode == true) {
829 			mode->mode ^= NRF_WIFI_TX_INJECTION_MODE;
830 		}
831 #endif /* CONFIG_NRF70_RAW_DATA_TX */
832 #ifdef CONFIG_NRF70_PROMISC_DATA_RX
833 		if (def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->promisc_mode == true) {
834 			mode->mode ^= NRF_WIFI_PROMISCUOUS_MODE;
835 		}
836 #endif /* CONFIG_NRF70_PROMISC_DATA_RX */
837 	}
838 	ret = 0;
839 out:
840 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
841 	return ret;
842 }
843 #endif /* CONFIG_NRF70_SYSTEM_WITH_RAW_MODES */
844 
845 #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)846 int nrf_wifi_channel(const struct device *dev,
847 		     struct wifi_channel_info *channel)
848 {
849 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
850 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
851 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
852 	struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL;
853 	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
854 	int ret = -1;
855 
856 	if (!dev || !channel) {
857 		LOG_ERR("%s: illegal input parameters", __func__);
858 		return ret;
859 	}
860 
861 	vif_ctx_zep = dev->data;
862 	if (!vif_ctx_zep) {
863 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
864 		return ret;
865 	}
866 
867 	if (vif_ctx_zep->authorized) {
868 		LOG_ERR("%s: Cannot change channel when in station connected mode", __func__);
869 		return ret;
870 	}
871 
872 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
873 	if (!rpu_ctx_zep) {
874 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
875 		return ret;
876 	}
877 
878 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
879 	if (!rpu_ctx_zep->rpu_ctx) {
880 		LOG_DBG("%s: RPU context not initialized", __func__);
881 		goto out;
882 	}
883 
884 	fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
885 	def_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
886 
887 	if (channel->oper == WIFI_MGMT_SET) {
888 		/**
889 		 * Send the driver vif_idx instead of upper layer sent if_index.
890 		 * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep
891 		 * context maps the correct network interface index to current driver
892 		 * interface index.
893 		 */
894 		status = nrf_wifi_fmac_set_channel(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx,
895 						   channel->channel);
896 
897 		if (status != NRF_WIFI_STATUS_SUCCESS) {
898 			LOG_ERR("%s: set channel failed", __func__);
899 			goto out;
900 		}
901 	} else {
902 		channel->channel = def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->channel;
903 	}
904 	ret = 0;
905 out:
906 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
907 	return ret;
908 }
909 #endif /* CONFIG_NRF70_RAW_DATA_TX || CONFIG_NRF70_RAW_DATA_RX */
910 
911 #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)912 int nrf_wifi_filter(const struct device *dev,
913 		    struct wifi_filter_info *filter)
914 {
915 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
916 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
917 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
918 	struct nrf_wifi_fmac_dev_ctx *fmac_dev_ctx = NULL;
919 	struct nrf_wifi_fmac_dev_ctx_def *def_dev_ctx = NULL;
920 	int ret = -1;
921 
922 	if (!dev || !filter) {
923 		LOG_ERR("%s: Illegal input parameters", __func__);
924 		goto out;
925 	}
926 
927 	vif_ctx_zep = dev->data;
928 	if (!vif_ctx_zep) {
929 		LOG_ERR("%s: vif_ctx_zep is NULL\n", __func__);
930 		goto out;
931 	}
932 
933 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
934 	fmac_dev_ctx = rpu_ctx_zep->rpu_ctx;
935 	def_dev_ctx = wifi_dev_priv(fmac_dev_ctx);
936 
937 	if (filter->oper == WIFI_MGMT_SET) {
938 		/**
939 		 * If promiscuous mode is enabled, filter settings
940 		 * cannot be plumbed to the lower layers as that might
941 		 * affect connectivity. Save the filter settings in the
942 		 * driver and filter packet type on packet receive by
943 		 * checking the 802.11 header in the packet
944 		 */
945 		if (((def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->mode) &
946 		    (NRF_WIFI_PROMISCUOUS_MODE)) == NRF_WIFI_PROMISCUOUS_MODE) {
947 			def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter =
948 				filter->filter;
949 			ret = 0;
950 			goto out;
951 		}
952 
953 		/**
954 		 * In case a user sets data + management + ctrl bits
955 		 * or all the filter bits. Map it to bit 0 set to
956 		 * enable "all" packet filter bit setting.
957 		 * In case only filter packet size is configured and filter
958 		 * setting is sent as zero, set the filter value to
959 		 * previously configured value.
960 		 */
961 		if (filter->filter == WIFI_MGMT_DATA_CTRL_FILTER_SETTING
962 		    || filter->filter == WIFI_ALL_FILTER_SETTING) {
963 			filter->filter = 1;
964 		} else if (filter->filter == 0) {
965 			filter->filter =
966 				def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter;
967 		}
968 
969 		/**
970 		 * Send the driver vif_idx instead of upper layer sent if_index.
971 		 * we map network if_index 1 to vif_idx of 0 and so on. The vif_ctx_zep
972 		 * context maps the correct network interface index to current driver
973 		 * interface index
974 		 */
975 		status = nrf_wifi_fmac_set_packet_filter(rpu_ctx_zep->rpu_ctx, filter->filter,
976 							 vif_ctx_zep->vif_idx, filter->buffer_size);
977 		if (status != NRF_WIFI_STATUS_SUCCESS) {
978 			LOG_ERR("%s: Set filter operation failed\n", __func__);
979 			goto out;
980 		}
981 	} else {
982 		filter->filter = def_dev_ctx->vif_ctx[vif_ctx_zep->vif_idx]->packet_filter;
983 	}
984 	ret = 0;
985 out:
986 	return ret;
987 }
988 #endif /* CONFIG_NRF70_RAW_DATA_RX || CONFIG_NRF70_PROMISC_DATA_RX */
989 
nrf_wifi_set_rts_threshold(const struct device * dev,unsigned int rts_threshold)990 int nrf_wifi_set_rts_threshold(const struct device *dev,
991 			       unsigned int rts_threshold)
992 {
993 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
994 	struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL;
995 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
996 	struct nrf_wifi_umac_set_wiphy_info wiphy_info;
997 	int ret = -1;
998 
999 	if (!dev) {
1000 		LOG_ERR("%s: dev is NULL", __func__);
1001 		return ret;
1002 	}
1003 
1004 	vif_ctx_zep = dev->data;
1005 
1006 	if (!vif_ctx_zep) {
1007 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
1008 		return ret;
1009 	}
1010 
1011 	rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep;
1012 
1013 	if (!rpu_ctx_zep) {
1014 		LOG_ERR("%s: rpu_ctx_zep is NULL", __func__);
1015 		return ret;
1016 	}
1017 
1018 
1019 	if (!rpu_ctx_zep->rpu_ctx) {
1020 		LOG_ERR("%s: RPU context not initialized", __func__);
1021 		return ret;
1022 	}
1023 
1024 	if ((int)rts_threshold < -1) {
1025 		/* 0 or any positive value is passed to f/w.
1026 		 * For RTS off, -1 is passed to f/w.
1027 		 * All other negative values considered as invalid.
1028 		 */
1029 		LOG_ERR("%s: Invalid threshold value : %d", __func__, (int)rts_threshold);
1030 		return ret;
1031 	}
1032 
1033 	memset(&wiphy_info, 0, sizeof(struct nrf_wifi_umac_set_wiphy_info));
1034 
1035 	wiphy_info.rts_threshold = (int)rts_threshold;
1036 
1037 	k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER);
1038 
1039 	status = nrf_wifi_fmac_set_wiphy_params(rpu_ctx_zep->rpu_ctx,
1040 						vif_ctx_zep->vif_idx,
1041 						&wiphy_info);
1042 
1043 	if (status != NRF_WIFI_STATUS_SUCCESS) {
1044 		LOG_ERR("%s: Configuring rts threshold failed\n", __func__);
1045 		goto out;
1046 	}
1047 
1048 	vif_ctx_zep->rts_threshold_value = (int)rts_threshold;
1049 
1050 	ret = 0;
1051 out:
1052 	k_mutex_unlock(&vif_ctx_zep->vif_lock);
1053 
1054 	return ret;
1055 }
1056 
nrf_wifi_get_rts_threshold(const struct device * dev,unsigned int * rts_threshold)1057 int nrf_wifi_get_rts_threshold(const struct device *dev,
1058 			       unsigned int *rts_threshold)
1059 {
1060 	struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL;
1061 	int ret = -1;
1062 
1063 	if (!dev) {
1064 		LOG_ERR("%s: dev is NULL", __func__);
1065 		return ret;
1066 	}
1067 
1068 	vif_ctx_zep = dev->data;
1069 	if (!vif_ctx_zep) {
1070 		LOG_ERR("%s: vif_ctx_zep is NULL", __func__);
1071 		return ret;
1072 	}
1073 
1074 	*rts_threshold = vif_ctx_zep->rts_threshold_value;
1075 	ret = 0;
1076 
1077 	return ret;
1078 }
1079