xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c (revision 5611ef508114526caa3c58ffe2e188650c7b53d1)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /*
18  * DOC: contains MLO manager ap related functionality
19  */
20 #include "wlan_objmgr_vdev_obj.h"
21 #include "wlan_mlo_mgr_ap.h"
22 #include <wlan_mlo_mgr_cmn.h>
23 #include <wlan_mlo_mgr_main.h>
24 
25 bool mlo_is_mld_ap(struct wlan_objmgr_vdev *vdev)
26 {
27 	return true;
28 }
29 
30 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
31 			uint8_t link_id,
32 			uint16_t vdev_count)
33 {
34 	struct wlan_mlo_dev_context *dev_ctx;
35 
36 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
37 		mlo_err("Invalid input");
38 		return false;
39 	}
40 
41 	dev_ctx = vdev->mlo_dev_ctx;
42 	wlan_vdev_set_link_id(vdev, link_id);
43 	wlan_vdev_mlme_feat_ext2_cap_set(vdev, WLAN_VDEV_FEXT2_MLO);
44 
45 	/**
46 	 * every link will trigger mlo_ap_vdev_attach,
47 	 * and they should provide the same vdev_count.
48 	 */
49 	mlo_dev_lock_acquire(dev_ctx);
50 	dev_ctx->ap_ctx->num_ml_vdevs = vdev_count;
51 	mlo_dev_lock_release(dev_ctx);
52 
53 	return true;
54 }
55 
56 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev,
57 			  uint16_t *vdev_count,
58 			  struct wlan_objmgr_vdev **wlan_vdev_list)
59 {
60 	struct wlan_mlo_dev_context *dev_ctx;
61 	int i;
62 	QDF_STATUS status;
63 
64 	*vdev_count = 0;
65 
66 	if (!vdev || !vdev->mlo_dev_ctx) {
67 		mlo_err("Invalid input");
68 		return;
69 	}
70 
71 	dev_ctx = vdev->mlo_dev_ctx;
72 
73 	mlo_dev_lock_acquire(dev_ctx);
74 	*vdev_count = 0;
75 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
76 		if (dev_ctx->wlan_vdev_list[i] &&
77 		    wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) {
78 			status = wlan_objmgr_vdev_try_get_ref(
79 						dev_ctx->wlan_vdev_list[i],
80 						WLAN_MLO_MGR_ID);
81 			if (QDF_IS_STATUS_ERROR(status))
82 				break;
83 			wlan_vdev_list[*vdev_count] =
84 				dev_ctx->wlan_vdev_list[i];
85 			(*vdev_count) += 1;
86 		}
87 	}
88 	mlo_dev_lock_release(dev_ctx);
89 }
90 
91 /**
92  * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up
93  * @vdev: vdev pointer
94  *
95  * Return: true if given ap is allowed to up, false otherwise.
96  */
97 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev)
98 {
99 	uint16_t vdev_count = 0;
100 	struct wlan_mlo_dev_context *dev_ctx;
101 	int i;
102 	bool up_allowed = false;
103 
104 	if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) {
105 		mlo_err("Invalid input");
106 		return up_allowed;
107 	}
108 
109 	dev_ctx = vdev->mlo_dev_ctx;
110 
111 	mlo_dev_lock_acquire(dev_ctx);
112 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
113 		if (dev_ctx->wlan_vdev_list[i] &&
114 		    wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i]) &&
115 		    QDF_IS_STATUS_SUCCESS(
116 		    wlan_vdev_chan_config_valid(dev_ctx->wlan_vdev_list[i])))
117 			vdev_count++;
118 	}
119 
120 	if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs)
121 		up_allowed = true;
122 	mlo_dev_lock_release(dev_ctx);
123 
124 	return up_allowed;
125 }
126 
127 /**
128  * mlo_pre_link_up() - Carry out preparation before bringing up the link
129  * @vdev: vdev pointer
130  *
131  * Return: true if preparation is done successfully
132  */
133 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev)
134 {
135 	if (!vdev) {
136 		mlo_err("vdev is NULL");
137 		return false;
138 	}
139 
140 	if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) &&
141 	    (wlan_vdev_mlme_get_substate(vdev) ==
142 	     WLAN_VDEV_SS_MLO_SYNC_WAIT))
143 		return true;
144 
145 	return false;
146 }
147 
148 /**
149  * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not.
150  *                           If it is allowed, for every link in the
151  *                           WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver
152  *                           event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE.
153  *
154  * This function is triggered once a link gets start response or enters
155  * LAN_VDEV_SS_MLO_SYNC_WAIT state
156  *
157  * @vdev: vdev pointer
158  *
159  * Return: None
160  */
161 static void mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev)
162 {
163 	struct wlan_mlo_dev_context *dev_ctx;
164 	int i;
165 
166 	if (!vdev || !vdev->mlo_dev_ctx) {
167 		mlo_err("Invalid input");
168 		return;
169 	}
170 
171 	dev_ctx = vdev->mlo_dev_ctx;
172 
173 	if (!mlo_is_ap_vdev_up_allowed(vdev))
174 		return;
175 
176 	mlo_dev_lock_acquire(dev_ctx);
177 	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
178 		if (dev_ctx->wlan_vdev_list[i] &&
179 		    wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i]) &&
180 		    mlo_pre_link_up(dev_ctx->wlan_vdev_list[i]))
181 			wlan_vdev_mlme_sm_deliver_evt_sync(
182 				dev_ctx->wlan_vdev_list[i],
183 				WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE,
184 				0, NULL);
185 	}
186 	mlo_dev_lock_release(dev_ctx);
187 }
188 
189 void mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev)
190 {
191 	mlo_handle_link_ready(vdev);
192 }
193 
194 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev)
195 {
196 	mlo_handle_link_ready(vdev);
197 }
198 
199 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev)
200 {
201 	if (!vdev || !vdev->mlo_dev_ctx) {
202 		mlo_err("Invalid input");
203 		return;
204 	}
205 	wlan_vdev_mlme_feat_ext2_cap_clear(vdev, WLAN_VDEV_FEXT2_MLO);
206 }
207 
208 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev)
209 {
210 	mlo_ap_vdev_detach(vdev);
211 }
212