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 if (!num_psocs) 365 return; 366 367 ml_peer->avg_link_rssi = total_rssi / num_psocs; 368 } 369 370 QDF_STATUS mlo_peer_allocate_primary_umac( 371 struct wlan_mlo_dev_context *ml_dev, 372 struct wlan_mlo_peer_context *ml_peer, 373 struct wlan_objmgr_vdev *link_vdevs[]) 374 { 375 struct wlan_mlo_link_peer_entry *peer_entry; 376 struct wlan_objmgr_peer *assoc_peer = NULL; 377 int32_t rssi; 378 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 379 uint8_t first_link_id = 0; 380 bool primary_umac_set = false; 381 uint8_t i, psoc_id; 382 383 peer_entry = &ml_peer->peer_list[0]; 384 assoc_peer = peer_entry->link_peer; 385 if (!assoc_peer) 386 return QDF_STATUS_E_FAILURE; 387 388 /* For Station mode, assign assoc peer as primary umac */ 389 if (wlan_peer_get_peer_type(assoc_peer) == WLAN_PEER_AP) { 390 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 391 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " primary umac soc %d ", 392 ml_dev->mld_id, 393 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 394 ml_peer->primary_umac_psoc_id); 395 396 return QDF_STATUS_SUCCESS; 397 } 398 399 /* Select assoc peer's PSOC as primary UMAC in Multi-chip solution, 400 * 1) for single link MLO connection 401 * 2) if MLD is single chip MLO 402 */ 403 if ((ml_peer->max_links == 1) || 404 (mlo_vdevs_check_single_soc(link_vdevs, ml_peer->max_links))) { 405 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 406 mlo_info("MLD ID %d Assoc peer " QDF_MAC_ADDR_FMT " primary umac soc %d ", 407 ml_dev->mld_id, 408 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 409 ml_peer->primary_umac_psoc_id); 410 411 return QDF_STATUS_SUCCESS; 412 } 413 414 if (mlo_ctx->mlo_is_force_primary_umac) { 415 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 416 if (!link_vdevs[i]) 417 continue; 418 419 psoc_id = wlan_vdev_get_psoc_id(link_vdevs[i]); 420 if (!first_link_id) 421 first_link_id = psoc_id; 422 423 if (psoc_id == mlo_ctx->mlo_forced_primary_umac_id) { 424 ml_peer->primary_umac_psoc_id = psoc_id; 425 primary_umac_set = true; 426 break; 427 } 428 } 429 430 if (!primary_umac_set) 431 ml_peer->primary_umac_psoc_id = first_link_id; 432 433 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 434 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " primary umac soc %d ", 435 ml_dev->mld_id, 436 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 437 ml_peer->primary_umac_psoc_id); 438 439 return QDF_STATUS_SUCCESS; 440 } 441 442 rssi = wlan_peer_get_rssi(assoc_peer); 443 mlo_peer_calculate_avg_rssi(ml_dev, ml_peer, rssi, 444 wlan_peer_get_vdev(assoc_peer)); 445 446 mld_get_best_primary_umac_w_rssi(ml_peer, link_vdevs); 447 448 mlo_peer_assign_primary_umac(ml_peer, peer_entry); 449 450 mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " avg RSSI %d primary umac soc %d ", 451 ml_dev->mld_id, 452 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes), 453 ml_peer->avg_link_rssi, ml_peer->primary_umac_psoc_id); 454 455 return QDF_STATUS_SUCCESS; 456 } 457 458 QDF_STATUS mlo_peer_free_primary_umac( 459 struct wlan_mlo_dev_context *ml_dev, 460 struct wlan_mlo_peer_context *ml_peer) 461 { 462 return QDF_STATUS_SUCCESS; 463 } 464