1 /* 2 * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include "qdf_list.h" 21 #include "qdf_status.h" 22 #include "qdf_talloc.h" 23 #include "qdf_types.h" 24 #include "__wlan_dsc.h" 25 #include "wlan_dsc.h" 26 27 #define __dsc_driver_lock(psoc) __dsc_lock((psoc)->driver) 28 #define __dsc_driver_unlock(psoc) __dsc_unlock((psoc)->driver) 29 30 static QDF_STATUS __dsc_psoc_create(struct dsc_driver * driver,struct dsc_psoc ** out_psoc)31 __dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc) 32 { 33 struct dsc_psoc *psoc; 34 35 if (!dsc_assert(driver)) 36 return QDF_STATUS_E_INVAL; 37 38 if (!dsc_assert(out_psoc)) 39 return QDF_STATUS_E_INVAL; 40 41 *out_psoc = NULL; 42 43 psoc = qdf_talloc_type(driver, psoc); 44 if (!psoc) 45 return QDF_STATUS_E_NOMEM; 46 47 /* init */ 48 psoc->driver = driver; 49 qdf_list_create(&psoc->vdevs, 0); 50 __dsc_trans_init(&psoc->trans); 51 __dsc_ops_init(&psoc->ops); 52 53 /* attach */ 54 __dsc_driver_lock(psoc); 55 qdf_list_insert_back(&driver->psocs, &psoc->node); 56 __dsc_driver_unlock(psoc); 57 58 *out_psoc = psoc; 59 60 return QDF_STATUS_SUCCESS; 61 } 62 63 QDF_STATUS dsc_psoc_create(struct dsc_driver * driver,struct dsc_psoc ** out_psoc)64 dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc) 65 { 66 QDF_STATUS status; 67 68 status = __dsc_psoc_create(driver, out_psoc); 69 70 return status; 71 } 72 __dsc_psoc_destroy(struct dsc_psoc ** out_psoc)73 static void __dsc_psoc_destroy(struct dsc_psoc **out_psoc) 74 { 75 struct dsc_psoc *psoc; 76 77 if (!dsc_assert(out_psoc)) 78 return; 79 80 psoc = *out_psoc; 81 if (!dsc_assert(psoc)) 82 return; 83 84 /* assert no children */ 85 dsc_assert(qdf_list_empty(&psoc->vdevs)); 86 87 /* flush pending transitions */ 88 while (__dsc_trans_abort(&psoc->trans)) 89 ; 90 91 /* detach */ 92 __dsc_driver_lock(psoc); 93 qdf_list_remove_node(&psoc->driver->psocs, &psoc->node); 94 __dsc_driver_unlock(psoc); 95 96 /* de-init */ 97 __dsc_ops_deinit(&psoc->ops); 98 __dsc_trans_deinit(&psoc->trans); 99 qdf_list_destroy(&psoc->vdevs); 100 psoc->driver = NULL; 101 102 *out_psoc = NULL; 103 104 qdf_tfree(psoc); 105 } 106 dsc_psoc_destroy(struct dsc_psoc ** out_psoc)107 void dsc_psoc_destroy(struct dsc_psoc **out_psoc) 108 { 109 __dsc_psoc_destroy(out_psoc); 110 } 111 __dsc_psoc_trans_active_down_tree(struct dsc_psoc * psoc)112 static bool __dsc_psoc_trans_active_down_tree(struct dsc_psoc *psoc) 113 { 114 struct dsc_vdev *vdev; 115 116 dsc_for_each_psoc_vdev(psoc, vdev) { 117 if (__dsc_trans_active(&vdev->trans)) 118 return true; 119 } 120 121 return false; 122 } 123 124 #define __dsc_psoc_can_op(psoc) __dsc_psoc_can_trans(psoc) 125 126 /* 127 * __dsc_psoc_can_trans() - Returns if the psoc transition can occur or not 128 * @psoc: The DSC psoc 129 * 130 * This function checks if the psoc transition can occur or not by checking if 131 * any other down the tree/up the tree transition/operation is taking place. 132 * 133 * If there are any driver transition taking place, then the psoc trans/ops 134 * should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL 135 * in this case. 136 * 137 * If there any psoc or vdev trans/ops is taking place, then the psoc trans/ops 138 * should be rejected and queued in the DSC queue so that it may be resumed 139 * after the current trans/ops is completed. Return QDF_STATUS_E_AGAIN in this 140 * case. 141 * 142 * Return: QDF_STATUS_SUCCESS if transition is allowed, error code if not. 143 */ __dsc_psoc_can_trans(struct dsc_psoc * psoc)144 static QDF_STATUS __dsc_psoc_can_trans(struct dsc_psoc *psoc) 145 { 146 if (__dsc_trans_active_or_queued(&psoc->driver->trans)) 147 return QDF_STATUS_E_INVAL; 148 149 if (__dsc_trans_active_or_queued(&psoc->trans) || 150 __dsc_psoc_trans_active_down_tree(psoc)) 151 return QDF_STATUS_E_AGAIN; 152 153 return QDF_STATUS_SUCCESS; 154 } 155 __dsc_psoc_can_trigger(struct dsc_psoc * psoc)156 static bool __dsc_psoc_can_trigger(struct dsc_psoc *psoc) 157 { 158 return !__dsc_trans_active_or_queued(&psoc->driver->trans) && 159 !__dsc_trans_active(&psoc->trans) && 160 !__dsc_psoc_trans_active_down_tree(psoc); 161 } 162 163 static QDF_STATUS __dsc_psoc_trans_start_nolock(struct dsc_psoc * psoc,const char * desc)164 __dsc_psoc_trans_start_nolock(struct dsc_psoc *psoc, const char *desc) 165 { 166 QDF_STATUS status; 167 168 status = __dsc_psoc_can_trans(psoc); 169 if (QDF_IS_STATUS_ERROR(status)) 170 return status; 171 172 return __dsc_trans_start(&psoc->trans, desc); 173 } 174 175 static QDF_STATUS __dsc_psoc_trans_start(struct dsc_psoc * psoc,const char * desc)176 __dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc) 177 { 178 QDF_STATUS status; 179 180 if (!dsc_assert(psoc)) 181 return QDF_STATUS_E_INVAL; 182 183 if (!dsc_assert(desc)) 184 return QDF_STATUS_E_INVAL; 185 186 __dsc_driver_lock(psoc); 187 status = __dsc_psoc_trans_start_nolock(psoc, desc); 188 __dsc_driver_unlock(psoc); 189 190 return status; 191 } 192 dsc_psoc_trans_start(struct dsc_psoc * psoc,const char * desc)193 QDF_STATUS dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc) 194 { 195 QDF_STATUS status; 196 197 dsc_enter_str(desc); 198 status = __dsc_psoc_trans_start(psoc, desc); 199 if (QDF_IS_STATUS_ERROR(status)) 200 dsc_exit_status(status); 201 202 return status; 203 } 204 205 static QDF_STATUS __dsc_psoc_trans_start_wait(struct dsc_psoc * psoc,const char * desc)206 __dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc) 207 { 208 QDF_STATUS status; 209 struct dsc_tran tran = { 0 }; 210 211 if (!dsc_assert(psoc)) 212 return QDF_STATUS_E_INVAL; 213 214 if (!dsc_assert(desc)) 215 return QDF_STATUS_E_INVAL; 216 217 __dsc_driver_lock(psoc); 218 219 /* try to start without waiting */ 220 status = __dsc_psoc_trans_start_nolock(psoc, desc); 221 if (QDF_IS_STATUS_SUCCESS(status) || status == QDF_STATUS_E_INVAL) 222 goto unlock; 223 224 status = __dsc_trans_queue(&psoc->trans, &tran, desc); 225 if (QDF_IS_STATUS_ERROR(status)) 226 goto unlock; 227 228 __dsc_driver_unlock(psoc); 229 230 return __dsc_tran_wait(&tran); 231 232 unlock: 233 __dsc_driver_unlock(psoc); 234 235 return status; 236 } 237 dsc_psoc_trans_start_wait(struct dsc_psoc * psoc,const char * desc)238 QDF_STATUS dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc) 239 { 240 QDF_STATUS status; 241 242 dsc_enter_str(desc); 243 status = __dsc_psoc_trans_start_wait(psoc, desc); 244 if (QDF_IS_STATUS_ERROR(status)) 245 dsc_exit_status(status); 246 247 return status; 248 } 249 __dsc_psoc_trigger_trans(struct dsc_psoc * psoc)250 static void __dsc_psoc_trigger_trans(struct dsc_psoc *psoc) 251 { 252 struct dsc_vdev *vdev; 253 254 if (__dsc_driver_trans_trigger_checked(psoc->driver)) 255 return; 256 257 if (__dsc_trans_trigger(&psoc->trans)) 258 return; 259 260 dsc_for_each_psoc_vdev(psoc, vdev) 261 __dsc_trans_trigger(&vdev->trans); 262 } 263 __dsc_psoc_trans_stop(struct dsc_psoc * psoc)264 static void __dsc_psoc_trans_stop(struct dsc_psoc *psoc) 265 { 266 if (!dsc_assert(psoc)) 267 return; 268 269 __dsc_driver_lock(psoc); 270 271 __dsc_trans_stop(&psoc->trans); 272 __dsc_psoc_trigger_trans(psoc); 273 274 __dsc_driver_unlock(psoc); 275 } 276 dsc_psoc_trans_stop(struct dsc_psoc * psoc)277 void dsc_psoc_trans_stop(struct dsc_psoc *psoc) 278 { 279 __dsc_psoc_trans_stop(psoc); 280 } 281 __dsc_psoc_assert_trans_protected(struct dsc_psoc * psoc)282 static void __dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc) 283 { 284 if (!dsc_assert(psoc)) 285 return; 286 287 __dsc_driver_lock(psoc); 288 dsc_assert(__dsc_trans_active(&psoc->trans) || 289 __dsc_trans_active(&psoc->driver->trans)); 290 __dsc_driver_unlock(psoc); 291 } 292 dsc_psoc_assert_trans_protected(struct dsc_psoc * psoc)293 void dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc) 294 { 295 __dsc_psoc_assert_trans_protected(psoc); 296 } 297 __dsc_psoc_trans_trigger_checked(struct dsc_psoc * psoc)298 bool __dsc_psoc_trans_trigger_checked(struct dsc_psoc *psoc) 299 { 300 if (qdf_list_empty(&psoc->trans.queue)) 301 return false; 302 303 /* handled, but don't trigger; we need to wait for more children */ 304 if (!__dsc_psoc_can_trigger(psoc)) 305 return true; 306 307 return __dsc_trans_trigger(&psoc->trans); 308 } 309 __dsc_psoc_op_start(struct dsc_psoc * psoc,const char * func)310 static QDF_STATUS __dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func) 311 { 312 QDF_STATUS status; 313 314 if (!dsc_assert(psoc)) 315 return QDF_STATUS_E_INVAL; 316 317 if (!dsc_assert(func)) 318 return QDF_STATUS_E_INVAL; 319 320 __dsc_driver_lock(psoc); 321 322 status = __dsc_psoc_can_op(psoc); 323 if (QDF_IS_STATUS_ERROR(status)) 324 goto unlock; 325 326 status = __dsc_ops_insert(&psoc->ops, func); 327 328 unlock: 329 __dsc_driver_unlock(psoc); 330 331 return status; 332 } 333 _dsc_psoc_op_start(struct dsc_psoc * psoc,const char * func)334 QDF_STATUS _dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func) 335 { 336 QDF_STATUS status; 337 338 status = __dsc_psoc_op_start(psoc, func); 339 340 return status; 341 } 342 __dsc_psoc_op_stop(struct dsc_psoc * psoc,const char * func)343 static void __dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func) 344 { 345 if (!dsc_assert(psoc)) 346 return; 347 348 if (!dsc_assert(func)) 349 return; 350 351 __dsc_driver_lock(psoc); 352 if (__dsc_ops_remove(&psoc->ops, func)) 353 qdf_event_set(&psoc->ops.event); 354 __dsc_driver_unlock(psoc); 355 } 356 _dsc_psoc_op_stop(struct dsc_psoc * psoc,const char * func)357 void _dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func) 358 { 359 __dsc_psoc_op_stop(psoc, func); 360 } 361 __dsc_psoc_wait_for_ops(struct dsc_psoc * psoc)362 static void __dsc_psoc_wait_for_ops(struct dsc_psoc *psoc) 363 { 364 struct dsc_vdev *vdev; 365 bool wait; 366 367 if (!dsc_assert(psoc)) 368 return; 369 370 __dsc_driver_lock(psoc); 371 372 wait = psoc->ops.count > 0; 373 if (wait) 374 qdf_event_reset(&psoc->ops.event); 375 376 __dsc_driver_unlock(psoc); 377 378 if (wait) 379 qdf_wait_single_event(&psoc->ops.event, 0); 380 381 /* wait for down-tree ops to complete as well */ 382 dsc_for_each_psoc_vdev(psoc, vdev) 383 dsc_vdev_wait_for_ops(vdev); 384 } 385 dsc_psoc_wait_for_ops(struct dsc_psoc * psoc)386 void dsc_psoc_wait_for_ops(struct dsc_psoc *psoc) 387 { 388 __dsc_psoc_wait_for_ops(psoc); 389 } 390 391