xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c (revision 2888b71da71bce103343119fa1b31f4a0cee07c8)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 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 #include "wlan_mlo_mgr_main.h"
19 #include "qdf_types.h"
20 #include "wlan_cmn.h"
21 #include "wlan_mlo_mgr_peer.h"
22 #include <wlan_mlo_mgr_ap.h>
23 #include <wlan_mlo_mgr_setup.h>
24 #include <wlan_utility.h>
25 #include <wlan_reg_services_api.h>
26 
27 /**
28  * struct mlpeer_data: PSOC peers MLO data
29  * @total_rssi:  sum of RSSI of all ML peers
30  * @num_ml_peers: Number of ML peer's with this PSOC as TQM
31  * @max_ml_peers: Max ML peers can have this PSOC as TQM
32  *                (it is to distribute peers across all PSOCs)
33  * @num_non_ml_peers: Non MLO peers of this PSOC
34  */
35 struct mlpeer_data {
36 	int32_t total_rssi;
37 	uint16_t num_ml_peers;
38 	uint16_t max_ml_peers;
39 	uint16_t num_non_ml_peers;
40 };
41 
42 /**
43  * struct mlo_all_link_rssi: structure to collect TQM params for all PSOCs
44  * @psoc_tqm_parms:  It collects peer data for all PSOCs
45  * @num_psocs:       Number of PSOCs in the system
46  * @current_psoc_id: current psoc id, it is for iterator
47  */
48 struct mlo_all_link_rssi {
49 	struct mlpeer_data psoc_tqm_parms[WLAN_OBJMGR_MAX_DEVICES];
50 	uint8_t num_psocs;
51 	uint8_t current_psoc_id;
52 };
53 
54 /* Invalid TQM/PSOC ID */
55 #define ML_INVALID_PRIMARY_TQM   0xff
56 
57 static void wlan_mlo_peer_get_rssi(struct wlan_objmgr_psoc *psoc,
58 				   void *obj, void *args)
59 {
60 	struct wlan_mlo_peer_context *mlo_peer_ctx;
61 	struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)obj;
62 	struct mlo_all_link_rssi *rssi_data = (struct mlo_all_link_rssi *)args;
63 	struct mlpeer_data *tqm_params = NULL;
64 	uint8_t index;
65 
66 	mlo_peer_ctx = peer->mlo_peer_ctx;
67 	index = rssi_data->current_psoc_id;
68 	tqm_params = &rssi_data->psoc_tqm_parms[index];
69 
70 	if (!wlan_peer_is_mlo(peer) || !mlo_peer_ctx) {
71 		if (wlan_peer_get_peer_type(peer) == WLAN_PEER_STA)
72 			tqm_params->num_non_ml_peers += 1;
73 		return;
74 	}
75 
76 	/* If this psoc is not primary UMAC, don't account RSSI */
77 	if (mlo_peer_ctx->primary_umac_psoc_id != rssi_data->current_psoc_id)
78 		return;
79 
80 	tqm_params->total_rssi += mlo_peer_ctx->avg_link_rssi;
81 	tqm_params->num_ml_peers += 1;
82 }
83 
84 static void wlan_get_rssi_data_each_psoc(struct wlan_objmgr_psoc *psoc,
85 					 void *arg, uint8_t index)
86 {
87 	struct mlo_all_link_rssi *rssi_data = (struct mlo_all_link_rssi *)arg;
88 	struct mlpeer_data *tqm_params = NULL;
89 
90 	tqm_params = &rssi_data->psoc_tqm_parms[index];
91 
92 	tqm_params->total_rssi = 0;
93 	tqm_params->num_ml_peers = 0;
94 	tqm_params->num_non_ml_peers = 0;
95 	tqm_params->max_ml_peers = MAX_MLO_PEER;
96 
97 	rssi_data->current_psoc_id = index;
98 
99 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PEER_OP,
100 				     wlan_mlo_peer_get_rssi, rssi_data, 0,
101 				     WLAN_MLO_MGR_ID);
102 }
103 
104 static QDF_STATUS mld_get_link_rssi(struct mlo_all_link_rssi *rssi_data)
105 {
106 	rssi_data->num_psocs = 0;
107 
108 	wlan_objmgr_iterate_psoc_list(wlan_get_rssi_data_each_psoc,
109 				      rssi_data, WLAN_MLO_MGR_ID);
110 
111 	return QDF_STATUS_SUCCESS;
112 }
113 
114 static void
115 mld_get_best_primary_umac_w_rssi(struct wlan_mlo_peer_context *ml_peer,
116 				 struct wlan_objmgr_vdev *link_vdevs[])
117 {
118 	struct mlo_all_link_rssi rssi_data;
119 	uint8_t i;
120 	int32_t avg_rssi[WLAN_OBJMGR_MAX_DEVICES] = {0};
121 	int32_t diff_rssi[WLAN_OBJMGR_MAX_DEVICES] = {0};
122 	int32_t diff_low;
123 	bool mld_sta_links[WLAN_OBJMGR_MAX_DEVICES] = {0};
124 	uint8_t num_psocs_w_no_sta = 0;
125 	struct wlan_objmgr_peer *assoc_peer = NULL;
126 	uint8_t prim_link, id;
127 	uint8_t num_psocs;
128 	struct mlpeer_data *tqm_params = NULL;
129 
130 	mld_get_link_rssi(&rssi_data);
131 
132 	for (i = 0; i < rssi_data.num_psocs; i++) {
133 		tqm_params = &rssi_data.psoc_tqm_parms[i];
134 
135 		if (tqm_params->num_ml_peers)
136 			avg_rssi[i] = (tqm_params->total_rssi /
137 				       tqm_params->num_ml_peers);
138 		else
139 			num_psocs_w_no_sta++;
140 	}
141 
142 	assoc_peer = wlan_mlo_peer_get_assoc_peer(ml_peer);
143 	if (!assoc_peer) {
144 		mlo_err("Assoc peer of ML Peer " QDF_MAC_ADDR_FMT " is invalid",
145 			QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes));
146 		QDF_BUG(0);
147 		return;
148 	}
149 
150 	/**
151 	 * If this is first station, then assign primary umac to
152 	 * assoc peer's psoc
153 	 */
154 	if (num_psocs_w_no_sta == rssi_data.num_psocs) {
155 		ml_peer->primary_umac_psoc_id =
156 			wlan_peer_get_psoc_id(assoc_peer);
157 		return;
158 	}
159 
160 	/**
161 	 * If MLD STA associated to a set of links, choose primary UMAC
162 	 * from those links only
163 	 */
164 	num_psocs = 0;
165 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
166 		if (!link_vdevs[i])
167 			continue;
168 
169 		id = wlan_vdev_get_psoc_id(link_vdevs[i]);
170 		if (id >= WLAN_OBJMGR_MAX_DEVICES)
171 			continue;
172 
173 		tqm_params = &rssi_data.psoc_tqm_parms[id];
174 		mld_sta_links[id] = true;
175 
176 		/* If this PSOC has exceeded limit, skip it */
177 		if ((tqm_params->num_ml_peers +
178 		     tqm_params->num_non_ml_peers) >=
179 		     tqm_params->max_ml_peers) {
180 			mld_sta_links[id] = false;
181 			continue;
182 		}
183 
184 		num_psocs++;
185 
186 		/* If no stations are associated, derive diff rssi
187 		 * based on psoc id {0-20, 20-40, 40 } so that
188 		 * stations are distributed across TQMs
189 		 */
190 		if (!avg_rssi[id]) {
191 			diff_rssi[id] = (id * 20);
192 			continue;
193 		}
194 		diff_rssi[id] = (ml_peer->avg_link_rssi >= avg_rssi[id]) ?
195 				(ml_peer->avg_link_rssi - avg_rssi[id]) :
196 				(avg_rssi[id] - ml_peer->avg_link_rssi);
197 	}
198 
199 	prim_link = ML_INVALID_PRIMARY_TQM;
200 	diff_low = 0;
201 
202 	/* find min diff, based on it, allocate primary umac */
203 	for (i = 0; i < WLAN_OBJMGR_MAX_DEVICES; i++) {
204 		if (!mld_sta_links[i])
205 			continue;
206 
207 		/* First iteration */
208 		if (diff_low == 0) {
209 			diff_low = diff_rssi[i];
210 			prim_link = i;
211 		} else if (diff_low > diff_rssi[i]) {
212 			diff_low = diff_rssi[i];
213 			prim_link = i;
214 		}
215 	}
216 
217 	if (prim_link != 0xff)
218 		ml_peer->primary_umac_psoc_id = prim_link;
219 	else
220 		ml_peer->primary_umac_psoc_id =
221 			wlan_peer_get_psoc_id(assoc_peer);
222 }
223 
224 void mlo_peer_assign_primary_umac(
225 		struct wlan_mlo_peer_context *ml_peer,
226 		struct wlan_mlo_link_peer_entry *peer_entry)
227 {
228 	struct wlan_mlo_link_peer_entry *peer_ent_iter;
229 	uint8_t i;
230 	uint8_t primary_umac_set = 0;
231 
232 	/* If MLD is within single SOC, then assoc link becomes
233 	 * primary umac
234 	 */
235 	if (ml_peer->primary_umac_psoc_id == ML_PRIMARY_UMAC_ID_INVAL) {
236 		if (wlan_peer_mlme_is_assoc_peer(peer_entry->link_peer)) {
237 			peer_entry->is_primary = true;
238 			ml_peer->primary_umac_psoc_id =
239 				wlan_peer_get_psoc_id(peer_entry->link_peer);
240 		} else {
241 			peer_entry->is_primary = false;
242 		}
243 	} else {
244 		/* If this peer PSOC is not derived as Primary PSOC,
245 		 * mark is_primary as false
246 		 */
247 		if (wlan_peer_get_psoc_id(peer_entry->link_peer) !=
248 				ml_peer->primary_umac_psoc_id) {
249 			peer_entry->is_primary = false;
250 			return;
251 		}
252 
253 		/* For single SOC, check whether is_primary is set for
254 		 * other partner peer, then mark is_primary false for this peer
255 		 */
256 		for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
257 			peer_ent_iter = &ml_peer->peer_list[i];
258 
259 			if (!peer_ent_iter->link_peer)
260 				continue;
261 
262 			/* Check for other link peers */
263 			if (peer_ent_iter == peer_entry)
264 				continue;
265 
266 			if (wlan_peer_get_psoc_id(peer_ent_iter->link_peer) !=
267 					ml_peer->primary_umac_psoc_id)
268 				continue;
269 
270 			if (peer_ent_iter->is_primary)
271 				primary_umac_set = 1;
272 		}
273 
274 		if (primary_umac_set)
275 			peer_entry->is_primary = false;
276 		else
277 			peer_entry->is_primary = true;
278 	}
279 }
280 
281 static int8_t wlan_vdev_derive_link_rssi(struct wlan_objmgr_vdev *vdev,
282 					 struct wlan_objmgr_vdev *assoc_vdev,
283 					 int8_t rssi)
284 {
285 	struct wlan_channel *channel, *assoc_channel;
286 	uint16_t ch_freq, assoc_freq;
287 	uint8_t tx_pow, assoc_tx_pow;
288 	int8_t diff_txpow;
289 	struct wlan_objmgr_pdev *pdev, *assoc_pdev;
290 	uint8_t log10_freq;
291 	uint8_t derived_rssi;
292 	int16_t ten_derived_rssi;
293 	int8_t ten_diff_pl = 0;
294 
295 	pdev = wlan_vdev_get_pdev(vdev);
296 	assoc_pdev = wlan_vdev_get_pdev(assoc_vdev);
297 
298 	channel = wlan_vdev_get_active_channel(vdev);
299 	if (channel)
300 		ch_freq = channel->ch_freq;
301 	else
302 		ch_freq = 1;
303 
304 	assoc_channel = wlan_vdev_get_active_channel(assoc_vdev);
305 	if (assoc_channel)
306 		assoc_freq = assoc_channel->ch_freq;
307 	else
308 		assoc_freq = 1;
309 
310 	/*
311 	 *  diff of path loss (of two links) = log10(freq1) - log10(freq2)
312 	 *                       (since distance is constant)
313 	 *  since log10 is not available, we cameup with approximate ranges
314 	 */
315 	log10_freq = (ch_freq * 10) / assoc_freq;
316 	if ((log10_freq >= 20) && (log10_freq < 30))
317 		ten_diff_pl = 4;  /* 0.4 *10 */
318 	else if ((log10_freq >= 11) && (log10_freq < 20))
319 		ten_diff_pl = 1;  /* 0.1 *10 */
320 	else if ((log10_freq >= 8) && (log10_freq < 11))
321 		ten_diff_pl = 0; /* 0 *10 */
322 	else if ((log10_freq >= 4) && (log10_freq < 8))
323 		ten_diff_pl = -1; /* -0.1 * 10 */
324 	else if ((log10_freq >= 1) && (log10_freq < 4))
325 		ten_diff_pl = -4;  /* -0.4 * 10 */
326 
327 	assoc_tx_pow = wlan_reg_get_channel_reg_power_for_freq(assoc_pdev,
328 							       assoc_freq);
329 	tx_pow = wlan_reg_get_channel_reg_power_for_freq(pdev, ch_freq);
330 
331 	diff_txpow = tx_pow -  assoc_tx_pow;
332 
333 	ten_derived_rssi = (diff_txpow * 10) - ten_diff_pl + (rssi * 10);
334 	derived_rssi = ten_derived_rssi / 10;
335 
336 	return derived_rssi;
337 }
338 
339 static void mlo_peer_calculate_avg_rssi(
340 		struct wlan_mlo_dev_context *ml_dev,
341 		struct wlan_mlo_peer_context *ml_peer,
342 		int8_t rssi,
343 		struct wlan_objmgr_vdev *assoc_vdev)
344 {
345 	int32_t total_rssi = 0;
346 	uint8_t num_psocs = 0;
347 	uint8_t i;
348 	struct wlan_objmgr_vdev *vdev;
349 
350 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
351 		vdev = ml_dev->wlan_vdev_list[i];
352 		if (!vdev)
353 			continue;
354 
355 		num_psocs++;
356 		if (vdev == assoc_vdev)
357 			total_rssi += rssi;
358 		else
359 			total_rssi += wlan_vdev_derive_link_rssi(vdev,
360 								 assoc_vdev,
361 								 rssi);
362 	}
363 
364 	ml_peer->avg_link_rssi = total_rssi / num_psocs;
365 }
366 
367 QDF_STATUS mlo_peer_allocate_primary_umac(
368 		struct wlan_mlo_dev_context *ml_dev,
369 		struct wlan_mlo_peer_context *ml_peer,
370 		struct wlan_objmgr_vdev *link_vdevs[])
371 {
372 	struct wlan_mlo_link_peer_entry *peer_entry;
373 	struct wlan_objmgr_peer *assoc_peer = NULL;
374 	int32_t rssi;
375 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
376 	uint8_t first_link_id = 0;
377 	bool primary_umac_set = false;
378 	uint8_t i, psoc_id;
379 
380 	peer_entry = &ml_peer->peer_list[0];
381 	assoc_peer = peer_entry->link_peer;
382 	if (!assoc_peer)
383 		return QDF_STATUS_E_FAILURE;
384 
385 	/* For Station mode, assign assoc peer as primary umac */
386 	if (wlan_peer_get_peer_type(assoc_peer) == WLAN_PEER_AP) {
387 		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
388 		mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " primary umac soc %d ",
389 			 ml_dev->mld_id,
390 			 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
391 			 ml_peer->primary_umac_psoc_id);
392 
393 		return QDF_STATUS_SUCCESS;
394 	}
395 
396 	/* Select assoc peer's PSOC as primary UMAC in Multi-chip solution,
397 	 * 1) for single link MLO connection
398 	 * 2) if MLD is single chip MLO
399 	 */
400 	if ((ml_peer->max_links == 1) ||
401 	    (mlo_vdevs_check_single_soc(link_vdevs, ml_peer->max_links))) {
402 		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
403 		mlo_info("MLD ID %d Assoc peer " QDF_MAC_ADDR_FMT " primary umac soc %d ",
404 			 ml_dev->mld_id,
405 			 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
406 			 ml_peer->primary_umac_psoc_id);
407 
408 		return QDF_STATUS_SUCCESS;
409 	}
410 
411 	if (mlo_ctx->mlo_is_force_primary_umac) {
412 		for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
413 			if (!link_vdevs[i])
414 				continue;
415 
416 			psoc_id = wlan_vdev_get_psoc_id(link_vdevs[i]);
417 			if (!first_link_id)
418 				first_link_id = psoc_id;
419 
420 			if (psoc_id == mlo_ctx->mlo_forced_primary_umac_id) {
421 				ml_peer->primary_umac_psoc_id = psoc_id;
422 				primary_umac_set = true;
423 				break;
424 			}
425 		}
426 
427 		if (!primary_umac_set)
428 			ml_peer->primary_umac_psoc_id = first_link_id;
429 
430 		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
431 		mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " primary umac soc %d ",
432 			 ml_dev->mld_id,
433 			 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
434 			 ml_peer->primary_umac_psoc_id);
435 
436 		return QDF_STATUS_SUCCESS;
437 	}
438 
439 	rssi = wlan_peer_get_rssi(assoc_peer);
440 	mlo_peer_calculate_avg_rssi(ml_dev, ml_peer, rssi,
441 				    wlan_peer_get_vdev(assoc_peer));
442 
443 	mld_get_best_primary_umac_w_rssi(ml_peer, link_vdevs);
444 
445 	mlo_peer_assign_primary_umac(ml_peer, peer_entry);
446 
447 	mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " avg RSSI %d primary umac soc %d ",
448 		 ml_dev->mld_id,
449 		 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
450 		 ml_peer->avg_link_rssi, ml_peer->primary_umac_psoc_id);
451 
452 	return QDF_STATUS_SUCCESS;
453 }
454 
455 QDF_STATUS mlo_peer_free_primary_umac(
456 		struct wlan_mlo_dev_context *ml_dev,
457 		struct wlan_mlo_peer_context *ml_peer)
458 {
459 	return QDF_STATUS_SUCCESS;
460 }
461