Loading drivers/iommu/amd_iommu.c +2 −0 Original line number Diff line number Diff line Loading @@ -3411,6 +3411,8 @@ static bool amd_iommu_capable(enum iommu_cap cap) return true; case IOMMU_CAP_INTR_REMAP: return (irq_remapping_enabled == 1); case IOMMU_CAP_NOEXEC: return false; } return false; Loading drivers/iommu/arm-smmu.c +109 −24 Original line number Diff line number Diff line Loading @@ -404,9 +404,16 @@ struct arm_smmu_cfg { #define ARM_SMMU_CB_ASID(cfg) ((cfg)->cbndx) #define ARM_SMMU_CB_VMID(cfg) ((cfg)->cbndx + 1) enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_S1 = 0, ARM_SMMU_DOMAIN_S2, ARM_SMMU_DOMAIN_NESTED, }; struct arm_smmu_domain { struct arm_smmu_device *smmu; struct arm_smmu_cfg cfg; enum arm_smmu_domain_stage stage; spinlock_t lock; }; Loading Loading @@ -906,19 +913,46 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, if (smmu_domain->smmu) goto out_unlock; if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) { /* * We will likely want to change this if/when KVM gets * involved. * Mapping the requested stage onto what we support is surprisingly * complicated, mainly because the spec allows S1+S2 SMMUs without * support for nested translation. That means we end up with the * following table: * * Requested Supported Actual * S1 N S1 * S1 S1+S2 S1 * S1 S2 S2 * S1 S1 S1 * N N N * N S1+S2 S2 * N S2 S2 * N S1 S1 * * Note that you can't actually request stage-2 mappings. */ if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1)) smmu_domain->stage = ARM_SMMU_DOMAIN_S2; if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S2)) smmu_domain->stage = ARM_SMMU_DOMAIN_S1; switch (smmu_domain->stage) { case ARM_SMMU_DOMAIN_S1: cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS; start = smmu->num_s2_context_banks; } else if (smmu->features & ARM_SMMU_FEAT_TRANS_S1) { cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS; start = smmu->num_s2_context_banks; } else { break; case ARM_SMMU_DOMAIN_NESTED: /* * We will likely want to change this if/when KVM gets * involved. */ case ARM_SMMU_DOMAIN_S2: cfg->cbar = CBAR_TYPE_S2_TRANS; start = 0; break; default: ret = -EINVAL; goto out_unlock; } ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, Loading Loading @@ -1281,7 +1315,7 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd, unsigned long pfn, int prot, int stage) { pte_t *pte, *start; pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF | ARM_SMMU_PTE_XN; pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF; if (pmd_none(*pmd)) { /* Allocate a new set of tables */ Loading Loading @@ -1315,10 +1349,11 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd, pteval |= ARM_SMMU_PTE_MEMATTR_NC; } if (prot & IOMMU_NOEXEC) pteval |= ARM_SMMU_PTE_XN; /* If no access, create a faulting entry to avoid TLB fills */ if (prot & IOMMU_EXEC) pteval &= ~ARM_SMMU_PTE_XN; else if (!(prot & (IOMMU_READ | IOMMU_WRITE))) if (!(prot & (IOMMU_READ | IOMMU_WRITE))) pteval &= ~ARM_SMMU_PTE_PAGE; pteval |= ARM_SMMU_PTE_SH_IS; Loading Loading @@ -1568,6 +1603,8 @@ static bool arm_smmu_capable(enum iommu_cap cap) return true; case IOMMU_CAP_INTR_REMAP: return true; /* MSIs are just memory writes */ case IOMMU_CAP_NOEXEC: return true; default: return false; } Loading Loading @@ -1644,6 +1681,40 @@ static void arm_smmu_remove_device(struct device *dev) iommu_group_remove_device(dev); } static int arm_smmu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data) { struct arm_smmu_domain *smmu_domain = domain->priv; switch (attr) { case DOMAIN_ATTR_NESTING: *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); return 0; default: return -ENODEV; } } static int arm_smmu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data) { struct arm_smmu_domain *smmu_domain = domain->priv; switch (attr) { case DOMAIN_ATTR_NESTING: if (smmu_domain->smmu) return -EPERM; if (*(int *)data) smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; else smmu_domain->stage = ARM_SMMU_DOMAIN_S1; return 0; default: return -ENODEV; } } static const struct iommu_ops arm_smmu_ops = { .capable = arm_smmu_capable, .domain_init = arm_smmu_domain_init, Loading @@ -1655,6 +1726,8 @@ static const struct iommu_ops arm_smmu_ops = { .iova_to_phys = arm_smmu_iova_to_phys, .add_device = arm_smmu_add_device, .remove_device = arm_smmu_remove_device, .domain_get_attr = arm_smmu_domain_get_attr, .domain_set_attr = arm_smmu_domain_set_attr, .pgsize_bitmap = (SECTION_SIZE | ARM_SMMU_PTE_CONT_SIZE | PAGE_SIZE), Loading Loading @@ -2072,8 +2145,20 @@ static struct platform_driver arm_smmu_driver = { static int __init arm_smmu_init(void) { struct device_node *np; int ret; /* * Play nice with systems that don't have an ARM SMMU by checking that * an ARM SMMU exists in the system before proceeding with the driver * and IOMMU bus operation registration. */ np = of_find_matching_node(NULL, arm_smmu_of_match); if (!np) return 0; of_node_put(np); ret = platform_driver_register(&arm_smmu_driver); if (ret) return ret; Loading include/linux/iommu.h +2 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ #define IOMMU_READ (1 << 0) #define IOMMU_WRITE (1 << 1) #define IOMMU_CACHE (1 << 2) /* DMA cache coherency */ #define IOMMU_EXEC (1 << 3) #define IOMMU_NOEXEC (1 << 3) struct iommu_ops; struct iommu_group; Loading Loading @@ -61,6 +61,7 @@ enum iommu_cap { IOMMU_CAP_CACHE_COHERENCY, /* IOMMU can enforce cache coherent DMA transactions */ IOMMU_CAP_INTR_REMAP, /* IOMMU supports interrupt isolation */ IOMMU_CAP_NOEXEC, /* IOMMU_NOEXEC flag */ }; /* Loading Loading
drivers/iommu/amd_iommu.c +2 −0 Original line number Diff line number Diff line Loading @@ -3411,6 +3411,8 @@ static bool amd_iommu_capable(enum iommu_cap cap) return true; case IOMMU_CAP_INTR_REMAP: return (irq_remapping_enabled == 1); case IOMMU_CAP_NOEXEC: return false; } return false; Loading
drivers/iommu/arm-smmu.c +109 −24 Original line number Diff line number Diff line Loading @@ -404,9 +404,16 @@ struct arm_smmu_cfg { #define ARM_SMMU_CB_ASID(cfg) ((cfg)->cbndx) #define ARM_SMMU_CB_VMID(cfg) ((cfg)->cbndx + 1) enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_S1 = 0, ARM_SMMU_DOMAIN_S2, ARM_SMMU_DOMAIN_NESTED, }; struct arm_smmu_domain { struct arm_smmu_device *smmu; struct arm_smmu_cfg cfg; enum arm_smmu_domain_stage stage; spinlock_t lock; }; Loading Loading @@ -906,19 +913,46 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, if (smmu_domain->smmu) goto out_unlock; if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) { /* * We will likely want to change this if/when KVM gets * involved. * Mapping the requested stage onto what we support is surprisingly * complicated, mainly because the spec allows S1+S2 SMMUs without * support for nested translation. That means we end up with the * following table: * * Requested Supported Actual * S1 N S1 * S1 S1+S2 S1 * S1 S2 S2 * S1 S1 S1 * N N N * N S1+S2 S2 * N S2 S2 * N S1 S1 * * Note that you can't actually request stage-2 mappings. */ if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1)) smmu_domain->stage = ARM_SMMU_DOMAIN_S2; if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S2)) smmu_domain->stage = ARM_SMMU_DOMAIN_S1; switch (smmu_domain->stage) { case ARM_SMMU_DOMAIN_S1: cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS; start = smmu->num_s2_context_banks; } else if (smmu->features & ARM_SMMU_FEAT_TRANS_S1) { cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS; start = smmu->num_s2_context_banks; } else { break; case ARM_SMMU_DOMAIN_NESTED: /* * We will likely want to change this if/when KVM gets * involved. */ case ARM_SMMU_DOMAIN_S2: cfg->cbar = CBAR_TYPE_S2_TRANS; start = 0; break; default: ret = -EINVAL; goto out_unlock; } ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, Loading Loading @@ -1281,7 +1315,7 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd, unsigned long pfn, int prot, int stage) { pte_t *pte, *start; pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF | ARM_SMMU_PTE_XN; pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF; if (pmd_none(*pmd)) { /* Allocate a new set of tables */ Loading Loading @@ -1315,10 +1349,11 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd, pteval |= ARM_SMMU_PTE_MEMATTR_NC; } if (prot & IOMMU_NOEXEC) pteval |= ARM_SMMU_PTE_XN; /* If no access, create a faulting entry to avoid TLB fills */ if (prot & IOMMU_EXEC) pteval &= ~ARM_SMMU_PTE_XN; else if (!(prot & (IOMMU_READ | IOMMU_WRITE))) if (!(prot & (IOMMU_READ | IOMMU_WRITE))) pteval &= ~ARM_SMMU_PTE_PAGE; pteval |= ARM_SMMU_PTE_SH_IS; Loading Loading @@ -1568,6 +1603,8 @@ static bool arm_smmu_capable(enum iommu_cap cap) return true; case IOMMU_CAP_INTR_REMAP: return true; /* MSIs are just memory writes */ case IOMMU_CAP_NOEXEC: return true; default: return false; } Loading Loading @@ -1644,6 +1681,40 @@ static void arm_smmu_remove_device(struct device *dev) iommu_group_remove_device(dev); } static int arm_smmu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data) { struct arm_smmu_domain *smmu_domain = domain->priv; switch (attr) { case DOMAIN_ATTR_NESTING: *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); return 0; default: return -ENODEV; } } static int arm_smmu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data) { struct arm_smmu_domain *smmu_domain = domain->priv; switch (attr) { case DOMAIN_ATTR_NESTING: if (smmu_domain->smmu) return -EPERM; if (*(int *)data) smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; else smmu_domain->stage = ARM_SMMU_DOMAIN_S1; return 0; default: return -ENODEV; } } static const struct iommu_ops arm_smmu_ops = { .capable = arm_smmu_capable, .domain_init = arm_smmu_domain_init, Loading @@ -1655,6 +1726,8 @@ static const struct iommu_ops arm_smmu_ops = { .iova_to_phys = arm_smmu_iova_to_phys, .add_device = arm_smmu_add_device, .remove_device = arm_smmu_remove_device, .domain_get_attr = arm_smmu_domain_get_attr, .domain_set_attr = arm_smmu_domain_set_attr, .pgsize_bitmap = (SECTION_SIZE | ARM_SMMU_PTE_CONT_SIZE | PAGE_SIZE), Loading Loading @@ -2072,8 +2145,20 @@ static struct platform_driver arm_smmu_driver = { static int __init arm_smmu_init(void) { struct device_node *np; int ret; /* * Play nice with systems that don't have an ARM SMMU by checking that * an ARM SMMU exists in the system before proceeding with the driver * and IOMMU bus operation registration. */ np = of_find_matching_node(NULL, arm_smmu_of_match); if (!np) return 0; of_node_put(np); ret = platform_driver_register(&arm_smmu_driver); if (ret) return ret; Loading
include/linux/iommu.h +2 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ #define IOMMU_READ (1 << 0) #define IOMMU_WRITE (1 << 1) #define IOMMU_CACHE (1 << 2) /* DMA cache coherency */ #define IOMMU_EXEC (1 << 3) #define IOMMU_NOEXEC (1 << 3) struct iommu_ops; struct iommu_group; Loading Loading @@ -61,6 +61,7 @@ enum iommu_cap { IOMMU_CAP_CACHE_COHERENCY, /* IOMMU can enforce cache coherent DMA transactions */ IOMMU_CAP_INTR_REMAP, /* IOMMU supports interrupt isolation */ IOMMU_CAP_NOEXEC, /* IOMMU_NOEXEC flag */ }; /* Loading