1 /* 2 * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-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 "linux/device.h" 21 #include "linux/netdevice.h" 22 #include "__osif_psoc_sync.h" 23 #include "__osif_vdev_sync.h" 24 #include "osif_vdev_sync.h" 25 #include "qdf_lock.h" 26 #include "qdf_status.h" 27 #include "qdf_types.h" 28 #include <qdf_trace.h> 29 #include <wlan_cfg80211.h> 30 31 static struct osif_vdev_sync __osif_vdev_sync_arr[WLAN_MAX_VDEVS + 32 WLAN_MAX_ML_VDEVS]; 33 static qdf_spinlock_t __osif_vdev_sync_lock; 34 35 #define osif_vdev_sync_lock_create() qdf_spinlock_create(&__osif_vdev_sync_lock) 36 #define osif_vdev_sync_lock_destroy() \ 37 qdf_spinlock_destroy(&__osif_vdev_sync_lock) 38 #define osif_vdev_sync_lock() qdf_spin_lock_bh(&__osif_vdev_sync_lock) 39 #define osif_vdev_sync_unlock() qdf_spin_unlock_bh(&__osif_vdev_sync_lock) 40 41 static struct osif_vdev_sync *osif_vdev_sync_lookup(struct net_device *net_dev) 42 { 43 int i; 44 45 for (i = 0; i < QDF_ARRAY_SIZE(__osif_vdev_sync_arr); i++) { 46 struct osif_vdev_sync *vdev_sync = __osif_vdev_sync_arr + i; 47 48 if (!vdev_sync->in_use) 49 continue; 50 51 if (vdev_sync->net_dev == net_dev) 52 return vdev_sync; 53 } 54 55 return NULL; 56 } 57 58 struct osif_vdev_sync *osif_get_vdev_sync_arr(void) 59 { 60 return __osif_vdev_sync_arr; 61 } 62 63 static struct osif_vdev_sync *osif_vdev_sync_get(void) 64 { 65 int i; 66 67 for (i = 0; i < QDF_ARRAY_SIZE(__osif_vdev_sync_arr); i++) { 68 struct osif_vdev_sync *vdev_sync = __osif_vdev_sync_arr + i; 69 70 if (!vdev_sync->in_use) { 71 vdev_sync->in_use = true; 72 return vdev_sync; 73 } 74 } 75 76 return NULL; 77 } 78 79 static void osif_vdev_sync_put(struct osif_vdev_sync *vdev_sync) 80 { 81 qdf_mem_zero(vdev_sync, sizeof(*vdev_sync)); 82 } 83 84 int osif_vdev_sync_create(struct device *dev, 85 struct osif_vdev_sync **out_vdev_sync) 86 { 87 struct osif_vdev_sync *vdev_sync; 88 QDF_STATUS status; 89 90 QDF_BUG(dev); 91 if (!dev) 92 return -EINVAL; 93 94 QDF_BUG(out_vdev_sync); 95 if (!out_vdev_sync) 96 return -EINVAL; 97 98 osif_vdev_sync_lock(); 99 vdev_sync = osif_vdev_sync_get(); 100 osif_vdev_sync_unlock(); 101 if (!vdev_sync) 102 return -ENOMEM; 103 104 status = osif_psoc_sync_dsc_vdev_create(dev, &vdev_sync->dsc_vdev); 105 if (QDF_IS_STATUS_ERROR(status)) 106 goto sync_put; 107 108 *out_vdev_sync = vdev_sync; 109 110 return 0; 111 112 sync_put: 113 osif_vdev_sync_lock(); 114 osif_vdev_sync_put(vdev_sync); 115 osif_vdev_sync_unlock(); 116 117 return qdf_status_to_os_return(status); 118 } 119 120 int __osif_vdev_sync_create_and_trans(struct device *dev, 121 struct osif_vdev_sync **out_vdev_sync, 122 const char *desc) 123 { 124 struct osif_vdev_sync *vdev_sync; 125 QDF_STATUS status; 126 int errno; 127 128 errno = osif_vdev_sync_create(dev, &vdev_sync); 129 if (errno) 130 return errno; 131 132 status = dsc_vdev_trans_start(vdev_sync->dsc_vdev, desc); 133 if (QDF_IS_STATUS_ERROR(status)) 134 goto sync_destroy; 135 136 *out_vdev_sync = vdev_sync; 137 138 return 0; 139 140 sync_destroy: 141 osif_vdev_sync_destroy(vdev_sync); 142 143 return qdf_status_to_os_return(status); 144 } 145 146 void osif_vdev_sync_destroy(struct osif_vdev_sync *vdev_sync) 147 { 148 QDF_BUG(vdev_sync); 149 if (!vdev_sync) 150 return; 151 152 dsc_vdev_destroy(&vdev_sync->dsc_vdev); 153 154 osif_vdev_sync_lock(); 155 osif_vdev_sync_put(vdev_sync); 156 osif_vdev_sync_unlock(); 157 } 158 159 void osif_vdev_sync_register(struct net_device *net_dev, 160 struct osif_vdev_sync *vdev_sync) 161 { 162 QDF_BUG(net_dev); 163 QDF_BUG(vdev_sync); 164 if (!vdev_sync) 165 return; 166 167 osif_vdev_sync_lock(); 168 vdev_sync->net_dev = net_dev; 169 osif_vdev_sync_unlock(); 170 } 171 172 struct osif_vdev_sync *osif_vdev_sync_unregister(struct net_device *net_dev) 173 { 174 struct osif_vdev_sync *vdev_sync; 175 176 QDF_BUG(net_dev); 177 if (!net_dev) 178 return NULL; 179 180 osif_vdev_sync_lock(); 181 vdev_sync = osif_vdev_sync_lookup(net_dev); 182 if (vdev_sync) 183 vdev_sync->net_dev = NULL; 184 osif_vdev_sync_unlock(); 185 186 return vdev_sync; 187 } 188 189 typedef QDF_STATUS (*vdev_start_func)(struct dsc_vdev *, const char *); 190 191 static int 192 __osif_vdev_sync_start_callback(struct net_device *net_dev, 193 struct osif_vdev_sync **out_vdev_sync, 194 const char *desc, 195 vdev_start_func vdev_start_cb) 196 { 197 QDF_STATUS status; 198 struct osif_vdev_sync *vdev_sync; 199 200 *out_vdev_sync = NULL; 201 202 vdev_sync = osif_vdev_sync_lookup(net_dev); 203 if (!vdev_sync) 204 return -EAGAIN; 205 206 *out_vdev_sync = vdev_sync; 207 208 status = vdev_start_cb(vdev_sync->dsc_vdev, desc); 209 if (QDF_IS_STATUS_ERROR(status)) 210 return qdf_status_to_os_return(status); 211 212 return 0; 213 } 214 215 static int 216 __osif_vdev_sync_start_wait_callback(struct net_device *net_dev, 217 struct osif_vdev_sync **out_vdev_sync, 218 const char *desc, 219 vdev_start_func vdev_start_cb) 220 { 221 QDF_STATUS status; 222 struct osif_vdev_sync *vdev_sync; 223 224 *out_vdev_sync = NULL; 225 226 osif_vdev_sync_lock(); 227 vdev_sync = osif_vdev_sync_lookup(net_dev); 228 osif_vdev_sync_unlock(); 229 if (!vdev_sync) 230 return -EAGAIN; 231 232 status = vdev_start_cb(vdev_sync->dsc_vdev, desc); 233 if (QDF_IS_STATUS_ERROR(status)) 234 return qdf_status_to_os_return(status); 235 236 *out_vdev_sync = vdev_sync; 237 238 return 0; 239 } 240 241 /** 242 * osif_vdev_sync_wait_for_uptree_ops - Wait for psoc/driver operations 243 * @vdev_sync: vdev sync pointer 244 * 245 * If there are any psoc/driver operations are taking place, then vdev 246 * trans/ops should wait for these operations to be completed to avoid 247 * memory domain mismatch issues. For example, if modules are closed 248 * because of idle shutdown, memory domain will be init domain and at 249 * that time if some psoc ops starts, memory allocated as part of this 250 * ops will be allocated in init domain and if at the same time if vdev 251 * up starts which will trigger the vdev trans and will start the 252 * modules and change the memory domain to active domain, now when the 253 * memory allocated as part of psoc operation is release on psoc ops 254 * completion will be released in the active domain which leads the 255 * memory domain mismatch. 256 * 257 * Return: None. 258 */ 259 static void osif_vdev_sync_wait_for_uptree_ops(struct osif_vdev_sync *vdev_sync) 260 { 261 dsc_vdev_wait_for_uptree_ops(vdev_sync->dsc_vdev); 262 } 263 264 int __osif_vdev_sync_trans_start(struct net_device *net_dev, 265 struct osif_vdev_sync **out_vdev_sync, 266 const char *desc) 267 { 268 int errno; 269 270 osif_vdev_sync_lock(); 271 errno = __osif_vdev_sync_start_callback(net_dev, out_vdev_sync, desc, 272 dsc_vdev_trans_start); 273 osif_vdev_sync_unlock(); 274 275 if (!errno) { 276 osif_vdev_sync_wait_for_ops(*out_vdev_sync); 277 osif_vdev_sync_wait_for_uptree_ops(*out_vdev_sync); 278 } 279 280 return errno; 281 } 282 283 int __osif_vdev_sync_trans_start_wait(struct net_device *net_dev, 284 struct osif_vdev_sync **out_vdev_sync, 285 const char *desc) 286 { 287 int errno; 288 289 /* since dsc_vdev_trans_start_wait may sleep do not take lock here */ 290 errno = __osif_vdev_sync_start_wait_callback(net_dev, 291 out_vdev_sync, desc, 292 dsc_vdev_trans_start_wait); 293 294 if (!errno) { 295 osif_vdev_sync_wait_for_ops(*out_vdev_sync); 296 osif_vdev_sync_wait_for_uptree_ops(*out_vdev_sync); 297 } 298 299 return errno; 300 } 301 302 void osif_vdev_sync_trans_stop(struct osif_vdev_sync *vdev_sync) 303 { 304 dsc_vdev_trans_stop(vdev_sync->dsc_vdev); 305 } 306 307 void osif_vdev_sync_assert_trans_protected(struct net_device *net_dev) 308 { 309 struct osif_vdev_sync *vdev_sync; 310 311 osif_vdev_sync_lock(); 312 313 vdev_sync = osif_vdev_sync_lookup(net_dev); 314 QDF_BUG(vdev_sync); 315 if (vdev_sync) 316 dsc_vdev_assert_trans_protected(vdev_sync->dsc_vdev); 317 318 osif_vdev_sync_unlock(); 319 } 320 321 int __osif_vdev_sync_op_start(struct net_device *net_dev, 322 struct osif_vdev_sync **out_vdev_sync, 323 const char *func) 324 { 325 int errno; 326 327 osif_vdev_sync_lock(); 328 errno = __osif_vdev_sync_start_callback(net_dev, out_vdev_sync, func, 329 _dsc_vdev_op_start); 330 osif_vdev_sync_unlock(); 331 332 return errno; 333 } 334 335 void __osif_vdev_sync_op_stop(struct osif_vdev_sync *vdev_sync, 336 const char *func) 337 { 338 _dsc_vdev_op_stop(vdev_sync->dsc_vdev, func); 339 } 340 341 void osif_vdev_sync_wait_for_ops(struct osif_vdev_sync *vdev_sync) 342 { 343 dsc_vdev_wait_for_ops(vdev_sync->dsc_vdev); 344 } 345 346 void osif_vdev_sync_init(void) 347 { 348 osif_vdev_sync_lock_create(); 349 } 350 351 void osif_vdev_sync_deinit(void) 352 { 353 osif_vdev_sync_lock_destroy(); 354 } 355 356 uint8_t osif_vdev_get_cached_cmd(struct osif_vdev_sync *vdev_sync) 357 { 358 return dsc_vdev_get_cached_cmd(vdev_sync->dsc_vdev); 359 } 360 361 void osif_vdev_cache_command(struct osif_vdev_sync *vdev_sync, uint8_t cmd_id) 362 { 363 dsc_vdev_cache_command(vdev_sync->dsc_vdev, cmd_id); 364 osif_debug("Set cache cmd to %d", cmd_id); 365 } 366 367