1 /*
2 * Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: This file contains ocb south bound interface definitions
22 */
23
24 #include <scheduler_api.h>
25 #include <wlan_objmgr_psoc_obj.h>
26 #include <wlan_objmgr_global_obj.h>
27 #include <wlan_objmgr_pdev_obj.h>
28 #include <wlan_objmgr_vdev_obj.h>
29 #include "wlan_ocb_public_structs.h"
30 #include "wlan_ocb_ucfg_api.h"
31 #include "wlan_ocb_tgt_api.h"
32 #include "wlan_ocb_main.h"
33
34 /**
35 * wlan_ocb_flush_callback() - OCB message flash callback
36 * @msg: OCB message
37 *
38 * Return: QDF_STATUS_SUCCESS on success.
39 */
wlan_ocb_flush_callback(struct scheduler_msg * msg)40 static QDF_STATUS wlan_ocb_flush_callback(struct scheduler_msg *msg)
41 {
42 struct ocb_rx_event *event;
43
44 if (!msg) {
45 ocb_err("Null point for OCB message");
46 return QDF_STATUS_E_INVAL;
47 }
48
49 event = msg->bodyptr;
50 wlan_ocb_release_rx_event(event);
51
52 return QDF_STATUS_SUCCESS;
53 }
54
55 /**
56 * tgt_ocb_channel_config_status() - handler for channel config response
57 * @psoc: psoc handle
58 * @status: status for last channel config
59 *
60 * Return: QDF_STATUS_SUCCESS on success
61 */
62 static QDF_STATUS
tgt_ocb_channel_config_status(struct wlan_objmgr_psoc * psoc,uint32_t status)63 tgt_ocb_channel_config_status(struct wlan_objmgr_psoc *psoc,
64 uint32_t status)
65 {
66 QDF_STATUS qdf_status;
67 struct scheduler_msg msg = {0};
68 struct ocb_rx_event *event;
69
70 event = qdf_mem_malloc(sizeof(*event));
71 if (!event)
72 return QDF_STATUS_E_NOMEM;
73
74 qdf_status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID);
75 if (QDF_IS_STATUS_ERROR(qdf_status)) {
76 ocb_err("Failed to get psoc ref");
77 wlan_ocb_release_rx_event(event);
78 return qdf_status;
79 }
80 event->psoc = psoc;
81 event->rsp.channel_cfg_rsp.status = status;
82 event->evt_id = OCB_CHANNEL_CONFIG_STATUS;
83 msg.type = OCB_CHANNEL_CONFIG_STATUS;
84 msg.bodyptr = event;
85 msg.callback = ocb_process_evt;
86 msg.flush_callback = wlan_ocb_flush_callback;
87 qdf_status = scheduler_post_message(QDF_MODULE_ID_OCB,
88 QDF_MODULE_ID_OCB,
89 QDF_MODULE_ID_TARGET_IF, &msg);
90
91 if (QDF_IS_STATUS_SUCCESS(qdf_status))
92 return QDF_STATUS_SUCCESS;
93
94 ocb_err("failed to send OCB_CHANNEL_CONFIG_STATUS msg");
95 wlan_ocb_release_rx_event(event);
96
97 return qdf_status;
98 }
99
100 /**
101 * tgt_ocb_get_tsf_timer() - handle for TSF timer response
102 * @psoc: psoc handle
103 * @response: TSF timer response
104 *
105 * Return: QDF_STATUS_SUCCESS on success
106 */
107 static QDF_STATUS
tgt_ocb_get_tsf_timer(struct wlan_objmgr_psoc * psoc,struct ocb_get_tsf_timer_response * response)108 tgt_ocb_get_tsf_timer(struct wlan_objmgr_psoc *psoc,
109 struct ocb_get_tsf_timer_response *response)
110 {
111 QDF_STATUS status;
112 struct scheduler_msg msg = {0};
113 struct ocb_rx_event *event;
114
115 event = qdf_mem_malloc(sizeof(*event));
116 if (!event)
117 return QDF_STATUS_E_NOMEM;
118
119 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID);
120 if (QDF_IS_STATUS_ERROR(status)) {
121 ocb_err("Failed to get psoc ref");
122 goto flush_ref;
123 }
124 event->psoc = psoc;
125 event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
126 response->vdev_id,
127 WLAN_OCB_SB_ID);
128 if (!event->vdev) {
129 ocb_err("Cannot get vdev handle");
130 status = QDF_STATUS_E_FAILURE;
131 goto flush_ref;
132 }
133
134 event->evt_id = OCB_TSF_TIMER;
135 event->rsp.tsf_timer.vdev_id = response->vdev_id;
136 event->rsp.tsf_timer.timer_high = response->timer_high;
137 event->rsp.tsf_timer.timer_low = response->timer_low;
138 msg.type = OCB_TSF_TIMER;
139 msg.bodyptr = event;
140 msg.callback = ocb_process_evt;
141 msg.flush_callback = wlan_ocb_flush_callback;
142
143 status = scheduler_post_message(QDF_MODULE_ID_OCB,
144 QDF_MODULE_ID_OCB,
145 QDF_MODULE_ID_TARGET_IF, &msg);
146 if (QDF_IS_STATUS_SUCCESS(status))
147 return QDF_STATUS_SUCCESS;
148
149 ocb_err("failed to send OCB_TSF_TIMER msg");
150 flush_ref:
151 wlan_ocb_release_rx_event(event);
152
153 return status;
154 }
155
156 /**
157 * tgt_ocb_dcc_ndl_update() - handler for NDL update response
158 * @psoc: psoc handle
159 * @resp: NDL update response
160 *
161 * Return: QDF_STATUS_SUCCESS on success
162 */
163 static QDF_STATUS
tgt_ocb_dcc_ndl_update(struct wlan_objmgr_psoc * psoc,struct ocb_dcc_update_ndl_response * resp)164 tgt_ocb_dcc_ndl_update(struct wlan_objmgr_psoc *psoc,
165 struct ocb_dcc_update_ndl_response *resp)
166 {
167 QDF_STATUS status;
168 struct scheduler_msg msg = {0};
169 struct ocb_rx_event *event;
170
171 event = qdf_mem_malloc(sizeof(*event));
172 if (!event)
173 return QDF_STATUS_E_NOMEM;
174
175 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID);
176 if (QDF_IS_STATUS_ERROR(status)) {
177 ocb_err("Failed to get psoc ref");
178 goto flush_ref;
179 }
180 event->psoc = psoc;
181 event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
182 resp->vdev_id,
183 WLAN_OCB_SB_ID);
184 if (!event->vdev) {
185 ocb_err("Cannot get vdev handle");
186 status = QDF_STATUS_E_FAILURE;
187 goto flush_ref;
188 }
189
190 event->evt_id = OCB_NDL_RESPONSE;
191 qdf_mem_copy(&event->rsp.ndl, resp, sizeof(*resp));
192 msg.type = OCB_NDL_RESPONSE;
193 msg.bodyptr = event;
194 msg.callback = ocb_process_evt;
195 msg.flush_callback = wlan_ocb_flush_callback;
196
197 status = scheduler_post_message(QDF_MODULE_ID_OCB,
198 QDF_MODULE_ID_OCB,
199 QDF_MODULE_ID_TARGET_IF, &msg);
200 if (QDF_IS_STATUS_SUCCESS(status))
201 return QDF_STATUS_SUCCESS;
202
203 ocb_err("failed to send OCB_NDL_RESPONSE msg");
204 flush_ref:
205 wlan_ocb_release_rx_event(event);
206
207 return status;
208 }
209
210 /**
211 * tgt_ocb_dcc_stats_indicate() - handler for DCC stats indication
212 * @psoc: psoc handle
213 * @response: DCC stats
214 * @active: true for active query, false for passive indicate
215 *
216 * Return: QDF_STATUS_SUCCESS on success
217 */
218 static QDF_STATUS
tgt_ocb_dcc_stats_indicate(struct wlan_objmgr_psoc * psoc,struct ocb_dcc_get_stats_response * response,bool active)219 tgt_ocb_dcc_stats_indicate(struct wlan_objmgr_psoc *psoc,
220 struct ocb_dcc_get_stats_response *response,
221 bool active)
222 {
223 QDF_STATUS status;
224 uint8_t *buf;
225 uint32_t size;
226 struct scheduler_msg msg = {0};
227 struct ocb_rx_event *event;
228
229 size = sizeof(*event) +
230 response->channel_stats_array_len;
231 buf = qdf_mem_malloc(size);
232 if (!buf)
233 return QDF_STATUS_E_NOMEM;
234
235 event = (struct ocb_rx_event *)buf;
236 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID);
237 if (QDF_IS_STATUS_ERROR(status)) {
238 ocb_err("Failed to get psoc ref");
239 goto flush_ref;
240 }
241 event->psoc = psoc;
242 event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc,
243 response->vdev_id,
244 WLAN_OCB_SB_ID);
245 if (!event->vdev) {
246 ocb_err("Cannot get vdev handle");
247 status = QDF_STATUS_E_FAILURE;
248 goto flush_ref;
249 }
250
251 event->rsp.dcc_stats.channel_stats_array =
252 (uint8_t *)&event->rsp.dcc_stats +
253 sizeof(struct ocb_dcc_get_stats_response);
254 event->rsp.dcc_stats.vdev_id = response->vdev_id;
255 event->rsp.dcc_stats.num_channels = response->num_channels;
256 event->rsp.dcc_stats.channel_stats_array_len =
257 response->channel_stats_array_len;
258 qdf_mem_copy(event->rsp.dcc_stats.channel_stats_array,
259 response->channel_stats_array,
260 response->channel_stats_array_len);
261 ocb_debug("Message type is %s",
262 active ? "Get stats response" : "DCC stats indication");
263 if (active)
264 msg.type = OCB_DCC_STATS_RESPONSE;
265 else
266 msg.type = OCB_DCC_INDICATION;
267 event->evt_id = msg.type;
268 msg.bodyptr = event;
269 msg.callback = ocb_process_evt;
270 msg.flush_callback = wlan_ocb_flush_callback;
271
272 status = scheduler_post_message(QDF_MODULE_ID_OCB,
273 QDF_MODULE_ID_OCB,
274 QDF_MODULE_ID_TARGET_IF, &msg);
275 if (QDF_IS_STATUS_SUCCESS(status))
276 return QDF_STATUS_SUCCESS;
277
278 ocb_err("failed to send DCC stats msg(%d)", msg.type);
279 flush_ref:
280 wlan_ocb_release_rx_event(event);
281
282 return status;
283 }
284
tgt_ocb_register_ev_handler(struct wlan_objmgr_pdev * pdev)285 QDF_STATUS tgt_ocb_register_ev_handler(struct wlan_objmgr_pdev *pdev)
286 {
287 struct wlan_objmgr_psoc *psoc;
288 struct wlan_ocb_tx_ops *ocb_ops;
289 QDF_STATUS status = QDF_STATUS_E_FAILURE;
290
291 psoc = wlan_pdev_get_psoc(pdev);
292 if (!psoc) {
293 ocb_err("Null soc handle");
294 return QDF_STATUS_E_INVAL;
295 }
296 ocb_ops = wlan_pdev_get_ocb_tx_ops(pdev);
297 if (ocb_ops && ocb_ops->ocb_reg_ev_handler) {
298 status = ocb_ops->ocb_reg_ev_handler(psoc, NULL);
299 ocb_debug("register ocb event, status:%d", status);
300 } else {
301 ocb_alert("No ocb objects or ocb_reg_ev_handler");
302 }
303
304 return status;
305 }
306
tgt_ocb_unregister_ev_handler(struct wlan_objmgr_pdev * pdev)307 QDF_STATUS tgt_ocb_unregister_ev_handler(struct wlan_objmgr_pdev *pdev)
308 {
309 struct wlan_objmgr_psoc *psoc;
310 struct wlan_ocb_tx_ops *ocb_ops;
311 QDF_STATUS status;
312
313 psoc = wlan_pdev_get_psoc(pdev);
314 if (!psoc) {
315 ocb_err("Null soc handle");
316 return QDF_STATUS_E_INVAL;
317 }
318 ocb_ops = wlan_pdev_get_ocb_tx_ops(pdev);
319 if (ocb_ops && ocb_ops->ocb_unreg_ev_handler) {
320 status = ocb_ops->ocb_unreg_ev_handler(psoc, NULL);
321 ocb_debug("unregister ocb event, status:%d", status);
322 } else {
323 ocb_alert("No ocb objects or ocb_unreg_ev_handler");
324 status = QDF_STATUS_E_FAILURE;
325 }
326
327 return status;
328 }
329
tgt_ocb_register_rx_ops(struct wlan_ocb_rx_ops * ocb_rxops)330 QDF_STATUS tgt_ocb_register_rx_ops(struct wlan_ocb_rx_ops *ocb_rxops)
331 {
332 ocb_rxops->ocb_set_config_status = tgt_ocb_channel_config_status;
333 ocb_rxops->ocb_tsf_timer = tgt_ocb_get_tsf_timer;
334 ocb_rxops->ocb_dcc_ndl_update = tgt_ocb_dcc_ndl_update;
335 ocb_rxops->ocb_dcc_stats_indicate = tgt_ocb_dcc_stats_indicate;
336
337 return QDF_STATUS_SUCCESS;
338 }
339