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