Path: blob/main/sys/contrib/dev/athk/ath11k/dbring.c
106412 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.4* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.5*/67#include "core.h"8#include "debug.h"910#define ATH11K_DB_MAGIC_VALUE 0xdeadbeaf1112int ath11k_dbring_validate_buffer(struct ath11k *ar, void *buffer, u32 size)13{14u32 *temp;15int idx;1617size = size >> 2;1819for (idx = 0, temp = buffer; idx < size; idx++, temp++) {20if (*temp == ATH11K_DB_MAGIC_VALUE)21return -EINVAL;22}2324return 0;25}2627static void ath11k_dbring_fill_magic_value(struct ath11k *ar,28void *buffer, u32 size)29{30/* memset32 function fills buffer payload with the ATH11K_DB_MAGIC_VALUE31* and the variable size is expected to be the number of u32 values32* to be stored, not the number of bytes.33*/34size = size / sizeof(u32);3536memset32(buffer, ATH11K_DB_MAGIC_VALUE, size);37}3839static int ath11k_dbring_bufs_replenish(struct ath11k *ar,40struct ath11k_dbring *ring,41struct ath11k_dbring_element *buff,42enum wmi_direct_buffer_module id)43{44struct ath11k_base *ab = ar->ab;45struct hal_srng *srng;46dma_addr_t paddr;47void *ptr_aligned, *ptr_unaligned, *desc;48int ret;49int buf_id;50u32 cookie;5152srng = &ab->hal.srng_list[ring->refill_srng.ring_id];5354lockdep_assert_held(&srng->lock);5556ath11k_hal_srng_access_begin(ab, srng);5758ptr_unaligned = buff->payload;59ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align);60ath11k_dbring_fill_magic_value(ar, ptr_aligned, ring->buf_sz);61paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz,62DMA_FROM_DEVICE);6364ret = dma_mapping_error(ab->dev, paddr);65if (ret)66goto err;6768spin_lock_bh(&ring->idr_lock);69buf_id = idr_alloc(&ring->bufs_idr, buff, 0, ring->bufs_max, GFP_ATOMIC);70spin_unlock_bh(&ring->idr_lock);71if (buf_id < 0) {72ret = -ENOBUFS;73goto err_dma_unmap;74}7576desc = ath11k_hal_srng_src_get_next_entry(ab, srng);77if (!desc) {78ret = -ENOENT;79goto err_idr_remove;80}8182buff->paddr = paddr;8384cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, ar->pdev_idx) |85FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);8687ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, 0);8889ath11k_debugfs_add_dbring_entry(ar, id, ATH11K_DBG_DBR_EVENT_REPLENISH, srng);90ath11k_hal_srng_access_end(ab, srng);9192return 0;9394err_idr_remove:95spin_lock_bh(&ring->idr_lock);96idr_remove(&ring->bufs_idr, buf_id);97spin_unlock_bh(&ring->idr_lock);98err_dma_unmap:99dma_unmap_single(ab->dev, paddr, ring->buf_sz,100DMA_FROM_DEVICE);101err:102ath11k_hal_srng_access_end(ab, srng);103return ret;104}105106static int ath11k_dbring_fill_bufs(struct ath11k *ar,107struct ath11k_dbring *ring,108enum wmi_direct_buffer_module id)109{110struct ath11k_dbring_element *buff;111struct hal_srng *srng;112int num_remain, req_entries, num_free;113u32 align;114int size, ret;115116srng = &ar->ab->hal.srng_list[ring->refill_srng.ring_id];117118spin_lock_bh(&srng->lock);119120num_free = ath11k_hal_srng_src_num_free(ar->ab, srng, true);121req_entries = min(num_free, ring->bufs_max);122num_remain = req_entries;123align = ring->buf_align;124size = ring->buf_sz + align - 1;125126while (num_remain > 0) {127buff = kzalloc(sizeof(*buff), GFP_ATOMIC);128if (!buff)129break;130131buff->payload = kzalloc(size, GFP_ATOMIC);132if (!buff->payload) {133kfree(buff);134break;135}136ret = ath11k_dbring_bufs_replenish(ar, ring, buff, id);137if (ret) {138ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n",139num_remain, req_entries);140kfree(buff->payload);141kfree(buff);142break;143}144num_remain--;145}146147spin_unlock_bh(&srng->lock);148149return num_remain;150}151152int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar,153struct ath11k_dbring *ring,154enum wmi_direct_buffer_module id)155{156struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {};157int ret;158159if (id >= WMI_DIRECT_BUF_MAX)160return -EINVAL;161162param.pdev_id = DP_SW2HW_MACID(ring->pdev_id);163param.module_id = id;164param.base_paddr_lo = lower_32_bits(ring->refill_srng.paddr);165param.base_paddr_hi = upper_32_bits(ring->refill_srng.paddr);166param.head_idx_paddr_lo = lower_32_bits(ring->hp_addr);167param.head_idx_paddr_hi = upper_32_bits(ring->hp_addr);168param.tail_idx_paddr_lo = lower_32_bits(ring->tp_addr);169param.tail_idx_paddr_hi = upper_32_bits(ring->tp_addr);170param.num_elems = ring->bufs_max;171param.buf_size = ring->buf_sz;172param.num_resp_per_event = ring->num_resp_per_event;173param.event_timeout_ms = ring->event_timeout_ms;174175ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m);176if (ret) {177ath11k_warn(ar->ab, "failed to setup db ring cfg\n");178return ret;179}180181return 0;182}183184int ath11k_dbring_set_cfg(struct ath11k *ar, struct ath11k_dbring *ring,185u32 num_resp_per_event, u32 event_timeout_ms,186int (*handler)(struct ath11k *,187struct ath11k_dbring_data *))188{189if (WARN_ON(!ring))190return -EINVAL;191192ring->num_resp_per_event = num_resp_per_event;193ring->event_timeout_ms = event_timeout_ms;194ring->handler = handler;195196return 0;197}198199int ath11k_dbring_buf_setup(struct ath11k *ar,200struct ath11k_dbring *ring,201struct ath11k_dbring_cap *db_cap)202{203struct ath11k_base *ab = ar->ab;204struct hal_srng *srng;205int ret;206207srng = &ab->hal.srng_list[ring->refill_srng.ring_id];208ring->bufs_max = ring->refill_srng.size /209ath11k_hal_srng_get_entrysize(ab, HAL_RXDMA_DIR_BUF);210211ring->buf_sz = db_cap->min_buf_sz;212ring->buf_align = db_cap->min_buf_align;213ring->pdev_id = db_cap->pdev_id;214ring->hp_addr = ath11k_hal_srng_get_hp_addr(ar->ab, srng);215ring->tp_addr = ath11k_hal_srng_get_tp_addr(ar->ab, srng);216217ret = ath11k_dbring_fill_bufs(ar, ring, db_cap->id);218219return ret;220}221222int ath11k_dbring_srng_setup(struct ath11k *ar, struct ath11k_dbring *ring,223int ring_num, int num_entries)224{225int ret;226227ret = ath11k_dp_srng_setup(ar->ab, &ring->refill_srng, HAL_RXDMA_DIR_BUF,228ring_num, ar->pdev_idx, num_entries);229if (ret < 0) {230ath11k_warn(ar->ab, "failed to setup srng: %d ring_id %d\n",231ret, ring_num);232goto err;233}234235return 0;236err:237ath11k_dp_srng_cleanup(ar->ab, &ring->refill_srng);238return ret;239}240241int ath11k_dbring_get_cap(struct ath11k_base *ab,242u8 pdev_idx,243enum wmi_direct_buffer_module id,244struct ath11k_dbring_cap *db_cap)245{246int i;247248if (!ab->num_db_cap || !ab->db_caps)249return -ENOENT;250251if (id >= WMI_DIRECT_BUF_MAX)252return -EINVAL;253254for (i = 0; i < ab->num_db_cap; i++) {255if (pdev_idx == ab->db_caps[i].pdev_id &&256id == ab->db_caps[i].id) {257*db_cap = ab->db_caps[i];258259return 0;260}261}262263return -ENOENT;264}265266int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,267struct ath11k_dbring_buf_release_event *ev)268{269struct ath11k_dbring *ring;270struct hal_srng *srng;271struct ath11k *ar;272struct ath11k_dbring_element *buff;273struct ath11k_dbring_data handler_data;274struct ath11k_buffer_addr desc;275u8 *vaddr_unalign;276u32 num_entry, num_buff_reaped;277u8 pdev_idx, rbm, module_id;278u32 cookie;279int buf_id;280int size;281dma_addr_t paddr;282int ret = 0;283284pdev_idx = ev->fixed.pdev_id;285module_id = ev->fixed.module_id;286287if (pdev_idx >= ab->num_radios) {288ath11k_warn(ab, "Invalid pdev id %d\n", pdev_idx);289return -EINVAL;290}291292if (ev->fixed.num_buf_release_entry !=293ev->fixed.num_meta_data_entry) {294ath11k_warn(ab, "Buffer entry %d mismatch meta entry %d\n",295ev->fixed.num_buf_release_entry,296ev->fixed.num_meta_data_entry);297return -EINVAL;298}299300ar = ab->pdevs[pdev_idx].ar;301302rcu_read_lock();303if (!rcu_dereference(ab->pdevs_active[pdev_idx])) {304ret = -EINVAL;305goto rcu_unlock;306}307308switch (ev->fixed.module_id) {309case WMI_DIRECT_BUF_SPECTRAL:310ring = ath11k_spectral_get_dbring(ar);311break;312default:313ring = NULL;314ath11k_warn(ab, "Recv dma buffer release ev on unsupp module %d\n",315ev->fixed.module_id);316break;317}318319if (!ring) {320ret = -EINVAL;321goto rcu_unlock;322}323324srng = &ab->hal.srng_list[ring->refill_srng.ring_id];325num_entry = ev->fixed.num_buf_release_entry;326size = ring->buf_sz + ring->buf_align - 1;327num_buff_reaped = 0;328329spin_lock_bh(&srng->lock);330331while (num_buff_reaped < num_entry) {332desc.info0 = ev->buf_entry[num_buff_reaped].paddr_lo;333desc.info1 = ev->buf_entry[num_buff_reaped].paddr_hi;334handler_data.meta = ev->meta_data[num_buff_reaped];335336num_buff_reaped++;337338ath11k_hal_rx_buf_addr_info_get(&desc, &paddr, &cookie, &rbm);339340buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie);341342spin_lock_bh(&ring->idr_lock);343buff = idr_find(&ring->bufs_idr, buf_id);344if (!buff) {345spin_unlock_bh(&ring->idr_lock);346continue;347}348idr_remove(&ring->bufs_idr, buf_id);349spin_unlock_bh(&ring->idr_lock);350351dma_unmap_single(ab->dev, buff->paddr, ring->buf_sz,352DMA_FROM_DEVICE);353354ath11k_debugfs_add_dbring_entry(ar, module_id,355ATH11K_DBG_DBR_EVENT_RX, srng);356357if (ring->handler) {358vaddr_unalign = buff->payload;359handler_data.data = PTR_ALIGN(vaddr_unalign,360ring->buf_align);361handler_data.data_sz = ring->buf_sz;362363ring->handler(ar, &handler_data);364}365366buff->paddr = 0;367memset(buff->payload, 0, size);368ath11k_dbring_bufs_replenish(ar, ring, buff, module_id);369}370371spin_unlock_bh(&srng->lock);372373rcu_unlock:374rcu_read_unlock();375376return ret;377}378379void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring)380{381ath11k_dp_srng_cleanup(ar->ab, &ring->refill_srng);382}383384void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring)385{386struct ath11k_dbring_element *buff;387int buf_id;388389spin_lock_bh(&ring->idr_lock);390idr_for_each_entry(&ring->bufs_idr, buff, buf_id) {391idr_remove(&ring->bufs_idr, buf_id);392dma_unmap_single(ar->ab->dev, buff->paddr,393ring->buf_sz, DMA_FROM_DEVICE);394kfree(buff->payload);395kfree(buff);396}397398idr_destroy(&ring->bufs_idr);399spin_unlock_bh(&ring->idr_lock);400}401402403