1 /*
2 * Copyright (c) 2017-2021 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 * DOC: wlan_serialization_internal.c
21 * This file defines the functions which are called
22 * from serialization public API's and are internal
23 * to serialization.
24 */
25
26 #include <wlan_objmgr_vdev_obj.h>
27 #include <wlan_objmgr_pdev_obj.h>
28 #include <wlan_objmgr_psoc_obj.h>
29 #include <qdf_list.h>
30 #include <qdf_status.h>
31 #include <wlan_utility.h>
32 #include "wlan_serialization_api.h"
33 #include "wlan_serialization_main_i.h"
34 #include "wlan_serialization_utils_i.h"
35 #include "wlan_serialization_non_scan_i.h"
36 #include "wlan_serialization_scan_i.h"
37 #include "wlan_serialization_internal_i.h"
38
wlan_serialization_is_cmd_present_queue(struct wlan_serialization_command * cmd,uint8_t is_active_queue)39 bool wlan_serialization_is_cmd_present_queue(
40 struct wlan_serialization_command *cmd,
41 uint8_t is_active_queue)
42 {
43 qdf_list_t *queue;
44 bool status = false;
45 enum wlan_serialization_node node_type;
46 struct wlan_ser_pdev_obj *ser_pdev_obj;
47 struct wlan_ser_vdev_obj *ser_vdev_obj;
48 enum wlan_serialization_cmd_type cmd_type;
49
50 if (!cmd) {
51 ser_err("invalid cmd");
52 goto error;
53 }
54
55 cmd_type = cmd->cmd_type;
56
57 ser_pdev_obj = wlan_serialization_get_pdev_obj(
58 wlan_serialization_get_pdev_from_cmd(cmd));
59
60 if (!ser_pdev_obj) {
61 ser_err("invalid ser vdev obj");
62 goto error;
63 }
64
65 ser_vdev_obj = wlan_serialization_get_vdev_obj(
66 wlan_serialization_get_vdev_from_cmd(cmd));
67 if (!ser_vdev_obj) {
68 ser_err("invalid ser pdev obj");
69 goto error;
70 }
71
72 if (cmd_type < WLAN_SER_CMD_NONSCAN) {
73 queue = wlan_serialization_get_list_from_pdev_queue(
74 ser_pdev_obj, cmd_type, is_active_queue);
75 node_type = WLAN_SER_PDEV_NODE;
76 } else {
77 queue = wlan_serialization_get_list_from_vdev_queue(
78 ser_vdev_obj, cmd_type, is_active_queue);
79 node_type = WLAN_SER_VDEV_NODE;
80 }
81
82 status = wlan_serialization_is_cmd_present_in_given_queue(queue, cmd,
83 node_type);
84
85 error:
86 return status;
87 }
88
89 enum wlan_serialization_status
wlan_serialization_enqueue_cmd(struct wlan_serialization_command * cmd,enum ser_queue_reason ser_reason)90 wlan_serialization_enqueue_cmd(struct wlan_serialization_command *cmd,
91 enum ser_queue_reason ser_reason)
92 {
93 enum wlan_serialization_status status = WLAN_SER_CMD_DENIED_UNSPECIFIED;
94 struct wlan_serialization_command_list *cmd_list;
95 qdf_list_node_t *nnode;
96 struct wlan_objmgr_pdev *pdev;
97 struct wlan_ser_pdev_obj *ser_pdev_obj;
98 struct wlan_serialization_pdev_queue *pdev_queue;
99 struct wlan_ser_vdev_obj *ser_vdev_obj;
100 struct wlan_serialization_vdev_queue *vdev_queue;
101 bool active_queue;
102 uint8_t vdev_id;
103
104 /* Enqueue process
105 * 1) peek through command structure and see what is the command type
106 * 2) two main types of commands to process
107 * a) SCAN
108 * b) NON-SCAN
109 * 3) for each command there are separate command queues per pdev
110 * 4) pull pdev from vdev structure and get the command queue associated
111 * with that pdev and try to enqueue on those queue
112 * 5) Thumb rule:
113 * a) There could be only 1 active non-scan command at a
114 * time including all total non-scan commands of all pdevs.
115 *
116 * example: pdev1 has 1 non-scan active command and
117 * pdev2 got 1 non-scan command then that command should go to
118 * pdev2's pending queue
119 *
120 * b) There could be only N number of scan commands at a time
121 * including all total scan commands of all pdevs
122 *
123 * example: Let's say N=8,
124 * pdev1's vdev1 has 5 scan command, pdev2's vdev1 has 3
125 * scan commands, if we get scan request on vdev2 then it will go
126 * to pending queue of vdev2 as we reached max allowed scan active
127 * command.
128 */
129
130 if (!cmd) {
131 ser_err("NULL command");
132 goto error;
133 }
134
135 if (!cmd->cmd_cb) {
136 ser_err("no cmd_cb for cmd type:%d, id: %d",
137 cmd->cmd_type,
138 cmd->cmd_id);
139 goto error;
140 }
141
142 pdev = wlan_serialization_get_pdev_from_cmd(cmd);
143 if (!pdev) {
144 ser_err("pdev is invalid");
145 goto error;
146 }
147 vdev_id = wlan_vdev_get_id(cmd->vdev);
148
149 ser_pdev_obj =
150 wlan_objmgr_pdev_get_comp_private_obj(
151 pdev,
152 WLAN_UMAC_COMP_SERIALIZATION);
153 if (!ser_pdev_obj) {
154 ser_err("Invalid ser_pdev_obj");
155 goto error;
156 }
157
158 pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj,
159 cmd->cmd_type);
160 if (!pdev_queue) {
161 ser_err("pdev_queue is invalid");
162 goto error;
163 }
164
165 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
166
167 /* Before queuing any non scan command,
168 * as part of wlan_serialization_request,
169 * we check if the vdev queues are disabled.
170 *
171 * The serialization command structure has an
172 * attribute, where after a given command is queued,
173 * we can block the vdev queues.
174 *
175 * For example, after VDEV_DOWN command is queued as
176 * part of a vdev deletion, no other commands should be queued
177 * until the deletion is complete, so with VDEV_DOWN(in case of
178 * vdev deletion) with pass the attribute to disable vdev queues
179 */
180 if (cmd->cmd_type > WLAN_SER_CMD_SCAN &&
181 ser_reason == SER_REQUEST) {
182 ser_vdev_obj =
183 wlan_serialization_get_vdev_obj(
184 wlan_serialization_get_vdev_from_cmd(cmd));
185
186 if (!ser_vdev_obj) {
187 wlan_serialization_release_lock(
188 &pdev_queue->pdev_queue_lock);
189 goto error;
190 }
191
192 vdev_queue =
193 wlan_serialization_get_vdev_queue_obj(
194 ser_vdev_obj,
195 cmd->cmd_type);
196
197 if (!vdev_queue) {
198 wlan_serialization_release_lock(
199 &pdev_queue->pdev_queue_lock);
200 goto error;
201 }
202
203 if (vdev_queue->queue_disable) {
204 wlan_serialization_release_lock(
205 &pdev_queue->pdev_queue_lock);
206 ser_err_rl("VDEV %d queue is disabled, reject cmd id %d type %d",
207 vdev_id, cmd->cmd_id, cmd->cmd_type);
208 status = WLAN_SER_CMD_QUEUE_DISABLED;
209 goto error;
210 }
211 }
212
213 active_queue = wlan_serialization_is_active_cmd_allowed(cmd);
214
215 if (wlan_serialization_is_cmd_present_queue(cmd, active_queue)) {
216 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
217 ser_err("duplicate command, reject cmd id %d type %d vdev %d",
218 cmd->cmd_id, cmd->cmd_type, vdev_id);
219 goto error;
220 }
221
222 if (wlan_serialization_remove_front(
223 &pdev_queue->cmd_pool_list,
224 &nnode) != QDF_STATUS_SUCCESS) {
225 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
226 ser_err("Failed to get cmd buffer from global pool cmd id %d type %d vdev %d",
227 cmd->cmd_id, cmd->cmd_type, vdev_id);
228 status = WLAN_SER_CMD_DENIED_LIST_FULL;
229 goto error;
230 }
231
232 ser_debug("Type %d id %d vdev %d high_priority %d blocking %d timeout %d allowed %d",
233 cmd->cmd_type, cmd->cmd_id, vdev_id, cmd->is_high_priority,
234 cmd->is_blocking, cmd->cmd_timeout_duration, active_queue);
235
236 cmd_list =
237 qdf_container_of(nnode,
238 struct wlan_serialization_command_list,
239 pdev_node);
240
241 qdf_mem_copy(&cmd_list->cmd, cmd,
242 sizeof(struct wlan_serialization_command));
243
244 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN) {
245 status = wlan_ser_add_scan_cmd(ser_pdev_obj,
246 cmd_list,
247 active_queue);
248 } else {
249 status = wlan_ser_add_non_scan_cmd(ser_pdev_obj,
250 cmd_list,
251 active_queue);
252 }
253
254 if (status != WLAN_SER_CMD_PENDING && status != WLAN_SER_CMD_ACTIVE) {
255 qdf_mem_zero(&cmd_list->cmd,
256 sizeof(struct wlan_serialization_command));
257 cmd_list->cmd_in_use = 0;
258 wlan_serialization_insert_back(
259 &pdev_queue->cmd_pool_list,
260 &cmd_list->pdev_node);
261 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
262 ser_err("Failed to add cmd id %d type %d to active/pending queue",
263 cmd->cmd_id, cmd->cmd_type);
264 goto error;
265 }
266
267 if (WLAN_SER_CMD_ACTIVE == status) {
268 qdf_atomic_set_bit(CMD_MARKED_FOR_ACTIVATION,
269 &cmd_list->cmd_in_use);
270 }
271
272 wlan_ser_update_cmd_history(pdev_queue, &cmd_list->cmd,
273 ser_reason, true, active_queue);
274
275 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
276
277 if (WLAN_SER_CMD_ACTIVE == status)
278 wlan_serialization_activate_cmd(cmd_list,
279 ser_pdev_obj, ser_reason);
280
281 error:
282
283 return status;
284 }
285
wlan_serialization_activate_cmd(struct wlan_serialization_command_list * cmd_list,struct wlan_ser_pdev_obj * ser_pdev_obj,enum ser_queue_reason ser_reason)286 QDF_STATUS wlan_serialization_activate_cmd(
287 struct wlan_serialization_command_list *cmd_list,
288 struct wlan_ser_pdev_obj *ser_pdev_obj,
289 enum ser_queue_reason ser_reason)
290 {
291 QDF_STATUS status = QDF_STATUS_E_FAILURE;
292 struct wlan_objmgr_psoc *psoc = NULL;
293 struct wlan_serialization_pdev_queue *pdev_queue;
294 uint8_t vdev_id;
295
296 pdev_queue = wlan_serialization_get_pdev_queue_obj(
297 ser_pdev_obj, cmd_list->cmd.cmd_type);
298
299 psoc = wlan_vdev_get_psoc(cmd_list->cmd.vdev);
300 if (!psoc) {
301 ser_err("invalid psoc");
302 goto error;
303 }
304 vdev_id = wlan_vdev_get_id(cmd_list->cmd.vdev);
305
306 /*
307 * command is already pushed to active queue above
308 * now start the timer and notify requestor
309 */
310
311 status = wlan_serialization_find_and_start_timer(psoc, &cmd_list->cmd,
312 ser_reason);
313 if (QDF_IS_STATUS_ERROR(status)) {
314 ser_err("Failed to start timer cmd type %d id %d vdev %d",
315 cmd_list->cmd.cmd_type,
316 cmd_list->cmd.cmd_id, vdev_id);
317 goto timer_failed;
318 }
319
320 /*
321 * Remember that serialization module may send
322 * this callback in same context through which it
323 * received the serialization request. Due to which
324 * it is caller's responsibility to ensure acquiring
325 * and releasing its own lock appropriately.
326 */
327
328 ser_debug("Activate type %d id %d vdev %d", cmd_list->cmd.cmd_type,
329 cmd_list->cmd.cmd_id, vdev_id);
330
331 cmd_list->cmd.activation_reason = ser_reason;
332
333 status = cmd_list->cmd.cmd_cb(&cmd_list->cmd,
334 WLAN_SER_CB_ACTIVATE_CMD);
335 timer_failed:
336 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
337
338 qdf_atomic_clear_bit(CMD_MARKED_FOR_ACTIVATION,
339 &cmd_list->cmd_in_use);
340 qdf_atomic_set_bit(CMD_IS_ACTIVE,
341 &cmd_list->cmd_in_use);
342
343 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
344
345 if (QDF_IS_STATUS_ERROR(status)) {
346 wlan_serialization_dequeue_cmd(&cmd_list->cmd,
347 SER_ACTIVATION_FAILED,
348 true);
349 return status;
350 }
351
352 /*
353 * Cmd was marked for activation and delete or cancel
354 * is received before activation completed, then the command
355 * should be immediately removed after activation
356 */
357 if (qdf_atomic_test_bit(CMD_ACTIVE_MARKED_FOR_REMOVAL,
358 &cmd_list->cmd_in_use)) {
359 wlan_serialization_dequeue_cmd(&cmd_list->cmd,
360 SER_REMOVE,
361 true);
362 return status;
363 }
364
365 if (qdf_atomic_test_bit(CMD_ACTIVE_MARKED_FOR_CANCEL,
366 &cmd_list->cmd_in_use))
367 wlan_serialization_cmd_cancel_handler(
368 ser_pdev_obj, &cmd_list->cmd,
369 NULL, NULL, cmd_list->cmd.cmd_type,
370 WLAN_SERIALIZATION_ACTIVE_QUEUE,
371 WLAN_SER_CMD_ATTR_NONE);
372 error:
373 return status;
374 }
375
376 bool
wlan_serialization_is_active_cmd_allowed(struct wlan_serialization_command * cmd)377 wlan_serialization_is_active_cmd_allowed(struct wlan_serialization_command *cmd)
378 {
379 struct wlan_objmgr_pdev *pdev;
380 bool active_cmd_allowed = 0;
381
382 pdev = wlan_serialization_get_pdev_from_cmd(cmd);
383 if (!pdev) {
384 ser_err("NULL pdev");
385 goto error;
386 }
387
388 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN)
389 active_cmd_allowed =
390 (wlan_serialization_is_active_scan_cmd_allowed(cmd) &&
391 wlan_serialization_is_scan_pending_queue_empty(cmd));
392 else
393 active_cmd_allowed =
394 (wlan_serialization_is_active_non_scan_cmd_allowed(cmd) &&
395 wlan_serialization_is_non_scan_pending_queue_empty(cmd));
396
397 error:
398 return active_cmd_allowed;
399 }
400
401 enum wlan_serialization_status
wlan_serialization_move_pending_to_active(enum wlan_serialization_cmd_type cmd_type,struct wlan_ser_pdev_obj * ser_pdev_obj,struct wlan_objmgr_vdev * vdev,bool blocking_cmd_removed)402 wlan_serialization_move_pending_to_active(
403 enum wlan_serialization_cmd_type cmd_type,
404 struct wlan_ser_pdev_obj *ser_pdev_obj,
405 struct wlan_objmgr_vdev *vdev,
406 bool blocking_cmd_removed)
407 {
408 enum wlan_serialization_status status;
409
410 if (cmd_type < WLAN_SER_CMD_NONSCAN) {
411 status =
412 wlan_ser_move_scan_pending_to_active(
413 ser_pdev_obj);
414 } else {
415 status =
416 wlan_ser_move_non_scan_pending_to_active(
417 ser_pdev_obj,
418 vdev,
419 blocking_cmd_removed);
420 }
421
422 return status;
423 }
424
425 enum wlan_serialization_cmd_status
wlan_serialization_dequeue_cmd(struct wlan_serialization_command * cmd,enum ser_queue_reason ser_reason,uint8_t active_cmd)426 wlan_serialization_dequeue_cmd(struct wlan_serialization_command *cmd,
427 enum ser_queue_reason ser_reason,
428 uint8_t active_cmd)
429 {
430 enum wlan_serialization_cmd_status status =
431 WLAN_SER_CMD_NOT_FOUND;
432 enum wlan_serialization_status ser_status =
433 WLAN_SER_CMD_DENIED_UNSPECIFIED;
434
435 QDF_STATUS qdf_status;
436 struct wlan_objmgr_pdev *pdev;
437 struct wlan_objmgr_psoc *psoc;
438 struct wlan_ser_pdev_obj *ser_pdev_obj;
439 struct wlan_serialization_command cmd_bkup;
440 struct wlan_serialization_command_list *cmd_list;
441 struct wlan_serialization_pdev_queue *pdev_queue;
442 bool blocking_cmd_removed = 0;
443
444 if (!cmd) {
445 ser_err("NULL command");
446 goto error;
447 }
448
449 pdev = wlan_serialization_get_pdev_from_cmd(cmd);
450 if (!pdev) {
451 ser_err("invalid pdev");
452 goto error;
453 }
454
455 psoc = wlan_pdev_get_psoc(pdev);
456 if (!psoc) {
457 ser_err("invalid psoc");
458 goto error;
459 }
460
461 ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev);
462 if (!ser_pdev_obj) {
463 ser_err("ser_pdev_obj is empty");
464 goto error;
465 }
466
467 pdev_queue = wlan_serialization_get_pdev_queue_obj(
468 ser_pdev_obj, cmd->cmd_type);
469
470 ser_debug("Type %d id %d vdev %d blocking %d reason %d active %d",
471 cmd->cmd_type, cmd->cmd_id, wlan_vdev_get_id(cmd->vdev),
472 cmd->is_blocking, ser_reason, active_cmd);
473
474 wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
475
476 if (cmd->cmd_type < WLAN_SER_CMD_NONSCAN)
477 qdf_status = wlan_ser_remove_scan_cmd(
478 ser_pdev_obj, &cmd_list, cmd, active_cmd);
479 else {
480 qdf_status = wlan_ser_remove_non_scan_cmd(
481 ser_pdev_obj, &cmd_list, cmd, active_cmd);
482 }
483
484 if (qdf_status == QDF_STATUS_E_PENDING) {
485 status = WLAN_SER_CMD_MARKED_FOR_ACTIVATION;
486 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
487 goto error;
488 }
489
490 if (qdf_status != QDF_STATUS_SUCCESS) {
491 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
492 status = WLAN_SER_CMD_NOT_FOUND;
493 goto error;
494 }
495
496 if (active_cmd) {
497 if (cmd_list->cmd.cmd_type >= WLAN_SER_CMD_NONSCAN)
498 blocking_cmd_removed = cmd_list->cmd.is_blocking;
499 }
500
501 if (active_cmd)
502 wlan_serialization_find_and_stop_timer(
503 psoc, &cmd_list->cmd,
504 ser_reason);
505
506 qdf_mem_copy(&cmd_bkup, &cmd_list->cmd,
507 sizeof(struct wlan_serialization_command));
508 qdf_mem_zero(&cmd_list->cmd,
509 sizeof(struct wlan_serialization_command));
510 cmd_list->cmd_in_use = 0;
511 qdf_status = wlan_serialization_insert_back(
512 &pdev_queue->cmd_pool_list,
513 &cmd_list->pdev_node);
514
515 wlan_ser_update_cmd_history(pdev_queue, &cmd_bkup, ser_reason,
516 false, active_cmd);
517
518 wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
519
520 if (active_cmd) {
521 ser_status = wlan_serialization_move_pending_to_active(
522 cmd_bkup.cmd_type, ser_pdev_obj,
523 cmd_bkup.vdev,
524 blocking_cmd_removed);
525 }
526
527 /* Call cmd cb for remove request*/
528 if (cmd_bkup.cmd_cb) {
529 /* caller should release the memory */
530 ser_debug("Release memory for type %d id %d vdev %d",
531 cmd_bkup.cmd_type, cmd_bkup.cmd_id,
532 wlan_vdev_get_id(cmd_bkup.vdev));
533 cmd_bkup.cmd_cb(&cmd_bkup, WLAN_SER_CB_RELEASE_MEM_CMD);
534 }
535
536 if (active_cmd)
537 status = WLAN_SER_CMD_IN_ACTIVE_LIST;
538 else
539 status = WLAN_SER_CMD_IN_PENDING_LIST;
540
541 error:
542 return status;
543 }
544
wlan_serialization_generic_timer_cb(void * arg)545 static void wlan_serialization_generic_timer_cb(void *arg)
546 {
547 struct wlan_serialization_command *timeout_cmd = arg;
548 struct wlan_objmgr_vdev *vdev = NULL;
549 struct wlan_objmgr_psoc *psoc;
550
551 if (!timeout_cmd) {
552 ser_err("cmd_info not found");
553 return;
554 }
555
556 vdev = timeout_cmd->vdev;
557 if (!vdev) {
558 ser_err("Invalid vdev");
559 qdf_mem_free(timeout_cmd);
560 return;
561 }
562
563 psoc = wlan_vdev_get_psoc(vdev);
564 if (!psoc) {
565 ser_err("Psoc is NULL");
566 goto free;
567 }
568 ser_err("Active cmd timeout for cmd_type[%d] vdev[%d] cmd_id[%d]",
569 timeout_cmd->cmd_type, wlan_vdev_get_id(vdev),
570 timeout_cmd->cmd_id);
571
572 /*
573 * Validate if active cmnd is still present, as actual command
574 * completion can removed it in parallel.
575 */
576 if (!wlan_serialization_is_cmd_present_in_active_queue(psoc,
577 timeout_cmd)) {
578 ser_err("cmd_type %d vdev %d not in active queue",
579 timeout_cmd->cmd_type, wlan_vdev_get_id(vdev));
580 goto free;
581 }
582
583 if (timeout_cmd->cmd_cb)
584 timeout_cmd->cmd_cb(timeout_cmd,
585 WLAN_SER_CB_ACTIVE_CMD_TIMEOUT);
586 /*
587 * dequeue cmd API will cleanup and destroy the timer. If it fails to
588 * dequeue command then we have to destroy the timer.
589 */
590 wlan_serialization_dequeue_cmd(timeout_cmd, SER_TIMEOUT, true);
591
592 free:
593 wlan_objmgr_vdev_release_ref(timeout_cmd->vdev, WLAN_SERIALIZATION_ID);
594 qdf_mem_free(timeout_cmd);
595 }
596
wlan_serialization_mc_flush(struct scheduler_msg * msg)597 static QDF_STATUS wlan_serialization_mc_flush(struct scheduler_msg *msg)
598 {
599 struct wlan_serialization_command *timeout_cmd =
600 scheduler_qdf_mc_timer_deinit_return_data_ptr(msg->bodyptr);
601
602 if (!timeout_cmd) {
603 ser_err("Error failed to release reference for vdev objmgr");
604 return QDF_STATUS_E_FAILURE;
605 }
606
607 wlan_objmgr_vdev_release_ref(timeout_cmd->vdev, WLAN_SERIALIZATION_ID);
608 qdf_mem_free(timeout_cmd);
609
610 return QDF_STATUS_SUCCESS;
611 }
612
613 static void
wlan_serialization_timer_cb_mc_ctx(struct wlan_serialization_command * cmd)614 wlan_serialization_timer_cb_mc_ctx(struct wlan_serialization_command *cmd)
615 {
616 struct scheduler_msg msg = {0};
617 struct wlan_serialization_command *timeout_cmd;
618 struct sched_qdf_mc_timer_cb_wrapper *mc_timer_wrapper;
619 QDF_STATUS status;
620
621 msg.type = SYS_MSG_ID_MC_TIMER;
622 msg.reserved = SYS_MSG_COOKIE;
623
624 status = wlan_objmgr_vdev_try_get_ref(cmd->vdev, WLAN_SERIALIZATION_ID);
625 if (QDF_IS_STATUS_ERROR(status)) {
626 ser_err("unable to get reference for vdev %d",
627 wlan_vdev_get_id(cmd->vdev));
628 return;
629 }
630
631 timeout_cmd = qdf_mem_malloc(sizeof(*timeout_cmd));
632 if (!timeout_cmd) {
633 wlan_objmgr_vdev_release_ref(cmd->vdev, WLAN_SERIALIZATION_ID);
634 return;
635 }
636
637 qdf_mem_copy(timeout_cmd, cmd, sizeof(*timeout_cmd));
638
639 mc_timer_wrapper =
640 scheduler_qdf_mc_timer_init(wlan_serialization_generic_timer_cb,
641 timeout_cmd);
642
643 if (!mc_timer_wrapper) {
644 ser_err("failed to allocate sched_qdf_mc_timer_cb_wrapper");
645 goto failed_mc_allocation;
646 }
647
648 msg.callback = scheduler_qdf_mc_timer_callback_t_wrapper;
649 msg.bodyptr = mc_timer_wrapper;
650 msg.bodyval = 0;
651 msg.flush_callback = wlan_serialization_mc_flush;
652
653 if (scheduler_post_message(QDF_MODULE_ID_SERIALIZATION,
654 QDF_MODULE_ID_SERIALIZATION,
655 QDF_MODULE_ID_SYS, &msg) ==
656 QDF_STATUS_SUCCESS)
657 return;
658
659 ser_err("Could not enqueue timer to timer queue");
660 qdf_mem_free(mc_timer_wrapper);
661 failed_mc_allocation:
662 /* free mem and release ref on error */
663 wlan_objmgr_vdev_release_ref(timeout_cmd->vdev, WLAN_SERIALIZATION_ID);
664 qdf_mem_free(timeout_cmd);
665 }
666
wlan_serialization_timer_handler(void * arg)667 static void wlan_serialization_timer_handler(void *arg)
668 {
669 struct wlan_serialization_timer *timer = arg;
670 struct wlan_serialization_command *cmd = timer->cmd;
671
672 if (!cmd) {
673 ser_err("Command not found");
674 return;
675 }
676
677 ser_err("Active cmd timeout for cmd_type %d vdev %d cmd id %d",
678 cmd->cmd_type, wlan_vdev_get_id(cmd->vdev),
679 cmd->cmd_id);
680
681 wlan_serialization_timer_cb_mc_ctx(cmd);
682 }
683
684 QDF_STATUS
wlan_serialization_find_and_update_timer(struct wlan_objmgr_psoc * psoc,struct wlan_serialization_command * cmd)685 wlan_serialization_find_and_update_timer(
686 struct wlan_objmgr_psoc *psoc,
687 struct wlan_serialization_command *cmd)
688 {
689 struct wlan_ser_psoc_obj *psoc_ser_obj;
690 struct wlan_serialization_timer *ser_timer;
691 QDF_STATUS status = QDF_STATUS_E_FAILURE;
692 int i = 0;
693
694 if (!psoc || !cmd) {
695 ser_err("invalid param");
696 goto exit;
697 }
698
699 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
700 /*
701 * Here cmd_id and cmd_type are used to locate the timer being
702 * associated with command.
703 */
704 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
705
706 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
707 ser_timer = &psoc_ser_obj->timers[i];
708 if (!(ser_timer->cmd) ||
709 (ser_timer->cmd->cmd_id != cmd->cmd_id) ||
710 (ser_timer->cmd->cmd_type != cmd->cmd_type) ||
711 (ser_timer->cmd->vdev != cmd->vdev))
712 continue;
713
714 qdf_timer_mod(&ser_timer->timer,
715 cmd->cmd_timeout_duration);
716 status = QDF_STATUS_SUCCESS;
717 break;
718 }
719
720 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
721
722 if (QDF_IS_STATUS_ERROR(status))
723 ser_debug("Can't find timer for cmd_type %d", cmd->cmd_type);
724
725 exit:
726 return status;
727 }
728
729 QDF_STATUS
wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc * psoc,struct wlan_serialization_command * cmd,enum ser_queue_reason ser_reason)730 wlan_serialization_find_and_stop_timer(struct wlan_objmgr_psoc *psoc,
731 struct wlan_serialization_command *cmd,
732 enum ser_queue_reason ser_reason)
733 {
734 struct wlan_ser_psoc_obj *psoc_ser_obj;
735 struct wlan_serialization_timer *ser_timer;
736 QDF_STATUS status = QDF_STATUS_E_FAILURE;
737 int i = 0;
738 uint32_t phy_version;
739 struct wlan_objmgr_vdev *vdev;
740
741 if (!psoc || !cmd) {
742 ser_err("invalid param");
743 goto exit;
744 }
745
746 if (cmd->cmd_timeout_duration == 0) {
747 phy_version = wlan_psoc_get_nif_phy_version(psoc);
748 if (wlan_is_emulation_platform(phy_version)) {
749 ser_err("[SCAN-EMULATION]: Not performing timer funcs");
750 status = QDF_STATUS_SUCCESS;
751 goto exit;
752 }
753 }
754
755 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
756 /*
757 * Here cmd_id and cmd_type are used to locate the timer being
758 * associated with command.
759 */
760 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
761
762 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
763 ser_timer = &psoc_ser_obj->timers[i];
764 if (!(ser_timer->cmd) ||
765 (ser_timer->cmd->cmd_id != cmd->cmd_id) ||
766 (ser_timer->cmd->cmd_type != cmd->cmd_type) ||
767 (ser_timer->cmd->vdev != cmd->vdev))
768 continue;
769
770 vdev = ser_timer->cmd->vdev;
771 status = wlan_serialization_stop_timer(ser_timer);
772 /*
773 * Release the vdev reference when the active cmd is removed
774 * through remove/cancel request.
775 */
776 wlan_objmgr_vdev_release_ref(vdev, WLAN_SERIALIZATION_ID);
777
778 break;
779
780 }
781
782 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
783
784 if (QDF_IS_STATUS_ERROR(status))
785 ser_err("Can't find timer for cmd_type %d cmd id %d",
786 cmd->cmd_type, cmd->cmd_id);
787
788 exit:
789 return status;
790 }
791
792 QDF_STATUS
wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc * psoc,struct wlan_serialization_command * cmd,enum ser_queue_reason ser_reason)793 wlan_serialization_find_and_start_timer(struct wlan_objmgr_psoc *psoc,
794 struct wlan_serialization_command *cmd,
795 enum ser_queue_reason ser_reason)
796 {
797 QDF_STATUS status = QDF_STATUS_E_FAILURE;
798 struct wlan_ser_psoc_obj *psoc_ser_obj;
799 struct wlan_serialization_timer *ser_timer;
800 int i = 0;
801 uint32_t nif_phy_ver;
802
803 if (!psoc || !cmd) {
804 ser_err("invalid param");
805 goto error;
806 }
807
808 nif_phy_ver = wlan_psoc_get_nif_phy_version(psoc);
809 if ((cmd->cmd_timeout_duration == 0) &&
810 (wlan_is_emulation_platform(nif_phy_ver))) {
811 ser_err("[SCAN-EMULATION]: Not performing timer functions\n");
812 status = QDF_STATUS_SUCCESS;
813 goto error;
814 }
815
816 psoc_ser_obj = wlan_serialization_get_psoc_obj(psoc);
817
818 wlan_serialization_acquire_lock(&psoc_ser_obj->timer_lock);
819
820 for (i = 0; psoc_ser_obj->max_active_cmds > i; i++) {
821 /* Keep trying timer */
822 ser_timer = &psoc_ser_obj->timers[i];
823 if (ser_timer->cmd)
824 continue;
825
826 /* Remember timer is pointing to command */
827 ser_timer->cmd = cmd;
828 status = QDF_STATUS_SUCCESS;
829
830 /*
831 * Get vdev reference before starting the timer
832 * Remove the reference before removing the command
833 * in any one of the cases:
834 * 1. Active command is removed through remove/cancel request
835 * 2. Timer expiry handler is completed.
836 */
837
838 status = wlan_objmgr_vdev_try_get_ref(ser_timer->cmd->vdev,
839 WLAN_SERIALIZATION_ID);
840 if (QDF_IS_STATUS_ERROR(status)) {
841 /*
842 * Set cmd to null so that ref release is not tried for
843 * vdev when timer is flushed.
844 */
845 ser_timer->cmd = NULL;
846 wlan_serialization_release_lock(
847 &psoc_ser_obj->timer_lock);
848 ser_err("Unbale to get vdev reference");
849 status = QDF_STATUS_E_FAILURE;
850 goto error;
851 }
852 break;
853 }
854
855 wlan_serialization_release_lock(&psoc_ser_obj->timer_lock);
856
857 if (QDF_IS_STATUS_SUCCESS(status)) {
858 qdf_timer_init(NULL, &ser_timer->timer,
859 wlan_serialization_timer_handler,
860 ser_timer, QDF_TIMER_TYPE_SW);
861 qdf_timer_mod(&ser_timer->timer, cmd->cmd_timeout_duration);
862 } else {
863 ser_err("Failed to start timer for cmd: type[%d] id[%d] high_priority[%d] blocking[%d]",
864 cmd->cmd_type, cmd->cmd_id, cmd->is_high_priority,
865 cmd->is_blocking);
866 }
867
868 error:
869 return status;
870 }
871
872 enum wlan_serialization_cmd_status
wlan_serialization_cmd_cancel_handler(struct wlan_ser_pdev_obj * ser_obj,struct wlan_serialization_command * cmd,struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev,enum wlan_serialization_cmd_type cmd_type,uint8_t queue_type,enum wlan_ser_cmd_attr cmd_attr)873 wlan_serialization_cmd_cancel_handler(
874 struct wlan_ser_pdev_obj *ser_obj,
875 struct wlan_serialization_command *cmd,
876 struct wlan_objmgr_pdev *pdev, struct wlan_objmgr_vdev *vdev,
877 enum wlan_serialization_cmd_type cmd_type, uint8_t queue_type,
878 enum wlan_ser_cmd_attr cmd_attr)
879 {
880 enum wlan_serialization_cmd_status active_status =
881 WLAN_SER_CMD_NOT_FOUND;
882 enum wlan_serialization_cmd_status pending_status =
883 WLAN_SER_CMD_NOT_FOUND;
884 enum wlan_serialization_cmd_status status =
885 WLAN_SER_CMD_NOT_FOUND;
886
887 if (!ser_obj) {
888 ser_err("invalid serial object");
889 goto error;
890 }
891
892 if (queue_type & WLAN_SERIALIZATION_ACTIVE_QUEUE) {
893 if (cmd_type < WLAN_SER_CMD_NONSCAN)
894 active_status = wlan_ser_cancel_scan_cmd(
895 ser_obj, pdev, vdev, cmd,
896 cmd_type, true);
897 else
898 active_status = wlan_ser_cancel_non_scan_cmd(
899 ser_obj, pdev, vdev, cmd,
900 cmd_type, true, cmd_attr);
901 }
902
903 if (queue_type & WLAN_SERIALIZATION_PENDING_QUEUE) {
904 if (cmd_type < WLAN_SER_CMD_NONSCAN)
905 pending_status = wlan_ser_cancel_scan_cmd(
906 ser_obj, pdev, vdev, cmd,
907 cmd_type, false);
908 else
909 pending_status = wlan_ser_cancel_non_scan_cmd(
910 ser_obj, pdev, vdev, cmd,
911 cmd_type, false, cmd_attr);
912 }
913
914 if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST &&
915 pending_status == WLAN_SER_CMD_IN_PENDING_LIST)
916 status = WLAN_SER_CMDS_IN_ALL_LISTS;
917 else if (active_status == WLAN_SER_CMD_IN_ACTIVE_LIST)
918 status = active_status;
919 else if (pending_status == WLAN_SER_CMD_IN_PENDING_LIST)
920 status = pending_status;
921
922 error:
923 return status;
924 }
925
926 enum wlan_serialization_cmd_status
wlan_serialization_find_and_cancel_cmd(struct wlan_serialization_command * cmd,enum wlan_serialization_cancel_type req_type,uint8_t queue_type)927 wlan_serialization_find_and_cancel_cmd(
928 struct wlan_serialization_command *cmd,
929 enum wlan_serialization_cancel_type req_type,
930 uint8_t queue_type)
931 {
932 enum wlan_serialization_cmd_status status = WLAN_SER_CMD_NOT_FOUND;
933 struct wlan_ser_pdev_obj *ser_obj = NULL;
934 struct wlan_objmgr_pdev *pdev;
935
936 if (!cmd) {
937 ser_err("Invalid cmd");
938 goto error;
939 }
940
941 pdev = wlan_serialization_get_pdev_from_cmd(cmd);
942 if (!pdev) {
943 ser_err("Invalid pdev");
944 goto error;
945 }
946 ser_obj = wlan_serialization_get_pdev_obj(pdev);
947 if (!ser_obj) {
948 ser_err("Invalid ser_obj");
949 goto error;
950 }
951
952 switch (req_type) {
953 case WLAN_SER_CANCEL_SINGLE_SCAN:
954 /* remove scan cmd which matches the given cmd struct */
955 status = wlan_serialization_cmd_cancel_handler(
956 ser_obj, cmd, NULL, NULL,
957 WLAN_SER_CMD_SCAN, queue_type,
958 WLAN_SER_CMD_ATTR_NONE);
959 break;
960 case WLAN_SER_CANCEL_PDEV_SCANS:
961 /* remove all scan cmds which matches the pdev object */
962 status = wlan_serialization_cmd_cancel_handler(
963 ser_obj, NULL, pdev, NULL,
964 WLAN_SER_CMD_SCAN, queue_type,
965 WLAN_SER_CMD_ATTR_NONE);
966 break;
967 case WLAN_SER_CANCEL_VDEV_SCANS:
968 case WLAN_SER_CANCEL_VDEV_HOST_SCANS:
969 /* remove all scan cmds which matches the vdev object */
970 status = wlan_serialization_cmd_cancel_handler(
971 ser_obj, NULL, NULL, cmd->vdev,
972 WLAN_SER_CMD_SCAN, queue_type,
973 WLAN_SER_CMD_ATTR_NONE);
974 break;
975 case WLAN_SER_CANCEL_NON_SCAN_CMD:
976 /* remove nonscan cmd which matches the given cmd */
977 status = wlan_serialization_cmd_cancel_handler(
978 ser_obj, cmd, NULL, NULL,
979 WLAN_SER_CMD_NONSCAN, queue_type,
980 WLAN_SER_CMD_ATTR_NONE);
981 break;
982 case WLAN_SER_CANCEL_PDEV_NON_SCAN_CMD:
983 /* remove all non scan cmds which matches the pdev object */
984 status = wlan_serialization_cmd_cancel_handler(
985 ser_obj, NULL, pdev, NULL,
986 WLAN_SER_CMD_NONSCAN, queue_type,
987 WLAN_SER_CMD_ATTR_NONE);
988 break;
989 case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD:
990 /* remove all non scan cmds which matches the vdev object */
991 status = wlan_serialization_cmd_cancel_handler(
992 ser_obj, NULL, NULL, cmd->vdev,
993 WLAN_SER_CMD_NONSCAN, queue_type,
994 WLAN_SER_CMD_ATTR_NONE);
995 break;
996 case WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE:
997 /*
998 * remove all non scan cmds which matches the vdev
999 * and given cmd type
1000 */
1001 status = wlan_serialization_cmd_cancel_handler(
1002 ser_obj, NULL, NULL, cmd->vdev,
1003 cmd->cmd_type, queue_type,
1004 WLAN_SER_CMD_ATTR_NONE);
1005 break;
1006 case WLAN_SER_CANCEL_VDEV_NON_SCAN_NB_CMD:
1007 /*
1008 * remove all non-blocking non-scan cmds which matches the given
1009 * vdev
1010 */
1011 status = wlan_serialization_cmd_cancel_handler(
1012 ser_obj, NULL, NULL, cmd->vdev,
1013 WLAN_SER_CMD_NONSCAN, queue_type,
1014 WLAN_SER_CMD_ATTR_NONBLOCK);
1015 break;
1016 default:
1017 ser_err("Invalid request");
1018 }
1019
1020 error:
1021
1022 return status;
1023 }
1024