xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
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 	/* If MLD is within single SOC, then assoc link becomes
229 	 * primary umac
230 	 */
231 	if (ml_peer->primary_umac_psoc_id == ML_PRIMARY_UMAC_ID_INVAL) {
232 		if (wlan_peer_mlme_is_assoc_peer(peer_entry->link_peer)) {
233 			peer_entry->is_primary = true;
234 			ml_peer->primary_umac_psoc_id =
235 				wlan_peer_get_psoc_id(peer_entry->link_peer);
236 		} else {
237 			peer_entry->is_primary = false;
238 		}
239 	} else {
240 		if (wlan_peer_get_psoc_id(peer_entry->link_peer) ==
241 				ml_peer->primary_umac_psoc_id)
242 			peer_entry->is_primary = true;
243 		else
244 			peer_entry->is_primary = false;
245 	}
246 }
247 
248 static int8_t wlan_vdev_derive_link_rssi(struct wlan_objmgr_vdev *vdev,
249 					 struct wlan_objmgr_vdev *assoc_vdev,
250 					 int8_t rssi)
251 {
252 	struct wlan_channel *channel, *assoc_channel;
253 	uint16_t ch_freq, assoc_freq;
254 	uint8_t tx_pow, assoc_tx_pow;
255 	int8_t diff_txpow;
256 	struct wlan_objmgr_pdev *pdev, *assoc_pdev;
257 	uint8_t log10_freq;
258 	uint8_t derived_rssi;
259 	int16_t ten_derived_rssi;
260 	int8_t ten_diff_pl = 0;
261 
262 	pdev = wlan_vdev_get_pdev(vdev);
263 	assoc_pdev = wlan_vdev_get_pdev(assoc_vdev);
264 
265 	channel = wlan_vdev_get_active_channel(vdev);
266 	if (channel)
267 		ch_freq = channel->ch_freq;
268 	else
269 		ch_freq = 1;
270 
271 	assoc_channel = wlan_vdev_get_active_channel(assoc_vdev);
272 	if (assoc_channel)
273 		assoc_freq = assoc_channel->ch_freq;
274 	else
275 		assoc_freq = 1;
276 
277 	/*
278 	 *  diff of path loss (of two links) = log10(freq1) - log10(freq2)
279 	 *                       (since distance is constant)
280 	 *  since log10 is not available, we cameup with approximate ranges
281 	 */
282 	log10_freq = (ch_freq * 10) / assoc_freq;
283 	if ((log10_freq >= 20) && (log10_freq < 30))
284 		ten_diff_pl = 4;  /* 0.4 *10 */
285 	else if ((log10_freq >= 11) && (log10_freq < 20))
286 		ten_diff_pl = 1;  /* 0.1 *10 */
287 	else if ((log10_freq >= 8) && (log10_freq < 11))
288 		ten_diff_pl = 0; /* 0 *10 */
289 	else if ((log10_freq >= 4) && (log10_freq < 8))
290 		ten_diff_pl = -1; /* -0.1 * 10 */
291 	else if ((log10_freq >= 1) && (log10_freq < 4))
292 		ten_diff_pl = -4;  /* -0.4 * 10 */
293 
294 	assoc_tx_pow = wlan_reg_get_channel_reg_power_for_freq(assoc_pdev,
295 							       assoc_freq);
296 	tx_pow = wlan_reg_get_channel_reg_power_for_freq(pdev, ch_freq);
297 
298 	diff_txpow = tx_pow -  assoc_tx_pow;
299 
300 	ten_derived_rssi = (diff_txpow * 10) - ten_diff_pl + (rssi * 10);
301 	derived_rssi = ten_derived_rssi / 10;
302 
303 	return derived_rssi;
304 }
305 
306 static void mlo_peer_calculate_avg_rssi(
307 		struct wlan_mlo_dev_context *ml_dev,
308 		struct wlan_mlo_peer_context *ml_peer,
309 		int8_t rssi,
310 		struct wlan_objmgr_vdev *assoc_vdev)
311 {
312 	int32_t total_rssi = 0;
313 	uint8_t num_psocs = 0;
314 	uint8_t i;
315 	struct wlan_objmgr_vdev *vdev;
316 
317 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
318 		vdev = ml_dev->wlan_vdev_list[i];
319 		if (!vdev)
320 			continue;
321 
322 		num_psocs++;
323 		if (vdev == assoc_vdev)
324 			total_rssi += rssi;
325 		else
326 			total_rssi += wlan_vdev_derive_link_rssi(vdev,
327 								 assoc_vdev,
328 								 rssi);
329 	}
330 
331 	ml_peer->avg_link_rssi = total_rssi / num_psocs;
332 }
333 
334 QDF_STATUS mlo_peer_allocate_primary_umac(
335 		struct wlan_mlo_dev_context *ml_dev,
336 		struct wlan_mlo_peer_context *ml_peer,
337 		struct wlan_objmgr_vdev *link_vdevs[])
338 {
339 	struct wlan_mlo_link_peer_entry *peer_entry;
340 	struct wlan_objmgr_peer *assoc_peer = NULL;
341 	int32_t rssi;
342 	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
343 	uint8_t first_link_id = 0;
344 	bool primary_umac_set = false;
345 	uint8_t i, psoc_id;
346 
347 	peer_entry = &ml_peer->peer_list[0];
348 	assoc_peer = peer_entry->link_peer;
349 	if (!assoc_peer)
350 		return QDF_STATUS_E_FAILURE;
351 
352 	/* For Station mode, assign assoc peer as primary umac */
353 	if (wlan_peer_get_peer_type(assoc_peer) == WLAN_PEER_AP) {
354 		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
355 		mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " primary umac soc %d ",
356 			 ml_dev->mld_id,
357 			 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
358 			 ml_peer->primary_umac_psoc_id);
359 
360 		return QDF_STATUS_SUCCESS;
361 	}
362 
363 	/* Select assoc peer's PSOC as primary UMAC in Multi-chip solution,
364 	 * 1) for single link MLO connection
365 	 * 2) if MLD is single chip MLO
366 	 */
367 	if ((ml_peer->max_links == 1) ||
368 	    (mlo_vdevs_check_single_soc(link_vdevs, ml_peer->max_links))) {
369 		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
370 		mlo_info("MLD ID %d Assoc peer " QDF_MAC_ADDR_FMT " primary umac soc %d ",
371 			 ml_dev->mld_id,
372 			 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
373 			 ml_peer->primary_umac_psoc_id);
374 
375 		return QDF_STATUS_SUCCESS;
376 	}
377 
378 	if (mlo_ctx->mlo_is_force_primary_umac) {
379 		for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
380 			if (!link_vdevs[i])
381 				continue;
382 
383 			psoc_id = wlan_vdev_get_psoc_id(link_vdevs[i]);
384 			if (!first_link_id)
385 				first_link_id = psoc_id;
386 
387 			if (psoc_id == mlo_ctx->mlo_forced_primary_umac_id) {
388 				ml_peer->primary_umac_psoc_id = psoc_id;
389 				primary_umac_set = true;
390 				break;
391 			}
392 		}
393 
394 		if (!primary_umac_set)
395 			ml_peer->primary_umac_psoc_id = first_link_id;
396 
397 		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
398 		mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " primary umac soc %d ",
399 			 ml_dev->mld_id,
400 			 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
401 			 ml_peer->primary_umac_psoc_id);
402 
403 		return QDF_STATUS_SUCCESS;
404 	}
405 
406 	rssi = wlan_peer_get_rssi(assoc_peer);
407 	mlo_peer_calculate_avg_rssi(ml_dev, ml_peer, rssi,
408 				    wlan_peer_get_vdev(assoc_peer));
409 
410 	mld_get_best_primary_umac_w_rssi(ml_peer, link_vdevs);
411 
412 	mlo_peer_assign_primary_umac(ml_peer, peer_entry);
413 
414 	mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " avg RSSI %d primary umac soc %d ",
415 		 ml_dev->mld_id,
416 		 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
417 		 ml_peer->avg_link_rssi, ml_peer->primary_umac_psoc_id);
418 
419 	return QDF_STATUS_SUCCESS;
420 }
421 
422 QDF_STATUS mlo_peer_free_primary_umac(
423 		struct wlan_mlo_dev_context *ml_dev,
424 		struct wlan_mlo_peer_context *ml_peer)
425 {
426 	return QDF_STATUS_SUCCESS;
427 }
428