Loading drivers/iommu/arm-smmu.c +85 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ #include <linux/amba/bus.h> #include <soc/qcom/msm_tz_smmu.h> #include <soc/qcom/secure_buffer.h> #include <linux/msm_pcie.h> #include <asm/cacheflush.h> Loading Loading @@ -407,6 +408,11 @@ enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_NESTED, }; struct arm_smmu_pte_info { phys_addr_t phys_addr; struct list_head entry; }; struct arm_smmu_domain { struct arm_smmu_device *smmu; struct io_pgtable_ops *pgtbl_ops; Loading @@ -417,6 +423,8 @@ struct arm_smmu_domain { struct mutex lock; struct mutex init_mutex; /* Protects smmu pointer */ u32 attributes; u32 secure_vmid; struct list_head pte_info_list; }; static struct iommu_ops arm_smmu_ops; Loading Loading @@ -911,11 +919,16 @@ static void arm_smmu_flush_pgtable(void *addr, size_t size, void *cookie) } } static void arm_smmu_prepare_pgtable(void *addr, void *cookie); static void arm_smmu_unprepare_pgtable(void *cookie, void *addr, size_t size); static struct iommu_gather_ops arm_smmu_gather_ops = { .tlb_flush_all = arm_smmu_tlb_inv_context, .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, .tlb_sync = arm_smmu_tlb_sync, .flush_pgtable = arm_smmu_flush_pgtable, .prepare_pgtable = arm_smmu_prepare_pgtable, .unprepare_pgtable = arm_smmu_unprepare_pgtable, }; static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, Loading Loading @@ -1319,6 +1332,8 @@ static int arm_smmu_domain_init(struct iommu_domain *domain) if (!smmu_domain) return -ENOMEM; smmu_domain->secure_vmid = VMID_INVAL; INIT_LIST_HEAD(&smmu_domain->pte_info_list); mutex_init(&smmu_domain->lock); mutex_init(&smmu_domain->init_mutex); spin_lock_init(&smmu_domain->pgtbl_lock); Loading Loading @@ -1613,6 +1628,63 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev) mutex_unlock(&smmu_domain->init_mutex); } static void arm_smmu_assign_table(struct arm_smmu_domain *smmu_domain) { int ret; int dest_vmids[2] = {VMID_HLOS, smmu_domain->secure_vmid}; int dest_perms[2] = {PERM_READ | PERM_WRITE, PERM_READ}; int source_vmid = VMID_HLOS; struct arm_smmu_pte_info *pte_info, *temp; if (smmu_domain->secure_vmid == VMID_INVAL) return; list_for_each_entry(pte_info, &smmu_domain->pte_info_list, entry) { ret = hyp_assign_phys(pte_info->phys_addr, PAGE_SIZE, &source_vmid, 1, dest_vmids, dest_perms, 2); if (WARN_ON(ret)) break; } list_for_each_entry_safe(pte_info, temp, &smmu_domain->pte_info_list, entry) { list_del(&pte_info->entry); kfree(pte_info); } } static void arm_smmu_unprepare_pgtable(void *cookie, void *addr, size_t size) { struct arm_smmu_domain *smmu_domain = cookie; int ret; int dest_vmids = VMID_HLOS; int dest_perms = PERM_READ | PERM_WRITE; int source_vmlist[2] = {VMID_HLOS, smmu_domain->secure_vmid}; if (smmu_domain->secure_vmid == VMID_INVAL) return; ret = hyp_assign_phys((phys_addr_t)virt_to_phys(addr), size, source_vmlist, 2, &dest_vmids, &dest_perms, 1); WARN_ON(ret); } static void arm_smmu_prepare_pgtable(void *addr, void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; struct arm_smmu_pte_info *pte_info; if (smmu_domain->secure_vmid == VMID_INVAL) return; pte_info = kzalloc(sizeof(struct arm_smmu_pte_info), GFP_ATOMIC); if (!pte_info) return; pte_info->phys_addr = (phys_addr_t)virt_to_phys(addr); list_add_tail(&pte_info->entry, &smmu_domain->pte_info_list); } static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot) { Loading @@ -1628,6 +1700,8 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, ret = ops->map(ops, iova, paddr, size, prot); spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); arm_smmu_assign_table(smmu_domain); return ret; } Loading @@ -1646,6 +1720,8 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, ret = ops->map_sg(ops, iova, sg, nents, prot); spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); arm_smmu_assign_table(smmu_domain); return ret; } Loading Loading @@ -1686,6 +1762,13 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, ret = ops->unmap(ops, iova, size); spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); /* * While splitting up block mappings, we might allocate page table * memory during unmap, so the vmids needs to be assigned to the * memory here as well. */ arm_smmu_assign_table(smmu_domain); if (atomic_ctx) { arm_smmu_disable_clocks_atomic(smmu_domain->smmu); } else { Loading Loading @@ -1865,7 +1948,8 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, break; } case DOMAIN_ATTR_SECURE_VMID: ret = 0; BUG_ON(smmu_domain->secure_vmid != VMID_INVAL); smmu_domain->secure_vmid = *((int *)data); break; case DOMAIN_ATTR_ATOMIC: { Loading drivers/iommu/io-pgtable-arm.c +5 −2 Original line number Diff line number Diff line Loading @@ -261,6 +261,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, pte |= ARM_LPAE_PTE_NSTABLE; *ptep = pte; data->iop.cfg.tlb->flush_pgtable(ptep, sizeof(*ptep), cookie); data->iop.cfg.tlb->prepare_pgtable(cptep, cookie); } else { cptep = iopte_deref(pte, data); } Loading Loading @@ -412,6 +413,8 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); } data->iop.cfg.tlb->unprepare_pgtable(data->iop.cookie, start, table_size); free_pages_exact(start, table_size); } Loading Loading @@ -745,7 +748,7 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) goto out_free_data; cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); cfg->tlb->prepare_pgtable(data->pgd, cookie); /* TTBRs */ cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd); cfg->arm_lpae_s1_cfg.ttbr[1] = 0; Loading Loading @@ -833,7 +836,7 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) goto out_free_data; cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); cfg->tlb->prepare_pgtable(data->pgd, cookie); /* VTTBR */ cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd); return &data->iop; Loading drivers/iommu/io-pgtable.h +4 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ enum io_pgtable_fmt { * @tlb_add_flush: Queue up a TLB invalidation for a virtual address range. * @tlb_sync: Ensure any queue TLB invalidation has taken effect. * @flush_pgtable: Ensure page table updates are visible to the IOMMU. * @prepare_pgtable: Do necessary fixup for newly allocated page table memory * @unprepare_pgtable: Undo fixups done during @prepare_pgtable * * Note that these can all be called in atomic context and must therefore * not block. Loading @@ -31,6 +33,8 @@ struct iommu_gather_ops { void *cookie); void (*tlb_sync)(void *cookie); void (*flush_pgtable)(void *ptr, size_t size, void *cookie); void (*prepare_pgtable)(void *addr, void *cookie); void (*unprepare_pgtable)(void *cookie, void *addr, size_t size); }; /** Loading drivers/soc/qcom/secure_buffer.c +4 −7 Original line number Diff line number Diff line Loading @@ -318,12 +318,11 @@ err1: return ret; } int hyp_assign_phys(phys_addr_t addr, u64 size, int *dest_vmids, int *dest_perms, int dest_nelems) int hyp_assign_phys(phys_addr_t addr, u64 size, u32 *source_vm_list, int source_nelems, int *dest_vmids, int *dest_perms, int dest_nelems) { struct sg_table *table; u32 source_vm; int ret; table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); Loading @@ -335,9 +334,7 @@ int hyp_assign_phys(phys_addr_t addr, u64 size, sg_set_page(table->sgl, phys_to_page(addr), size, 0); source_vm = VMID_HLOS; ret = hyp_assign_table(table, &source_vm, 1, dest_vmids, ret = hyp_assign_table(table, source_vm_list, source_nelems, dest_vmids, dest_perms, dest_nelems); if (ret) goto err2; Loading include/soc/qcom/secure_buffer.h +4 −4 Original line number Diff line number Diff line Loading @@ -38,8 +38,8 @@ int hyp_assign_table(struct sg_table *table, int *dest_vmids, int *dest_perms, int dest_nelems); int hyp_assign_phys(phys_addr_t addr, u64 size, int *dest_vmids, int *dest_perms, int dest_nelems); u32 *source_vmlist, int source_nelems, int *dest_vmids, int *dest_perms, int dest_nelems); bool msm_secure_v2_is_supported(void); #else static inline int msm_secure_table(struct sg_table *table) Loading @@ -58,8 +58,8 @@ static inline int hyp_assign_table(struct sg_table *table, return -ENOSYS; } static inline int hyp_assign_phys(phys_addr_t addr, u64 size, int *dest_vmids, int *dest_perms, int dest_nelems) u32 *source_vmlist, int source_nelems, int *dest_vmids, int *dest_perms, int dest_nelems) { return -ENOSYS; } Loading Loading
drivers/iommu/arm-smmu.c +85 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ #include <linux/amba/bus.h> #include <soc/qcom/msm_tz_smmu.h> #include <soc/qcom/secure_buffer.h> #include <linux/msm_pcie.h> #include <asm/cacheflush.h> Loading Loading @@ -407,6 +408,11 @@ enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_NESTED, }; struct arm_smmu_pte_info { phys_addr_t phys_addr; struct list_head entry; }; struct arm_smmu_domain { struct arm_smmu_device *smmu; struct io_pgtable_ops *pgtbl_ops; Loading @@ -417,6 +423,8 @@ struct arm_smmu_domain { struct mutex lock; struct mutex init_mutex; /* Protects smmu pointer */ u32 attributes; u32 secure_vmid; struct list_head pte_info_list; }; static struct iommu_ops arm_smmu_ops; Loading Loading @@ -911,11 +919,16 @@ static void arm_smmu_flush_pgtable(void *addr, size_t size, void *cookie) } } static void arm_smmu_prepare_pgtable(void *addr, void *cookie); static void arm_smmu_unprepare_pgtable(void *cookie, void *addr, size_t size); static struct iommu_gather_ops arm_smmu_gather_ops = { .tlb_flush_all = arm_smmu_tlb_inv_context, .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, .tlb_sync = arm_smmu_tlb_sync, .flush_pgtable = arm_smmu_flush_pgtable, .prepare_pgtable = arm_smmu_prepare_pgtable, .unprepare_pgtable = arm_smmu_unprepare_pgtable, }; static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, Loading Loading @@ -1319,6 +1332,8 @@ static int arm_smmu_domain_init(struct iommu_domain *domain) if (!smmu_domain) return -ENOMEM; smmu_domain->secure_vmid = VMID_INVAL; INIT_LIST_HEAD(&smmu_domain->pte_info_list); mutex_init(&smmu_domain->lock); mutex_init(&smmu_domain->init_mutex); spin_lock_init(&smmu_domain->pgtbl_lock); Loading Loading @@ -1613,6 +1628,63 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev) mutex_unlock(&smmu_domain->init_mutex); } static void arm_smmu_assign_table(struct arm_smmu_domain *smmu_domain) { int ret; int dest_vmids[2] = {VMID_HLOS, smmu_domain->secure_vmid}; int dest_perms[2] = {PERM_READ | PERM_WRITE, PERM_READ}; int source_vmid = VMID_HLOS; struct arm_smmu_pte_info *pte_info, *temp; if (smmu_domain->secure_vmid == VMID_INVAL) return; list_for_each_entry(pte_info, &smmu_domain->pte_info_list, entry) { ret = hyp_assign_phys(pte_info->phys_addr, PAGE_SIZE, &source_vmid, 1, dest_vmids, dest_perms, 2); if (WARN_ON(ret)) break; } list_for_each_entry_safe(pte_info, temp, &smmu_domain->pte_info_list, entry) { list_del(&pte_info->entry); kfree(pte_info); } } static void arm_smmu_unprepare_pgtable(void *cookie, void *addr, size_t size) { struct arm_smmu_domain *smmu_domain = cookie; int ret; int dest_vmids = VMID_HLOS; int dest_perms = PERM_READ | PERM_WRITE; int source_vmlist[2] = {VMID_HLOS, smmu_domain->secure_vmid}; if (smmu_domain->secure_vmid == VMID_INVAL) return; ret = hyp_assign_phys((phys_addr_t)virt_to_phys(addr), size, source_vmlist, 2, &dest_vmids, &dest_perms, 1); WARN_ON(ret); } static void arm_smmu_prepare_pgtable(void *addr, void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; struct arm_smmu_pte_info *pte_info; if (smmu_domain->secure_vmid == VMID_INVAL) return; pte_info = kzalloc(sizeof(struct arm_smmu_pte_info), GFP_ATOMIC); if (!pte_info) return; pte_info->phys_addr = (phys_addr_t)virt_to_phys(addr); list_add_tail(&pte_info->entry, &smmu_domain->pte_info_list); } static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot) { Loading @@ -1628,6 +1700,8 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, ret = ops->map(ops, iova, paddr, size, prot); spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); arm_smmu_assign_table(smmu_domain); return ret; } Loading @@ -1646,6 +1720,8 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, ret = ops->map_sg(ops, iova, sg, nents, prot); spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); arm_smmu_assign_table(smmu_domain); return ret; } Loading Loading @@ -1686,6 +1762,13 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, ret = ops->unmap(ops, iova, size); spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags); /* * While splitting up block mappings, we might allocate page table * memory during unmap, so the vmids needs to be assigned to the * memory here as well. */ arm_smmu_assign_table(smmu_domain); if (atomic_ctx) { arm_smmu_disable_clocks_atomic(smmu_domain->smmu); } else { Loading Loading @@ -1865,7 +1948,8 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, break; } case DOMAIN_ATTR_SECURE_VMID: ret = 0; BUG_ON(smmu_domain->secure_vmid != VMID_INVAL); smmu_domain->secure_vmid = *((int *)data); break; case DOMAIN_ATTR_ATOMIC: { Loading
drivers/iommu/io-pgtable-arm.c +5 −2 Original line number Diff line number Diff line Loading @@ -261,6 +261,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, pte |= ARM_LPAE_PTE_NSTABLE; *ptep = pte; data->iop.cfg.tlb->flush_pgtable(ptep, sizeof(*ptep), cookie); data->iop.cfg.tlb->prepare_pgtable(cptep, cookie); } else { cptep = iopte_deref(pte, data); } Loading Loading @@ -412,6 +413,8 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); } data->iop.cfg.tlb->unprepare_pgtable(data->iop.cookie, start, table_size); free_pages_exact(start, table_size); } Loading Loading @@ -745,7 +748,7 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) goto out_free_data; cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); cfg->tlb->prepare_pgtable(data->pgd, cookie); /* TTBRs */ cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd); cfg->arm_lpae_s1_cfg.ttbr[1] = 0; Loading Loading @@ -833,7 +836,7 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) goto out_free_data; cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); cfg->tlb->prepare_pgtable(data->pgd, cookie); /* VTTBR */ cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd); return &data->iop; Loading
drivers/iommu/io-pgtable.h +4 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ enum io_pgtable_fmt { * @tlb_add_flush: Queue up a TLB invalidation for a virtual address range. * @tlb_sync: Ensure any queue TLB invalidation has taken effect. * @flush_pgtable: Ensure page table updates are visible to the IOMMU. * @prepare_pgtable: Do necessary fixup for newly allocated page table memory * @unprepare_pgtable: Undo fixups done during @prepare_pgtable * * Note that these can all be called in atomic context and must therefore * not block. Loading @@ -31,6 +33,8 @@ struct iommu_gather_ops { void *cookie); void (*tlb_sync)(void *cookie); void (*flush_pgtable)(void *ptr, size_t size, void *cookie); void (*prepare_pgtable)(void *addr, void *cookie); void (*unprepare_pgtable)(void *cookie, void *addr, size_t size); }; /** Loading
drivers/soc/qcom/secure_buffer.c +4 −7 Original line number Diff line number Diff line Loading @@ -318,12 +318,11 @@ err1: return ret; } int hyp_assign_phys(phys_addr_t addr, u64 size, int *dest_vmids, int *dest_perms, int dest_nelems) int hyp_assign_phys(phys_addr_t addr, u64 size, u32 *source_vm_list, int source_nelems, int *dest_vmids, int *dest_perms, int dest_nelems) { struct sg_table *table; u32 source_vm; int ret; table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); Loading @@ -335,9 +334,7 @@ int hyp_assign_phys(phys_addr_t addr, u64 size, sg_set_page(table->sgl, phys_to_page(addr), size, 0); source_vm = VMID_HLOS; ret = hyp_assign_table(table, &source_vm, 1, dest_vmids, ret = hyp_assign_table(table, source_vm_list, source_nelems, dest_vmids, dest_perms, dest_nelems); if (ret) goto err2; Loading
include/soc/qcom/secure_buffer.h +4 −4 Original line number Diff line number Diff line Loading @@ -38,8 +38,8 @@ int hyp_assign_table(struct sg_table *table, int *dest_vmids, int *dest_perms, int dest_nelems); int hyp_assign_phys(phys_addr_t addr, u64 size, int *dest_vmids, int *dest_perms, int dest_nelems); u32 *source_vmlist, int source_nelems, int *dest_vmids, int *dest_perms, int dest_nelems); bool msm_secure_v2_is_supported(void); #else static inline int msm_secure_table(struct sg_table *table) Loading @@ -58,8 +58,8 @@ static inline int hyp_assign_table(struct sg_table *table, return -ENOSYS; } static inline int hyp_assign_phys(phys_addr_t addr, u64 size, int *dest_vmids, int *dest_perms, int dest_nelems) u32 *source_vmlist, int source_nelems, int *dest_vmids, int *dest_perms, int dest_nelems) { return -ENOSYS; } Loading