162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "core.h" 862306a36Sopenharmony_ci#include "debug.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic int ath12k_dbring_bufs_replenish(struct ath12k *ar, 1162306a36Sopenharmony_ci struct ath12k_dbring *ring, 1262306a36Sopenharmony_ci struct ath12k_dbring_element *buff, 1362306a36Sopenharmony_ci gfp_t gfp) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 1662306a36Sopenharmony_ci struct hal_srng *srng; 1762306a36Sopenharmony_ci dma_addr_t paddr; 1862306a36Sopenharmony_ci void *ptr_aligned, *ptr_unaligned, *desc; 1962306a36Sopenharmony_ci int ret; 2062306a36Sopenharmony_ci int buf_id; 2162306a36Sopenharmony_ci u32 cookie; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci lockdep_assert_held(&srng->lock); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, srng); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci ptr_unaligned = buff->payload; 3062306a36Sopenharmony_ci ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align); 3162306a36Sopenharmony_ci paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz, 3262306a36Sopenharmony_ci DMA_FROM_DEVICE); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci ret = dma_mapping_error(ab->dev, paddr); 3562306a36Sopenharmony_ci if (ret) 3662306a36Sopenharmony_ci goto err; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci spin_lock_bh(&ring->idr_lock); 3962306a36Sopenharmony_ci buf_id = idr_alloc(&ring->bufs_idr, buff, 0, ring->bufs_max, gfp); 4062306a36Sopenharmony_ci spin_unlock_bh(&ring->idr_lock); 4162306a36Sopenharmony_ci if (buf_id < 0) { 4262306a36Sopenharmony_ci ret = -ENOBUFS; 4362306a36Sopenharmony_ci goto err_dma_unmap; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci desc = ath12k_hal_srng_src_get_next_entry(ab, srng); 4762306a36Sopenharmony_ci if (!desc) { 4862306a36Sopenharmony_ci ret = -ENOENT; 4962306a36Sopenharmony_ci goto err_idr_remove; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci buff->paddr = paddr; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci cookie = u32_encode_bits(ar->pdev_idx, DP_RXDMA_BUF_COOKIE_PDEV_ID) | 5562306a36Sopenharmony_ci u32_encode_bits(buf_id, DP_RXDMA_BUF_COOKIE_BUF_ID); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ath12k_hal_rx_buf_addr_info_set(desc, paddr, cookie, 0); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cierr_idr_remove: 6462306a36Sopenharmony_ci spin_lock_bh(&ring->idr_lock); 6562306a36Sopenharmony_ci idr_remove(&ring->bufs_idr, buf_id); 6662306a36Sopenharmony_ci spin_unlock_bh(&ring->idr_lock); 6762306a36Sopenharmony_cierr_dma_unmap: 6862306a36Sopenharmony_ci dma_unmap_single(ab->dev, paddr, ring->buf_sz, 6962306a36Sopenharmony_ci DMA_FROM_DEVICE); 7062306a36Sopenharmony_cierr: 7162306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, srng); 7262306a36Sopenharmony_ci return ret; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int ath12k_dbring_fill_bufs(struct ath12k *ar, 7662306a36Sopenharmony_ci struct ath12k_dbring *ring, 7762306a36Sopenharmony_ci gfp_t gfp) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct ath12k_dbring_element *buff; 8062306a36Sopenharmony_ci struct hal_srng *srng; 8162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 8262306a36Sopenharmony_ci int num_remain, req_entries, num_free; 8362306a36Sopenharmony_ci u32 align; 8462306a36Sopenharmony_ci int size, ret; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci num_free = ath12k_hal_srng_src_num_free(ab, srng, true); 9162306a36Sopenharmony_ci req_entries = min(num_free, ring->bufs_max); 9262306a36Sopenharmony_ci num_remain = req_entries; 9362306a36Sopenharmony_ci align = ring->buf_align; 9462306a36Sopenharmony_ci size = sizeof(*buff) + ring->buf_sz + align - 1; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci while (num_remain > 0) { 9762306a36Sopenharmony_ci buff = kzalloc(size, gfp); 9862306a36Sopenharmony_ci if (!buff) 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ret = ath12k_dbring_bufs_replenish(ar, ring, buff, gfp); 10262306a36Sopenharmony_ci if (ret) { 10362306a36Sopenharmony_ci ath12k_warn(ab, "failed to replenish db ring num_remain %d req_ent %d\n", 10462306a36Sopenharmony_ci num_remain, req_entries); 10562306a36Sopenharmony_ci kfree(buff); 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci num_remain--; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return num_remain; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciint ath12k_dbring_wmi_cfg_setup(struct ath12k *ar, 11762306a36Sopenharmony_ci struct ath12k_dbring *ring, 11862306a36Sopenharmony_ci enum wmi_direct_buffer_module id) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct ath12k_wmi_pdev_dma_ring_cfg_arg arg = {0}; 12162306a36Sopenharmony_ci int ret; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (id >= WMI_DIRECT_BUF_MAX) 12462306a36Sopenharmony_ci return -EINVAL; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci arg.pdev_id = DP_SW2HW_MACID(ring->pdev_id); 12762306a36Sopenharmony_ci arg.module_id = id; 12862306a36Sopenharmony_ci arg.base_paddr_lo = lower_32_bits(ring->refill_srng.paddr); 12962306a36Sopenharmony_ci arg.base_paddr_hi = upper_32_bits(ring->refill_srng.paddr); 13062306a36Sopenharmony_ci arg.head_idx_paddr_lo = lower_32_bits(ring->hp_addr); 13162306a36Sopenharmony_ci arg.head_idx_paddr_hi = upper_32_bits(ring->hp_addr); 13262306a36Sopenharmony_ci arg.tail_idx_paddr_lo = lower_32_bits(ring->tp_addr); 13362306a36Sopenharmony_ci arg.tail_idx_paddr_hi = upper_32_bits(ring->tp_addr); 13462306a36Sopenharmony_ci arg.num_elems = ring->bufs_max; 13562306a36Sopenharmony_ci arg.buf_size = ring->buf_sz; 13662306a36Sopenharmony_ci arg.num_resp_per_event = ring->num_resp_per_event; 13762306a36Sopenharmony_ci arg.event_timeout_ms = ring->event_timeout_ms; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ret = ath12k_wmi_pdev_dma_ring_cfg(ar, &arg); 14062306a36Sopenharmony_ci if (ret) { 14162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to setup db ring cfg\n"); 14262306a36Sopenharmony_ci return ret; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ciint ath12k_dbring_set_cfg(struct ath12k *ar, struct ath12k_dbring *ring, 14962306a36Sopenharmony_ci u32 num_resp_per_event, u32 event_timeout_ms, 15062306a36Sopenharmony_ci int (*handler)(struct ath12k *, 15162306a36Sopenharmony_ci struct ath12k_dbring_data *)) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci if (WARN_ON(!ring)) 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci ring->num_resp_per_event = num_resp_per_event; 15762306a36Sopenharmony_ci ring->event_timeout_ms = event_timeout_ms; 15862306a36Sopenharmony_ci ring->handler = handler; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ciint ath12k_dbring_buf_setup(struct ath12k *ar, 16462306a36Sopenharmony_ci struct ath12k_dbring *ring, 16562306a36Sopenharmony_ci struct ath12k_dbring_cap *db_cap) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 16862306a36Sopenharmony_ci struct hal_srng *srng; 16962306a36Sopenharmony_ci int ret; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; 17262306a36Sopenharmony_ci ring->bufs_max = ring->refill_srng.size / 17362306a36Sopenharmony_ci ath12k_hal_srng_get_entrysize(ab, HAL_RXDMA_DIR_BUF); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci ring->buf_sz = db_cap->min_buf_sz; 17662306a36Sopenharmony_ci ring->buf_align = db_cap->min_buf_align; 17762306a36Sopenharmony_ci ring->pdev_id = db_cap->pdev_id; 17862306a36Sopenharmony_ci ring->hp_addr = ath12k_hal_srng_get_hp_addr(ab, srng); 17962306a36Sopenharmony_ci ring->tp_addr = ath12k_hal_srng_get_tp_addr(ab, srng); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ret = ath12k_dbring_fill_bufs(ar, ring, GFP_KERNEL); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ciint ath12k_dbring_srng_setup(struct ath12k *ar, struct ath12k_dbring *ring, 18762306a36Sopenharmony_ci int ring_num, int num_entries) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci int ret; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci ret = ath12k_dp_srng_setup(ar->ab, &ring->refill_srng, HAL_RXDMA_DIR_BUF, 19262306a36Sopenharmony_ci ring_num, ar->pdev_idx, num_entries); 19362306a36Sopenharmony_ci if (ret < 0) { 19462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to setup srng: %d ring_id %d\n", 19562306a36Sopenharmony_ci ret, ring_num); 19662306a36Sopenharmony_ci goto err; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_cierr: 20162306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ar->ab, &ring->refill_srng); 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ciint ath12k_dbring_get_cap(struct ath12k_base *ab, 20662306a36Sopenharmony_ci u8 pdev_idx, 20762306a36Sopenharmony_ci enum wmi_direct_buffer_module id, 20862306a36Sopenharmony_ci struct ath12k_dbring_cap *db_cap) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci int i; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!ab->num_db_cap || !ab->db_caps) 21362306a36Sopenharmony_ci return -ENOENT; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (id >= WMI_DIRECT_BUF_MAX) 21662306a36Sopenharmony_ci return -EINVAL; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci for (i = 0; i < ab->num_db_cap; i++) { 21962306a36Sopenharmony_ci if (pdev_idx == ab->db_caps[i].pdev_id && 22062306a36Sopenharmony_ci id == ab->db_caps[i].id) { 22162306a36Sopenharmony_ci *db_cap = ab->db_caps[i]; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return -ENOENT; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ciint ath12k_dbring_buffer_release_event(struct ath12k_base *ab, 23162306a36Sopenharmony_ci struct ath12k_dbring_buf_release_event *ev) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct ath12k_dbring *ring = NULL; 23462306a36Sopenharmony_ci struct hal_srng *srng; 23562306a36Sopenharmony_ci struct ath12k *ar; 23662306a36Sopenharmony_ci struct ath12k_dbring_element *buff; 23762306a36Sopenharmony_ci struct ath12k_dbring_data handler_data; 23862306a36Sopenharmony_ci struct ath12k_buffer_addr desc; 23962306a36Sopenharmony_ci u8 *vaddr_unalign; 24062306a36Sopenharmony_ci u32 num_entry, num_buff_reaped; 24162306a36Sopenharmony_ci u8 pdev_idx, rbm; 24262306a36Sopenharmony_ci u32 cookie; 24362306a36Sopenharmony_ci int buf_id; 24462306a36Sopenharmony_ci int size; 24562306a36Sopenharmony_ci dma_addr_t paddr; 24662306a36Sopenharmony_ci int ret = 0; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci pdev_idx = le32_to_cpu(ev->fixed.pdev_id); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (pdev_idx >= ab->num_radios) { 25162306a36Sopenharmony_ci ath12k_warn(ab, "Invalid pdev id %d\n", pdev_idx); 25262306a36Sopenharmony_ci return -EINVAL; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (ev->fixed.num_buf_release_entry != 25662306a36Sopenharmony_ci ev->fixed.num_meta_data_entry) { 25762306a36Sopenharmony_ci ath12k_warn(ab, "Buffer entry %d mismatch meta entry %d\n", 25862306a36Sopenharmony_ci ev->fixed.num_buf_release_entry, 25962306a36Sopenharmony_ci ev->fixed.num_meta_data_entry); 26062306a36Sopenharmony_ci return -EINVAL; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci ar = ab->pdevs[pdev_idx].ar; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci rcu_read_lock(); 26662306a36Sopenharmony_ci if (!rcu_dereference(ab->pdevs_active[pdev_idx])) { 26762306a36Sopenharmony_ci ret = -EINVAL; 26862306a36Sopenharmony_ci goto rcu_unlock; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci switch (ev->fixed.module_id) { 27262306a36Sopenharmony_ci case WMI_DIRECT_BUF_SPECTRAL: 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci default: 27562306a36Sopenharmony_ci ring = NULL; 27662306a36Sopenharmony_ci ath12k_warn(ab, "Recv dma buffer release ev on unsupp module %d\n", 27762306a36Sopenharmony_ci ev->fixed.module_id); 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (!ring) { 28262306a36Sopenharmony_ci ret = -EINVAL; 28362306a36Sopenharmony_ci goto rcu_unlock; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; 28762306a36Sopenharmony_ci num_entry = le32_to_cpu(ev->fixed.num_buf_release_entry); 28862306a36Sopenharmony_ci size = sizeof(*buff) + ring->buf_sz + ring->buf_align - 1; 28962306a36Sopenharmony_ci num_buff_reaped = 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci spin_lock_bh(&srng->lock); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci while (num_buff_reaped < num_entry) { 29462306a36Sopenharmony_ci desc.info0 = ev->buf_entry[num_buff_reaped].paddr_lo; 29562306a36Sopenharmony_ci desc.info1 = ev->buf_entry[num_buff_reaped].paddr_hi; 29662306a36Sopenharmony_ci handler_data.meta = ev->meta_data[num_buff_reaped]; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci num_buff_reaped++; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci ath12k_hal_rx_buf_addr_info_get(&desc, &paddr, &cookie, &rbm); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci buf_id = u32_get_bits(cookie, DP_RXDMA_BUF_COOKIE_BUF_ID); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci spin_lock_bh(&ring->idr_lock); 30562306a36Sopenharmony_ci buff = idr_find(&ring->bufs_idr, buf_id); 30662306a36Sopenharmony_ci if (!buff) { 30762306a36Sopenharmony_ci spin_unlock_bh(&ring->idr_lock); 30862306a36Sopenharmony_ci continue; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci idr_remove(&ring->bufs_idr, buf_id); 31162306a36Sopenharmony_ci spin_unlock_bh(&ring->idr_lock); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci dma_unmap_single(ab->dev, buff->paddr, ring->buf_sz, 31462306a36Sopenharmony_ci DMA_FROM_DEVICE); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (ring->handler) { 31762306a36Sopenharmony_ci vaddr_unalign = buff->payload; 31862306a36Sopenharmony_ci handler_data.data = PTR_ALIGN(vaddr_unalign, 31962306a36Sopenharmony_ci ring->buf_align); 32062306a36Sopenharmony_ci handler_data.data_sz = ring->buf_sz; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci ring->handler(ar, &handler_data); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci memset(buff, 0, size); 32662306a36Sopenharmony_ci ath12k_dbring_bufs_replenish(ar, ring, buff, GFP_ATOMIC); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci spin_unlock_bh(&srng->lock); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_circu_unlock: 33262306a36Sopenharmony_ci rcu_read_unlock(); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return ret; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_civoid ath12k_dbring_srng_cleanup(struct ath12k *ar, struct ath12k_dbring *ring) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci ath12k_dp_srng_cleanup(ar->ab, &ring->refill_srng); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_civoid ath12k_dbring_buf_cleanup(struct ath12k *ar, struct ath12k_dbring *ring) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct ath12k_dbring_element *buff; 34562306a36Sopenharmony_ci int buf_id; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci spin_lock_bh(&ring->idr_lock); 34862306a36Sopenharmony_ci idr_for_each_entry(&ring->bufs_idr, buff, buf_id) { 34962306a36Sopenharmony_ci idr_remove(&ring->bufs_idr, buf_id); 35062306a36Sopenharmony_ci dma_unmap_single(ar->ab->dev, buff->paddr, 35162306a36Sopenharmony_ci ring->buf_sz, DMA_FROM_DEVICE); 35262306a36Sopenharmony_ci kfree(buff); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci idr_destroy(&ring->bufs_idr); 35662306a36Sopenharmony_ci spin_unlock_bh(&ring->idr_lock); 35762306a36Sopenharmony_ci} 358