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 #include <wlan_utility.h> 25 26 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev, 27 uint8_t link_id, 28 uint16_t vdev_count) 29 { 30 struct wlan_mlo_dev_context *dev_ctx; 31 32 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 33 mlo_err("Invalid input"); 34 return false; 35 } 36 37 dev_ctx = vdev->mlo_dev_ctx; 38 wlan_vdev_set_link_id(vdev, link_id); 39 wlan_vdev_mlme_feat_ext2_cap_set(vdev, WLAN_VDEV_FEXT2_MLO); 40 41 /** 42 * every link will trigger mlo_ap_vdev_attach, 43 * and they should provide the same vdev_count. 44 */ 45 mlo_dev_lock_acquire(dev_ctx); 46 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count; 47 mlo_dev_lock_release(dev_ctx); 48 49 return true; 50 } 51 52 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev, 53 uint16_t *vdev_count, 54 struct wlan_objmgr_vdev **wlan_vdev_list) 55 { 56 struct wlan_mlo_dev_context *dev_ctx; 57 int i; 58 QDF_STATUS status; 59 60 *vdev_count = 0; 61 62 if (!vdev || !vdev->mlo_dev_ctx) { 63 mlo_err("Invalid input"); 64 return; 65 } 66 67 dev_ctx = vdev->mlo_dev_ctx; 68 69 mlo_dev_lock_acquire(dev_ctx); 70 *vdev_count = 0; 71 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 72 if (dev_ctx->wlan_vdev_list[i] && 73 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) { 74 status = wlan_objmgr_vdev_try_get_ref( 75 dev_ctx->wlan_vdev_list[i], 76 WLAN_MLO_MGR_ID); 77 if (QDF_IS_STATUS_ERROR(status)) 78 break; 79 wlan_vdev_list[*vdev_count] = 80 dev_ctx->wlan_vdev_list[i]; 81 (*vdev_count) += 1; 82 } 83 } 84 mlo_dev_lock_release(dev_ctx); 85 } 86 87 /** 88 * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up 89 * @vdev: vdev pointer 90 * 91 * Return: true if given ap is allowed to up, false otherwise. 92 */ 93 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev) 94 { 95 uint16_t vdev_count = 0; 96 struct wlan_mlo_dev_context *dev_ctx; 97 int i; 98 bool up_allowed = false; 99 100 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 101 mlo_err("Invalid input"); 102 return up_allowed; 103 } 104 105 dev_ctx = vdev->mlo_dev_ctx; 106 107 mlo_dev_lock_acquire(dev_ctx); 108 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 109 if (dev_ctx->wlan_vdev_list[i] && 110 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i]) && 111 QDF_IS_STATUS_SUCCESS( 112 wlan_vdev_chan_config_valid(dev_ctx->wlan_vdev_list[i]))) 113 vdev_count++; 114 } 115 116 if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs) 117 up_allowed = true; 118 mlo_dev_lock_release(dev_ctx); 119 120 return up_allowed; 121 } 122 123 /** 124 * mlo_pre_link_up() - Carry out preparation before bringing up the link 125 * @vdev: vdev pointer 126 * 127 * Return: true if preparation is done successfully 128 */ 129 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev) 130 { 131 if (!vdev) { 132 mlo_err("vdev is NULL"); 133 return false; 134 } 135 136 if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) && 137 (wlan_vdev_mlme_get_substate(vdev) == 138 WLAN_VDEV_SS_MLO_SYNC_WAIT)) 139 return true; 140 141 return false; 142 } 143 144 /** 145 * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not. 146 * If it is allowed, for every link in the 147 * WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver 148 * event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE. 149 * 150 * This function is triggered once a link gets start response or enters 151 * LAN_VDEV_SS_MLO_SYNC_WAIT state 152 * 153 * @vdev: vdev pointer 154 * 155 * Return: None 156 */ 157 static void mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev) 158 { 159 struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL}; 160 uint16_t num_links = 0; 161 uint8_t i; 162 163 if (!vdev || !vdev->mlo_dev_ctx) { 164 mlo_err("Invalid input"); 165 return; 166 } 167 168 if (!mlo_is_ap_vdev_up_allowed(vdev)) 169 return; 170 171 mlo_ap_get_vdev_list(vdev, &num_links, vdev_list); 172 if (!num_links || (num_links > QDF_ARRAY_SIZE(vdev_list))) { 173 mlo_err("Invalid number of VDEVs under AP-MLD"); 174 return; 175 } 176 177 for (i = 0; i < num_links; i++) { 178 if (mlo_pre_link_up(vdev_list[i])) 179 wlan_vdev_mlme_sm_deliver_evt_sync( 180 vdev_list[i], 181 WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE, 182 0, NULL); 183 /* Release ref taken as part of mlo_ap_get_vdev_list */ 184 mlo_release_vdev_ref(vdev_list[i]); 185 } 186 } 187 188 void mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev) 189 { 190 mlo_handle_link_ready(vdev); 191 } 192 193 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev) 194 { 195 mlo_handle_link_ready(vdev); 196 } 197 198 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev) 199 { 200 if (!vdev || !vdev->mlo_dev_ctx) { 201 mlo_err("Invalid input"); 202 return; 203 } 204 wlan_vdev_mlme_feat_ext2_cap_clear(vdev, WLAN_VDEV_FEXT2_MLO); 205 } 206 207 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev) 208 { 209 mlo_ap_vdev_detach(vdev); 210 } 211 212 uint16_t mlo_ap_ml_peerid_alloc(void) 213 { 214 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 215 uint16_t i; 216 217 ml_peerid_lock_acquire(mlo_ctx); 218 for (i = 0; i < mlo_ctx->max_mlo_peer_id; i++) { 219 if (qdf_test_bit(i, mlo_ctx->mlo_peer_id_bmap)) 220 continue; 221 222 qdf_set_bit(i, mlo_ctx->mlo_peer_id_bmap); 223 break; 224 } 225 ml_peerid_lock_release(mlo_ctx); 226 227 if (i == mlo_ctx->max_mlo_peer_id) 228 return MLO_INVALID_PEER_ID; 229 230 return i + 1; 231 } 232 233 void mlo_ap_ml_peerid_free(uint16_t mlo_peer_id) 234 { 235 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 236 237 if (mlo_peer_id == MLO_INVALID_PEER_ID) 238 return; 239 240 ml_peerid_lock_acquire(mlo_ctx); 241 if (qdf_test_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap)) 242 qdf_clear_bit(mlo_peer_id - 1, mlo_ctx->mlo_peer_id_bmap); 243 244 ml_peerid_lock_release(mlo_ctx); 245 } 246 247 void mlo_ap_vdev_quiet_set(struct wlan_objmgr_vdev *vdev) 248 { 249 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 250 uint8_t idx; 251 252 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 253 return; 254 255 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 256 if (idx == MLO_INVALID_LINK_IDX) 257 return; 258 259 mlo_debug("Quiet set for PSOC:%d vdev:%d", 260 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 261 wlan_vdev_get_id(vdev)); 262 263 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 264 idx, 1); 265 } 266 267 void mlo_ap_vdev_quiet_clear(struct wlan_objmgr_vdev *vdev) 268 { 269 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 270 uint8_t idx; 271 272 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 273 return; 274 275 idx = mlo_get_link_vdev_ix(mld_ctx, vdev); 276 if (idx == MLO_INVALID_LINK_IDX) 277 return; 278 279 mlo_debug("Quiet clear for PSOC:%d vdev:%d", 280 wlan_psoc_get_id(wlan_vdev_get_psoc(vdev)), 281 wlan_vdev_get_id(vdev)); 282 283 wlan_util_change_map_index(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 284 idx, 0); 285 } 286 287 bool mlo_ap_vdev_quiet_is_any_idx_set(struct wlan_objmgr_vdev *vdev) 288 { 289 struct wlan_mlo_dev_context *mld_ctx = vdev->mlo_dev_ctx; 290 291 if (!mld_ctx || !wlan_vdev_mlme_is_mlo_ap(vdev)) 292 return false; 293 294 return wlan_util_map_is_any_index_set( 295 mld_ctx->ap_ctx->mlo_vdev_quiet_bmap, 296 sizeof(mld_ctx->ap_ctx->mlo_vdev_quiet_bmap)); 297 } 298