1ba764c4dSAlex Elder // SPDX-License-Identifier: GPL-2.0 2ba764c4dSAlex Elder 3ba764c4dSAlex Elder /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. 4ba764c4dSAlex Elder * Copyright (C) 2019-2020 Linaro Ltd. 5ba764c4dSAlex Elder */ 6ba764c4dSAlex Elder 7ba764c4dSAlex Elder #include <linux/types.h> 8ba764c4dSAlex Elder #include <linux/bitfield.h> 9ba764c4dSAlex Elder #include <linux/bug.h> 10ba764c4dSAlex Elder #include <linux/dma-mapping.h> 113e313c3fSAlex Elder #include <linux/iommu.h> 12ba764c4dSAlex Elder #include <linux/io.h> 13a0036bb4SAlex Elder #include <linux/soc/qcom/smem.h> 14ba764c4dSAlex Elder 15ba764c4dSAlex Elder #include "ipa.h" 16ba764c4dSAlex Elder #include "ipa_reg.h" 173128aae8SAlex Elder #include "ipa_data.h" 18ba764c4dSAlex Elder #include "ipa_cmd.h" 19ba764c4dSAlex Elder #include "ipa_mem.h" 20ba764c4dSAlex Elder #include "ipa_table.h" 21ba764c4dSAlex Elder #include "gsi_trans.h" 22ba764c4dSAlex Elder 23ba764c4dSAlex Elder /* "Canary" value placed between memory regions to detect overflow */ 24ba764c4dSAlex Elder #define IPA_MEM_CANARY_VAL cpu_to_le32(0xdeadbeef) 25ba764c4dSAlex Elder 26a0036bb4SAlex Elder /* SMEM host id representing the modem. */ 27a0036bb4SAlex Elder #define QCOM_SMEM_HOST_MODEM 1 28a0036bb4SAlex Elder 29ba764c4dSAlex Elder /* Add an immediate command to a transaction that zeroes a memory region */ 30ba764c4dSAlex Elder static void 31ba764c4dSAlex Elder ipa_mem_zero_region_add(struct gsi_trans *trans, const struct ipa_mem *mem) 32ba764c4dSAlex Elder { 33ba764c4dSAlex Elder struct ipa *ipa = container_of(trans->gsi, struct ipa, gsi); 34ba764c4dSAlex Elder dma_addr_t addr = ipa->zero_addr; 35ba764c4dSAlex Elder 36ba764c4dSAlex Elder if (!mem->size) 37ba764c4dSAlex Elder return; 38ba764c4dSAlex Elder 39ba764c4dSAlex Elder ipa_cmd_dma_shared_mem_add(trans, mem->offset, mem->size, addr, true); 40ba764c4dSAlex Elder } 41ba764c4dSAlex Elder 42ba764c4dSAlex Elder /** 43ba764c4dSAlex Elder * ipa_mem_setup() - Set up IPA AP and modem shared memory areas 44e3eea08eSAlex Elder * @ipa: IPA pointer 45ba764c4dSAlex Elder * 46ba764c4dSAlex Elder * Set up the shared memory regions in IPA local memory. This involves 47ba764c4dSAlex Elder * zero-filling memory regions, and in the case of header memory, telling 48ba764c4dSAlex Elder * the IPA where it's located. 49ba764c4dSAlex Elder * 50ba764c4dSAlex Elder * This function performs the initial setup of this memory. If the modem 51ba764c4dSAlex Elder * crashes, its regions are re-zeroed in ipa_mem_zero_modem(). 52ba764c4dSAlex Elder * 53ba764c4dSAlex Elder * The AP informs the modem where its portions of memory are located 54ba764c4dSAlex Elder * in a QMI exchange that occurs at modem startup. 55ba764c4dSAlex Elder * 56e3eea08eSAlex Elder * Return: 0 if successful, or a negative error code 57ba764c4dSAlex Elder */ 58ba764c4dSAlex Elder int ipa_mem_setup(struct ipa *ipa) 59ba764c4dSAlex Elder { 60ba764c4dSAlex Elder dma_addr_t addr = ipa->zero_addr; 61ba764c4dSAlex Elder struct gsi_trans *trans; 62ba764c4dSAlex Elder u32 offset; 63ba764c4dSAlex Elder u16 size; 64ba764c4dSAlex Elder 65ba764c4dSAlex Elder /* Get a transaction to define the header memory region and to zero 66ba764c4dSAlex Elder * the processing context and modem memory regions. 67ba764c4dSAlex Elder */ 68ba764c4dSAlex Elder trans = ipa_cmd_trans_alloc(ipa, 4); 69ba764c4dSAlex Elder if (!trans) { 70ba764c4dSAlex Elder dev_err(&ipa->pdev->dev, "no transaction for memory setup\n"); 71ba764c4dSAlex Elder return -EBUSY; 72ba764c4dSAlex Elder } 73ba764c4dSAlex Elder 74ba764c4dSAlex Elder /* Initialize IPA-local header memory. The modem and AP header 75ba764c4dSAlex Elder * regions are contiguous, and initialized together. 76ba764c4dSAlex Elder */ 77ba764c4dSAlex Elder offset = ipa->mem[IPA_MEM_MODEM_HEADER].offset; 78ba764c4dSAlex Elder size = ipa->mem[IPA_MEM_MODEM_HEADER].size; 79ba764c4dSAlex Elder size += ipa->mem[IPA_MEM_AP_HEADER].size; 80ba764c4dSAlex Elder 81ba764c4dSAlex Elder ipa_cmd_hdr_init_local_add(trans, offset, size, addr); 82ba764c4dSAlex Elder 83ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM_PROC_CTX]); 84ba764c4dSAlex Elder 85ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_AP_PROC_CTX]); 86ba764c4dSAlex Elder 87ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM]); 88ba764c4dSAlex Elder 89ba764c4dSAlex Elder gsi_trans_commit_wait(trans); 90ba764c4dSAlex Elder 91ba764c4dSAlex Elder /* Tell the hardware where the processing context area is located */ 92*279dc955SAlex Elder iowrite32(ipa->mem_offset + ipa->mem[IPA_MEM_MODEM_PROC_CTX].offset, 93ba764c4dSAlex Elder ipa->reg_virt + IPA_REG_LOCAL_PKT_PROC_CNTXT_BASE_OFFSET); 94ba764c4dSAlex Elder 95ba764c4dSAlex Elder return 0; 96ba764c4dSAlex Elder } 97ba764c4dSAlex Elder 98ba764c4dSAlex Elder void ipa_mem_teardown(struct ipa *ipa) 99ba764c4dSAlex Elder { 100ba764c4dSAlex Elder /* Nothing to do */ 101ba764c4dSAlex Elder } 102ba764c4dSAlex Elder 103ba764c4dSAlex Elder #ifdef IPA_VALIDATE 104ba764c4dSAlex Elder 105ba764c4dSAlex Elder static bool ipa_mem_valid(struct ipa *ipa, enum ipa_mem_id mem_id) 106ba764c4dSAlex Elder { 107ba764c4dSAlex Elder const struct ipa_mem *mem = &ipa->mem[mem_id]; 108ba764c4dSAlex Elder struct device *dev = &ipa->pdev->dev; 109ba764c4dSAlex Elder u16 size_multiple; 110ba764c4dSAlex Elder 111ba764c4dSAlex Elder /* Other than modem memory, sizes must be a multiple of 8 */ 112ba764c4dSAlex Elder size_multiple = mem_id == IPA_MEM_MODEM ? 4 : 8; 113ba764c4dSAlex Elder if (mem->size % size_multiple) 114ba764c4dSAlex Elder dev_err(dev, "region %u size not a multiple of %u bytes\n", 115ba764c4dSAlex Elder mem_id, size_multiple); 116ba764c4dSAlex Elder else if (mem->offset % 8) 117ba764c4dSAlex Elder dev_err(dev, "region %u offset not 8-byte aligned\n", mem_id); 118ba764c4dSAlex Elder else if (mem->offset < mem->canary_count * sizeof(__le32)) 119ba764c4dSAlex Elder dev_err(dev, "region %u offset too small for %hu canaries\n", 120ba764c4dSAlex Elder mem_id, mem->canary_count); 121ba764c4dSAlex Elder else if (mem->offset + mem->size > ipa->mem_size) 122ba764c4dSAlex Elder dev_err(dev, "region %u ends beyond memory limit (0x%08x)\n", 123ba764c4dSAlex Elder mem_id, ipa->mem_size); 124ba764c4dSAlex Elder else 125ba764c4dSAlex Elder return true; 126ba764c4dSAlex Elder 127ba764c4dSAlex Elder return false; 128ba764c4dSAlex Elder } 129ba764c4dSAlex Elder 130ba764c4dSAlex Elder #else /* !IPA_VALIDATE */ 131ba764c4dSAlex Elder 132ba764c4dSAlex Elder static bool ipa_mem_valid(struct ipa *ipa, enum ipa_mem_id mem_id) 133ba764c4dSAlex Elder { 134ba764c4dSAlex Elder return true; 135ba764c4dSAlex Elder } 136ba764c4dSAlex Elder 137ba764c4dSAlex Elder #endif /*! IPA_VALIDATE */ 138ba764c4dSAlex Elder 139ba764c4dSAlex Elder /** 140ba764c4dSAlex Elder * ipa_mem_config() - Configure IPA shared memory 141e3eea08eSAlex Elder * @ipa: IPA pointer 142ba764c4dSAlex Elder * 143e3eea08eSAlex Elder * Return: 0 if successful, or a negative error code 144ba764c4dSAlex Elder */ 145ba764c4dSAlex Elder int ipa_mem_config(struct ipa *ipa) 146ba764c4dSAlex Elder { 147ba764c4dSAlex Elder struct device *dev = &ipa->pdev->dev; 148ba764c4dSAlex Elder enum ipa_mem_id mem_id; 149ba764c4dSAlex Elder dma_addr_t addr; 150ba764c4dSAlex Elder u32 mem_size; 151ba764c4dSAlex Elder void *virt; 152ba764c4dSAlex Elder u32 val; 153ba764c4dSAlex Elder 154ba764c4dSAlex Elder /* Check the advertised location and size of the shared memory area */ 155ba764c4dSAlex Elder val = ioread32(ipa->reg_virt + IPA_REG_SHARED_MEM_SIZE_OFFSET); 156ba764c4dSAlex Elder 157ba764c4dSAlex Elder /* The fields in the register are in 8 byte units */ 158ba764c4dSAlex Elder ipa->mem_offset = 8 * u32_get_bits(val, SHARED_MEM_BADDR_FMASK); 159ba764c4dSAlex Elder /* Make sure the end is within the region's mapped space */ 160ba764c4dSAlex Elder mem_size = 8 * u32_get_bits(val, SHARED_MEM_SIZE_FMASK); 161ba764c4dSAlex Elder 162ba764c4dSAlex Elder /* If the sizes don't match, issue a warning */ 163ba764c4dSAlex Elder if (ipa->mem_offset + mem_size > ipa->mem_size) { 164ba764c4dSAlex Elder dev_warn(dev, "ignoring larger reported memory size: 0x%08x\n", 165ba764c4dSAlex Elder mem_size); 166ba764c4dSAlex Elder } else if (ipa->mem_offset + mem_size < ipa->mem_size) { 167ba764c4dSAlex Elder dev_warn(dev, "limiting IPA memory size to 0x%08x\n", 168ba764c4dSAlex Elder mem_size); 169ba764c4dSAlex Elder ipa->mem_size = mem_size; 170ba764c4dSAlex Elder } 171ba764c4dSAlex Elder 172ba764c4dSAlex Elder /* Prealloc DMA memory for zeroing regions */ 173ba764c4dSAlex Elder virt = dma_alloc_coherent(dev, IPA_MEM_MAX, &addr, GFP_KERNEL); 174ba764c4dSAlex Elder if (!virt) 175ba764c4dSAlex Elder return -ENOMEM; 176ba764c4dSAlex Elder ipa->zero_addr = addr; 177ba764c4dSAlex Elder ipa->zero_virt = virt; 178ba764c4dSAlex Elder ipa->zero_size = IPA_MEM_MAX; 179ba764c4dSAlex Elder 180ba764c4dSAlex Elder /* Verify each defined memory region is valid, and if indicated 181ba764c4dSAlex Elder * for the region, write "canary" values in the space prior to 182ba764c4dSAlex Elder * the region's base address. 183ba764c4dSAlex Elder */ 184ba764c4dSAlex Elder for (mem_id = 0; mem_id < IPA_MEM_COUNT; mem_id++) { 185ba764c4dSAlex Elder const struct ipa_mem *mem = &ipa->mem[mem_id]; 186ba764c4dSAlex Elder u16 canary_count; 187ba764c4dSAlex Elder __le32 *canary; 188ba764c4dSAlex Elder 189ba764c4dSAlex Elder /* Validate all regions (even undefined ones) */ 190ba764c4dSAlex Elder if (!ipa_mem_valid(ipa, mem_id)) 191ba764c4dSAlex Elder goto err_dma_free; 192ba764c4dSAlex Elder 193ba764c4dSAlex Elder /* Skip over undefined regions */ 194ba764c4dSAlex Elder if (!mem->offset && !mem->size) 195ba764c4dSAlex Elder continue; 196ba764c4dSAlex Elder 197ba764c4dSAlex Elder canary_count = mem->canary_count; 198ba764c4dSAlex Elder if (!canary_count) 199ba764c4dSAlex Elder continue; 200ba764c4dSAlex Elder 201ba764c4dSAlex Elder /* Write canary values in the space before the region */ 202ba764c4dSAlex Elder canary = ipa->mem_virt + ipa->mem_offset + mem->offset; 203ba764c4dSAlex Elder do 204ba764c4dSAlex Elder *--canary = IPA_MEM_CANARY_VAL; 205ba764c4dSAlex Elder while (--canary_count); 206ba764c4dSAlex Elder } 207ba764c4dSAlex Elder 208ba764c4dSAlex Elder /* Make sure filter and route table memory regions are valid */ 209ba764c4dSAlex Elder if (!ipa_table_valid(ipa)) 210ba764c4dSAlex Elder goto err_dma_free; 211ba764c4dSAlex Elder 212ba764c4dSAlex Elder /* Validate memory-related properties relevant to immediate commands */ 213ba764c4dSAlex Elder if (!ipa_cmd_data_valid(ipa)) 214ba764c4dSAlex Elder goto err_dma_free; 215ba764c4dSAlex Elder 216ba764c4dSAlex Elder /* Verify the microcontroller ring alignment (0 is OK too) */ 217ba764c4dSAlex Elder if (ipa->mem[IPA_MEM_UC_EVENT_RING].offset % 1024) { 218ba764c4dSAlex Elder dev_err(dev, "microcontroller ring not 1024-byte aligned\n"); 219ba764c4dSAlex Elder goto err_dma_free; 220ba764c4dSAlex Elder } 221ba764c4dSAlex Elder 222ba764c4dSAlex Elder return 0; 223ba764c4dSAlex Elder 224ba764c4dSAlex Elder err_dma_free: 225ba764c4dSAlex Elder dma_free_coherent(dev, IPA_MEM_MAX, ipa->zero_virt, ipa->zero_addr); 226ba764c4dSAlex Elder 227ba764c4dSAlex Elder return -EINVAL; 228ba764c4dSAlex Elder } 229ba764c4dSAlex Elder 230ba764c4dSAlex Elder /* Inverse of ipa_mem_config() */ 231ba764c4dSAlex Elder void ipa_mem_deconfig(struct ipa *ipa) 232ba764c4dSAlex Elder { 233ba764c4dSAlex Elder struct device *dev = &ipa->pdev->dev; 234ba764c4dSAlex Elder 235ba764c4dSAlex Elder dma_free_coherent(dev, ipa->zero_size, ipa->zero_virt, ipa->zero_addr); 236ba764c4dSAlex Elder ipa->zero_size = 0; 237ba764c4dSAlex Elder ipa->zero_virt = NULL; 238ba764c4dSAlex Elder ipa->zero_addr = 0; 239ba764c4dSAlex Elder } 240ba764c4dSAlex Elder 241ba764c4dSAlex Elder /** 242ba764c4dSAlex Elder * ipa_mem_zero_modem() - Zero IPA-local memory regions owned by the modem 243e3eea08eSAlex Elder * @ipa: IPA pointer 244ba764c4dSAlex Elder * 245ba764c4dSAlex Elder * Zero regions of IPA-local memory used by the modem. These are configured 246ba764c4dSAlex Elder * (and initially zeroed) by ipa_mem_setup(), but if the modem crashes and 247ba764c4dSAlex Elder * restarts via SSR we need to re-initialize them. A QMI message tells the 248ba764c4dSAlex Elder * modem where to find regions of IPA local memory it needs to know about 249ba764c4dSAlex Elder * (these included). 250ba764c4dSAlex Elder */ 251ba764c4dSAlex Elder int ipa_mem_zero_modem(struct ipa *ipa) 252ba764c4dSAlex Elder { 253ba764c4dSAlex Elder struct gsi_trans *trans; 254ba764c4dSAlex Elder 255ba764c4dSAlex Elder /* Get a transaction to zero the modem memory, modem header, 256ba764c4dSAlex Elder * and modem processing context regions. 257ba764c4dSAlex Elder */ 258ba764c4dSAlex Elder trans = ipa_cmd_trans_alloc(ipa, 3); 259ba764c4dSAlex Elder if (!trans) { 260ba764c4dSAlex Elder dev_err(&ipa->pdev->dev, 261ba764c4dSAlex Elder "no transaction to zero modem memory\n"); 262ba764c4dSAlex Elder return -EBUSY; 263ba764c4dSAlex Elder } 264ba764c4dSAlex Elder 265ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM_HEADER]); 266ba764c4dSAlex Elder 267ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM_PROC_CTX]); 268ba764c4dSAlex Elder 269ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM]); 270ba764c4dSAlex Elder 271ba764c4dSAlex Elder gsi_trans_commit_wait(trans); 272ba764c4dSAlex Elder 273ba764c4dSAlex Elder return 0; 274ba764c4dSAlex Elder } 275ba764c4dSAlex Elder 2763e313c3fSAlex Elder /** 2773e313c3fSAlex Elder * ipa_imem_init() - Initialize IMEM memory used by the IPA 2783e313c3fSAlex Elder * @ipa: IPA pointer 2793e313c3fSAlex Elder * @addr: Physical address of the IPA region in IMEM 2803e313c3fSAlex Elder * @size: Size (bytes) of the IPA region in IMEM 2813e313c3fSAlex Elder * 2823e313c3fSAlex Elder * IMEM is a block of shared memory separate from system DRAM, and 2833e313c3fSAlex Elder * a portion of this memory is available for the IPA to use. The 2843e313c3fSAlex Elder * modem accesses this memory directly, but the IPA accesses it 2853e313c3fSAlex Elder * via the IOMMU, using the AP's credentials. 2863e313c3fSAlex Elder * 2873e313c3fSAlex Elder * If this region exists (size > 0) we map it for read/write access 2883e313c3fSAlex Elder * through the IOMMU using the IPA device. 2893e313c3fSAlex Elder * 2903e313c3fSAlex Elder * Note: @addr and @size are not guaranteed to be page-aligned. 2913e313c3fSAlex Elder */ 2923e313c3fSAlex Elder static int ipa_imem_init(struct ipa *ipa, unsigned long addr, size_t size) 2933e313c3fSAlex Elder { 2943e313c3fSAlex Elder struct device *dev = &ipa->pdev->dev; 2953e313c3fSAlex Elder struct iommu_domain *domain; 2963e313c3fSAlex Elder unsigned long iova; 2973e313c3fSAlex Elder phys_addr_t phys; 2983e313c3fSAlex Elder int ret; 2993e313c3fSAlex Elder 3003e313c3fSAlex Elder if (!size) 3013e313c3fSAlex Elder return 0; /* IMEM memory not used */ 3023e313c3fSAlex Elder 3033e313c3fSAlex Elder domain = iommu_get_domain_for_dev(dev); 3043e313c3fSAlex Elder if (!domain) { 3053e313c3fSAlex Elder dev_err(dev, "no IOMMU domain found for IMEM\n"); 3063e313c3fSAlex Elder return -EINVAL; 3073e313c3fSAlex Elder } 3083e313c3fSAlex Elder 3093e313c3fSAlex Elder /* Align the address down and the size up to page boundaries */ 3103e313c3fSAlex Elder phys = addr & PAGE_MASK; 3113e313c3fSAlex Elder size = PAGE_ALIGN(size + addr - phys); 3123e313c3fSAlex Elder iova = phys; /* We just want a direct mapping */ 3133e313c3fSAlex Elder 3143e313c3fSAlex Elder ret = iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE); 3153e313c3fSAlex Elder if (ret) 3163e313c3fSAlex Elder return ret; 3173e313c3fSAlex Elder 3183e313c3fSAlex Elder ipa->imem_iova = iova; 3193e313c3fSAlex Elder ipa->imem_size = size; 3203e313c3fSAlex Elder 3213e313c3fSAlex Elder return 0; 3223e313c3fSAlex Elder } 3233e313c3fSAlex Elder 3243e313c3fSAlex Elder static void ipa_imem_exit(struct ipa *ipa) 3253e313c3fSAlex Elder { 3263e313c3fSAlex Elder struct iommu_domain *domain; 3273e313c3fSAlex Elder struct device *dev; 3283e313c3fSAlex Elder 3293e313c3fSAlex Elder if (!ipa->imem_size) 3303e313c3fSAlex Elder return; 3313e313c3fSAlex Elder 3323e313c3fSAlex Elder dev = &ipa->pdev->dev; 3333e313c3fSAlex Elder domain = iommu_get_domain_for_dev(dev); 3343e313c3fSAlex Elder if (domain) { 3353e313c3fSAlex Elder size_t size; 3363e313c3fSAlex Elder 3373e313c3fSAlex Elder size = iommu_unmap(domain, ipa->imem_iova, ipa->imem_size); 3383e313c3fSAlex Elder if (size != ipa->imem_size) 3393e313c3fSAlex Elder dev_warn(dev, "unmapped %zu IMEM bytes, expected %lu\n", 3403e313c3fSAlex Elder size, ipa->imem_size); 3413e313c3fSAlex Elder } else { 3423e313c3fSAlex Elder dev_err(dev, "couldn't get IPA IOMMU domain for IMEM\n"); 3433e313c3fSAlex Elder } 3443e313c3fSAlex Elder 3453e313c3fSAlex Elder ipa->imem_size = 0; 3463e313c3fSAlex Elder ipa->imem_iova = 0; 3473e313c3fSAlex Elder } 3483e313c3fSAlex Elder 349a0036bb4SAlex Elder /** 350a0036bb4SAlex Elder * ipa_smem_init() - Initialize SMEM memory used by the IPA 351a0036bb4SAlex Elder * @ipa: IPA pointer 352a0036bb4SAlex Elder * @item: Item ID of SMEM memory 353a0036bb4SAlex Elder * @size: Size (bytes) of SMEM memory region 354a0036bb4SAlex Elder * 355a0036bb4SAlex Elder * SMEM is a managed block of shared DRAM, from which numbered "items" 356a0036bb4SAlex Elder * can be allocated. One item is designated for use by the IPA. 357a0036bb4SAlex Elder * 358a0036bb4SAlex Elder * The modem accesses SMEM memory directly, but the IPA accesses it 359a0036bb4SAlex Elder * via the IOMMU, using the AP's credentials. 360a0036bb4SAlex Elder * 361a0036bb4SAlex Elder * If size provided is non-zero, we allocate it and map it for 362a0036bb4SAlex Elder * access through the IOMMU. 363a0036bb4SAlex Elder * 364a0036bb4SAlex Elder * Note: @size and the item address are is not guaranteed to be page-aligned. 365a0036bb4SAlex Elder */ 366a0036bb4SAlex Elder static int ipa_smem_init(struct ipa *ipa, u32 item, size_t size) 367a0036bb4SAlex Elder { 368a0036bb4SAlex Elder struct device *dev = &ipa->pdev->dev; 369a0036bb4SAlex Elder struct iommu_domain *domain; 370a0036bb4SAlex Elder unsigned long iova; 371a0036bb4SAlex Elder phys_addr_t phys; 372a0036bb4SAlex Elder phys_addr_t addr; 373a0036bb4SAlex Elder size_t actual; 374a0036bb4SAlex Elder void *virt; 375a0036bb4SAlex Elder int ret; 376a0036bb4SAlex Elder 377a0036bb4SAlex Elder if (!size) 378a0036bb4SAlex Elder return 0; /* SMEM memory not used */ 379a0036bb4SAlex Elder 380a0036bb4SAlex Elder /* SMEM is memory shared between the AP and another system entity 381a0036bb4SAlex Elder * (in this case, the modem). An allocation from SMEM is persistent 382a0036bb4SAlex Elder * until the AP reboots; there is no way to free an allocated SMEM 383a0036bb4SAlex Elder * region. Allocation only reserves the space; to use it you need 384a0036bb4SAlex Elder * to "get" a pointer it (this implies no reference counting). 385a0036bb4SAlex Elder * The item might have already been allocated, in which case we 386a0036bb4SAlex Elder * use it unless the size isn't what we expect. 387a0036bb4SAlex Elder */ 388a0036bb4SAlex Elder ret = qcom_smem_alloc(QCOM_SMEM_HOST_MODEM, item, size); 389a0036bb4SAlex Elder if (ret && ret != -EEXIST) { 390a0036bb4SAlex Elder dev_err(dev, "error %d allocating size %zu SMEM item %u\n", 391a0036bb4SAlex Elder ret, size, item); 392a0036bb4SAlex Elder return ret; 393a0036bb4SAlex Elder } 394a0036bb4SAlex Elder 395a0036bb4SAlex Elder /* Now get the address of the SMEM memory region */ 396a0036bb4SAlex Elder virt = qcom_smem_get(QCOM_SMEM_HOST_MODEM, item, &actual); 397a0036bb4SAlex Elder if (IS_ERR(virt)) { 398a0036bb4SAlex Elder ret = PTR_ERR(virt); 399a0036bb4SAlex Elder dev_err(dev, "error %d getting SMEM item %u\n", ret, item); 400a0036bb4SAlex Elder return ret; 401a0036bb4SAlex Elder } 402a0036bb4SAlex Elder 403a0036bb4SAlex Elder /* In case the region was already allocated, verify the size */ 404a0036bb4SAlex Elder if (ret && actual != size) { 405a0036bb4SAlex Elder dev_err(dev, "SMEM item %u has size %zu, expected %zu\n", 406a0036bb4SAlex Elder item, actual, size); 407a0036bb4SAlex Elder return -EINVAL; 408a0036bb4SAlex Elder } 409a0036bb4SAlex Elder 410a0036bb4SAlex Elder domain = iommu_get_domain_for_dev(dev); 411a0036bb4SAlex Elder if (!domain) { 412a0036bb4SAlex Elder dev_err(dev, "no IOMMU domain found for SMEM\n"); 413a0036bb4SAlex Elder return -EINVAL; 414a0036bb4SAlex Elder } 415a0036bb4SAlex Elder 416a0036bb4SAlex Elder /* Align the address down and the size up to a page boundary */ 417a0036bb4SAlex Elder addr = qcom_smem_virt_to_phys(virt) & PAGE_MASK; 418a0036bb4SAlex Elder phys = addr & PAGE_MASK; 419a0036bb4SAlex Elder size = PAGE_ALIGN(size + addr - phys); 420a0036bb4SAlex Elder iova = phys; /* We just want a direct mapping */ 421a0036bb4SAlex Elder 422a0036bb4SAlex Elder ret = iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE); 423a0036bb4SAlex Elder if (ret) 424a0036bb4SAlex Elder return ret; 425a0036bb4SAlex Elder 426a0036bb4SAlex Elder ipa->smem_iova = iova; 427a0036bb4SAlex Elder ipa->smem_size = size; 428a0036bb4SAlex Elder 429a0036bb4SAlex Elder return 0; 430a0036bb4SAlex Elder } 431a0036bb4SAlex Elder 432a0036bb4SAlex Elder static void ipa_smem_exit(struct ipa *ipa) 433a0036bb4SAlex Elder { 434a0036bb4SAlex Elder struct device *dev = &ipa->pdev->dev; 435a0036bb4SAlex Elder struct iommu_domain *domain; 436a0036bb4SAlex Elder 437a0036bb4SAlex Elder domain = iommu_get_domain_for_dev(dev); 438a0036bb4SAlex Elder if (domain) { 439a0036bb4SAlex Elder size_t size; 440a0036bb4SAlex Elder 441a0036bb4SAlex Elder size = iommu_unmap(domain, ipa->smem_iova, ipa->smem_size); 442a0036bb4SAlex Elder if (size != ipa->smem_size) 443a0036bb4SAlex Elder dev_warn(dev, "unmapped %zu SMEM bytes, expected %lu\n", 444a0036bb4SAlex Elder size, ipa->smem_size); 445a0036bb4SAlex Elder 446a0036bb4SAlex Elder } else { 447a0036bb4SAlex Elder dev_err(dev, "couldn't get IPA IOMMU domain for SMEM\n"); 448a0036bb4SAlex Elder } 449a0036bb4SAlex Elder 450a0036bb4SAlex Elder ipa->smem_size = 0; 451a0036bb4SAlex Elder ipa->smem_iova = 0; 452a0036bb4SAlex Elder } 453a0036bb4SAlex Elder 454ba764c4dSAlex Elder /* Perform memory region-related initialization */ 4553128aae8SAlex Elder int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data) 456ba764c4dSAlex Elder { 457ba764c4dSAlex Elder struct device *dev = &ipa->pdev->dev; 458ba764c4dSAlex Elder struct resource *res; 459ba764c4dSAlex Elder int ret; 460ba764c4dSAlex Elder 4613128aae8SAlex Elder if (mem_data->local_count > IPA_MEM_COUNT) { 462ba764c4dSAlex Elder dev_err(dev, "to many memory regions (%u > %u)\n", 4633128aae8SAlex Elder mem_data->local_count, IPA_MEM_COUNT); 464ba764c4dSAlex Elder return -EINVAL; 465ba764c4dSAlex Elder } 466ba764c4dSAlex Elder 467ba764c4dSAlex Elder ret = dma_set_mask_and_coherent(&ipa->pdev->dev, DMA_BIT_MASK(64)); 468ba764c4dSAlex Elder if (ret) { 469ba764c4dSAlex Elder dev_err(dev, "error %d setting DMA mask\n", ret); 470ba764c4dSAlex Elder return ret; 471ba764c4dSAlex Elder } 472ba764c4dSAlex Elder 473ba764c4dSAlex Elder res = platform_get_resource_byname(ipa->pdev, IORESOURCE_MEM, 474ba764c4dSAlex Elder "ipa-shared"); 475ba764c4dSAlex Elder if (!res) { 476ba764c4dSAlex Elder dev_err(dev, 477ba764c4dSAlex Elder "DT error getting \"ipa-shared\" memory property\n"); 478ba764c4dSAlex Elder return -ENODEV; 479ba764c4dSAlex Elder } 480ba764c4dSAlex Elder 481ba764c4dSAlex Elder ipa->mem_virt = memremap(res->start, resource_size(res), MEMREMAP_WC); 482ba764c4dSAlex Elder if (!ipa->mem_virt) { 483ba764c4dSAlex Elder dev_err(dev, "unable to remap \"ipa-shared\" memory\n"); 484ba764c4dSAlex Elder return -ENOMEM; 485ba764c4dSAlex Elder } 486ba764c4dSAlex Elder 487ba764c4dSAlex Elder ipa->mem_addr = res->start; 488ba764c4dSAlex Elder ipa->mem_size = resource_size(res); 489ba764c4dSAlex Elder 490ba764c4dSAlex Elder /* The ipa->mem[] array is indexed by enum ipa_mem_id values */ 4913128aae8SAlex Elder ipa->mem = mem_data->local; 492ba764c4dSAlex Elder 4933e313c3fSAlex Elder ret = ipa_imem_init(ipa, mem_data->imem_addr, mem_data->imem_size); 4943e313c3fSAlex Elder if (ret) 4953e313c3fSAlex Elder goto err_unmap; 4963e313c3fSAlex Elder 497a0036bb4SAlex Elder ret = ipa_smem_init(ipa, mem_data->smem_id, mem_data->smem_size); 498a0036bb4SAlex Elder if (ret) 499a0036bb4SAlex Elder goto err_imem_exit; 500a0036bb4SAlex Elder 501ba764c4dSAlex Elder return 0; 5023e313c3fSAlex Elder 503a0036bb4SAlex Elder err_imem_exit: 504a0036bb4SAlex Elder ipa_imem_exit(ipa); 5053e313c3fSAlex Elder err_unmap: 5063e313c3fSAlex Elder memunmap(ipa->mem_virt); 5073e313c3fSAlex Elder 5083e313c3fSAlex Elder return ret; 509ba764c4dSAlex Elder } 510ba764c4dSAlex Elder 511ba764c4dSAlex Elder /* Inverse of ipa_mem_init() */ 512ba764c4dSAlex Elder void ipa_mem_exit(struct ipa *ipa) 513ba764c4dSAlex Elder { 514a0036bb4SAlex Elder ipa_smem_exit(ipa); 5153e313c3fSAlex Elder ipa_imem_exit(ipa); 516ba764c4dSAlex Elder memunmap(ipa->mem_virt); 517ba764c4dSAlex Elder } 518