Path: blob/main/sys/contrib/dev/athk/ath11k/dbring.c
48378 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.3*/45#include "core.h"6#include "debug.h"78#define ATH11K_DB_MAGIC_VALUE 0xdeadbeaf910int ath11k_dbring_validate_buffer(struct ath11k *ar, void *buffer, u32 size)11{12u32 *temp;13int idx;1415size = size >> 2;1617for (idx = 0, temp = buffer; idx < size; idx++, temp++) {18if (*temp == ATH11K_DB_MAGIC_VALUE)19return -EINVAL;20}2122return 0;23}2425static void ath11k_dbring_fill_magic_value(struct ath11k *ar,26void *buffer, u32 size)27{28/* memset32 function fills buffer payload with the ATH11K_DB_MAGIC_VALUE29* and the variable size is expected to be the number of u32 values30* to be stored, not the number of bytes.31*/32size = size / sizeof(u32);3334memset32(buffer, ATH11K_DB_MAGIC_VALUE, size);35}3637static int ath11k_dbring_bufs_replenish(struct ath11k *ar,38struct ath11k_dbring *ring,39struct ath11k_dbring_element *buff,40enum wmi_direct_buffer_module id)41{42struct ath11k_base *ab = ar->ab;43struct hal_srng *srng;44dma_addr_t paddr;45void *ptr_aligned, *ptr_unaligned, *desc;46int ret;47int buf_id;48u32 cookie;4950srng = &ab->hal.srng_list[ring->refill_srng.ring_id];5152lockdep_assert_held(&srng->lock);5354ath11k_hal_srng_access_begin(ab, srng);5556ptr_unaligned = buff->payload;57ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align);58ath11k_dbring_fill_magic_value(ar, ptr_aligned, ring->buf_sz);59paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz,60DMA_FROM_DEVICE);6162ret = dma_mapping_error(ab->dev, paddr);63if (ret)64goto err;6566spin_lock_bh(&ring->idr_lock);67buf_id = idr_alloc(&ring->bufs_idr, buff, 0, ring->bufs_max, GFP_ATOMIC);68spin_unlock_bh(&ring->idr_lock);69if (buf_id < 0) {70ret = -ENOBUFS;71goto err_dma_unmap;72}7374desc = ath11k_hal_srng_src_get_next_entry(ab, srng);75if (!desc) {76ret = -ENOENT;77goto err_idr_remove;78}7980buff->paddr = paddr;8182cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, ar->pdev_idx) |83FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);8485ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, 0);8687ath11k_debugfs_add_dbring_entry(ar, id, ATH11K_DBG_DBR_EVENT_REPLENISH, srng);88ath11k_hal_srng_access_end(ab, srng);8990return 0;9192err_idr_remove:93spin_lock_bh(&ring->idr_lock);94idr_remove(&ring->bufs_idr, buf_id);95spin_unlock_bh(&ring->idr_lock);96err_dma_unmap:97dma_unmap_single(ab->dev, paddr, ring->buf_sz,98DMA_FROM_DEVICE);99err:100ath11k_hal_srng_access_end(ab, srng);101return ret;102}103104static int ath11k_dbring_fill_bufs(struct ath11k *ar,105struct ath11k_dbring *ring,106enum wmi_direct_buffer_module id)107{108struct ath11k_dbring_element *buff;109struct hal_srng *srng;110int num_remain, req_entries, num_free;111u32 align;112int size, ret;113114srng = &ar->ab->hal.srng_list[ring->refill_srng.ring_id];115116spin_lock_bh(&srng->lock);117118num_free = ath11k_hal_srng_src_num_free(ar->ab, srng, true);119req_entries = min(num_free, ring->bufs_max);120num_remain = req_entries;121align = ring->buf_align;122size = ring->buf_sz + align - 1;123124while (num_remain > 0) {125buff = kzalloc(sizeof(*buff), GFP_ATOMIC);126if (!buff)127break;128129buff->payload = kzalloc(size, GFP_ATOMIC);130if (!buff->payload) {131kfree(buff);132break;133}134ret = ath11k_dbring_bufs_replenish(ar, ring, buff, id);135if (ret) {136ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n",137num_remain, req_entries);138kfree(buff->payload);139kfree(buff);140break;141}142num_remain--;143}144145spin_unlock_bh(&srng->lock);146147return num_remain;148}149150int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar,151struct ath11k_dbring *ring,152enum wmi_direct_buffer_module id)153{154struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {0};155int ret;156157if (id >= WMI_DIRECT_BUF_MAX)158return -EINVAL;159160param.pdev_id = DP_SW2HW_MACID(ring->pdev_id);161param.module_id = id;162param.base_paddr_lo = lower_32_bits(ring->refill_srng.paddr);163param.base_paddr_hi = upper_32_bits(ring->refill_srng.paddr);164param.head_idx_paddr_lo = lower_32_bits(ring->hp_addr);165param.head_idx_paddr_hi = upper_32_bits(ring->hp_addr);166param.tail_idx_paddr_lo = lower_32_bits(ring->tp_addr);167param.tail_idx_paddr_hi = upper_32_bits(ring->tp_addr);168param.num_elems = ring->bufs_max;169param.buf_size = ring->buf_sz;170param.num_resp_per_event = ring->num_resp_per_event;171param.event_timeout_ms = ring->event_timeout_ms;172173ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m);174if (ret) {175ath11k_warn(ar->ab, "failed to setup db ring cfg\n");176return ret;177}178179return 0;180}181182int ath11k_dbring_set_cfg(struct ath11k *ar, struct ath11k_dbring *ring,183u32 num_resp_per_event, u32 event_timeout_ms,184int (*handler)(struct ath11k *,185struct ath11k_dbring_data *))186{187if (WARN_ON(!ring))188return -EINVAL;189190ring->num_resp_per_event = num_resp_per_event;191ring->event_timeout_ms = event_timeout_ms;192ring->handler = handler;193194return 0;195}196197int ath11k_dbring_buf_setup(struct ath11k *ar,198struct ath11k_dbring *ring,199struct ath11k_dbring_cap *db_cap)200{201struct ath11k_base *ab = ar->ab;202struct hal_srng *srng;203int ret;204205srng = &ab->hal.srng_list[ring->refill_srng.ring_id];206ring->bufs_max = ring->refill_srng.size /207ath11k_hal_srng_get_entrysize(ab, HAL_RXDMA_DIR_BUF);208209ring->buf_sz = db_cap->min_buf_sz;210ring->buf_align = db_cap->min_buf_align;211ring->pdev_id = db_cap->pdev_id;212ring->hp_addr = ath11k_hal_srng_get_hp_addr(ar->ab, srng);213ring->tp_addr = ath11k_hal_srng_get_tp_addr(ar->ab, srng);214215ret = ath11k_dbring_fill_bufs(ar, ring, db_cap->id);216217return ret;218}219220int ath11k_dbring_srng_setup(struct ath11k *ar, struct ath11k_dbring *ring,221int ring_num, int num_entries)222{223int ret;224225ret = ath11k_dp_srng_setup(ar->ab, &ring->refill_srng, HAL_RXDMA_DIR_BUF,226ring_num, ar->pdev_idx, num_entries);227if (ret < 0) {228ath11k_warn(ar->ab, "failed to setup srng: %d ring_id %d\n",229ret, ring_num);230goto err;231}232233return 0;234err:235ath11k_dp_srng_cleanup(ar->ab, &ring->refill_srng);236return ret;237}238239int ath11k_dbring_get_cap(struct ath11k_base *ab,240u8 pdev_idx,241enum wmi_direct_buffer_module id,242struct ath11k_dbring_cap *db_cap)243{244int i;245246if (!ab->num_db_cap || !ab->db_caps)247return -ENOENT;248249if (id >= WMI_DIRECT_BUF_MAX)250return -EINVAL;251252for (i = 0; i < ab->num_db_cap; i++) {253if (pdev_idx == ab->db_caps[i].pdev_id &&254id == ab->db_caps[i].id) {255*db_cap = ab->db_caps[i];256257return 0;258}259}260261return -ENOENT;262}263264int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,265struct ath11k_dbring_buf_release_event *ev)266{267struct ath11k_dbring *ring;268struct hal_srng *srng;269struct ath11k *ar;270struct ath11k_dbring_element *buff;271struct ath11k_dbring_data handler_data;272struct ath11k_buffer_addr desc;273u8 *vaddr_unalign;274u32 num_entry, num_buff_reaped;275u8 pdev_idx, rbm, module_id;276u32 cookie;277int buf_id;278int size;279dma_addr_t paddr;280int ret = 0;281282pdev_idx = ev->fixed.pdev_id;283module_id = ev->fixed.module_id;284285if (pdev_idx >= ab->num_radios) {286ath11k_warn(ab, "Invalid pdev id %d\n", pdev_idx);287return -EINVAL;288}289290if (ev->fixed.num_buf_release_entry !=291ev->fixed.num_meta_data_entry) {292ath11k_warn(ab, "Buffer entry %d mismatch meta entry %d\n",293ev->fixed.num_buf_release_entry,294ev->fixed.num_meta_data_entry);295return -EINVAL;296}297298ar = ab->pdevs[pdev_idx].ar;299300rcu_read_lock();301if (!rcu_dereference(ab->pdevs_active[pdev_idx])) {302ret = -EINVAL;303goto rcu_unlock;304}305306switch (ev->fixed.module_id) {307case WMI_DIRECT_BUF_SPECTRAL:308ring = ath11k_spectral_get_dbring(ar);309break;310default:311ring = NULL;312ath11k_warn(ab, "Recv dma buffer release ev on unsupp module %d\n",313ev->fixed.module_id);314break;315}316317if (!ring) {318ret = -EINVAL;319goto rcu_unlock;320}321322srng = &ab->hal.srng_list[ring->refill_srng.ring_id];323num_entry = ev->fixed.num_buf_release_entry;324size = ring->buf_sz + ring->buf_align - 1;325num_buff_reaped = 0;326327spin_lock_bh(&srng->lock);328329while (num_buff_reaped < num_entry) {330desc.info0 = ev->buf_entry[num_buff_reaped].paddr_lo;331desc.info1 = ev->buf_entry[num_buff_reaped].paddr_hi;332handler_data.meta = ev->meta_data[num_buff_reaped];333334num_buff_reaped++;335336ath11k_hal_rx_buf_addr_info_get(&desc, &paddr, &cookie, &rbm);337338buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie);339340spin_lock_bh(&ring->idr_lock);341buff = idr_find(&ring->bufs_idr, buf_id);342if (!buff) {343spin_unlock_bh(&ring->idr_lock);344continue;345}346idr_remove(&ring->bufs_idr, buf_id);347spin_unlock_bh(&ring->idr_lock);348349dma_unmap_single(ab->dev, buff->paddr, ring->buf_sz,350DMA_FROM_DEVICE);351352ath11k_debugfs_add_dbring_entry(ar, module_id,353ATH11K_DBG_DBR_EVENT_RX, srng);354355if (ring->handler) {356vaddr_unalign = buff->payload;357handler_data.data = PTR_ALIGN(vaddr_unalign,358ring->buf_align);359handler_data.data_sz = ring->buf_sz;360361ring->handler(ar, &handler_data);362}363364buff->paddr = 0;365memset(buff->payload, 0, size);366ath11k_dbring_bufs_replenish(ar, ring, buff, module_id);367}368369spin_unlock_bh(&srng->lock);370371rcu_unlock:372rcu_read_unlock();373374return ret;375}376377void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring)378{379ath11k_dp_srng_cleanup(ar->ab, &ring->refill_srng);380}381382void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring)383{384struct ath11k_dbring_element *buff;385int buf_id;386387spin_lock_bh(&ring->idr_lock);388idr_for_each_entry(&ring->bufs_idr, buff, buf_id) {389idr_remove(&ring->bufs_idr, buf_id);390dma_unmap_single(ar->ab->dev, buff->paddr,391ring->buf_sz, DMA_FROM_DEVICE);392kfree(buff->payload);393kfree(buff);394}395396idr_destroy(&ring->bufs_idr);397spin_unlock_bh(&ring->idr_lock);398}399400401