162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc. 462306a36Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/fs.h> 1062306a36Sopenharmony_ci#include <linux/seq_file.h> 1162306a36Sopenharmony_ci#include "wmi.h" 1262306a36Sopenharmony_ci#include "wil6210.h" 1362306a36Sopenharmony_ci#include "txrx.h" 1462306a36Sopenharmony_ci#include "pmc.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct desc_alloc_info { 1762306a36Sopenharmony_ci dma_addr_t pa; 1862306a36Sopenharmony_ci void *va; 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int wil_is_pmc_allocated(struct pmc_ctx *pmc) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci return !!pmc->pring_va; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_civoid wil_pmc_init(struct wil6210_priv *wil) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci memset(&wil->pmc, 0, sizeof(struct pmc_ctx)); 2962306a36Sopenharmony_ci mutex_init(&wil->pmc.lock); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Allocate the physical ring (p-ring) and the required 3362306a36Sopenharmony_ci * number of descriptors of required size. 3462306a36Sopenharmony_ci * Initialize the descriptors as required by pmc dma. 3562306a36Sopenharmony_ci * The descriptors' buffers dwords are initialized to hold 3662306a36Sopenharmony_ci * dword's serial number in the lsw and reserved value 3762306a36Sopenharmony_ci * PCM_DATA_INVALID_DW_VAL in the msw. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_civoid wil_pmc_alloc(struct wil6210_priv *wil, 4062306a36Sopenharmony_ci int num_descriptors, 4162306a36Sopenharmony_ci int descriptor_size) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci u32 i; 4462306a36Sopenharmony_ci struct pmc_ctx *pmc = &wil->pmc; 4562306a36Sopenharmony_ci struct device *dev = wil_to_dev(wil); 4662306a36Sopenharmony_ci struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); 4762306a36Sopenharmony_ci struct wmi_pmc_cmd pmc_cmd = {0}; 4862306a36Sopenharmony_ci int last_cmd_err = -ENOMEM; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci mutex_lock(&pmc->lock); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (wil_is_pmc_allocated(pmc)) { 5362306a36Sopenharmony_ci /* sanity check */ 5462306a36Sopenharmony_ci wil_err(wil, "ERROR pmc is already allocated\n"); 5562306a36Sopenharmony_ci goto no_release_err; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci if ((num_descriptors <= 0) || (descriptor_size <= 0)) { 5862306a36Sopenharmony_ci wil_err(wil, 5962306a36Sopenharmony_ci "Invalid params num_descriptors(%d), descriptor_size(%d)\n", 6062306a36Sopenharmony_ci num_descriptors, descriptor_size); 6162306a36Sopenharmony_ci last_cmd_err = -EINVAL; 6262306a36Sopenharmony_ci goto no_release_err; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (num_descriptors > (1 << WIL_RING_SIZE_ORDER_MAX)) { 6662306a36Sopenharmony_ci wil_err(wil, 6762306a36Sopenharmony_ci "num_descriptors(%d) exceeds max ring size %d\n", 6862306a36Sopenharmony_ci num_descriptors, 1 << WIL_RING_SIZE_ORDER_MAX); 6962306a36Sopenharmony_ci last_cmd_err = -EINVAL; 7062306a36Sopenharmony_ci goto no_release_err; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (num_descriptors > INT_MAX / descriptor_size) { 7462306a36Sopenharmony_ci wil_err(wil, 7562306a36Sopenharmony_ci "Overflow in num_descriptors(%d)*descriptor_size(%d)\n", 7662306a36Sopenharmony_ci num_descriptors, descriptor_size); 7762306a36Sopenharmony_ci last_cmd_err = -EINVAL; 7862306a36Sopenharmony_ci goto no_release_err; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci pmc->num_descriptors = num_descriptors; 8262306a36Sopenharmony_ci pmc->descriptor_size = descriptor_size; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci wil_dbg_misc(wil, "pmc_alloc: %d descriptors x %d bytes each\n", 8562306a36Sopenharmony_ci num_descriptors, descriptor_size); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* allocate descriptors info list in pmc context*/ 8862306a36Sopenharmony_ci pmc->descriptors = kcalloc(num_descriptors, 8962306a36Sopenharmony_ci sizeof(struct desc_alloc_info), 9062306a36Sopenharmony_ci GFP_KERNEL); 9162306a36Sopenharmony_ci if (!pmc->descriptors) { 9262306a36Sopenharmony_ci wil_err(wil, "ERROR allocating pmc skb list\n"); 9362306a36Sopenharmony_ci goto no_release_err; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci wil_dbg_misc(wil, "pmc_alloc: allocated descriptors info list %p\n", 9762306a36Sopenharmony_ci pmc->descriptors); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* Allocate pring buffer and descriptors. 10062306a36Sopenharmony_ci * vring->va should be aligned on its size rounded up to power of 2 10162306a36Sopenharmony_ci * This is granted by the dma_alloc_coherent. 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * HW has limitation that all vrings addresses must share the same 10462306a36Sopenharmony_ci * upper 16 msb bits part of 48 bits address. To workaround that, 10562306a36Sopenharmony_ci * if we are using more than 32 bit addresses switch to 32 bit 10662306a36Sopenharmony_ci * allocation before allocating vring memory. 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * There's no check for the return value of dma_set_mask_and_coherent, 10962306a36Sopenharmony_ci * since we assume if we were able to set the mask during 11062306a36Sopenharmony_ci * initialization in this system it will not fail if we set it again 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci if (wil->dma_addr_size > 32) 11362306a36Sopenharmony_ci dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci pmc->pring_va = dma_alloc_coherent(dev, 11662306a36Sopenharmony_ci sizeof(struct vring_tx_desc) * num_descriptors, 11762306a36Sopenharmony_ci &pmc->pring_pa, 11862306a36Sopenharmony_ci GFP_KERNEL); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (wil->dma_addr_size > 32) 12162306a36Sopenharmony_ci dma_set_mask_and_coherent(dev, 12262306a36Sopenharmony_ci DMA_BIT_MASK(wil->dma_addr_size)); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci wil_dbg_misc(wil, 12562306a36Sopenharmony_ci "pmc_alloc: allocated pring %p => %pad. %zd x %d = total %zd bytes\n", 12662306a36Sopenharmony_ci pmc->pring_va, &pmc->pring_pa, 12762306a36Sopenharmony_ci sizeof(struct vring_tx_desc), 12862306a36Sopenharmony_ci num_descriptors, 12962306a36Sopenharmony_ci sizeof(struct vring_tx_desc) * num_descriptors); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (!pmc->pring_va) { 13262306a36Sopenharmony_ci wil_err(wil, "ERROR allocating pmc pring\n"); 13362306a36Sopenharmony_ci goto release_pmc_skb_list; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* initially, all descriptors are SW owned 13762306a36Sopenharmony_ci * For Tx, Rx, and PMC, ownership bit is at the same location, thus 13862306a36Sopenharmony_ci * we can use any 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci for (i = 0; i < num_descriptors; i++) { 14162306a36Sopenharmony_ci struct vring_tx_desc *_d = &pmc->pring_va[i]; 14262306a36Sopenharmony_ci struct vring_tx_desc dd = {}, *d = ⅆ 14362306a36Sopenharmony_ci int j = 0; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci pmc->descriptors[i].va = dma_alloc_coherent(dev, 14662306a36Sopenharmony_ci descriptor_size, 14762306a36Sopenharmony_ci &pmc->descriptors[i].pa, 14862306a36Sopenharmony_ci GFP_KERNEL); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (unlikely(!pmc->descriptors[i].va)) { 15162306a36Sopenharmony_ci wil_err(wil, "ERROR allocating pmc descriptor %d", i); 15262306a36Sopenharmony_ci goto release_pmc_skbs; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci for (j = 0; j < descriptor_size / sizeof(u32); j++) { 15662306a36Sopenharmony_ci u32 *p = (u32 *)pmc->descriptors[i].va + j; 15762306a36Sopenharmony_ci *p = PCM_DATA_INVALID_DW_VAL | j; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* configure dma descriptor */ 16162306a36Sopenharmony_ci d->dma.addr.addr_low = 16262306a36Sopenharmony_ci cpu_to_le32(lower_32_bits(pmc->descriptors[i].pa)); 16362306a36Sopenharmony_ci d->dma.addr.addr_high = 16462306a36Sopenharmony_ci cpu_to_le16((u16)upper_32_bits(pmc->descriptors[i].pa)); 16562306a36Sopenharmony_ci d->dma.status = 0; /* 0 = HW_OWNED */ 16662306a36Sopenharmony_ci d->dma.length = cpu_to_le16(descriptor_size); 16762306a36Sopenharmony_ci d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT; 16862306a36Sopenharmony_ci *_d = *d; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci wil_dbg_misc(wil, "pmc_alloc: allocated successfully\n"); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci pmc_cmd.op = WMI_PMC_ALLOCATE; 17462306a36Sopenharmony_ci pmc_cmd.ring_size = cpu_to_le16(pmc->num_descriptors); 17562306a36Sopenharmony_ci pmc_cmd.mem_base = cpu_to_le64(pmc->pring_pa); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci wil_dbg_misc(wil, "pmc_alloc: send WMI_PMC_CMD with ALLOCATE op\n"); 17862306a36Sopenharmony_ci pmc->last_cmd_status = wmi_send(wil, 17962306a36Sopenharmony_ci WMI_PMC_CMDID, 18062306a36Sopenharmony_ci vif->mid, 18162306a36Sopenharmony_ci &pmc_cmd, 18262306a36Sopenharmony_ci sizeof(pmc_cmd)); 18362306a36Sopenharmony_ci if (pmc->last_cmd_status) { 18462306a36Sopenharmony_ci wil_err(wil, 18562306a36Sopenharmony_ci "WMI_PMC_CMD with ALLOCATE op failed with status %d", 18662306a36Sopenharmony_ci pmc->last_cmd_status); 18762306a36Sopenharmony_ci goto release_pmc_skbs; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cirelease_pmc_skbs: 19562306a36Sopenharmony_ci wil_err(wil, "exit on error: Releasing skbs...\n"); 19662306a36Sopenharmony_ci for (i = 0; i < num_descriptors && pmc->descriptors[i].va; i++) { 19762306a36Sopenharmony_ci dma_free_coherent(dev, 19862306a36Sopenharmony_ci descriptor_size, 19962306a36Sopenharmony_ci pmc->descriptors[i].va, 20062306a36Sopenharmony_ci pmc->descriptors[i].pa); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci pmc->descriptors[i].va = NULL; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci wil_err(wil, "exit on error: Releasing pring...\n"); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci dma_free_coherent(dev, 20762306a36Sopenharmony_ci sizeof(struct vring_tx_desc) * num_descriptors, 20862306a36Sopenharmony_ci pmc->pring_va, 20962306a36Sopenharmony_ci pmc->pring_pa); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci pmc->pring_va = NULL; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cirelease_pmc_skb_list: 21462306a36Sopenharmony_ci wil_err(wil, "exit on error: Releasing descriptors info list...\n"); 21562306a36Sopenharmony_ci kfree(pmc->descriptors); 21662306a36Sopenharmony_ci pmc->descriptors = NULL; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cino_release_err: 21962306a36Sopenharmony_ci pmc->last_cmd_status = last_cmd_err; 22062306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* Traverse the p-ring and release all buffers. 22462306a36Sopenharmony_ci * At the end release the p-ring memory 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_civoid wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct pmc_ctx *pmc = &wil->pmc; 22962306a36Sopenharmony_ci struct device *dev = wil_to_dev(wil); 23062306a36Sopenharmony_ci struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); 23162306a36Sopenharmony_ci struct wmi_pmc_cmd pmc_cmd = {0}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci mutex_lock(&pmc->lock); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci pmc->last_cmd_status = 0; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (!wil_is_pmc_allocated(pmc)) { 23862306a36Sopenharmony_ci wil_dbg_misc(wil, 23962306a36Sopenharmony_ci "pmc_free: Error, can't free - not allocated\n"); 24062306a36Sopenharmony_ci pmc->last_cmd_status = -EPERM; 24162306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 24262306a36Sopenharmony_ci return; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (send_pmc_cmd) { 24662306a36Sopenharmony_ci wil_dbg_misc(wil, "send WMI_PMC_CMD with RELEASE op\n"); 24762306a36Sopenharmony_ci pmc_cmd.op = WMI_PMC_RELEASE; 24862306a36Sopenharmony_ci pmc->last_cmd_status = 24962306a36Sopenharmony_ci wmi_send(wil, WMI_PMC_CMDID, vif->mid, 25062306a36Sopenharmony_ci &pmc_cmd, sizeof(pmc_cmd)); 25162306a36Sopenharmony_ci if (pmc->last_cmd_status) { 25262306a36Sopenharmony_ci wil_err(wil, 25362306a36Sopenharmony_ci "WMI_PMC_CMD with RELEASE op failed, status %d", 25462306a36Sopenharmony_ci pmc->last_cmd_status); 25562306a36Sopenharmony_ci /* There's nothing we can do with this error. 25662306a36Sopenharmony_ci * Normally, it should never occur. 25762306a36Sopenharmony_ci * Continue to freeing all memory allocated for pmc. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (pmc->pring_va) { 26362306a36Sopenharmony_ci size_t buf_size = sizeof(struct vring_tx_desc) * 26462306a36Sopenharmony_ci pmc->num_descriptors; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci wil_dbg_misc(wil, "pmc_free: free pring va %p\n", 26762306a36Sopenharmony_ci pmc->pring_va); 26862306a36Sopenharmony_ci dma_free_coherent(dev, buf_size, pmc->pring_va, pmc->pring_pa); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci pmc->pring_va = NULL; 27162306a36Sopenharmony_ci } else { 27262306a36Sopenharmony_ci pmc->last_cmd_status = -ENOENT; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (pmc->descriptors) { 27662306a36Sopenharmony_ci int i; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci for (i = 0; 27962306a36Sopenharmony_ci i < pmc->num_descriptors && pmc->descriptors[i].va; i++) { 28062306a36Sopenharmony_ci dma_free_coherent(dev, 28162306a36Sopenharmony_ci pmc->descriptor_size, 28262306a36Sopenharmony_ci pmc->descriptors[i].va, 28362306a36Sopenharmony_ci pmc->descriptors[i].pa); 28462306a36Sopenharmony_ci pmc->descriptors[i].va = NULL; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci wil_dbg_misc(wil, "pmc_free: free descriptor info %d/%d\n", i, 28762306a36Sopenharmony_ci pmc->num_descriptors); 28862306a36Sopenharmony_ci wil_dbg_misc(wil, 28962306a36Sopenharmony_ci "pmc_free: free pmc descriptors info list %p\n", 29062306a36Sopenharmony_ci pmc->descriptors); 29162306a36Sopenharmony_ci kfree(pmc->descriptors); 29262306a36Sopenharmony_ci pmc->descriptors = NULL; 29362306a36Sopenharmony_ci } else { 29462306a36Sopenharmony_ci pmc->last_cmd_status = -ENOENT; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* Status of the last operation requested via debugfs: alloc/free/read. 30162306a36Sopenharmony_ci * 0 - success or negative errno 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ciint wil_pmc_last_cmd_status(struct wil6210_priv *wil) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci wil_dbg_misc(wil, "pmc_last_cmd_status: status %d\n", 30662306a36Sopenharmony_ci wil->pmc.last_cmd_status); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return wil->pmc.last_cmd_status; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* Read from required position up to the end of current descriptor, 31262306a36Sopenharmony_ci * depends on descriptor size configured during alloc request. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_cissize_t wil_pmc_read(struct file *filp, char __user *buf, size_t count, 31562306a36Sopenharmony_ci loff_t *f_pos) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct wil6210_priv *wil = filp->private_data; 31862306a36Sopenharmony_ci struct pmc_ctx *pmc = &wil->pmc; 31962306a36Sopenharmony_ci size_t retval = 0; 32062306a36Sopenharmony_ci unsigned long long idx; 32162306a36Sopenharmony_ci loff_t offset; 32262306a36Sopenharmony_ci size_t pmc_size; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci mutex_lock(&pmc->lock); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!wil_is_pmc_allocated(pmc)) { 32762306a36Sopenharmony_ci wil_err(wil, "error, pmc is not allocated!\n"); 32862306a36Sopenharmony_ci pmc->last_cmd_status = -EPERM; 32962306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 33062306a36Sopenharmony_ci return -EPERM; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci pmc_size = pmc->descriptor_size * pmc->num_descriptors; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci wil_dbg_misc(wil, 33662306a36Sopenharmony_ci "pmc_read: size %u, pos %lld\n", 33762306a36Sopenharmony_ci (u32)count, *f_pos); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci pmc->last_cmd_status = 0; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci idx = *f_pos; 34262306a36Sopenharmony_ci do_div(idx, pmc->descriptor_size); 34362306a36Sopenharmony_ci offset = *f_pos - (idx * pmc->descriptor_size); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (*f_pos >= pmc_size) { 34662306a36Sopenharmony_ci wil_dbg_misc(wil, 34762306a36Sopenharmony_ci "pmc_read: reached end of pmc buf: %lld >= %u\n", 34862306a36Sopenharmony_ci *f_pos, (u32)pmc_size); 34962306a36Sopenharmony_ci pmc->last_cmd_status = -ERANGE; 35062306a36Sopenharmony_ci goto out; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci wil_dbg_misc(wil, 35462306a36Sopenharmony_ci "pmc_read: read from pos %lld (descriptor %llu, offset %llu) %zu bytes\n", 35562306a36Sopenharmony_ci *f_pos, idx, offset, count); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* if no errors, return the copied byte count */ 35862306a36Sopenharmony_ci retval = simple_read_from_buffer(buf, 35962306a36Sopenharmony_ci count, 36062306a36Sopenharmony_ci &offset, 36162306a36Sopenharmony_ci pmc->descriptors[idx].va, 36262306a36Sopenharmony_ci pmc->descriptor_size); 36362306a36Sopenharmony_ci *f_pos += retval; 36462306a36Sopenharmony_ciout: 36562306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return retval; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ciloff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci loff_t newpos; 37362306a36Sopenharmony_ci struct wil6210_priv *wil = filp->private_data; 37462306a36Sopenharmony_ci struct pmc_ctx *pmc = &wil->pmc; 37562306a36Sopenharmony_ci size_t pmc_size; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci mutex_lock(&pmc->lock); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (!wil_is_pmc_allocated(pmc)) { 38062306a36Sopenharmony_ci wil_err(wil, "error, pmc is not allocated!\n"); 38162306a36Sopenharmony_ci pmc->last_cmd_status = -EPERM; 38262306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 38362306a36Sopenharmony_ci return -EPERM; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci pmc_size = pmc->descriptor_size * pmc->num_descriptors; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci switch (whence) { 38962306a36Sopenharmony_ci case 0: /* SEEK_SET */ 39062306a36Sopenharmony_ci newpos = off; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci case 1: /* SEEK_CUR */ 39462306a36Sopenharmony_ci newpos = filp->f_pos + off; 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci case 2: /* SEEK_END */ 39862306a36Sopenharmony_ci newpos = pmc_size; 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci default: /* can't happen */ 40262306a36Sopenharmony_ci newpos = -EINVAL; 40362306a36Sopenharmony_ci goto out; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (newpos < 0) { 40762306a36Sopenharmony_ci newpos = -EINVAL; 40862306a36Sopenharmony_ci goto out; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci if (newpos > pmc_size) 41162306a36Sopenharmony_ci newpos = pmc_size; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci filp->f_pos = newpos; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ciout: 41662306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return newpos; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ciint wil_pmcring_read(struct seq_file *s, void *data) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct wil6210_priv *wil = s->private; 42462306a36Sopenharmony_ci struct pmc_ctx *pmc = &wil->pmc; 42562306a36Sopenharmony_ci size_t pmc_ring_size = 42662306a36Sopenharmony_ci sizeof(struct vring_rx_desc) * pmc->num_descriptors; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci mutex_lock(&pmc->lock); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (!wil_is_pmc_allocated(pmc)) { 43162306a36Sopenharmony_ci wil_err(wil, "error, pmc is not allocated!\n"); 43262306a36Sopenharmony_ci pmc->last_cmd_status = -EPERM; 43362306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 43462306a36Sopenharmony_ci return -EPERM; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci wil_dbg_misc(wil, "pmcring_read: size %zu\n", pmc_ring_size); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci seq_write(s, pmc->pring_va, pmc_ring_size); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci mutex_unlock(&pmc->lock); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci} 445