1 /* 2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-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 /** 21 * DOC: target_if_wifi_pos.c 22 * This file defines the functions pertinent to wifi positioning component's 23 * target if layer. 24 */ 25 #include "wifi_pos_utils_pub.h" 26 27 #include "wmi_unified_api.h" 28 #include "wlan_lmac_if_def.h" 29 #include "target_if_wifi_pos.h" 30 #include "../../../../umac/wifi_pos/src/wifi_pos_main_i.h" 31 #include "wifi_pos_utils_i.h" 32 #include "target_if.h" 33 #ifdef WLAN_FEATURE_CIF_CFR 34 #include "hal_api.h" 35 36 #define RING_BASE_ALIGN 8 37 38 static void *target_if_wifi_pos_vaddr_lookup( 39 struct wifi_pos_psoc_priv_obj *priv, 40 void *paddr, uint8_t ring_num, uint32_t cookie) 41 { 42 if (priv->dma_buf_pool[ring_num][cookie].paddr == paddr) { 43 return priv->dma_buf_pool[ring_num][cookie].vaddr + 44 priv->dma_buf_pool[ring_num][cookie].offset; 45 } else { 46 target_if_err("incorrect paddr found on cookie slot"); 47 return NULL; 48 } 49 } 50 51 QDF_STATUS 52 target_if_wifi_pos_replenish_ring(struct wifi_pos_psoc_priv_obj *priv, 53 uint8_t ring_idx, 54 void *aligned_vaddr, uint32_t cookie) 55 { 56 uint64_t *ring_entry; 57 uint32_t dw_lo, dw_hi = 0, map_status; 58 void *hal_soc = priv->hal_soc; 59 void *srng = priv->dma_cfg[ring_idx].srng; 60 void *paddr; 61 62 if (!aligned_vaddr) { 63 target_if_debug("NULL aligned_vaddr provided"); 64 return QDF_STATUS_SUCCESS; 65 } 66 67 map_status = qdf_mem_map_nbytes_single(NULL, aligned_vaddr, 68 QDF_DMA_FROM_DEVICE, 69 priv->dma_cap[ring_idx].min_buf_size, 70 (qdf_dma_addr_t *)&paddr); 71 if (map_status) { 72 target_if_err("mem map failed status: %d", map_status); 73 return QDF_STATUS_E_FAILURE; 74 } 75 QDF_ASSERT(!((uint64_t)paddr % priv->dma_cap[ring_idx].min_buf_align)); 76 priv->dma_buf_pool[ring_idx][cookie].paddr = paddr; 77 78 hal_srng_access_start(hal_soc, srng); 79 ring_entry = hal_srng_src_get_next(hal_soc, srng); 80 dw_lo = (uint64_t)paddr & 0xFFFFFFFF; 81 WMI_OEM_DMA_DATA_ADDR_HI_SET(dw_hi, (uint64_t)paddr >> 32); 82 WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA_SET(dw_hi, cookie); 83 *ring_entry = (uint64_t)dw_hi << 32 | dw_lo; 84 hal_srng_access_end(hal_soc, srng); 85 86 return QDF_STATUS_SUCCESS; 87 } 88 89 QDF_STATUS target_if_wifi_pos_get_indirect_data( 90 struct wifi_pos_psoc_priv_obj *priv_obj, 91 struct wmi_host_oem_indirect_data *indirect, 92 struct oem_data_rsp *rsp, uint32_t *cookie) 93 { 94 void *paddr = NULL; 95 uint32_t addr_hi; 96 uint8_t ring_idx = 0, num_rings; 97 uint32_t allocated_len; 98 99 if (!indirect) { 100 target_if_debug("no indirect data. regular event received"); 101 return QDF_STATUS_SUCCESS; 102 } 103 104 ring_idx = indirect->pdev_id - 1; 105 num_rings = priv_obj->num_rings; 106 if (ring_idx >= num_rings) { 107 target_if_err("incorrect pdev_id: %d", indirect->pdev_id); 108 return QDF_STATUS_E_INVAL; 109 } 110 111 allocated_len = priv_obj->dma_cap[ring_idx].min_buf_size + 112 (priv_obj->dma_cap[ring_idx].min_buf_align - 1); 113 if (indirect->len > allocated_len || 114 indirect->len > OEM_DATA_DMA_BUFF_SIZE) { 115 target_if_err("Invalid indirect len: %d, allocated_len:%d", 116 indirect->len, allocated_len); 117 return QDF_STATUS_E_INVAL; 118 } 119 120 addr_hi = (uint64_t)WMI_OEM_DMA_DATA_ADDR_HI_GET( 121 indirect->addr_hi); 122 paddr = (void *)((uint64_t)addr_hi << 32 | indirect->addr_lo); 123 *cookie = WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA_GET( 124 indirect->addr_hi); 125 rsp->vaddr = target_if_wifi_pos_vaddr_lookup(priv_obj, 126 paddr, ring_idx, *cookie); 127 rsp->dma_len = indirect->len; 128 qdf_mem_unmap_nbytes_single(NULL, (qdf_dma_addr_t)paddr, 129 QDF_DMA_FROM_DEVICE, 130 priv_obj->dma_cap[ring_idx].min_buf_size); 131 132 return QDF_STATUS_SUCCESS; 133 } 134 #endif 135 136 QDF_STATUS target_if_wifi_pos_get_vht_ch_width(struct wlan_objmgr_psoc *psoc, 137 enum phy_ch_width *ch_width) 138 { 139 struct target_psoc_info *tgt_hdl; 140 int vht_cap_info; 141 142 *ch_width = CH_WIDTH_INVALID; 143 144 if (!psoc) 145 return QDF_STATUS_E_INVAL; 146 147 tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); 148 if (!tgt_hdl) 149 return QDF_STATUS_E_INVAL; 150 151 *ch_width = CH_WIDTH_80MHZ; 152 153 vht_cap_info = target_if_get_vht_cap_info(tgt_hdl); 154 155 if (vht_cap_info & WLAN_VHTCAP_SUP_CHAN_WIDTH_80_160) 156 *ch_width = CH_WIDTH_80P80MHZ; 157 else if (vht_cap_info & WLAN_VHTCAP_SUP_CHAN_WIDTH_160) 158 *ch_width = CH_WIDTH_160MHZ; 159 160 return QDF_STATUS_SUCCESS; 161 } 162 163 #ifndef CNSS_GENL 164 QDF_STATUS target_if_wifi_pos_convert_pdev_id_host_to_target( 165 struct wlan_objmgr_psoc *psoc, uint32_t host_pdev_id, 166 uint32_t *target_pdev_id) 167 { 168 wmi_unified_t wmi_hdl = GET_WMI_HDL_FROM_PSOC(psoc); 169 170 if (!wmi_hdl) { 171 target_if_err("null wmi_hdl"); 172 return QDF_STATUS_E_NULL_VALUE; 173 } 174 175 return wmi_convert_pdev_id_host_to_target(wmi_hdl, host_pdev_id, 176 target_pdev_id); 177 } 178 179 QDF_STATUS target_if_wifi_pos_convert_pdev_id_target_to_host( 180 struct wlan_objmgr_psoc *psoc, uint32_t target_pdev_id, 181 uint32_t *host_pdev_id) 182 { 183 wmi_unified_t wmi_hdl = GET_WMI_HDL_FROM_PSOC(psoc); 184 185 if (!wmi_hdl) { 186 target_if_err("null wmi_hdl"); 187 return QDF_STATUS_E_NULL_VALUE; 188 } 189 190 return wmi_convert_pdev_id_target_to_host(wmi_hdl, target_pdev_id, 191 host_pdev_id); 192 } 193 #endif /* CNSS_GENL */ 194 195 #ifdef WLAN_FEATURE_CIF_CFR 196 static QDF_STATUS target_if_wifi_pos_fill_ring(uint8_t ring_idx, 197 struct hal_srng *srng, 198 struct wifi_pos_psoc_priv_obj *priv) 199 { 200 uint32_t i; 201 void *buf, *buf_aligned; 202 203 for (i = 0; i < priv->dma_cfg[ring_idx].num_ptr; i++) { 204 buf = qdf_mem_malloc(priv->dma_cap[ring_idx].min_buf_size + 205 priv->dma_cap[ring_idx].min_buf_align - 1); 206 if (!buf) 207 return QDF_STATUS_E_NOMEM; 208 209 priv->dma_buf_pool[ring_idx][i].vaddr = buf; 210 buf_aligned = (void *)qdf_roundup((uint64_t)buf, 211 priv->dma_cap[ring_idx].min_buf_align); 212 priv->dma_buf_pool[ring_idx][i].offset = buf_aligned - buf; 213 priv->dma_buf_pool[ring_idx][i].cookie = i; 214 target_if_wifi_pos_replenish_ring(priv, ring_idx, 215 buf_aligned, i); 216 } 217 218 return QDF_STATUS_SUCCESS; 219 } 220 221 static QDF_STATUS target_if_wifi_pos_empty_ring(uint8_t ring_idx, 222 struct wifi_pos_psoc_priv_obj *priv) 223 { 224 uint32_t i; 225 226 for (i = 0; i < priv->dma_cfg[ring_idx].num_ptr; i++) { 227 qdf_mem_unmap_nbytes_single(NULL, 228 (qdf_dma_addr_t)priv->dma_buf_pool[ring_idx][i].vaddr, 229 QDF_DMA_FROM_DEVICE, 230 priv->dma_cap[ring_idx].min_buf_size); 231 qdf_mem_free(priv->dma_buf_pool[ring_idx][i].vaddr); 232 } 233 234 return QDF_STATUS_SUCCESS; 235 } 236 237 static QDF_STATUS target_if_wifi_pos_init_ring(uint8_t ring_idx, 238 struct wifi_pos_psoc_priv_obj *priv) 239 { 240 void *srng; 241 uint32_t num_entries; 242 qdf_dma_addr_t paddr; 243 uint32_t ring_alloc_size; 244 void *hal_soc = priv->hal_soc; 245 struct hal_srng_params ring_params = {0}; 246 uint32_t max_entries = hal_srng_max_entries(hal_soc, WIFI_POS_SRC); 247 uint32_t entry_size = hal_srng_get_entrysize(hal_soc, WIFI_POS_SRC); 248 249 num_entries = priv->dma_cap[ring_idx].min_num_ptr > max_entries ? 250 max_entries : priv->dma_cap[ring_idx].min_num_ptr; 251 priv->dma_cfg[ring_idx].num_ptr = num_entries; 252 priv->dma_buf_pool[ring_idx] = qdf_mem_malloc(num_entries * 253 sizeof(struct wifi_pos_dma_buf_info)); 254 if (!priv->dma_buf_pool[ring_idx]) 255 return QDF_STATUS_E_NOMEM; 256 257 ring_alloc_size = (num_entries * entry_size) + RING_BASE_ALIGN - 1; 258 priv->dma_cfg[ring_idx].ring_alloc_size = ring_alloc_size; 259 priv->dma_cfg[ring_idx].base_vaddr_unaligned = 260 qdf_mem_alloc_consistent(NULL, NULL, ring_alloc_size, &paddr); 261 priv->dma_cfg[ring_idx].base_paddr_unaligned = (void *)paddr; 262 if (!priv->dma_cfg[ring_idx].base_vaddr_unaligned) { 263 target_if_err("malloc failed"); 264 return QDF_STATUS_E_NOMEM; 265 } 266 267 priv->dma_cfg[ring_idx].base_vaddr_aligned = (void *)qdf_roundup( 268 (uint64_t)priv->dma_cfg[ring_idx].base_vaddr_unaligned, 269 RING_BASE_ALIGN); 270 ring_params.ring_base_vaddr = 271 priv->dma_cfg[ring_idx].base_vaddr_aligned; 272 priv->dma_cfg[ring_idx].base_paddr_aligned = (void *)qdf_roundup( 273 (uint64_t)priv->dma_cfg[ring_idx].base_paddr_unaligned, 274 RING_BASE_ALIGN); 275 ring_params.ring_base_paddr = 276 (qdf_dma_addr_t)priv->dma_cfg[ring_idx].base_paddr_aligned; 277 ring_params.num_entries = num_entries; 278 srng = hal_srng_setup(hal_soc, WIFI_POS_SRC, 0, 279 priv->dma_cap[ring_idx].pdev_id, &ring_params, 0); 280 if (!srng) { 281 target_if_err("srng setup failed"); 282 return QDF_STATUS_E_FAILURE; 283 } 284 priv->dma_cfg[ring_idx].srng = srng; 285 priv->dma_cfg[ring_idx].tail_idx_addr = 286 (void *)hal_srng_get_tp_addr(hal_soc, srng); 287 priv->dma_cfg[ring_idx].head_idx_addr = 288 (void *)hal_srng_get_tp_addr(hal_soc, srng); 289 290 return target_if_wifi_pos_fill_ring(ring_idx, srng, priv); 291 } 292 293 static QDF_STATUS target_if_wifi_pos_deinit_ring(uint8_t ring_idx, 294 struct wifi_pos_psoc_priv_obj *priv) 295 { 296 target_if_wifi_pos_empty_ring(ring_idx, priv); 297 priv->dma_buf_pool[ring_idx] = NULL; 298 hal_srng_cleanup(priv->hal_soc, priv->dma_cfg[ring_idx].srng, 0); 299 qdf_mem_free_consistent(NULL, NULL, 300 priv->dma_cfg[ring_idx].ring_alloc_size, 301 priv->dma_cfg[ring_idx].base_vaddr_unaligned, 302 (qdf_dma_addr_t)priv->dma_cfg[ring_idx].base_paddr_unaligned, 303 0); 304 qdf_mem_free(priv->dma_buf_pool[ring_idx]); 305 306 return QDF_STATUS_SUCCESS; 307 } 308 309 static QDF_STATUS target_if_wifi_pos_init_srngs( 310 struct wifi_pos_psoc_priv_obj *priv) 311 { 312 uint8_t i; 313 QDF_STATUS status; 314 315 /* allocate memory for num_rings pointers */ 316 priv->dma_cfg = qdf_mem_malloc(priv->num_rings * 317 sizeof(struct wifi_pos_dma_rings_cap)); 318 if (!priv->dma_cfg) 319 return QDF_STATUS_E_NOMEM; 320 321 priv->dma_buf_pool = qdf_mem_malloc(priv->num_rings * 322 sizeof(struct wifi_pos_dma_buf_info *)); 323 if (!priv->dma_buf_pool) 324 return QDF_STATUS_E_NOMEM; 325 326 for (i = 0; i < priv->num_rings; i++) { 327 status = target_if_wifi_pos_init_ring(i, priv); 328 if (QDF_IS_STATUS_ERROR(status)) { 329 target_if_err("init for ring[%d] failed", i); 330 return status; 331 } 332 } 333 334 return QDF_STATUS_SUCCESS; 335 } 336 337 static QDF_STATUS target_if_wifi_pos_deinit_srngs( 338 struct wifi_pos_psoc_priv_obj *priv) 339 { 340 uint8_t i; 341 342 for (i = 0; i < priv->num_rings; i++) 343 target_if_wifi_pos_deinit_ring(i, priv); 344 345 qdf_mem_free(priv->dma_buf_pool); 346 priv->dma_buf_pool = NULL; 347 348 return QDF_STATUS_SUCCESS; 349 } 350 351 static QDF_STATUS target_if_wifi_pos_cfg_fw(struct wlan_objmgr_psoc *psoc, 352 struct wifi_pos_psoc_priv_obj *priv) 353 { 354 uint8_t i; 355 QDF_STATUS status; 356 wmi_unified_t wmi_hdl = GET_WMI_HDL_FROM_PSOC(psoc); 357 wmi_oem_dma_ring_cfg_req_fixed_param cfg = {0}; 358 359 if (!wmi_hdl) { 360 target_if_err("WMA closed, can't send oem data req cmd"); 361 return QDF_STATUS_E_INVAL; 362 } 363 364 target_if_debug("Sending oem dma ring cfg to target"); 365 366 for (i = 0; i < priv->num_rings; i++) { 367 cfg.pdev_id = priv->dma_cfg[i].pdev_id; 368 cfg.base_addr_lo = (uint64_t)priv->dma_cfg[i].base_paddr_aligned 369 & 0xFFFFFFFF; 370 cfg.base_addr_hi = (uint64_t)priv->dma_cfg[i].base_paddr_aligned 371 & 0xFFFFFFFF00000000; 372 cfg.head_idx_addr_lo = (uint64_t)priv->dma_cfg[i].head_idx_addr 373 & 0xFFFFFFFF; 374 cfg.head_idx_addr_hi = (uint64_t)priv->dma_cfg[i].head_idx_addr 375 & 0xFFFFFFFF00000000; 376 cfg.tail_idx_addr_lo = (uint64_t)priv->dma_cfg[i].tail_idx_addr 377 & 0xFFFFFFFF; 378 cfg.tail_idx_addr_hi = (uint64_t)priv->dma_cfg[i].tail_idx_addr 379 & 0xFFFFFFFF00000000; 380 cfg.num_ptr = priv->dma_cfg[i].num_ptr; 381 status = wmi_unified_oem_dma_ring_cfg(wmi_hdl, &cfg); 382 if (!QDF_IS_STATUS_SUCCESS(status)) { 383 target_if_err("wmi cmd send failed"); 384 return status; 385 } 386 } 387 388 return status; 389 } 390 391 QDF_STATUS target_if_wifi_pos_deinit_dma_rings(struct wlan_objmgr_psoc *psoc) 392 { 393 struct wifi_pos_psoc_priv_obj *priv = wifi_pos_get_psoc_priv_obj(psoc); 394 395 target_if_wifi_pos_deinit_srngs(priv); 396 qdf_mem_free(priv->dma_cap); 397 priv->dma_cap = NULL; 398 399 return QDF_STATUS_SUCCESS; 400 } 401 402 QDF_STATUS target_if_wifi_pos_init_cir_cfr_rings(struct wlan_objmgr_psoc *psoc, 403 void *hal_soc, uint8_t num_mac, 404 void *buf) 405 { 406 uint8_t i; 407 QDF_STATUS status = QDF_STATUS_SUCCESS; 408 WMI_OEM_DMA_RING_CAPABILITIES *dma_cap = buf; 409 struct wifi_pos_psoc_priv_obj *priv = wifi_pos_get_psoc_priv_obj(psoc); 410 411 if (!priv) { 412 target_if_err("unable to get wifi_pos psoc obj"); 413 return QDF_STATUS_E_NULL_VALUE; 414 } 415 416 priv->hal_soc = hal_soc; 417 priv->num_rings = num_mac; 418 priv->dma_cap = qdf_mem_malloc(priv->num_rings * 419 sizeof(struct wifi_pos_dma_rings_cap)); 420 if (!priv->dma_cap) 421 return QDF_STATUS_E_NOMEM; 422 423 for (i = 0; i < num_mac; i++) { 424 priv->dma_cap[i].pdev_id = dma_cap[i].pdev_id; 425 priv->dma_cap[i].min_num_ptr = dma_cap[i].min_num_ptr; 426 priv->dma_cap[i].min_buf_size = dma_cap[i].min_buf_size; 427 priv->dma_cap[i].min_buf_align = dma_cap[i].min_buf_align; 428 } 429 430 /* initialize DMA rings now */ 431 status = target_if_wifi_pos_init_srngs(priv); 432 if (QDF_IS_STATUS_ERROR(status)) { 433 target_if_err("dma init failed: %d", status); 434 goto dma_init_failed; 435 } 436 437 /* send cfg req cmd to firmware */ 438 status = target_if_wifi_pos_cfg_fw(psoc, priv); 439 if (QDF_IS_STATUS_ERROR(status)) { 440 target_if_err("configure to FW failed: %d", status); 441 goto dma_init_failed; 442 } 443 444 return QDF_STATUS_SUCCESS; 445 446 dma_init_failed: 447 target_if_wifi_pos_deinit_dma_rings(psoc); 448 return status; 449 } 450 451 #endif 452