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: contains core ocb function definitions
22 */
23
24 #include <qdf_status.h>
25 #include "scheduler_api.h"
26 #include "wlan_objmgr_cmn.h"
27 #include "wlan_objmgr_global_obj.h"
28 #include "wlan_objmgr_psoc_obj.h"
29 #include "wlan_objmgr_pdev_obj.h"
30 #include "wlan_objmgr_vdev_obj.h"
31 #include <cdp_txrx_handle.h>
32 #include <cdp_txrx_cmn.h>
33 #include <cdp_txrx_ocb.h>
34 #include "wlan_ocb_main.h"
35 #include "wlan_ocb_tgt_api.h"
36 #include "target_if_ocb.h"
37
38 /**
39 * ocb_get_evt_type_str() - parse event to string
40 * @evt_type: ocb event type
41 *
42 * This function parse ocb event to string.
43 *
44 * Return: command string
45 */
ocb_get_evt_type_str(enum ocb_southbound_event evt_type)46 static const char *ocb_get_evt_type_str(enum ocb_southbound_event evt_type)
47 {
48 switch (evt_type) {
49 case OCB_CHANNEL_CONFIG_STATUS:
50 return "OCB channel config status";
51 case OCB_TSF_TIMER:
52 return "OCB TSF timer";
53 case OCB_DCC_STATS_RESPONSE:
54 return "OCB DCC get stats response";
55 case OCB_NDL_RESPONSE:
56 return "OCB NDL indication";
57 case OCB_DCC_INDICATION:
58 return "OCB DCC stats indication";
59 default:
60 return "Invalid OCB command";
61 }
62 }
63
64 /**
65 * ocb_set_chan_info() - Set channel info to dp
66 * @dp_soc: data path soc handle
67 * @dp_pdev: data path pdev handle
68 * @vdev_id: OCB vdev_id
69 * @config: channel config parameters
70 *
71 * Return: QDF_STATUS_SUCCESS on success
72 */
ocb_set_chan_info(void * dp_soc,void * dp_pdev,uint32_t vdev_id,struct ocb_config * config)73 static QDF_STATUS ocb_set_chan_info(void *dp_soc,
74 void *dp_pdev,
75 uint32_t vdev_id,
76 struct ocb_config *config)
77 {
78 struct ol_txrx_ocb_set_chan ocb_set_chan;
79 struct ol_txrx_ocb_chan_info *ocb_channel_info;
80
81 if (!dp_soc || !dp_pdev) {
82 ocb_err("DP global handle is null");
83 return QDF_STATUS_E_INVAL;
84 }
85
86 ocb_set_chan.ocb_channel_count = config->channel_count;
87
88 /* release old settings */
89 ocb_channel_info = cdp_get_ocb_chan_info(dp_soc, vdev_id);
90 if (ocb_channel_info)
91 qdf_mem_free(ocb_channel_info);
92
93 if (config->channel_count) {
94 int i, buf_size;
95
96 buf_size = sizeof(*ocb_channel_info) * config->channel_count;
97 ocb_set_chan.ocb_channel_info = qdf_mem_malloc(buf_size);
98 if (!ocb_set_chan.ocb_channel_info)
99 return QDF_STATUS_E_NOMEM;
100
101 ocb_channel_info = ocb_set_chan.ocb_channel_info;
102 for (i = 0; i < config->channel_count; i++) {
103 ocb_channel_info[i].chan_freq =
104 config->channels[i].chan_freq;
105 if (config->channels[i].flags &
106 OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR)
107 ocb_channel_info[i].disable_rx_stats_hdr = 1;
108 }
109 } else {
110 ocb_debug("No channel config to dp");
111 ocb_set_chan.ocb_channel_info = NULL;
112 }
113 ocb_debug("Sync channel config to dp");
114 cdp_set_ocb_chan_info(dp_soc, vdev_id, ocb_set_chan);
115
116 return QDF_STATUS_SUCCESS;
117 }
118
119 /**
120 * ocb_channel_config_status() - Process set channel config response
121 * @evt: response event
122 *
123 * Return: QDF_STATUS_SUCCESS on success
124 */
ocb_channel_config_status(struct ocb_rx_event * evt)125 static QDF_STATUS ocb_channel_config_status(struct ocb_rx_event *evt)
126 {
127 QDF_STATUS status;
128 uint32_t vdev_id;
129 struct ocb_rx_event *event;
130 struct wlan_objmgr_psoc *psoc;
131 struct wlan_objmgr_pdev *pdev;
132 struct ocb_pdev_obj *ocb_obj;
133 struct ocb_callbacks *cbs;
134 struct ocb_set_config_response config_rsp;
135
136 if (!evt) {
137 ocb_err("Event buffer is NULL");
138 return QDF_STATUS_E_FAILURE;
139 }
140 event = evt;
141 psoc = event->psoc;
142 pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_OCB_SB_ID);
143 if (!pdev) {
144 ocb_alert("Pdev is NULL");
145 return QDF_STATUS_E_FAILURE;
146 }
147
148 ocb_obj = wlan_get_pdev_ocb_obj(pdev);
149 if (!ocb_obj) {
150 ocb_err("Pdev object is NULL");
151 status = QDF_STATUS_E_INVAL;
152 goto exit;
153 }
154
155 cbs = &ocb_obj->ocb_cbs;
156 if (ocb_obj->channel_config) {
157 vdev_id = ocb_obj->channel_config->vdev_id;
158 config_rsp = event->rsp.channel_cfg_rsp;
159
160 /* Sync channel status to data path */
161 if (config_rsp.status == OCB_CHANNEL_CONFIG_SUCCESS)
162 ocb_set_chan_info(ocb_obj->dp_soc,
163 ocb_obj->pdev,
164 vdev_id,
165 ocb_obj->channel_config);
166 qdf_mem_free(ocb_obj->channel_config);
167 ocb_obj->channel_config = NULL;
168 } else {
169 ocb_err("Failed to sync channel info to DP");
170 config_rsp.status = OCB_CHANNEL_CONFIG_FAIL;
171 }
172
173 if (cbs->ocb_set_config_callback) {
174 cbs->ocb_set_config_callback(cbs->ocb_set_config_context,
175 &config_rsp);
176 status = QDF_STATUS_SUCCESS;
177 } else {
178 ocb_err("ocb_set_config_resp_cb is NULL");
179 status = QDF_STATUS_E_INVAL;
180 }
181 exit:
182 wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID);
183
184 return status;
185 }
186
187 /**
188 * ocb_tsf_timer() - Process get TSF timer response
189 * @evt: response event
190 *
191 * Return: QDF_STATUS_SUCCESS on success
192 */
ocb_tsf_timer(struct ocb_rx_event * evt)193 static QDF_STATUS ocb_tsf_timer(struct ocb_rx_event *evt)
194 {
195 QDF_STATUS status;
196 struct ocb_rx_event *event;
197 struct wlan_objmgr_vdev *vdev;
198 struct wlan_objmgr_pdev *pdev;
199 struct ocb_callbacks *cbs;
200 struct ocb_get_tsf_timer_response *tsf_timer;
201
202 if (!evt) {
203 ocb_err("Event buffer is NULL");
204 return QDF_STATUS_E_FAILURE;
205 }
206 event = evt;
207 vdev = event->vdev;
208 pdev = wlan_vdev_get_pdev(vdev);
209 cbs = wlan_ocb_get_callbacks(pdev);
210 tsf_timer = &event->rsp.tsf_timer;
211 ocb_debug("TSF timer low=%d, high=%d",
212 tsf_timer->timer_low, tsf_timer->timer_high);
213 if (cbs && cbs->ocb_get_tsf_timer_callback) {
214 ocb_debug("send TSF timer");
215 cbs->ocb_get_tsf_timer_callback(cbs->ocb_get_tsf_timer_context,
216 tsf_timer);
217 status = QDF_STATUS_SUCCESS;
218 } else {
219 ocb_err("ocb_get_tsf_timer_cb is NULL");
220 status = QDF_STATUS_E_FAILURE;
221 }
222
223 return status;
224 }
225
226 /**
227 * ocb_dcc_stats_response() - Process get DCC stats response
228 * @evt: response event
229 *
230 * Return: QDF_STATUS_SUCCESS on success
231 */
ocb_dcc_stats_response(struct ocb_rx_event * evt)232 static QDF_STATUS ocb_dcc_stats_response(struct ocb_rx_event *evt)
233 {
234 QDF_STATUS status;
235 struct ocb_rx_event *event;
236 struct wlan_objmgr_vdev *vdev;
237 struct wlan_objmgr_pdev *pdev;
238 struct ocb_callbacks *cbs;
239 struct ocb_dcc_get_stats_response *dcc_stats;
240
241 if (!evt) {
242 ocb_err("Event buffer is NULL");
243 return QDF_STATUS_E_FAILURE;
244 }
245
246 event = evt;
247 vdev = event->vdev;
248 pdev = wlan_vdev_get_pdev(vdev);
249 cbs = wlan_ocb_get_callbacks(pdev);
250 dcc_stats = &event->rsp.dcc_stats;
251 if (cbs && cbs->ocb_dcc_get_stats_callback) {
252 ocb_debug("send DCC stats");
253 cbs->ocb_dcc_get_stats_callback(cbs->ocb_dcc_get_stats_context,
254 dcc_stats);
255 status = QDF_STATUS_SUCCESS;
256 } else {
257 ocb_err("dcc_get_stats_cb is NULL");
258 status = QDF_STATUS_E_FAILURE;
259 }
260
261 return status;
262 }
263
264 /**
265 * ocb_ndl_response() - Process NDL update response
266 * @evt: response event
267 *
268 * Return: QDF_STATUS_SUCCESS on success
269 */
ocb_ndl_response(struct ocb_rx_event * evt)270 static QDF_STATUS ocb_ndl_response(struct ocb_rx_event *evt)
271 {
272 QDF_STATUS status;
273 struct ocb_rx_event *event;
274 struct wlan_objmgr_vdev *vdev;
275 struct wlan_objmgr_pdev *pdev;
276 struct ocb_callbacks *cbs;
277 struct ocb_dcc_update_ndl_response *ndl;
278
279 if (!evt) {
280 ocb_err("Event buffer is NULL");
281 return QDF_STATUS_E_FAILURE;
282 }
283 event = evt;
284 vdev = event->vdev;
285 pdev = wlan_vdev_get_pdev(vdev);
286 cbs = wlan_ocb_get_callbacks(pdev);
287 ndl = &event->rsp.ndl;
288 if (cbs && cbs->ocb_dcc_update_ndl_callback) {
289 ocb_debug("NDL update response");
290 cbs->ocb_dcc_update_ndl_callback(
291 cbs->ocb_dcc_update_ndl_context, ndl);
292 status = QDF_STATUS_SUCCESS;
293 } else {
294 ocb_err("dcc_update_ndl is NULL");
295 status = QDF_STATUS_E_FAILURE;
296 }
297
298 return status;
299 }
300
301 /**
302 * ocb_dcc_indication() - Process DCC stats indication
303 * @evt: response event
304 *
305 * Return: QDF_STATUS_SUCCESS on success
306 */
ocb_dcc_indication(struct ocb_rx_event * evt)307 static QDF_STATUS ocb_dcc_indication(struct ocb_rx_event *evt)
308 {
309 QDF_STATUS status;
310 struct ocb_rx_event *event;
311 struct wlan_objmgr_vdev *vdev;
312 struct ocb_callbacks *cbs;
313 struct wlan_objmgr_pdev *pdev;
314 struct ocb_dcc_get_stats_response *dcc_stats;
315
316 if (!evt) {
317 ocb_err("Event buffer is NULL");
318 return QDF_STATUS_E_FAILURE;
319 }
320
321 event = evt;
322 vdev = event->vdev;
323 pdev = wlan_vdev_get_pdev(vdev);
324 cbs = wlan_ocb_get_callbacks(pdev);
325 dcc_stats = &event->rsp.dcc_stats;
326 if (cbs && cbs->ocb_dcc_stats_event_callback) {
327 ocb_debug("DCC stats indication");
328 cbs->ocb_dcc_stats_event_callback(
329 cbs->ocb_dcc_stats_event_context, dcc_stats);
330 status = QDF_STATUS_SUCCESS;
331 } else {
332 ocb_err("dcc_get_stats_cb is NULL");
333 status = QDF_STATUS_E_FAILURE;
334 }
335
336 return status;
337 }
338
339 /**
340 * ocb_flush_start_msg() - Flush ocb start message
341 * @msg: OCB start vdev message
342 *
343 * Return: QDF_STATUS_SUCCESS on success.
344 */
ocb_flush_start_msg(struct scheduler_msg * msg)345 static QDF_STATUS ocb_flush_start_msg(struct scheduler_msg *msg)
346 {
347 struct ocb_pdev_obj *ocb_obj;
348
349 if (!msg) {
350 ocb_err("Null point for OCB message");
351 return QDF_STATUS_E_INVAL;
352 }
353
354 ocb_obj = msg->bodyptr;
355 if (ocb_obj && ocb_obj->channel_config) {
356 ocb_info("release the backed config parameters");
357 qdf_mem_free(ocb_obj->channel_config);
358 ocb_obj->channel_config = NULL;
359 }
360
361 return QDF_STATUS_SUCCESS;
362 }
363
364 /**
365 * ocb_process_start_vdev_msg() - Handler for OCB vdev start message
366 * @msg: OCB start vdev message
367 *
368 * Return: QDF_STATUS_SUCCESS on success.
369 */
ocb_process_start_vdev_msg(struct scheduler_msg * msg)370 static QDF_STATUS ocb_process_start_vdev_msg(struct scheduler_msg *msg)
371 {
372 QDF_STATUS status;
373 struct ocb_config *config;
374 struct ocb_pdev_obj *ocb_obj;
375 struct ocb_callbacks *ocb_cbs;
376 struct wlan_objmgr_vdev *vdev;
377
378 if (!msg || !msg->bodyptr) {
379 ocb_err("invalid message");
380 return QDF_STATUS_E_INVAL;
381 }
382
383 ocb_obj = msg->bodyptr;
384 ocb_cbs = &ocb_obj->ocb_cbs;
385 if (!ocb_cbs->start_ocb_vdev) {
386 ocb_err("No callback to start ocb vdev");
387 return QDF_STATUS_E_FAILURE;
388 }
389
390 config = ocb_obj->channel_config;
391 if (!config) {
392 ocb_err("NULL config parameters");
393 return QDF_STATUS_E_INVAL;
394 }
395
396 vdev = wlan_objmgr_get_vdev_by_id_from_pdev(ocb_obj->pdev,
397 config->vdev_id,
398 WLAN_OCB_SB_ID);
399 if (!vdev) {
400 ocb_err("Cannot get vdev");
401 return QDF_STATUS_E_FAILURE;
402 }
403
404 ocb_debug("Start to send OCB vdev start cmd");
405 status = ocb_cbs->start_ocb_vdev(config);
406 wlan_objmgr_vdev_release_ref(vdev, WLAN_OCB_SB_ID);
407 if (QDF_IS_STATUS_ERROR(status)) {
408 ocb_err("Failed to start OCB vdev");
409 return QDF_STATUS_E_FAILURE;
410 }
411
412 return QDF_STATUS_SUCCESS;
413 }
414
ocb_vdev_start(struct ocb_pdev_obj * ocb_obj)415 QDF_STATUS ocb_vdev_start(struct ocb_pdev_obj *ocb_obj)
416 {
417 QDF_STATUS status;
418 struct scheduler_msg msg = {0};
419
420 msg.bodyptr = ocb_obj;
421 msg.callback = ocb_process_start_vdev_msg;
422 msg.flush_callback = ocb_flush_start_msg;
423 status = scheduler_post_message(QDF_MODULE_ID_OCB,
424 QDF_MODULE_ID_OCB,
425 QDF_MODULE_ID_TARGET_IF, &msg);
426
427 return status;
428 }
429
ocb_process_evt(struct scheduler_msg * msg)430 QDF_STATUS ocb_process_evt(struct scheduler_msg *msg)
431 {
432 QDF_STATUS status;
433 struct ocb_rx_event *event;
434
435 ocb_debug("msg type %d, %s", msg->type,
436 ocb_get_evt_type_str(msg->type));
437
438 if (!(msg->bodyptr)) {
439 ocb_err("Invalid message body");
440 return QDF_STATUS_E_INVAL;
441 }
442 event = msg->bodyptr;
443 switch (msg->type) {
444 case OCB_CHANNEL_CONFIG_STATUS:
445 status = ocb_channel_config_status(event);
446 break;
447 case OCB_TSF_TIMER:
448 status = ocb_tsf_timer(event);
449 break;
450 case OCB_DCC_STATS_RESPONSE:
451 status = ocb_dcc_stats_response(event);
452 break;
453 case OCB_NDL_RESPONSE:
454 status = ocb_ndl_response(event);
455 break;
456 case OCB_DCC_INDICATION:
457 status = ocb_dcc_indication(event);
458 break;
459 default:
460 status = QDF_STATUS_E_INVAL;
461 break;
462 }
463
464 wlan_ocb_release_rx_event(event);
465 msg->bodyptr = NULL;
466
467 return status;
468 }
469
ocb_copy_config(struct ocb_config * src)470 struct ocb_config *ocb_copy_config(struct ocb_config *src)
471 {
472 struct ocb_config *dst;
473 uint32_t length;
474 uint8_t *cursor;
475
476 length = sizeof(*src) +
477 src->channel_count * sizeof(*src->channels) +
478 src->schedule_size * sizeof(*src->schedule) +
479 src->dcc_ndl_chan_list_len +
480 src->dcc_ndl_active_state_list_len;
481
482 dst = qdf_mem_malloc(length);
483 if (!dst)
484 return NULL;
485
486 *dst = *src;
487
488 cursor = (uint8_t *)dst;
489 cursor += sizeof(*dst);
490 dst->channels = (struct ocb_config_chan *)cursor;
491 cursor += src->channel_count * sizeof(*dst->channels);
492 qdf_mem_copy(dst->channels, src->channels,
493 src->channel_count * sizeof(*dst->channels));
494 dst->schedule = (struct ocb_config_schdl *)cursor;
495 cursor += src->schedule_size * sizeof(*dst->schedule);
496 qdf_mem_copy(dst->schedule, src->schedule,
497 src->schedule_size * sizeof(*dst->schedule));
498 dst->dcc_ndl_chan_list = cursor;
499 cursor += src->dcc_ndl_chan_list_len;
500 qdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list,
501 src->dcc_ndl_chan_list_len);
502 dst->dcc_ndl_active_state_list = cursor;
503 cursor += src->dcc_ndl_active_state_list_len;
504 qdf_mem_copy(dst->dcc_ndl_active_state_list,
505 src->dcc_ndl_active_state_list,
506 src->dcc_ndl_active_state_list_len);
507
508 return dst;
509 }
510
ocb_pdev_obj_create_notification(struct wlan_objmgr_pdev * pdev,void * arg_list)511 QDF_STATUS ocb_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
512 void *arg_list)
513 {
514 QDF_STATUS status;
515 struct ocb_pdev_obj *ocb_obj;
516
517 ocb_notice("ocb pdev created");
518 ocb_obj = qdf_mem_malloc(sizeof(*ocb_obj));
519 if (!ocb_obj)
520 return QDF_STATUS_E_FAILURE;
521
522 status = wlan_objmgr_pdev_component_obj_attach(pdev,
523 WLAN_UMAC_COMP_OCB,
524 (void *)ocb_obj,
525 QDF_STATUS_SUCCESS);
526 if (QDF_IS_STATUS_ERROR(status)) {
527 ocb_err("Failed to attach pdev ocb component");
528 qdf_mem_free(ocb_obj);
529 return status;
530 }
531 ocb_obj->pdev = pdev;
532
533 /* register OCB tx/rx ops */
534 tgt_ocb_register_rx_ops(&ocb_obj->ocb_rxops);
535 target_if_ocb_register_tx_ops(&ocb_obj->ocb_txops);
536 ocb_notice("ocb pdev attached");
537
538 return status;
539 }
540
ocb_pdev_obj_destroy_notification(struct wlan_objmgr_pdev * pdev,void * arg_list)541 QDF_STATUS ocb_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev,
542 void *arg_list)
543 {
544 QDF_STATUS status;
545 struct ocb_pdev_obj *ocb_obj;
546
547 ocb_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev,
548 WLAN_UMAC_COMP_OCB);
549 if (!ocb_obj) {
550 ocb_err("Failed to get ocb pdev object");
551 return QDF_STATUS_E_FAILURE;
552 }
553
554 status = wlan_objmgr_pdev_component_obj_detach(pdev,
555 WLAN_UMAC_COMP_OCB,
556 ocb_obj);
557 if (QDF_IS_STATUS_ERROR(status))
558 ocb_err("Failed to detach ocb pdev object");
559
560 qdf_mem_free(ocb_obj);
561
562 return QDF_STATUS_SUCCESS;
563 }
564