diff options
Diffstat (limited to 'drivers/iommu/arm-smmu.c')
-rw-r--r-- | drivers/iommu/arm-smmu.c | 135 |
1 files changed, 110 insertions, 25 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index e393ae01b5d2..b8aac1389a96 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,21 +1681,57 @@ 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 | .map_sg = default_iommu_map_sg, | 1726 | .map_sg = default_iommu_map_sg, |
1656 | .iova_to_phys = arm_smmu_iova_to_phys, | 1727 | .iova_to_phys = arm_smmu_iova_to_phys, |
1657 | .add_device = arm_smmu_add_device, | 1728 | .add_device = arm_smmu_add_device, |
1658 | .remove_device = arm_smmu_remove_device, | 1729 | .remove_device = arm_smmu_remove_device, |
1659 | .pgsize_bitmap = (SECTION_SIZE | | 1730 | .domain_get_attr = arm_smmu_domain_get_attr, |
1660 | ARM_SMMU_PTE_CONT_SIZE | | 1731 | .domain_set_attr = arm_smmu_domain_set_attr, |
1661 | PAGE_SIZE), | 1732 | .pgsize_bitmap = (SECTION_SIZE | |
1733 | ARM_SMMU_PTE_CONT_SIZE | | ||
1734 | PAGE_SIZE), | ||
1662 | }; | 1735 | }; |
1663 | 1736 | ||
1664 | static void arm_smmu_device_reset(struct arm_smmu_device *smmu) | 1737 | static void arm_smmu_device_reset(struct arm_smmu_device *smmu) |
@@ -2073,8 +2146,20 @@ static struct platform_driver arm_smmu_driver = { | |||
2073 | 2146 | ||
2074 | static int __init arm_smmu_init(void) | 2147 | static int __init arm_smmu_init(void) |
2075 | { | 2148 | { |
2149 | struct device_node *np; | ||
2076 | int ret; | 2150 | int ret; |
2077 | 2151 | ||
2152 | /* | ||
2153 | * Play nice with systems that don't have an ARM SMMU by checking that | ||
2154 | * an ARM SMMU exists in the system before proceeding with the driver | ||
2155 | * and IOMMU bus operation registration. | ||
2156 | */ | ||
2157 | np = of_find_matching_node(NULL, arm_smmu_of_match); | ||
2158 | if (!np) | ||
2159 | return 0; | ||
2160 | |||
2161 | of_node_put(np); | ||
2162 | |||
2078 | ret = platform_driver_register(&arm_smmu_driver); | 2163 | ret = platform_driver_register(&arm_smmu_driver); |
2079 | if (ret) | 2164 | if (ret) |
2080 | return ret; | 2165 | return ret; |