1 /*
2 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /*
19 * DOC: contains MLO manager ap related functionality
20 */
21 #include <qdf_module.h>
22 #include "wlan_objmgr_vdev_obj.h"
23 #include "wlan_mlo_mgr_ap.h"
24 #include <wlan_mlo_mgr_cmn.h>
25 #include <wlan_mlo_mgr_main.h>
26 #include <wlan_utility.h>
27 #ifdef WLAN_MLO_MULTI_CHIP
28 #include "cdp_txrx_mlo.h"
29 #endif
30 #include "wlan_mlo_mgr_peer.h"
31
32 #ifdef WLAN_MLO_MULTI_CHIP
mlo_ap_vdev_attach(struct wlan_objmgr_vdev * vdev,uint8_t link_id,uint16_t vdev_count)33 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
34 uint8_t link_id,
35 uint16_t vdev_count)
36 {
37 struct wlan_mlo_dev_context *dev_ctx;
38 uint8_t pr_vdev_ids[WLAN_UMAC_MLO_MAX_VDEVS] = { CDP_INVALID_VDEV_ID };
39 struct wlan_objmgr_psoc *psoc;
40 int i;
41
42 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
43 mlo_err("Invalid input");
44 return false;
45 }
46
47 psoc = wlan_vdev_get_psoc(vdev);
48 if (!psoc)
49 return false;
50
51 dev_ctx = vdev->mlo_dev_ctx;
52
53 if (!vdev->vdev_objmgr.mlo_bridge_vdev) {
54 wlan_vdev_set_link_id(vdev, link_id);
55 wlan_vdev_mlme_set_mlo_vdev(vdev);
56
57 /*
58 * every link will trigger mlo_ap_vdev_attach,
59 * and they should provide the same vdev_count.
60 */
61 mlo_dev_lock_acquire(dev_ctx);
62 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count;
63 mlo_dev_lock_release(dev_ctx);
64 }
65
66 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
67 if (dev_ctx->wlan_vdev_list[i])
68 pr_vdev_ids[i] = wlan_vdev_get_id(dev_ctx->wlan_vdev_list[i]);
69 }
70
71 /* reset the vdev id list */
72 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++)
73 pr_vdev_ids[i] = CDP_INVALID_VDEV_ID;
74
75 /* update the bridge vaps in partner list*/
76 for (i = 0; i < WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS; i++) {
77 if (dev_ctx->wlan_bridge_vdev_list[i])
78 pr_vdev_ids[i] = wlan_vdev_get_id(
79 dev_ctx->wlan_bridge_vdev_list[i]);
80 }
81
82 return true;
83 }
84 #else
mlo_ap_vdev_attach(struct wlan_objmgr_vdev * vdev,uint8_t link_id,uint16_t vdev_count)85 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
86 uint8_t link_id,
87 uint16_t vdev_count)
88 {
89 struct wlan_mlo_dev_context *dev_ctx;
90
91 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
92 mlo_err("Invalid input");
93 return false;
94 }
95
96 dev_ctx = vdev->mlo_dev_ctx;
97 wlan_vdev_set_link_id(vdev, link_id);
98 wlan_vdev_mlme_set_mlo_vdev(vdev);
99
100 /*
101 * every link will trigger mlo_ap_vdev_attach,
102 * and they should provide the same vdev_count.
103 */
104 mlo_dev_lock_acquire(dev_ctx);
105 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count;
106 mlo_dev_lock_release(dev_ctx);
107
108 return true;
109 }
110 #endif
111
112 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
mlo_ap_get_bridge_vdev_list(struct wlan_objmgr_vdev * vdev,uint16_t * vdev_count,struct wlan_objmgr_vdev ** wlan_bridge_vdev_list)113 void mlo_ap_get_bridge_vdev_list(struct wlan_objmgr_vdev *vdev,
114 uint16_t *vdev_count,
115 struct wlan_objmgr_vdev **wlan_bridge_vdev_list)
116 {
117 struct wlan_mlo_dev_context *dev_ctx;
118 int i;
119 QDF_STATUS status;
120
121 *vdev_count = 0;
122
123 if (!vdev || !vdev->mlo_dev_ctx) {
124 mlo_err("Invalid input");
125 return;
126 }
127
128 dev_ctx = vdev->mlo_dev_ctx;
129
130 mlo_dev_lock_acquire(dev_ctx);
131 *vdev_count = 0;
132 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_bridge_vdev_list); i++) {
133 if (dev_ctx->wlan_bridge_vdev_list[i]) {
134 status = wlan_objmgr_vdev_try_get_ref(
135 dev_ctx->wlan_bridge_vdev_list[i],
136 WLAN_MLO_MGR_ID);
137 if (QDF_IS_STATUS_ERROR(status))
138 break;
139 wlan_bridge_vdev_list[*vdev_count] =
140 dev_ctx->wlan_bridge_vdev_list[i];
141 (*vdev_count) += 1;
142 }
143 }
144 mlo_dev_lock_release(dev_ctx);
145 }
146
mlo_ap_get_bridge_vdev_count(struct wlan_mlo_dev_context * mld_ctx,uint16_t * vdev_count)147 QDF_STATUS mlo_ap_get_bridge_vdev_count(struct wlan_mlo_dev_context *mld_ctx,
148 uint16_t *vdev_count)
149 {
150 int i;
151
152 *vdev_count = 0;
153
154 if (!mld_ctx) {
155 mlo_err("Invalid input");
156 return QDF_STATUS_E_NULL_VALUE;
157 }
158
159 mlo_dev_lock_acquire(mld_ctx);
160 *vdev_count = 0;
161 for (i = 0; i < QDF_ARRAY_SIZE(mld_ctx->wlan_bridge_vdev_list); i++) {
162 if (mld_ctx->wlan_bridge_vdev_list[i])
163 (*vdev_count) += 1;
164 }
165 mlo_dev_lock_release(mld_ctx);
166
167 return QDF_STATUS_SUCCESS;
168 }
169
mlo_ap_get_vdev_list_no_flag(struct wlan_objmgr_vdev * vdev,uint16_t * vdev_count,struct wlan_objmgr_vdev ** wlan_vdev_list)170 void mlo_ap_get_vdev_list_no_flag(struct wlan_objmgr_vdev *vdev,
171 uint16_t *vdev_count,
172 struct wlan_objmgr_vdev **wlan_vdev_list)
173 {
174 struct wlan_mlo_dev_context *dev_ctx;
175 int i;
176 QDF_STATUS status;
177
178 *vdev_count = 0;
179
180 if (!vdev || !vdev->mlo_dev_ctx) {
181 mlo_err("Invalid input");
182 return;
183 }
184
185 dev_ctx = vdev->mlo_dev_ctx;
186
187 mlo_dev_lock_acquire(dev_ctx);
188 *vdev_count = 0;
189 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
190 if (dev_ctx->wlan_vdev_list[i]) {
191 status = wlan_objmgr_vdev_try_get_ref(
192 dev_ctx->wlan_vdev_list[i],
193 WLAN_MLO_MGR_ID);
194 if (QDF_IS_STATUS_ERROR(status))
195 break;
196 wlan_vdev_list[*vdev_count] =
197 dev_ctx->wlan_vdev_list[i];
198 (*vdev_count) += 1;
199 }
200 }
201 mlo_dev_lock_release(dev_ctx);
202 }
203 #endif
204
mlo_peer_get_vdev_list(struct wlan_objmgr_peer * peer,uint16_t * vdev_count,struct wlan_objmgr_vdev ** wlan_vdev_list)205 void mlo_peer_get_vdev_list(struct wlan_objmgr_peer *peer,
206 uint16_t *vdev_count,
207 struct wlan_objmgr_vdev **wlan_vdev_list)
208 {
209 struct wlan_mlo_link_peer_entry *peer_entry;
210 struct wlan_objmgr_peer *link_peer;
211 int i;
212 QDF_STATUS status;
213
214 *vdev_count = 0;
215
216 if (!peer) {
217 mlo_err("Invalid input");
218 return;
219 }
220
221 mlo_peer_lock_acquire(peer->mlo_peer_ctx);
222
223 for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
224 peer_entry = &peer->mlo_peer_ctx->peer_list[i];
225 link_peer = peer_entry->link_peer;
226 if (!link_peer)
227 continue;
228
229 status = wlan_objmgr_vdev_try_get_ref(
230 wlan_peer_get_vdev(link_peer),
231 WLAN_MLO_MGR_ID);
232 if (QDF_IS_STATUS_ERROR(status))
233 break;
234
235 wlan_vdev_list[*vdev_count] =
236 wlan_peer_get_vdev(link_peer);
237 (*vdev_count) += 1;
238 }
239
240 mlo_peer_lock_release(peer->mlo_peer_ctx);
241 }
242
mlo_ap_get_vdev_list(struct wlan_objmgr_vdev * vdev,uint16_t * vdev_count,struct wlan_objmgr_vdev ** wlan_vdev_list)243 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev,
244 uint16_t *vdev_count,
245 struct wlan_objmgr_vdev **wlan_vdev_list)
246 {
247 struct wlan_mlo_dev_context *dev_ctx;
248 int i;
249 QDF_STATUS status;
250
251 *vdev_count = 0;
252
253 if (!vdev || !vdev->mlo_dev_ctx) {
254 mlo_err("Invalid input");
255 return;
256 }
257
258 dev_ctx = vdev->mlo_dev_ctx;
259
260 mlo_dev_lock_acquire(dev_ctx);
261 *vdev_count = 0;
262 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
263 if (dev_ctx->wlan_vdev_list[i] &&
264 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) {
265 status = wlan_objmgr_vdev_try_get_ref(
266 dev_ctx->wlan_vdev_list[i],
267 WLAN_MLO_MGR_ID);
268 if (QDF_IS_STATUS_ERROR(status))
269 break;
270 wlan_vdev_list[*vdev_count] =
271 dev_ctx->wlan_vdev_list[i];
272 (*vdev_count) += 1;
273 }
274 }
275 mlo_dev_lock_release(dev_ctx);
276 }
277
mlo_ap_get_active_vdev_list(struct wlan_objmgr_vdev * vdev,uint16_t * vdev_count,struct wlan_objmgr_vdev ** wlan_vdev_list)278 void mlo_ap_get_active_vdev_list(struct wlan_objmgr_vdev *vdev,
279 uint16_t *vdev_count,
280 struct wlan_objmgr_vdev **wlan_vdev_list)
281 {
282 struct wlan_mlo_dev_context *dev_ctx;
283 int i;
284 QDF_STATUS status;
285 struct wlan_objmgr_vdev *partner_vdev = NULL;
286
287 *vdev_count = 0;
288
289 if (!vdev || !vdev->mlo_dev_ctx) {
290 mlo_err("Invalid input");
291 return;
292 }
293
294 dev_ctx = vdev->mlo_dev_ctx;
295
296 mlo_dev_lock_acquire(dev_ctx);
297 *vdev_count = 0;
298 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
299 partner_vdev = dev_ctx->wlan_vdev_list[i];
300 if (partner_vdev &&
301 wlan_vdev_mlme_is_mlo_ap(partner_vdev)) {
302 if (wlan_vdev_chan_config_valid(partner_vdev) !=
303 QDF_STATUS_SUCCESS)
304 continue;
305
306 status = wlan_objmgr_vdev_try_get_ref(partner_vdev,
307 WLAN_MLO_MGR_ID);
308 if (QDF_IS_STATUS_ERROR(status))
309 break;
310 wlan_vdev_list[*vdev_count] = partner_vdev;
311 (*vdev_count) += 1;
312 }
313 }
314 mlo_dev_lock_release(dev_ctx);
315 }
316
mlo_ap_get_partner_vdev_list_from_mld(struct wlan_objmgr_vdev * vdev,uint16_t * vdev_count,struct wlan_objmgr_vdev ** wlan_vdev_list)317 void mlo_ap_get_partner_vdev_list_from_mld(
318 struct wlan_objmgr_vdev *vdev,
319 uint16_t *vdev_count,
320 struct wlan_objmgr_vdev **wlan_vdev_list)
321 {
322 struct wlan_mlo_dev_context *dev_ctx;
323 int i;
324 QDF_STATUS status;
325
326 *vdev_count = 0;
327
328 if (!vdev || !vdev->mlo_dev_ctx) {
329 mlo_err("Invalid input");
330 return;
331 }
332
333 dev_ctx = vdev->mlo_dev_ctx;
334
335 mlo_dev_lock_acquire(dev_ctx);
336 *vdev_count = 0;
337 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
338 if (dev_ctx->wlan_vdev_list[i] &&
339 (QDF_SAP_MODE ==
340 wlan_vdev_mlme_get_opmode(dev_ctx->wlan_vdev_list[i]))) {
341 status = wlan_objmgr_vdev_try_get_ref(
342 dev_ctx->wlan_vdev_list[i],
343 WLAN_MLO_MGR_ID);
344 if (QDF_IS_STATUS_ERROR(status))
345 break;
346 wlan_vdev_list[*vdev_count] =
347 dev_ctx->wlan_vdev_list[i];
348 (*vdev_count) += 1;
349 }
350 }
351 mlo_dev_lock_release(dev_ctx);
352 }
353
354 /**
355 * mlo_ap_vdev_is_start_resp_rcvd() - Is start response received on this vdev
356 * @vdev: vdev pointer
357 *
358 * Return: SUCCESS if start response is received, ERROR otherwise.
359 */
mlo_ap_vdev_is_start_resp_rcvd(struct wlan_objmgr_vdev * vdev)360 static QDF_STATUS mlo_ap_vdev_is_start_resp_rcvd(struct wlan_objmgr_vdev *vdev)
361 {
362 enum wlan_vdev_state state;
363
364 if (!vdev) {
365 mlme_err("vdev is null");
366 return QDF_STATUS_E_FAILURE;
367 }
368
369 if (!wlan_vdev_mlme_is_mlo_ap(vdev))
370 return QDF_STATUS_E_FAILURE;
371
372 state = wlan_vdev_mlme_get_state(vdev);
373 if ((state == WLAN_VDEV_S_UP) ||
374 (state == WLAN_VDEV_S_DFS_CAC_WAIT) ||
375 (state == WLAN_VDEV_S_SUSPEND))
376 return QDF_STATUS_SUCCESS;
377
378 return QDF_STATUS_E_FAILURE;
379 }
380
wlan_mlo_ap_get_active_links(struct wlan_objmgr_vdev * vdev)381 uint16_t wlan_mlo_ap_get_active_links(struct wlan_objmgr_vdev *vdev)
382 {
383 uint16_t vdev_count = 0;
384 struct wlan_mlo_dev_context *dev_ctx;
385 int i;
386
387 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
388 mlo_err("Invalid input");
389 return vdev_count;
390 }
391
392 dev_ctx = vdev->mlo_dev_ctx;
393
394 mlo_dev_lock_acquire(dev_ctx);
395 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
396 if (dev_ctx->wlan_vdev_list[i] && QDF_IS_STATUS_SUCCESS(
397 mlo_ap_vdev_is_start_resp_rcvd(dev_ctx->wlan_vdev_list[i])))
398 vdev_count++;
399 }
400
401 mlo_dev_lock_release(dev_ctx);
402
403 return vdev_count;
404 }
405
406 /**
407 * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up
408 * @vdev: vdev pointer
409 *
410 * Return: true if given ap is allowed to up, false otherwise.
411 */
mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev * vdev)412 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev)
413 {
414 uint16_t vdev_count = 0;
415 bool up_allowed = false;
416 struct wlan_mlo_dev_context *dev_ctx;
417
418 if (!vdev) {
419 mlo_err("Invalid input");
420 return up_allowed;
421 }
422
423 dev_ctx = vdev->mlo_dev_ctx;
424
425 vdev_count = wlan_mlo_ap_get_active_links(vdev);
426 if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs)
427 up_allowed = true;
428
429 return up_allowed;
430 }
431
432 /**
433 * mlo_pre_link_up() - Carry out preparation before bringing up the link
434 * @vdev: vdev pointer
435 *
436 * Return: true if preparation is done successfully
437 */
mlo_pre_link_up(struct wlan_objmgr_vdev * vdev)438 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev)
439 {
440 if (!vdev) {
441 mlo_err("vdev is NULL");
442 return false;
443 }
444
445 if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) &&
446 (wlan_vdev_mlme_get_substate(vdev) ==
447 WLAN_VDEV_SS_MLO_SYNC_WAIT))
448 return true;
449
450 return false;
451 }
452
453 /**
454 * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not.
455 * If it is allowed, for every link in the
456 * WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver
457 * event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE.
458 *
459 * This function is triggered once a link gets start response or enters
460 * WLAN_VDEV_SS_MLO_SYNC_WAIT state
461 *
462 * @vdev: vdev pointer
463 *
464 * Return: true if MLO_SYNC_COMPLETE is posted, else false
465 */
mlo_handle_link_ready(struct wlan_objmgr_vdev * vdev)466 static bool mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev)
467 {
468 struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
469 struct wlan_mlo_dev_context *mld_ctx = NULL;
470 uint16_t num_links = 0;
471 uint8_t i;
472 uint8_t idx;
473 enum wlan_vdev_state state;
474 enum wlan_vdev_state substate;
475
476
477 if (!vdev || !vdev->mlo_dev_ctx) {
478 mlo_err("Invalid input");
479 return false;
480 }
481
482 if (wlan_vdev_is_up(vdev) == QDF_STATUS_SUCCESS)
483 return true;
484
485 mld_ctx = vdev->mlo_dev_ctx;
486 /*
487 * The last vdev in MLD to receive start response is responsible for
488 * dispatching MLO_SYNC_COMPLETE event all the partner vdevs and then to
489 * self.
490 *
491 * If vdev_up_bmap is set, then return.
492 */
493 idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
494 if (idx == MLO_INVALID_LINK_IDX)
495 return false;
496
497 if (wlan_util_map_index_is_set(mld_ctx->ap_ctx->mlo_vdev_up_bmap,
498 idx)) {
499 mlo_debug("Bmap is set for idx:%u mld_addr " QDF_MAC_ADDR_FMT,
500 idx, QDF_MAC_ADDR_REF(mld_ctx->mld_addr.bytes));
501 return false;
502 }
503
504 mlo_ap_lock_acquire(vdev->mlo_dev_ctx->ap_ctx);
505 state = wlan_vdev_mlme_get_state(vdev);
506 substate = wlan_vdev_mlme_get_substate(vdev);
507 if (state == WLAN_VDEV_S_UP && substate == WLAN_VDEV_SS_MLO_SYNC_WAIT) {
508 idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
509 if (idx == MLO_INVALID_LINK_IDX) {
510 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx);
511 return false;
512 }
513 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_up_bmap,
514 idx, 1);
515 mlo_debug("Setting Bmap for idx:%u mld_addr " QDF_MAC_ADDR_FMT,
516 idx, QDF_MAC_ADDR_REF(mld_ctx->mld_addr.bytes));
517 }
518
519 if (!mlo_is_ap_vdev_up_allowed(vdev)) {
520 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx);
521 return false;
522 }
523
524 mlo_ap_get_vdev_list(vdev, &num_links, vdev_list);
525 if (!num_links || (num_links > QDF_ARRAY_SIZE(vdev_list))) {
526 mlo_err("Invalid number of VDEVs under AP-MLD");
527 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx);
528 return false;
529 }
530
531 for (i = 0; i < num_links; i++) {
532 if (mlo_pre_link_up(vdev_list[i])) {
533 if (vdev_list[i] == vdev) {
534 mlo_release_vdev_ref(vdev_list[i]);
535 continue;
536 }
537
538 idx = mlo_get_link_vdev_ix(mld_ctx, vdev_list[i]);
539 if (idx == MLO_INVALID_LINK_IDX) {
540 mlo_release_vdev_ref(vdev_list[i]);
541 continue;
542 }
543
544 if (wlan_util_map_index_is_set(
545 vdev->mlo_dev_ctx->ap_ctx->mlo_vdev_up_bmap,
546 idx))
547 wlan_vdev_mlme_sm_deliver_evt(
548 vdev_list[i],
549 WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE,
550 0, NULL);
551 }
552 /* Release ref taken as part of mlo_ap_get_vdev_list */
553 mlo_release_vdev_ref(vdev_list[i]);
554 }
555
556 /* Clear up bmap for this vdev as it is moving to UP_ACTIVE state */
557 idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
558 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_up_bmap, idx, 0);
559
560 mlo_ap_lock_release(vdev->mlo_dev_ctx->ap_ctx);
561 return true;
562 }
563
mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev * vdev)564 bool mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev)
565 {
566 return mlo_handle_link_ready(vdev);
567 }
568
mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev * vdev)569 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev)
570 {
571 mlo_handle_link_ready(vdev);
572 }
573
mlo_ap_vdev_detach(struct wlan_objmgr_vdev * vdev)574 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev)
575 {
576 struct wlan_mlo_dev_context *dev_ctx;
577
578 if (!vdev || !vdev->mlo_dev_ctx) {
579 mlo_err("Invalid input");
580 return;
581 }
582
583 dev_ctx = vdev->mlo_dev_ctx;
584
585 mlo_dev_lock_acquire(dev_ctx);
586 dev_ctx->ap_ctx->num_ml_vdevs--;
587 mlo_dev_lock_release(dev_ctx);
588
589 wlan_vdev_mlme_clear_mlo_vdev(vdev);
590 }
591
mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev * vdev)592 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev)
593 {
594 mlo_ap_vdev_detach(vdev);
595 }
596
597 QDF_STATUS
mlo_ap_update_max_ml_peer_ids(uint32_t pdev_id,uint32_t max_ml_peer_ids)598 mlo_ap_update_max_ml_peer_ids(uint32_t pdev_id, uint32_t max_ml_peer_ids)
599 {
600 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
601 uint16_t max_mlo_peer_id_stale;
602
603 max_mlo_peer_id_stale = mlo_mgr_ctx->max_mlo_peer_id;
604
605 ml_peerid_lock_acquire(mlo_mgr_ctx);
606
607 /* Reset the value to default if max_ml_peer_ids received is "0" */
608 mlo_mgr_ctx->max_mlo_peer_id = max_ml_peer_ids ?
609 max_ml_peer_ids : MAX_MLO_PEER_ID;
610
611 mlo_info("max_ml_peer_ids update from: %d to: %d for pdev: %d",
612 max_mlo_peer_id_stale,
613 mlo_mgr_ctx->max_mlo_peer_id, pdev_id);
614
615 mlo_info("max_peer support from target obtained :%d", max_ml_peer_ids);
616
617 ml_peerid_lock_release(mlo_mgr_ctx);
618
619 return QDF_STATUS_SUCCESS;
620 }
621
622 qdf_export_symbol(mlo_ap_update_max_ml_peer_ids);
623
mlo_ap_ml_peerid_alloc(void)624 uint16_t mlo_ap_ml_peerid_alloc(void)
625 {
626 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
627 uint16_t i;
628 uint16_t mlo_peer_id;
629
630 ml_peerid_lock_acquire(mlo_ctx);
631 mlo_peer_id = mlo_ctx->last_mlo_peer_id;
632 for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) {
633 mlo_peer_id = (mlo_peer_id + 1) % mlo_ctx->max_mlo_peer_id;
634
635 if (!mlo_peer_id)
636 continue;
637
638 if (qdf_test_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap))
639 continue;
640
641 qdf_set_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap);
642 break;
643 }
644 mlo_ctx->last_mlo_peer_id = mlo_peer_id;
645 ml_peerid_lock_release(mlo_ctx);
646
647 if (i == mlo_ctx->max_mlo_peer_id)
648 return MLO_INVALID_PEER_ID;
649
650 mlo_debug(" ML peer id %d is allocated", mlo_peer_id);
651
652 return mlo_peer_id;
653 }
654
655 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE
mlo_ap_ml_ptqm_peerid_free(struct wlan_mlo_dev_context * ml_dev,uint16_t mlo_peer_id)656 void mlo_ap_ml_ptqm_peerid_free(struct wlan_mlo_dev_context *ml_dev,
657 uint16_t mlo_peer_id)
658 {
659 /* Free the bitmap for ptqm migration */
660 if (qdf_test_bit(mlo_peer_id, ml_dev->mlo_peer_id_bmap))
661 qdf_clear_bit(mlo_peer_id, ml_dev->mlo_peer_id_bmap);
662 }
663 #endif
664
mlo_ap_ml_peerid_free(uint16_t mlo_peer_id)665 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id)
666 {
667 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
668
669 if ((mlo_peer_id == 0) || (mlo_peer_id == MLO_INVALID_PEER_ID)) {
670 mlo_err(" ML peer id %d is invalid", mlo_peer_id);
671 return;
672 }
673
674 if ((mlo_peer_id > mlo_ctx->max_mlo_peer_id) ||
675 (mlo_peer_id > MAX_MLO_PEER_ID)) {
676 mlo_err(" ML peer id %d is invalid", mlo_peer_id);
677 QDF_BUG(0);
678 return;
679 }
680
681 ml_peerid_lock_acquire(mlo_ctx);
682 if (qdf_test_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap))
683 qdf_clear_bit(mlo_peer_id, mlo_ctx->mlo_peer_id_bmap);
684
685 ml_peerid_lock_release(mlo_ctx);
686
687 mlo_debug(" ML peer id %d is freed", mlo_peer_id);
688 }
689
mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev * vdev)690 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev)
691 {
692 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
693 uint8_t idx;
694
695 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
696 return;
697
698 idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
699 if (idx == MLO_INVALID_LINK_IDX)
700 return;
701
702 mlo_debug("Quiet set for PSOC:%d vdev:%d",
703 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)),
704 wlan_vdev_get_id(vdev));
705
706 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
707 idx, 1);
708 }
709
mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev * vdev)710 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev)
711 {
712 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
713 uint8_t idx;
714
715 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
716 return;
717
718 idx = mlo_get_link_vdev_ix(mld_ctx, vdev);
719 if (idx == MLO_INVALID_LINK_IDX)
720 return;
721
722 mlo_debug("Quiet clear for PSOC:%d vdev:%d",
723 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)),
724 wlan_vdev_get_id(vdev));
725
726 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
727 idx, 0);
728 }
729
mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev * vdev)730 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev)
731 {
732 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx;
733
734 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev))
735 return false;
736
737 return wlan_util_map_is_any_index_set(
738 mld_ctx->ap_ctx->mlo_vdev_quiet_bmap,
739 sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap));
740 }
741
742 QDF_STATUS
mlo_peer_create_get_frm_buf(struct wlan_mlo_peer_context * ml_peer,struct peer_create_notif_s * peer_create,qdf_nbuf_t frm_buf)743 mlo_peer_create_get_frm_buf(
744 struct wlan_mlo_peer_context *ml_peer,
745 struct peer_create_notif_s *peer_create,
746 qdf_nbuf_t frm_buf)
747 {
748 if (wlan_mlo_peer_is_nawds(ml_peer) ||
749 wlan_mlo_peer_is_mesh(ml_peer)) {
750 peer_create->frm_buf = NULL;
751 return QDF_STATUS_SUCCESS;
752 }
753
754 if (!frm_buf)
755 return QDF_STATUS_E_FAILURE;
756
757 peer_create->frm_buf = qdf_nbuf_clone(frm_buf);
758 if (!peer_create->frm_buf)
759 return QDF_STATUS_E_NOMEM;
760
761 return QDF_STATUS_SUCCESS;
762 }
763
764 #ifdef UMAC_SUPPORT_MLNAWDS
mlo_peer_populate_nawds_params(struct wlan_mlo_peer_context * ml_peer,struct mlo_partner_info * ml_info)765 void mlo_peer_populate_nawds_params(
766 struct wlan_mlo_peer_context *ml_peer,
767 struct mlo_partner_info *ml_info)
768 {
769 uint8_t i;
770 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00,
771 0x00, 0x00, 0x00};
772 struct mlnawds_config nawds_config;
773
774 mlo_peer_lock_acquire(ml_peer);
775 ml_peer->is_nawds_ml_peer = false;
776 for (i = 0; i < ml_info->num_partner_links; i++) {
777 nawds_config = ml_info->partner_link_info[i].nawds_config;
778 /*
779 * if ml_info->partner_link_info[i].nawds_config has valid
780 * config(check for non-null mac or non-0 caps), then mark
781 * ml_peer's is_nawds_ml_peer true & copy the config
782 */
783 if ((nawds_config.caps) ||
784 (qdf_mem_cmp(null_mac,
785 nawds_config.mac,
786 sizeof(null_mac)))) {
787 ml_peer->is_nawds_ml_peer = true;
788 ml_peer->nawds_config[i] = nawds_config;
789 }
790 }
791 mlo_peer_lock_release(ml_peer);
792 }
793 #endif
794
795 #ifdef MESH_MODE_SUPPORT
mlo_peer_populate_mesh_params(struct wlan_mlo_peer_context * ml_peer,struct mlo_partner_info * ml_info)796 void mlo_peer_populate_mesh_params(
797 struct wlan_mlo_peer_context *ml_peer,
798 struct mlo_partner_info *ml_info)
799 {
800 uint8_t i;
801 uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0};
802 struct mlnawds_config mesh_config;
803
804 mlo_peer_lock_acquire(ml_peer);
805 ml_peer->is_mesh_ml_peer = false;
806 for (i = 0; i < ml_info->num_partner_links; i++) {
807 mesh_config = ml_info->partner_link_info[i].mesh_config;
808 /*
809 * if ml_info->partner_link_info[i].mesh_config has valid
810 * config(check for non-null mac or non-0 caps), then mark
811 * ml_peer's is_mesh_ml_peer true & copy the config
812 */
813 if ((mesh_config.caps) ||
814 (qdf_mem_cmp(null_mac,
815 mesh_config.mac,
816 sizeof(null_mac)))) {
817 ml_peer->is_mesh_ml_peer = true;
818 ml_peer->mesh_config[i] = mesh_config;
819 }
820 }
821 mlo_peer_lock_release(ml_peer);
822 }
823 #endif
824