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