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_data.h" 21ba764c4dSAlex Elder #include "ipa_table.h" 22ba764c4dSAlex Elder #include "gsi_trans.h" 23ba764c4dSAlex Elder 24ba764c4dSAlex Elder /* "Canary" value placed between memory regions to detect overflow */ 25ba764c4dSAlex Elder #define IPA_MEM_CANARY_VAL cpu_to_le32(0xdeadbeef) 26ba764c4dSAlex Elder 27a0036bb4SAlex Elder /* SMEM host id representing the modem. */ 28a0036bb4SAlex Elder #define QCOM_SMEM_HOST_MODEM 1 29a0036bb4SAlex Elder 30ba764c4dSAlex Elder /* Add an immediate command to a transaction that zeroes a memory region */ 31ba764c4dSAlex Elder static void 32ba764c4dSAlex Elder ipa_mem_zero_region_add(struct gsi_trans *trans, const struct ipa_mem *mem) 33ba764c4dSAlex Elder { 34ba764c4dSAlex Elder struct ipa *ipa = container_of(trans->gsi, struct ipa, gsi); 35ba764c4dSAlex Elder dma_addr_t addr = ipa->zero_addr; 36ba764c4dSAlex Elder 37ba764c4dSAlex Elder if (!mem->size) 38ba764c4dSAlex Elder return; 39ba764c4dSAlex Elder 40ba764c4dSAlex Elder ipa_cmd_dma_shared_mem_add(trans, mem->offset, mem->size, addr, true); 41ba764c4dSAlex Elder } 42ba764c4dSAlex Elder 43ba764c4dSAlex Elder /** 44ba764c4dSAlex Elder * ipa_mem_setup() - Set up IPA AP and modem shared memory areas 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 * 56ba764c4dSAlex 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 */ 92ba764c4dSAlex Elder iowrite32(ipa->mem_offset + 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 141ba764c4dSAlex Elder * 142ba764c4dSAlex Elder * @Return: 0 if successful, or a negative error code 143ba764c4dSAlex Elder */ 144ba764c4dSAlex Elder int ipa_mem_config(struct ipa *ipa) 145ba764c4dSAlex Elder { 146ba764c4dSAlex Elder struct device *dev = &ipa->pdev->dev; 147ba764c4dSAlex Elder enum ipa_mem_id mem_id; 148ba764c4dSAlex Elder dma_addr_t addr; 149ba764c4dSAlex Elder u32 mem_size; 150ba764c4dSAlex Elder void *virt; 151ba764c4dSAlex Elder u32 val; 152ba764c4dSAlex Elder 153ba764c4dSAlex Elder /* Check the advertised location and size of the shared memory area */ 154ba764c4dSAlex Elder val = ioread32(ipa->reg_virt + IPA_REG_SHARED_MEM_SIZE_OFFSET); 155ba764c4dSAlex Elder 156ba764c4dSAlex Elder /* The fields in the register are in 8 byte units */ 157ba764c4dSAlex Elder ipa->mem_offset = 8 * u32_get_bits(val, SHARED_MEM_BADDR_FMASK); 158ba764c4dSAlex Elder /* Make sure the end is within the region's mapped space */ 159ba764c4dSAlex Elder mem_size = 8 * u32_get_bits(val, SHARED_MEM_SIZE_FMASK); 160ba764c4dSAlex Elder 161ba764c4dSAlex Elder /* If the sizes don't match, issue a warning */ 162ba764c4dSAlex Elder if (ipa->mem_offset + mem_size > ipa->mem_size) { 163ba764c4dSAlex Elder dev_warn(dev, "ignoring larger reported memory size: 0x%08x\n", 164ba764c4dSAlex Elder mem_size); 165ba764c4dSAlex Elder } else 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; 169ba764c4dSAlex Elder } 170ba764c4dSAlex Elder 171ba764c4dSAlex Elder /* Prealloc DMA memory for zeroing regions */ 172ba764c4dSAlex Elder virt = dma_alloc_coherent(dev, IPA_MEM_MAX, &addr, GFP_KERNEL); 173ba764c4dSAlex Elder if (!virt) 174ba764c4dSAlex Elder return -ENOMEM; 175ba764c4dSAlex Elder ipa->zero_addr = addr; 176ba764c4dSAlex Elder ipa->zero_virt = virt; 177ba764c4dSAlex Elder ipa->zero_size = IPA_MEM_MAX; 178ba764c4dSAlex Elder 179ba764c4dSAlex Elder /* Verify each defined memory region is valid, and if indicated 180ba764c4dSAlex Elder * for the region, write "canary" values in the space prior to 181ba764c4dSAlex Elder * the region's base address. 182ba764c4dSAlex Elder */ 183ba764c4dSAlex Elder for (mem_id = 0; mem_id < IPA_MEM_COUNT; mem_id++) { 184ba764c4dSAlex Elder const struct ipa_mem *mem = &ipa->mem[mem_id]; 185ba764c4dSAlex Elder u16 canary_count; 186ba764c4dSAlex Elder __le32 *canary; 187ba764c4dSAlex Elder 188ba764c4dSAlex Elder /* Validate all regions (even undefined ones) */ 189ba764c4dSAlex Elder if (!ipa_mem_valid(ipa, mem_id)) 190ba764c4dSAlex Elder goto err_dma_free; 191ba764c4dSAlex Elder 192ba764c4dSAlex Elder /* Skip over undefined regions */ 193ba764c4dSAlex Elder if (!mem->offset && !mem->size) 194ba764c4dSAlex Elder continue; 195ba764c4dSAlex Elder 196ba764c4dSAlex Elder canary_count = mem->canary_count; 197ba764c4dSAlex Elder if (!canary_count) 198ba764c4dSAlex Elder continue; 199ba764c4dSAlex Elder 200ba764c4dSAlex Elder /* Write canary values in the space before the region */ 201ba764c4dSAlex Elder canary = ipa->mem_virt + ipa->mem_offset + mem->offset; 202ba764c4dSAlex Elder do 203ba764c4dSAlex Elder *--canary = IPA_MEM_CANARY_VAL; 204ba764c4dSAlex Elder while (--canary_count); 205ba764c4dSAlex Elder } 206ba764c4dSAlex Elder 207ba764c4dSAlex Elder /* Make sure filter and route table memory regions are valid */ 208ba764c4dSAlex Elder if (!ipa_table_valid(ipa)) 209ba764c4dSAlex Elder goto err_dma_free; 210ba764c4dSAlex Elder 211ba764c4dSAlex Elder /* Validate memory-related properties relevant to immediate commands */ 212ba764c4dSAlex Elder if (!ipa_cmd_data_valid(ipa)) 213ba764c4dSAlex Elder goto err_dma_free; 214ba764c4dSAlex Elder 215ba764c4dSAlex Elder /* Verify the microcontroller ring alignment (0 is OK too) */ 216ba764c4dSAlex Elder if (ipa->mem[IPA_MEM_UC_EVENT_RING].offset % 1024) { 217ba764c4dSAlex Elder dev_err(dev, "microcontroller ring not 1024-byte aligned\n"); 218ba764c4dSAlex Elder goto err_dma_free; 219ba764c4dSAlex Elder } 220ba764c4dSAlex Elder 221ba764c4dSAlex Elder return 0; 222ba764c4dSAlex Elder 223ba764c4dSAlex Elder err_dma_free: 224ba764c4dSAlex Elder dma_free_coherent(dev, IPA_MEM_MAX, ipa->zero_virt, ipa->zero_addr); 225ba764c4dSAlex Elder 226ba764c4dSAlex Elder return -EINVAL; 227ba764c4dSAlex Elder } 228ba764c4dSAlex Elder 229ba764c4dSAlex Elder /* Inverse of ipa_mem_config() */ 230ba764c4dSAlex Elder void ipa_mem_deconfig(struct ipa *ipa) 231ba764c4dSAlex Elder { 232ba764c4dSAlex Elder struct device *dev = &ipa->pdev->dev; 233ba764c4dSAlex Elder 234ba764c4dSAlex Elder dma_free_coherent(dev, ipa->zero_size, ipa->zero_virt, ipa->zero_addr); 235ba764c4dSAlex Elder ipa->zero_size = 0; 236ba764c4dSAlex Elder ipa->zero_virt = NULL; 237ba764c4dSAlex Elder ipa->zero_addr = 0; 238ba764c4dSAlex Elder } 239ba764c4dSAlex Elder 240ba764c4dSAlex Elder /** 241ba764c4dSAlex Elder * ipa_mem_zero_modem() - Zero IPA-local memory regions owned by the modem 242ba764c4dSAlex Elder * 243ba764c4dSAlex Elder * Zero regions of IPA-local memory used by the modem. These are configured 244ba764c4dSAlex Elder * (and initially zeroed) by ipa_mem_setup(), but if the modem crashes and 245ba764c4dSAlex Elder * restarts via SSR we need to re-initialize them. A QMI message tells the 246ba764c4dSAlex Elder * modem where to find regions of IPA local memory it needs to know about 247ba764c4dSAlex Elder * (these included). 248ba764c4dSAlex Elder */ 249ba764c4dSAlex Elder int ipa_mem_zero_modem(struct ipa *ipa) 250ba764c4dSAlex Elder { 251ba764c4dSAlex Elder struct gsi_trans *trans; 252ba764c4dSAlex Elder 253ba764c4dSAlex Elder /* Get a transaction to zero the modem memory, modem header, 254ba764c4dSAlex Elder * and modem processing context regions. 255ba764c4dSAlex Elder */ 256ba764c4dSAlex Elder trans = ipa_cmd_trans_alloc(ipa, 3); 257ba764c4dSAlex Elder if (!trans) { 258ba764c4dSAlex Elder dev_err(&ipa->pdev->dev, 259ba764c4dSAlex Elder "no transaction to zero modem memory\n"); 260ba764c4dSAlex Elder return -EBUSY; 261ba764c4dSAlex Elder } 262ba764c4dSAlex Elder 263ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM_HEADER]); 264ba764c4dSAlex Elder 265ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM_PROC_CTX]); 266ba764c4dSAlex Elder 267ba764c4dSAlex Elder ipa_mem_zero_region_add(trans, &ipa->mem[IPA_MEM_MODEM]); 268ba764c4dSAlex Elder 269ba764c4dSAlex Elder gsi_trans_commit_wait(trans); 270ba764c4dSAlex Elder 271ba764c4dSAlex Elder return 0; 272ba764c4dSAlex Elder } 273ba764c4dSAlex Elder 2743e313c3fSAlex Elder /** 2753e313c3fSAlex Elder * ipa_imem_init() - Initialize IMEM memory used by the IPA 2763e313c3fSAlex Elder * @ipa: IPA pointer 2773e313c3fSAlex Elder * @addr: Physical address of the IPA region in IMEM 2783e313c3fSAlex Elder * @size: Size (bytes) of the IPA region in IMEM 2793e313c3fSAlex Elder * 2803e313c3fSAlex Elder * IMEM is a block of shared memory separate from system DRAM, and 2813e313c3fSAlex Elder * a portion of this memory is available for the IPA to use. The 2823e313c3fSAlex Elder * modem accesses this memory directly, but the IPA accesses it 2833e313c3fSAlex Elder * via the IOMMU, using the AP's credentials. 2843e313c3fSAlex Elder * 2853e313c3fSAlex Elder * If this region exists (size > 0) we map it for read/write access 2863e313c3fSAlex Elder * through the IOMMU using the IPA device. 2873e313c3fSAlex Elder * 2883e313c3fSAlex Elder * Note: @addr and @size are not guaranteed to be page-aligned. 2893e313c3fSAlex Elder */ 2903e313c3fSAlex Elder static int ipa_imem_init(struct ipa *ipa, unsigned long addr, size_t size) 2913e313c3fSAlex Elder { 2923e313c3fSAlex Elder struct device *dev = &ipa->pdev->dev; 2933e313c3fSAlex Elder struct iommu_domain *domain; 2943e313c3fSAlex Elder unsigned long iova; 2953e313c3fSAlex Elder phys_addr_t phys; 2963e313c3fSAlex Elder int ret; 2973e313c3fSAlex Elder 2983e313c3fSAlex Elder if (!size) 2993e313c3fSAlex Elder return 0; /* IMEM memory not used */ 3003e313c3fSAlex Elder 3013e313c3fSAlex Elder domain = iommu_get_domain_for_dev(dev); 3023e313c3fSAlex Elder if (!domain) { 3033e313c3fSAlex Elder dev_err(dev, "no IOMMU domain found for IMEM\n"); 3043e313c3fSAlex Elder return -EINVAL; 3053e313c3fSAlex Elder } 3063e313c3fSAlex Elder 3073e313c3fSAlex Elder /* Align the address down and the size up to page boundaries */ 3083e313c3fSAlex Elder phys = addr & PAGE_MASK; 3093e313c3fSAlex Elder size = PAGE_ALIGN(size + addr - phys); 3103e313c3fSAlex Elder iova = phys; /* We just want a direct mapping */ 3113e313c3fSAlex Elder 3123e313c3fSAlex Elder ret = iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE); 3133e313c3fSAlex Elder if (ret) 3143e313c3fSAlex Elder return ret; 3153e313c3fSAlex Elder 3163e313c3fSAlex Elder ipa->imem_iova = iova; 3173e313c3fSAlex Elder ipa->imem_size = size; 3183e313c3fSAlex Elder 3193e313c3fSAlex Elder return 0; 3203e313c3fSAlex Elder } 3213e313c3fSAlex Elder 3223e313c3fSAlex Elder static void ipa_imem_exit(struct ipa *ipa) 3233e313c3fSAlex Elder { 3243e313c3fSAlex Elder struct iommu_domain *domain; 3253e313c3fSAlex Elder struct device *dev; 3263e313c3fSAlex Elder 3273e313c3fSAlex Elder if (!ipa->imem_size) 3283e313c3fSAlex Elder return; 3293e313c3fSAlex Elder 3303e313c3fSAlex Elder dev = &ipa->pdev->dev; 3313e313c3fSAlex Elder domain = iommu_get_domain_for_dev(dev); 3323e313c3fSAlex Elder if (domain) { 3333e313c3fSAlex Elder size_t size; 3343e313c3fSAlex Elder 3353e313c3fSAlex Elder size = iommu_unmap(domain, ipa->imem_iova, ipa->imem_size); 3363e313c3fSAlex Elder if (size != ipa->imem_size) 3373e313c3fSAlex Elder dev_warn(dev, "unmapped %zu IMEM bytes, expected %lu\n", 3383e313c3fSAlex Elder size, ipa->imem_size); 3393e313c3fSAlex Elder } else { 3403e313c3fSAlex Elder dev_err(dev, "couldn't get IPA IOMMU domain for IMEM\n"); 3413e313c3fSAlex Elder } 3423e313c3fSAlex Elder 3433e313c3fSAlex Elder ipa->imem_size = 0; 3443e313c3fSAlex Elder ipa->imem_iova = 0; 3453e313c3fSAlex Elder } 3463e313c3fSAlex Elder 347a0036bb4SAlex Elder /** 348a0036bb4SAlex Elder * ipa_smem_init() - Initialize SMEM memory used by the IPA 349a0036bb4SAlex Elder * @ipa: IPA pointer 350a0036bb4SAlex Elder * @item: Item ID of SMEM memory 351a0036bb4SAlex Elder * @size: Size (bytes) of SMEM memory region 352a0036bb4SAlex Elder * 353a0036bb4SAlex Elder * SMEM is a managed block of shared DRAM, from which numbered "items" 354a0036bb4SAlex Elder * can be allocated. One item is designated for use by the IPA. 355a0036bb4SAlex Elder * 356a0036bb4SAlex Elder * The modem accesses SMEM memory directly, but the IPA accesses it 357a0036bb4SAlex Elder * via the IOMMU, using the AP's credentials. 358a0036bb4SAlex Elder * 359a0036bb4SAlex Elder * If size provided is non-zero, we allocate it and map it for 360a0036bb4SAlex Elder * access through the IOMMU. 361a0036bb4SAlex Elder * 362a0036bb4SAlex Elder * Note: @size and the item address are is not guaranteed to be page-aligned. 363a0036bb4SAlex Elder */ 364a0036bb4SAlex Elder static int ipa_smem_init(struct ipa *ipa, u32 item, size_t size) 365a0036bb4SAlex Elder { 366a0036bb4SAlex Elder struct device *dev = &ipa->pdev->dev; 367a0036bb4SAlex Elder struct iommu_domain *domain; 368a0036bb4SAlex Elder unsigned long iova; 369a0036bb4SAlex Elder phys_addr_t phys; 370a0036bb4SAlex Elder phys_addr_t addr; 371a0036bb4SAlex Elder size_t actual; 372a0036bb4SAlex Elder void *virt; 373a0036bb4SAlex Elder int ret; 374a0036bb4SAlex Elder 375a0036bb4SAlex Elder if (!size) 376a0036bb4SAlex Elder return 0; /* SMEM memory not used */ 377a0036bb4SAlex Elder 378a0036bb4SAlex Elder /* SMEM is memory shared between the AP and another system entity 379a0036bb4SAlex Elder * (in this case, the modem). An allocation from SMEM is persistent 380a0036bb4SAlex Elder * until the AP reboots; there is no way to free an allocated SMEM 381a0036bb4SAlex Elder * region. Allocation only reserves the space; to use it you need 382a0036bb4SAlex Elder * to "get" a pointer it (this implies no reference counting). 383a0036bb4SAlex Elder * The item might have already been allocated, in which case we 384a0036bb4SAlex Elder * use it unless the size isn't what we expect. 385a0036bb4SAlex Elder */ 386a0036bb4SAlex Elder ret = qcom_smem_alloc(QCOM_SMEM_HOST_MODEM, item, size); 387a0036bb4SAlex Elder if (ret && ret != -EEXIST) { 388a0036bb4SAlex Elder dev_err(dev, "error %d allocating size %zu SMEM item %u\n", 389a0036bb4SAlex Elder ret, size, item); 390a0036bb4SAlex Elder return ret; 391a0036bb4SAlex Elder } 392a0036bb4SAlex Elder 393a0036bb4SAlex Elder /* Now get the address of the SMEM memory region */ 394a0036bb4SAlex Elder virt = qcom_smem_get(QCOM_SMEM_HOST_MODEM, item, &actual); 395a0036bb4SAlex Elder if (IS_ERR(virt)) { 396a0036bb4SAlex Elder ret = PTR_ERR(virt); 397a0036bb4SAlex Elder dev_err(dev, "error %d getting SMEM item %u\n", ret, item); 398a0036bb4SAlex Elder return ret; 399a0036bb4SAlex Elder } 400a0036bb4SAlex Elder 401a0036bb4SAlex Elder /* In case the region was already allocated, verify the size */ 402a0036bb4SAlex Elder if (ret && actual != size) { 403a0036bb4SAlex Elder dev_err(dev, "SMEM item %u has size %zu, expected %zu\n", 404a0036bb4SAlex Elder item, actual, size); 405a0036bb4SAlex Elder return -EINVAL; 406a0036bb4SAlex Elder } 407a0036bb4SAlex Elder 408a0036bb4SAlex Elder domain = iommu_get_domain_for_dev(dev); 409a0036bb4SAlex Elder if (!domain) { 410a0036bb4SAlex Elder dev_err(dev, "no IOMMU domain found for SMEM\n"); 411a0036bb4SAlex Elder return -EINVAL; 412a0036bb4SAlex Elder } 413a0036bb4SAlex Elder 414a0036bb4SAlex Elder /* Align the address down and the size up to a page boundary */ 415a0036bb4SAlex Elder addr = qcom_smem_virt_to_phys(virt) & PAGE_MASK; 416a0036bb4SAlex Elder phys = addr & PAGE_MASK; 417a0036bb4SAlex Elder size = PAGE_ALIGN(size + addr - phys); 418a0036bb4SAlex Elder iova = phys; /* We just want a direct mapping */ 419a0036bb4SAlex Elder 420a0036bb4SAlex Elder ret = iommu_map(domain, iova, phys, size, IOMMU_READ | IOMMU_WRITE); 421a0036bb4SAlex Elder if (ret) 422a0036bb4SAlex Elder return ret; 423a0036bb4SAlex Elder 424a0036bb4SAlex Elder ipa->smem_iova = iova; 425a0036bb4SAlex Elder ipa->smem_size = size; 426a0036bb4SAlex Elder 427a0036bb4SAlex Elder return 0; 428a0036bb4SAlex Elder } 429a0036bb4SAlex Elder 430a0036bb4SAlex Elder static void ipa_smem_exit(struct ipa *ipa) 431a0036bb4SAlex Elder { 432a0036bb4SAlex Elder struct device *dev = &ipa->pdev->dev; 433a0036bb4SAlex Elder struct iommu_domain *domain; 434a0036bb4SAlex Elder 435a0036bb4SAlex Elder domain = iommu_get_domain_for_dev(dev); 436a0036bb4SAlex Elder if (domain) { 437a0036bb4SAlex Elder size_t size; 438a0036bb4SAlex Elder 439a0036bb4SAlex Elder size = iommu_unmap(domain, ipa->smem_iova, ipa->smem_size); 440a0036bb4SAlex Elder if (size != ipa->smem_size) 441a0036bb4SAlex Elder dev_warn(dev, "unmapped %zu SMEM bytes, expected %lu\n", 442a0036bb4SAlex Elder size, ipa->smem_size); 443a0036bb4SAlex Elder 444a0036bb4SAlex Elder } else { 445a0036bb4SAlex Elder dev_err(dev, "couldn't get IPA IOMMU domain for SMEM\n"); 446a0036bb4SAlex Elder } 447a0036bb4SAlex Elder 448a0036bb4SAlex Elder ipa->smem_size = 0; 449a0036bb4SAlex Elder ipa->smem_iova = 0; 450a0036bb4SAlex Elder } 451a0036bb4SAlex Elder 452ba764c4dSAlex Elder /* Perform memory region-related initialization */ 4533128aae8SAlex Elder int ipa_mem_init(struct ipa *ipa, const struct ipa_mem_data *mem_data) 454ba764c4dSAlex Elder { 455ba764c4dSAlex Elder struct device *dev = &ipa->pdev->dev; 456ba764c4dSAlex Elder struct resource *res; 457ba764c4dSAlex Elder int ret; 458ba764c4dSAlex Elder 4593128aae8SAlex Elder if (mem_data->local_count > IPA_MEM_COUNT) { 460ba764c4dSAlex Elder dev_err(dev, "to many memory regions (%u > %u)\n", 4613128aae8SAlex Elder mem_data->local_count, IPA_MEM_COUNT); 462ba764c4dSAlex Elder return -EINVAL; 463ba764c4dSAlex Elder } 464ba764c4dSAlex Elder 465ba764c4dSAlex Elder ret = dma_set_mask_and_coherent(&ipa->pdev->dev, DMA_BIT_MASK(64)); 466ba764c4dSAlex Elder if (ret) { 467ba764c4dSAlex Elder dev_err(dev, "error %d setting DMA mask\n", ret); 468ba764c4dSAlex Elder return ret; 469ba764c4dSAlex Elder } 470ba764c4dSAlex Elder 471ba764c4dSAlex Elder res = platform_get_resource_byname(ipa->pdev, IORESOURCE_MEM, 472ba764c4dSAlex Elder "ipa-shared"); 473ba764c4dSAlex Elder if (!res) { 474ba764c4dSAlex Elder dev_err(dev, 475ba764c4dSAlex Elder "DT error getting \"ipa-shared\" memory property\n"); 476ba764c4dSAlex Elder return -ENODEV; 477ba764c4dSAlex Elder } 478ba764c4dSAlex Elder 479ba764c4dSAlex Elder ipa->mem_virt = memremap(res->start, resource_size(res), MEMREMAP_WC); 480ba764c4dSAlex Elder if (!ipa->mem_virt) { 481ba764c4dSAlex Elder dev_err(dev, "unable to remap \"ipa-shared\" memory\n"); 482ba764c4dSAlex Elder return -ENOMEM; 483ba764c4dSAlex Elder } 484ba764c4dSAlex Elder 485ba764c4dSAlex Elder ipa->mem_addr = res->start; 486ba764c4dSAlex Elder ipa->mem_size = resource_size(res); 487ba764c4dSAlex Elder 488ba764c4dSAlex Elder /* The ipa->mem[] array is indexed by enum ipa_mem_id values */ 4893128aae8SAlex Elder ipa->mem = mem_data->local; 490ba764c4dSAlex Elder 4913e313c3fSAlex Elder ret = ipa_imem_init(ipa, mem_data->imem_addr, mem_data->imem_size); 4923e313c3fSAlex Elder if (ret) 4933e313c3fSAlex Elder goto err_unmap; 4943e313c3fSAlex Elder 495a0036bb4SAlex Elder ret = ipa_smem_init(ipa, mem_data->smem_id, mem_data->smem_size); 496a0036bb4SAlex Elder if (ret) 497a0036bb4SAlex Elder goto err_imem_exit; 498a0036bb4SAlex Elder 499ba764c4dSAlex Elder return 0; 5003e313c3fSAlex Elder 501a0036bb4SAlex Elder err_imem_exit: 502a0036bb4SAlex Elder ipa_imem_exit(ipa); 5033e313c3fSAlex Elder err_unmap: 5043e313c3fSAlex Elder memunmap(ipa->mem_virt); 5053e313c3fSAlex Elder 5063e313c3fSAlex Elder return ret; 507ba764c4dSAlex Elder } 508ba764c4dSAlex Elder 509ba764c4dSAlex Elder /* Inverse of ipa_mem_init() */ 510ba764c4dSAlex Elder void ipa_mem_exit(struct ipa *ipa) 511ba764c4dSAlex Elder { 512a0036bb4SAlex Elder ipa_smem_exit(ipa); 5133e313c3fSAlex Elder ipa_imem_exit(ipa); 514ba764c4dSAlex Elder memunmap(ipa->mem_virt); 515ba764c4dSAlex Elder } 516