1 /*
2  * Copyright (c) 2025 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /**
8  * @brief File containing API definitions for the
9  * HAL Layer of the Wi-Fi driver in the radio test mode of operation.
10  */
11 
12 #include "queue.h"
13 #include "common/hal_structs_common.h"
14 #include "common/hal_common.h"
15 #include "common/hal_reg.h"
16 #include "common/hal_mem.h"
17 #include "common/hal_interrupt.h"
18 #include "common/pal.h"
19 #include "radio_test/hal_api.h"
20 
event_tasklet_fn(unsigned long data)21 static void event_tasklet_fn(unsigned long data)
22 {
23 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
24 	struct nrf_wifi_hal_dev_ctx *hal_dev_ctx = NULL;
25 	unsigned long flags = 0;
26 
27 	hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)data;
28 
29 	nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->lock_rx,
30 					&flags);
31 
32 	if (hal_dev_ctx->hal_status != NRF_WIFI_HAL_STATUS_ENABLED) {
33 		/* Ignore the interrupt if the HAL is not enabled */
34 		status = NRF_WIFI_STATUS_SUCCESS;
35 		goto out;
36 	}
37 
38 	status = hal_rpu_eventq_process(hal_dev_ctx);
39 
40 	if (status != NRF_WIFI_STATUS_SUCCESS) {
41 		nrf_wifi_osal_log_err("%s: Event queue processing failed",
42 				      __func__);
43 	}
44 
45 out:
46 	nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->lock_rx,
47 				       &flags);
48 }
49 
50 
hal_rpu_recovery(struct nrf_wifi_hal_dev_ctx * hal_dev_ctx)51 static enum nrf_wifi_status hal_rpu_recovery(struct nrf_wifi_hal_dev_ctx *hal_dev_ctx)
52 {
53 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
54 
55 	if (!hal_dev_ctx->hpriv->rpu_recovery_callbk_fn) {
56 		nrf_wifi_osal_log_dbg("%s: RPU recovery callback not registered",
57 				      __func__);
58 		goto out;
59 	}
60 
61 	status = hal_dev_ctx->hpriv->rpu_recovery_callbk_fn(hal_dev_ctx->mac_dev_ctx, NULL, 0);
62 	if (status != NRF_WIFI_STATUS_SUCCESS) {
63 		nrf_wifi_osal_log_err("%s: RPU recovery failed",
64 				      __func__);
65 		goto out;
66 	}
67 
68 out:
69 	return status;
70 }
71 
recovery_tasklet_fn(unsigned long data)72 static void recovery_tasklet_fn(unsigned long data)
73 {
74 	struct nrf_wifi_hal_dev_ctx *hal_dev_ctx = NULL;
75 	unsigned long flags = 0;
76 
77 	hal_dev_ctx = (struct nrf_wifi_hal_dev_ctx *)data;
78 	if (!hal_dev_ctx) {
79 		nrf_wifi_osal_log_err("%s: Invalid hal_dev_ctx",
80 				      __func__);
81 		return;
82 	}
83 
84 	nrf_wifi_osal_spinlock_irq_take(hal_dev_ctx->lock_recovery,
85 					&flags);
86 	hal_rpu_recovery(hal_dev_ctx);
87 	nrf_wifi_osal_spinlock_irq_rel(hal_dev_ctx->lock_recovery,
88 				       &flags);
89 }
90 
91 
nrf_wifi_rt_hal_dev_add(struct nrf_wifi_hal_priv * hpriv,void * mac_dev_ctx)92 struct nrf_wifi_hal_dev_ctx *nrf_wifi_rt_hal_dev_add(struct nrf_wifi_hal_priv *hpriv,
93 						     void *mac_dev_ctx)
94 {
95 	enum nrf_wifi_status status = NRF_WIFI_STATUS_FAIL;
96 	struct nrf_wifi_hal_dev_ctx *hal_dev_ctx = NULL;
97 
98 	hal_dev_ctx = nrf_wifi_osal_mem_zalloc(sizeof(*hal_dev_ctx));
99 
100 	if (!hal_dev_ctx) {
101 		nrf_wifi_osal_log_err("%s: Unable to allocate hal_dev_ctx",
102 				      __func__);
103 		goto err;
104 	}
105 
106 	hal_dev_ctx->hpriv = hpriv;
107 	hal_dev_ctx->mac_dev_ctx = mac_dev_ctx;
108 	hal_dev_ctx->idx = hpriv->num_devs++;
109 
110 	hal_dev_ctx->num_cmds = RPU_CMD_START_MAGIC;
111 
112 	hal_dev_ctx->cmd_q = nrf_wifi_utils_q_alloc();
113 
114 	if (!hal_dev_ctx->cmd_q) {
115 		nrf_wifi_osal_log_err("%s: Unable to allocate command queue",
116 				      __func__);
117 		goto hal_dev_free;
118 	}
119 
120 	hal_dev_ctx->event_q = nrf_wifi_utils_q_alloc();
121 
122 	if (!hal_dev_ctx->event_q) {
123 		nrf_wifi_osal_log_err("%s: Unable to allocate event queue",
124 				      __func__);
125 		goto cmd_q_free;
126 	}
127 
128 	hal_dev_ctx->lock_hal = nrf_wifi_osal_spinlock_alloc();
129 
130 	if (!hal_dev_ctx->lock_hal) {
131 		nrf_wifi_osal_log_err("%s: Unable to allocate HAL lock", __func__);
132 		hal_dev_ctx = NULL;
133 		goto event_q_free;
134 	}
135 
136 	nrf_wifi_osal_spinlock_init(hal_dev_ctx->lock_hal);
137 
138 	hal_dev_ctx->lock_rx = nrf_wifi_osal_spinlock_alloc();
139 
140 	if (!hal_dev_ctx->lock_rx) {
141 		nrf_wifi_osal_log_err("%s: Unable to allocate HAL lock",
142 				      __func__);
143 		goto lock_hal_free;
144 	}
145 
146 	nrf_wifi_osal_spinlock_init(hal_dev_ctx->lock_rx);
147 
148 	hal_dev_ctx->event_tasklet = nrf_wifi_osal_tasklet_alloc(NRF_WIFI_TASKLET_TYPE_BH);
149 
150 	if (!hal_dev_ctx->event_tasklet) {
151 		nrf_wifi_osal_log_err("%s: Unable to allocate event_tasklet",
152 				      __func__);
153 		goto lock_rx_free;
154 	}
155 
156 	nrf_wifi_osal_tasklet_init(hal_dev_ctx->event_tasklet,
157 				   event_tasklet_fn,
158 				   (unsigned long)hal_dev_ctx);
159 
160 	hal_dev_ctx->recovery_tasklet = nrf_wifi_osal_tasklet_alloc(NRF_WIFI_TASKLET_TYPE_BH);
161 	if (!hal_dev_ctx->recovery_tasklet) {
162 		nrf_wifi_osal_log_err("%s: Unable to allocate recovery_tasklet",
163 				      __func__);
164 		goto event_tasklet_free;
165 	}
166 	nrf_wifi_osal_tasklet_init(hal_dev_ctx->recovery_tasklet,
167 				   recovery_tasklet_fn,
168 				   (unsigned long)hal_dev_ctx);
169 
170 	hal_dev_ctx->lock_recovery = nrf_wifi_osal_spinlock_alloc();
171 	if (!hal_dev_ctx->lock_recovery) {
172 		nrf_wifi_osal_log_err("%s: Unable to allocate recovery lock",
173 				      __func__);
174 		goto recovery_tasklet_free;
175 	}
176 
177 	nrf_wifi_osal_spinlock_init(hal_dev_ctx->lock_recovery);
178 #ifdef NRF_WIFI_LOW_POWER
179 	status = hal_rpu_ps_init(hal_dev_ctx);
180 
181 	if (status != NRF_WIFI_STATUS_SUCCESS) {
182 		nrf_wifi_osal_log_err("%s: hal_rpu_ps_init failed",
183 				      __func__);
184 		goto lock_recovery_free;
185 	}
186 #endif /* NRF_WIFI_LOW_POWER */
187 
188 	hal_dev_ctx->bal_dev_ctx = nrf_wifi_bal_dev_add(hpriv->bpriv,
189 							hal_dev_ctx);
190 
191 	if (!hal_dev_ctx->bal_dev_ctx) {
192 		nrf_wifi_osal_log_err("%s: nrf_wifi_bal_dev_add failed",
193 				      __func__);
194 		goto lock_recovery_free;
195 	}
196 
197 	status = hal_rpu_irq_enable(hal_dev_ctx);
198 
199 	if (status != NRF_WIFI_STATUS_SUCCESS) {
200 		nrf_wifi_osal_log_err("%s: hal_rpu_irq_enable failed",
201 				      __func__);
202 		goto bal_dev_free;
203 	}
204 
205 	return hal_dev_ctx;
206 bal_dev_free:
207 	nrf_wifi_bal_dev_rem(hal_dev_ctx->bal_dev_ctx);
208 lock_recovery_free:
209 	nrf_wifi_osal_spinlock_free(hal_dev_ctx->lock_recovery);
210 recovery_tasklet_free:
211 	nrf_wifi_osal_tasklet_free(hal_dev_ctx->recovery_tasklet);
212 event_tasklet_free:
213 	nrf_wifi_osal_tasklet_free(hal_dev_ctx->event_tasklet);
214 lock_rx_free:
215 	nrf_wifi_osal_spinlock_free(hal_dev_ctx->lock_rx);
216 lock_hal_free:
217 	nrf_wifi_osal_spinlock_free(hal_dev_ctx->lock_hal);
218 event_q_free:
219 	nrf_wifi_utils_q_free(hal_dev_ctx->event_q);
220 cmd_q_free:
221 	nrf_wifi_utils_q_free(hal_dev_ctx->cmd_q);
222 hal_dev_free:
223 	nrf_wifi_osal_mem_free(hal_dev_ctx);
224 	hal_dev_ctx = NULL;
225 err:
226 	return NULL;
227 }