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 25 bool mlo_is_mld_ap(struct wlan_objmgr_vdev *vdev) 26 { 27 return true; 28 } 29 30 bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev, 31 uint8_t link_id, 32 uint16_t vdev_count) 33 { 34 struct wlan_mlo_dev_context *dev_ctx; 35 36 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 37 mlo_err("Invalid input"); 38 return false; 39 } 40 41 dev_ctx = vdev->mlo_dev_ctx; 42 wlan_vdev_set_link_id(vdev, link_id); 43 wlan_vdev_mlme_feat_ext2_cap_set(vdev, WLAN_VDEV_FEXT2_MLO); 44 45 /** 46 * every link will trigger mlo_ap_vdev_attach, 47 * and they should provide the same vdev_count. 48 */ 49 mlo_dev_lock_acquire(dev_ctx); 50 dev_ctx->ap_ctx->num_ml_vdevs = vdev_count; 51 mlo_dev_lock_release(dev_ctx); 52 53 return true; 54 } 55 56 void mlo_ap_get_vdev_list(struct wlan_objmgr_vdev *vdev, 57 uint16_t *vdev_count, 58 struct wlan_objmgr_vdev **wlan_vdev_list) 59 { 60 struct wlan_mlo_dev_context *dev_ctx; 61 int i; 62 QDF_STATUS status; 63 64 *vdev_count = 0; 65 66 if (!vdev || !vdev->mlo_dev_ctx) { 67 mlo_err("Invalid input"); 68 return; 69 } 70 71 dev_ctx = vdev->mlo_dev_ctx; 72 73 mlo_dev_lock_acquire(dev_ctx); 74 *vdev_count = 0; 75 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 76 if (dev_ctx->wlan_vdev_list[i] && 77 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i])) { 78 status = wlan_objmgr_vdev_try_get_ref( 79 dev_ctx->wlan_vdev_list[i], 80 WLAN_MLO_MGR_ID); 81 if (QDF_IS_STATUS_ERROR(status)) 82 break; 83 wlan_vdev_list[*vdev_count] = 84 dev_ctx->wlan_vdev_list[i]; 85 (*vdev_count) += 1; 86 } 87 } 88 mlo_dev_lock_release(dev_ctx); 89 } 90 91 /** 92 * mlo_is_ap_vdev_up_allowed() - Is mlo ap allowed to come up 93 * @vdev: vdev pointer 94 * 95 * Return: true if given ap is allowed to up, false otherwise. 96 */ 97 static bool mlo_is_ap_vdev_up_allowed(struct wlan_objmgr_vdev *vdev) 98 { 99 uint16_t vdev_count = 0; 100 struct wlan_mlo_dev_context *dev_ctx; 101 int i; 102 bool up_allowed = false; 103 104 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->ap_ctx) { 105 mlo_err("Invalid input"); 106 return up_allowed; 107 } 108 109 dev_ctx = vdev->mlo_dev_ctx; 110 111 mlo_dev_lock_acquire(dev_ctx); 112 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 113 if (dev_ctx->wlan_vdev_list[i] && 114 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i]) && 115 QDF_IS_STATUS_SUCCESS( 116 wlan_vdev_chan_config_valid(dev_ctx->wlan_vdev_list[i]))) 117 vdev_count++; 118 } 119 120 if (vdev_count == dev_ctx->ap_ctx->num_ml_vdevs) 121 up_allowed = true; 122 mlo_dev_lock_release(dev_ctx); 123 124 return up_allowed; 125 } 126 127 /** 128 * mlo_pre_link_up() - Carry out preparation before bringing up the link 129 * @vdev: vdev pointer 130 * 131 * Return: true if preparation is done successfully 132 */ 133 static bool mlo_pre_link_up(struct wlan_objmgr_vdev *vdev) 134 { 135 if (!vdev) { 136 mlo_err("vdev is NULL"); 137 return false; 138 } 139 140 if ((wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP) && 141 (wlan_vdev_mlme_get_substate(vdev) == 142 WLAN_VDEV_SS_MLO_SYNC_WAIT)) 143 return true; 144 145 return false; 146 } 147 148 /** 149 * mlo_handle_link_ready() - Check if mlo ap is allowed to up or not. 150 * If it is allowed, for every link in the 151 * WLAN_VDEV_SS_MLO_SYNC_WAIT state, deliver 152 * event WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE. 153 * 154 * This function is triggered once a link gets start response or enters 155 * LAN_VDEV_SS_MLO_SYNC_WAIT state 156 * 157 * @vdev: vdev pointer 158 * 159 * Return: None 160 */ 161 static void mlo_handle_link_ready(struct wlan_objmgr_vdev *vdev) 162 { 163 struct wlan_mlo_dev_context *dev_ctx; 164 int i; 165 166 if (!vdev || !vdev->mlo_dev_ctx) { 167 mlo_err("Invalid input"); 168 return; 169 } 170 171 dev_ctx = vdev->mlo_dev_ctx; 172 173 if (!mlo_is_ap_vdev_up_allowed(vdev)) 174 return; 175 176 mlo_dev_lock_acquire(dev_ctx); 177 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 178 if (dev_ctx->wlan_vdev_list[i] && 179 wlan_vdev_mlme_is_mlo_ap(dev_ctx->wlan_vdev_list[i]) && 180 mlo_pre_link_up(dev_ctx->wlan_vdev_list[i])) 181 wlan_vdev_mlme_sm_deliver_evt_sync( 182 dev_ctx->wlan_vdev_list[i], 183 WLAN_VDEV_SM_EV_MLO_SYNC_COMPLETE, 184 0, NULL); 185 } 186 mlo_dev_lock_release(dev_ctx); 187 } 188 189 void mlo_ap_link_sync_wait_notify(struct wlan_objmgr_vdev *vdev) 190 { 191 mlo_handle_link_ready(vdev); 192 } 193 194 void mlo_ap_link_start_rsp_notify(struct wlan_objmgr_vdev *vdev) 195 { 196 mlo_handle_link_ready(vdev); 197 } 198 199 void mlo_ap_vdev_detach(struct wlan_objmgr_vdev *vdev) 200 { 201 if (!vdev || !vdev->mlo_dev_ctx) { 202 mlo_err("Invalid input"); 203 return; 204 } 205 wlan_vdev_mlme_feat_ext2_cap_clear(vdev, WLAN_VDEV_FEXT2_MLO); 206 } 207 208 void mlo_ap_link_down_cmpl_notify(struct wlan_objmgr_vdev *vdev) 209 { 210 mlo_ap_vdev_detach(vdev); 211 } 212