aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2014-06-25 17:46:31 -0400
committerWill Deacon <will.deacon@arm.com>2014-11-14 09:41:39 -0500
commitc752ce45b213de8532baaf987ba930638f77c439 (patch)
treed7f99d2fdb4c231029339e045e277d91c9d1dc56 /drivers/iommu
parent0e7d37adbe45404a76d05d4ef11544f23cf639dd (diff)
iommu/arm-smmu: add support for DOMAIN_ATTR_NESTING attribute
When domains are set with the DOMAIN_ATTR_NESTING flag, we must ensure that we allocate them to stage-2 context banks if the hardware permits it. This patch adds support for the attribute to the ARM SMMU driver, with the actual stage being determined depending on the features supported by the hardware. Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/arm-smmu.c110
1 files changed, 90 insertions, 20 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 217581469f79..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
407enum arm_smmu_domain_stage {
408 ARM_SMMU_DOMAIN_S1 = 0,
409 ARM_SMMU_DOMAIN_S2,
410 ARM_SMMU_DOMAIN_NESTED,
411};
412
407struct arm_smmu_domain { 413struct 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,
@@ -1647,20 +1681,56 @@ static void arm_smmu_remove_device(struct device *dev)
1647 iommu_group_remove_device(dev); 1681 iommu_group_remove_device(dev);
1648} 1682}
1649 1683
1684static 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
1698static 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
1650static const struct iommu_ops arm_smmu_ops = { 1718static const struct iommu_ops arm_smmu_ops = {
1651 .capable = arm_smmu_capable, 1719 .capable = arm_smmu_capable,
1652 .domain_init = arm_smmu_domain_init, 1720 .domain_init = arm_smmu_domain_init,
1653 .domain_destroy = arm_smmu_domain_destroy, 1721 .domain_destroy = arm_smmu_domain_destroy,
1654 .attach_dev = arm_smmu_attach_dev, 1722 .attach_dev = arm_smmu_attach_dev,
1655 .detach_dev = arm_smmu_detach_dev, 1723 .detach_dev = arm_smmu_detach_dev,
1656 .map = arm_smmu_map, 1724 .map = arm_smmu_map,
1657 .unmap = arm_smmu_unmap, 1725 .unmap = arm_smmu_unmap,
1658 .iova_to_phys = arm_smmu_iova_to_phys, 1726 .iova_to_phys = arm_smmu_iova_to_phys,
1659 .add_device = arm_smmu_add_device, 1727 .add_device = arm_smmu_add_device,
1660 .remove_device = arm_smmu_remove_device, 1728 .remove_device = arm_smmu_remove_device,
1661 .pgsize_bitmap = (SECTION_SIZE | 1729 .domain_get_attr = arm_smmu_domain_get_attr,
1662 ARM_SMMU_PTE_CONT_SIZE | 1730 .domain_set_attr = arm_smmu_domain_set_attr,
1663 PAGE_SIZE), 1731 .pgsize_bitmap = (SECTION_SIZE |
1732 ARM_SMMU_PTE_CONT_SIZE |
1733 PAGE_SIZE),
1664}; 1734};
1665 1735
1666static void arm_smmu_device_reset(struct arm_smmu_device *smmu) 1736static void arm_smmu_device_reset(struct arm_smmu_device *smmu)