diff options
-rw-r--r-- | drivers/iommu/amd_iommu.c | 2 | ||||
-rw-r--r-- | drivers/iommu/arm-smmu.c | 133 | ||||
-rw-r--r-- | include/linux/iommu.h | 3 |
3 files changed, 113 insertions, 25 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 505a9adac2d5..3d78a8fb5a6a 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
@@ -3411,6 +3411,8 @@ static bool amd_iommu_capable(enum iommu_cap cap) | |||
3411 | return true; | 3411 | return true; |
3412 | case IOMMU_CAP_INTR_REMAP: | 3412 | case IOMMU_CAP_INTR_REMAP: |
3413 | return (irq_remapping_enabled == 1); | 3413 | return (irq_remapping_enabled == 1); |
3414 | case IOMMU_CAP_NOEXEC: | ||
3415 | return false; | ||
3414 | } | 3416 | } |
3415 | 3417 | ||
3416 | return false; | 3418 | return false; |
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 60558f794922..7a80f710ba2d 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c | |||
@@ -404,9 +404,16 @@ struct arm_smmu_cfg { | |||
404 | #define ARM_SMMU_CB_ASID(cfg) ((cfg)->cbndx) | 404 | #define ARM_SMMU_CB_ASID(cfg) ((cfg)->cbndx) |
405 | #define ARM_SMMU_CB_VMID(cfg) ((cfg)->cbndx + 1) | 405 | #define ARM_SMMU_CB_VMID(cfg) ((cfg)->cbndx + 1) |
406 | 406 | ||
407 | enum arm_smmu_domain_stage { | ||
408 | ARM_SMMU_DOMAIN_S1 = 0, | ||
409 | ARM_SMMU_DOMAIN_S2, | ||
410 | ARM_SMMU_DOMAIN_NESTED, | ||
411 | }; | ||
412 | |||
407 | struct arm_smmu_domain { | 413 | struct arm_smmu_domain { |
408 | struct arm_smmu_device *smmu; | 414 | struct arm_smmu_device *smmu; |
409 | struct arm_smmu_cfg cfg; | 415 | struct arm_smmu_cfg cfg; |
416 | enum arm_smmu_domain_stage stage; | ||
410 | spinlock_t lock; | 417 | spinlock_t lock; |
411 | }; | 418 | }; |
412 | 419 | ||
@@ -906,19 +913,46 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, | |||
906 | if (smmu_domain->smmu) | 913 | if (smmu_domain->smmu) |
907 | goto out_unlock; | 914 | goto out_unlock; |
908 | 915 | ||
909 | if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) { | 916 | /* |
917 | * Mapping the requested stage onto what we support is surprisingly | ||
918 | * complicated, mainly because the spec allows S1+S2 SMMUs without | ||
919 | * support for nested translation. That means we end up with the | ||
920 | * following table: | ||
921 | * | ||
922 | * Requested Supported Actual | ||
923 | * S1 N S1 | ||
924 | * S1 S1+S2 S1 | ||
925 | * S1 S2 S2 | ||
926 | * S1 S1 S1 | ||
927 | * N N N | ||
928 | * N S1+S2 S2 | ||
929 | * N S2 S2 | ||
930 | * N S1 S1 | ||
931 | * | ||
932 | * Note that you can't actually request stage-2 mappings. | ||
933 | */ | ||
934 | if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1)) | ||
935 | smmu_domain->stage = ARM_SMMU_DOMAIN_S2; | ||
936 | if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S2)) | ||
937 | smmu_domain->stage = ARM_SMMU_DOMAIN_S1; | ||
938 | |||
939 | switch (smmu_domain->stage) { | ||
940 | case ARM_SMMU_DOMAIN_S1: | ||
941 | cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS; | ||
942 | start = smmu->num_s2_context_banks; | ||
943 | break; | ||
944 | case ARM_SMMU_DOMAIN_NESTED: | ||
910 | /* | 945 | /* |
911 | * We will likely want to change this if/when KVM gets | 946 | * We will likely want to change this if/when KVM gets |
912 | * involved. | 947 | * involved. |
913 | */ | 948 | */ |
914 | cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS; | 949 | case ARM_SMMU_DOMAIN_S2: |
915 | start = smmu->num_s2_context_banks; | ||
916 | } else if (smmu->features & ARM_SMMU_FEAT_TRANS_S1) { | ||
917 | cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS; | ||
918 | start = smmu->num_s2_context_banks; | ||
919 | } else { | ||
920 | cfg->cbar = CBAR_TYPE_S2_TRANS; | 950 | cfg->cbar = CBAR_TYPE_S2_TRANS; |
921 | start = 0; | 951 | start = 0; |
952 | break; | ||
953 | default: | ||
954 | ret = -EINVAL; | ||
955 | goto out_unlock; | ||
922 | } | 956 | } |
923 | 957 | ||
924 | ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, | 958 | ret = __arm_smmu_alloc_bitmap(smmu->context_map, start, |
@@ -1281,7 +1315,7 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd, | |||
1281 | unsigned long pfn, int prot, int stage) | 1315 | unsigned long pfn, int prot, int stage) |
1282 | { | 1316 | { |
1283 | pte_t *pte, *start; | 1317 | pte_t *pte, *start; |
1284 | pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF | ARM_SMMU_PTE_XN; | 1318 | pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF; |
1285 | 1319 | ||
1286 | if (pmd_none(*pmd)) { | 1320 | if (pmd_none(*pmd)) { |
1287 | /* Allocate a new set of tables */ | 1321 | /* Allocate a new set of tables */ |
@@ -1315,10 +1349,11 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd, | |||
1315 | pteval |= ARM_SMMU_PTE_MEMATTR_NC; | 1349 | pteval |= ARM_SMMU_PTE_MEMATTR_NC; |
1316 | } | 1350 | } |
1317 | 1351 | ||
1352 | if (prot & IOMMU_NOEXEC) | ||
1353 | pteval |= ARM_SMMU_PTE_XN; | ||
1354 | |||
1318 | /* If no access, create a faulting entry to avoid TLB fills */ | 1355 | /* If no access, create a faulting entry to avoid TLB fills */ |
1319 | if (prot & IOMMU_EXEC) | 1356 | if (!(prot & (IOMMU_READ | IOMMU_WRITE))) |
1320 | pteval &= ~ARM_SMMU_PTE_XN; | ||
1321 | else if (!(prot & (IOMMU_READ | IOMMU_WRITE))) | ||
1322 | pteval &= ~ARM_SMMU_PTE_PAGE; | 1357 | pteval &= ~ARM_SMMU_PTE_PAGE; |
1323 | 1358 | ||
1324 | pteval |= ARM_SMMU_PTE_SH_IS; | 1359 | pteval |= ARM_SMMU_PTE_SH_IS; |
@@ -1568,6 +1603,8 @@ static bool arm_smmu_capable(enum iommu_cap cap) | |||
1568 | return true; | 1603 | return true; |
1569 | case IOMMU_CAP_INTR_REMAP: | 1604 | case IOMMU_CAP_INTR_REMAP: |
1570 | return true; /* MSIs are just memory writes */ | 1605 | return true; /* MSIs are just memory writes */ |
1606 | case IOMMU_CAP_NOEXEC: | ||
1607 | return true; | ||
1571 | default: | 1608 | default: |
1572 | return false; | 1609 | return false; |
1573 | } | 1610 | } |
@@ -1644,20 +1681,56 @@ static void arm_smmu_remove_device(struct device *dev) | |||
1644 | iommu_group_remove_device(dev); | 1681 | iommu_group_remove_device(dev); |
1645 | } | 1682 | } |
1646 | 1683 | ||
1684 | static int arm_smmu_domain_get_attr(struct iommu_domain *domain, | ||
1685 | enum iommu_attr attr, void *data) | ||
1686 | { | ||
1687 | struct arm_smmu_domain *smmu_domain = domain->priv; | ||
1688 | |||
1689 | switch (attr) { | ||
1690 | case DOMAIN_ATTR_NESTING: | ||
1691 | *(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED); | ||
1692 | return 0; | ||
1693 | default: | ||
1694 | return -ENODEV; | ||
1695 | } | ||
1696 | } | ||
1697 | |||
1698 | static int arm_smmu_domain_set_attr(struct iommu_domain *domain, | ||
1699 | enum iommu_attr attr, void *data) | ||
1700 | { | ||
1701 | struct arm_smmu_domain *smmu_domain = domain->priv; | ||
1702 | |||
1703 | switch (attr) { | ||
1704 | case DOMAIN_ATTR_NESTING: | ||
1705 | if (smmu_domain->smmu) | ||
1706 | return -EPERM; | ||
1707 | if (*(int *)data) | ||
1708 | smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; | ||
1709 | else | ||
1710 | smmu_domain->stage = ARM_SMMU_DOMAIN_S1; | ||
1711 | |||
1712 | return 0; | ||
1713 | default: | ||
1714 | return -ENODEV; | ||
1715 | } | ||
1716 | } | ||
1717 | |||
1647 | static const struct iommu_ops arm_smmu_ops = { | 1718 | static const struct iommu_ops arm_smmu_ops = { |
1648 | .capable = arm_smmu_capable, | 1719 | .capable = arm_smmu_capable, |
1649 | .domain_init = arm_smmu_domain_init, | 1720 | .domain_init = arm_smmu_domain_init, |
1650 | .domain_destroy = arm_smmu_domain_destroy, | 1721 | .domain_destroy = arm_smmu_domain_destroy, |
1651 | .attach_dev = arm_smmu_attach_dev, | 1722 | .attach_dev = arm_smmu_attach_dev, |
1652 | .detach_dev = arm_smmu_detach_dev, | 1723 | .detach_dev = arm_smmu_detach_dev, |
1653 | .map = arm_smmu_map, | 1724 | .map = arm_smmu_map, |
1654 | .unmap = arm_smmu_unmap, | 1725 | .unmap = arm_smmu_unmap, |
1655 | .iova_to_phys = arm_smmu_iova_to_phys, | 1726 | .iova_to_phys = arm_smmu_iova_to_phys, |
1656 | .add_device = arm_smmu_add_device, | 1727 | .add_device = arm_smmu_add_device, |
1657 | .remove_device = arm_smmu_remove_device, | 1728 | .remove_device = arm_smmu_remove_device, |
1658 | .pgsize_bitmap = (SECTION_SIZE | | 1729 | .domain_get_attr = arm_smmu_domain_get_attr, |
1659 | ARM_SMMU_PTE_CONT_SIZE | | 1730 | .domain_set_attr = arm_smmu_domain_set_attr, |
1660 | PAGE_SIZE), | 1731 | .pgsize_bitmap = (SECTION_SIZE | |
1732 | ARM_SMMU_PTE_CONT_SIZE | | ||
1733 | PAGE_SIZE), | ||
1661 | }; | 1734 | }; |
1662 | 1735 | ||
1663 | static void arm_smmu_device_reset(struct arm_smmu_device *smmu) | 1736 | static void arm_smmu_device_reset(struct arm_smmu_device *smmu) |
@@ -2072,8 +2145,20 @@ static struct platform_driver arm_smmu_driver = { | |||
2072 | 2145 | ||
2073 | static int __init arm_smmu_init(void) | 2146 | static int __init arm_smmu_init(void) |
2074 | { | 2147 | { |
2148 | struct device_node *np; | ||
2075 | int ret; | 2149 | int ret; |
2076 | 2150 | ||
2151 | /* | ||
2152 | * Play nice with systems that don't have an ARM SMMU by checking that | ||
2153 | * an ARM SMMU exists in the system before proceeding with the driver | ||
2154 | * and IOMMU bus operation registration. | ||
2155 | */ | ||
2156 | np = of_find_matching_node(NULL, arm_smmu_of_match); | ||
2157 | if (!np) | ||
2158 | return 0; | ||
2159 | |||
2160 | of_node_put(np); | ||
2161 | |||
2077 | ret = platform_driver_register(&arm_smmu_driver); | 2162 | ret = platform_driver_register(&arm_smmu_driver); |
2078 | if (ret) | 2163 | if (ret) |
2079 | return ret; | 2164 | return ret; |
diff --git a/include/linux/iommu.h b/include/linux/iommu.h index e6a7c9ff72f2..e438b30f062b 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h | |||
@@ -27,7 +27,7 @@ | |||
27 | #define IOMMU_READ (1 << 0) | 27 | #define IOMMU_READ (1 << 0) |
28 | #define IOMMU_WRITE (1 << 1) | 28 | #define IOMMU_WRITE (1 << 1) |
29 | #define IOMMU_CACHE (1 << 2) /* DMA cache coherency */ | 29 | #define IOMMU_CACHE (1 << 2) /* DMA cache coherency */ |
30 | #define IOMMU_EXEC (1 << 3) | 30 | #define IOMMU_NOEXEC (1 << 3) |
31 | 31 | ||
32 | struct iommu_ops; | 32 | struct iommu_ops; |
33 | struct iommu_group; | 33 | struct iommu_group; |
@@ -61,6 +61,7 @@ enum iommu_cap { | |||
61 | IOMMU_CAP_CACHE_COHERENCY, /* IOMMU can enforce cache coherent DMA | 61 | IOMMU_CAP_CACHE_COHERENCY, /* IOMMU can enforce cache coherent DMA |
62 | transactions */ | 62 | transactions */ |
63 | IOMMU_CAP_INTR_REMAP, /* IOMMU supports interrupt isolation */ | 63 | IOMMU_CAP_INTR_REMAP, /* IOMMU supports interrupt isolation */ |
64 | IOMMU_CAP_NOEXEC, /* IOMMU_NOEXEC flag */ | ||
64 | }; | 65 | }; |
65 | 66 | ||
66 | /* | 67 | /* |