1 /* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 */ 15 16 /* 17 * DOC: contains MLO manager ap related functionality 18 */ 19 #include "wlan_mlo_mgr_cmn.h" 20 #include "wlan_mlo_mgr_main.h" 21 #ifdef WLAN_MLO_MULTI_CHIP 22 #include "wlan_lmac_if_def.h" 23 #include <cdp_txrx_mlo.h> 24 #endif 25 26 #ifdef WLAN_MLO_MULTI_CHIP 27 void mlo_setup_update_total_socs(uint8_t tot_socs) 28 { 29 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 30 31 if (!mlo_ctx) 32 return; 33 34 mlo_ctx->setup_info.tot_socs = tot_socs; 35 } 36 37 qdf_export_symbol(mlo_setup_update_total_socs); 38 39 void mlo_setup_update_num_links(struct wlan_objmgr_psoc *psoc, 40 uint8_t num_links) 41 { 42 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 43 44 if (!mlo_ctx) 45 return; 46 47 mlo_ctx->setup_info.tot_links += num_links; 48 } 49 50 qdf_export_symbol(mlo_setup_update_num_links); 51 52 void mlo_setup_update_soc_ready(struct wlan_objmgr_psoc *psoc) 53 { 54 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 55 uint8_t chip_idx; 56 57 if (!mlo_ctx || !mlo_ctx->setup_info.tot_socs) 58 return; 59 60 chip_idx = mlo_ctx->setup_info.num_soc; 61 qdf_assert_always(chip_idx < MAX_MLO_CHIPS); 62 mlo_ctx->setup_info.soc_list[chip_idx] = psoc; 63 mlo_ctx->setup_info.num_soc++; 64 65 if (mlo_ctx->setup_info.num_soc != mlo_ctx->setup_info.tot_socs) 66 return; 67 68 for (chip_idx = 0; chip_idx < mlo_ctx->setup_info.num_soc; 69 chip_idx++) { 70 struct wlan_objmgr_psoc *tmp_soc = 71 mlo_ctx->setup_info.soc_list[chip_idx]; 72 73 cdp_soc_mlo_soc_setup(wlan_psoc_get_dp_handle(tmp_soc), 74 mlo_ctx->dp_handle); 75 } 76 77 cdp_mlo_setup_complete(wlan_psoc_get_dp_handle(psoc), 78 mlo_ctx->dp_handle); 79 } 80 81 qdf_export_symbol(mlo_setup_update_soc_ready); 82 83 void mlo_setup_link_ready(struct wlan_objmgr_pdev *pdev) 84 { 85 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 86 uint8_t link_idx; 87 88 if (!mlo_ctx || !mlo_ctx->setup_info.tot_links) 89 return; 90 91 link_idx = mlo_ctx->setup_info.num_links; 92 /* TODO: Get reference to PDEV */ 93 qdf_assert_always(link_idx < MAX_MLO_LINKS); 94 mlo_ctx->setup_info.pdev_list[link_idx] = pdev; 95 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_SETUP_INIT; 96 mlo_ctx->setup_info.num_links++; 97 98 if (mlo_ctx->setup_info.num_links == mlo_ctx->setup_info.tot_links && 99 mlo_ctx->setup_info.num_soc == mlo_ctx->setup_info.tot_socs) { 100 struct wlan_objmgr_psoc *psoc; 101 struct wlan_lmac_if_tx_ops *tx_ops; 102 103 psoc = wlan_pdev_get_psoc(pdev); 104 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 105 /* Trigger MLO setup */ 106 if (tx_ops && tx_ops->mops.target_if_mlo_setup_req) { 107 tx_ops->mops.target_if_mlo_setup_req( 108 mlo_ctx->setup_info.pdev_list, 109 mlo_ctx->setup_info.num_links, 110 mlo_ctx->setup_info.ml_grp_id); 111 } 112 } 113 } 114 115 qdf_export_symbol(mlo_setup_link_ready); 116 117 void mlo_link_setup_complete(struct wlan_objmgr_pdev *pdev) 118 { 119 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 120 uint8_t link_idx; 121 122 if (!mlo_ctx) 123 return; 124 125 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 126 if (mlo_ctx->setup_info.pdev_list[link_idx] == pdev) { 127 mlo_ctx->setup_info.state[link_idx] = 128 MLO_LINK_SETUP_DONE; 129 break; 130 } 131 132 for (link_idx = 0; link_idx < mlo_ctx->setup_info.tot_links; link_idx++) 133 if (mlo_ctx->setup_info.state[link_idx] == MLO_LINK_SETUP_DONE) 134 continue; 135 else 136 break; 137 138 if (link_idx == mlo_ctx->setup_info.tot_links) { 139 struct wlan_objmgr_psoc *psoc; 140 struct wlan_lmac_if_tx_ops *tx_ops; 141 142 psoc = wlan_pdev_get_psoc(pdev); 143 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 144 /* Trigger MLO ready */ 145 if (tx_ops && tx_ops->mops.target_if_mlo_ready) { 146 tx_ops->mops.target_if_mlo_ready( 147 mlo_ctx->setup_info.pdev_list, 148 mlo_ctx->setup_info.num_links); 149 } 150 } 151 } 152 153 qdf_export_symbol(mlo_link_setup_complete); 154 155 static QDF_STATUS mlo_find_pdev_idx(struct wlan_objmgr_pdev *pdev, 156 uint8_t *link_idx) 157 { 158 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 159 uint8_t idx; 160 161 if (!mlo_ctx) 162 return QDF_STATUS_E_FAILURE; 163 164 if (!link_idx) 165 return QDF_STATUS_E_FAILURE; 166 167 for (idx = 0; idx < mlo_ctx->setup_info.tot_links; idx++) { 168 if (mlo_ctx->setup_info.pdev_list[idx] == pdev) { 169 *link_idx = idx; 170 return QDF_STATUS_SUCCESS; 171 } 172 } 173 174 return QDF_STATUS_E_FAILURE; 175 } 176 177 void mlo_link_teardown_complete(struct wlan_objmgr_pdev *pdev) 178 { 179 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 180 uint8_t link_idx; 181 182 if (!mlo_ctx) 183 return; 184 185 if (!mlo_ctx->setup_info.num_links) { 186 qdf_err("Delayed response ignore"); 187 return; 188 } 189 190 if (mlo_find_pdev_idx(pdev, &link_idx) != QDF_STATUS_SUCCESS) { 191 qdf_info("Failed to find pdev"); 192 return; 193 } 194 195 qdf_debug("link idx = %d", link_idx); 196 mlo_ctx->setup_info.pdev_list[link_idx] = NULL; 197 mlo_ctx->setup_info.state[link_idx] = MLO_LINK_TEARDOWN; 198 mlo_ctx->setup_info.num_links--; 199 200 if (!mlo_ctx->setup_info.num_links) { 201 qdf_info("Teardown complete"); 202 qdf_event_set(&mlo_ctx->setup_info.event); 203 } 204 } 205 206 qdf_export_symbol(mlo_link_teardown_complete); 207 208 #define MLO_MGR_TEARDOWN_TIMEOUT 3000 209 QDF_STATUS mlo_link_teardown_link(struct wlan_objmgr_psoc *psoc, 210 uint32_t reason) 211 { 212 struct wlan_lmac_if_tx_ops *tx_ops; 213 QDF_STATUS status; 214 struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); 215 216 qdf_debug(" %d %d ", 217 mlo_ctx->setup_info.num_soc, 218 mlo_ctx->setup_info.num_links); 219 220 if (!mlo_ctx) 221 return QDF_STATUS_E_FAILURE; 222 223 if (!mlo_ctx->setup_info.num_soc) 224 return QDF_STATUS_SUCCESS; 225 226 if (!mlo_ctx->setup_info.num_links) { 227 mlo_ctx->setup_info.num_soc--; 228 return QDF_STATUS_SUCCESS; 229 } 230 231 if (qdf_event_create(&mlo_ctx->setup_info.event) != QDF_STATUS_SUCCESS) 232 return QDF_STATUS_E_FAULT; 233 234 tx_ops = wlan_psoc_get_lmac_if_txops(psoc); 235 /* Trigger MLO teardown */ 236 if (tx_ops && tx_ops->mops.target_if_mlo_teardown_req) { 237 tx_ops->mops.target_if_mlo_teardown_req( 238 mlo_ctx->setup_info.pdev_list, 239 mlo_ctx->setup_info.num_links, 240 reason); 241 } 242 243 status = qdf_wait_for_event_completion(&mlo_ctx->setup_info.event, 244 MLO_MGR_TEARDOWN_TIMEOUT); 245 if (status != QDF_STATUS_SUCCESS) { 246 qdf_info("Teardown timeout"); 247 mlo_ctx->setup_info.num_links = 0; 248 } 249 250 qdf_event_destroy(&mlo_ctx->setup_info.event); 251 252 mlo_ctx->setup_info.num_soc--; 253 254 return status; 255 } 256 257 qdf_export_symbol(mlo_link_teardown_link); 258 #endif /*WLAN_MLO_MULTI_CHIP*/ 259