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