iommu/arm-smmu: Add support for TTBR1
Subsystems (3)
RFC 1/1 iommu/arm-smmu: Add support for TTBR1
(Reupping this from a few months back as requested for discussion)
Allow a domain to opt into allocating and maintaining a TTBR1 pagetable. The size of the TTBR1 region will be the same as the TTBR0 size with the sign extension bit set on the highest bit in the region.
By example, given a TTBR0/TTBR1 virtual address range of 36 bits the memory map will look like this:
TTBR0 [0x0000000000000000:0x00000007FFFFFFFF]
TTBR1 [0xFFFFFFF800000000:0xFFFFFFFFFFFFFFFF]
The map/unmap operations will automatically use the appropriate pagetable for the given iova.
Signed-off-by Jordan Crouse <[email protected]>
--- drivers/iommu/arm-smmu.c | 40 +++++++++- drivers/iommu/io-pgtable-arm.c | 162 +++++++++++++++++++++++++++++++++++++---- drivers/iommu/io-pgtable.h | 5 ++ include/linux/iommu.h | 1 + 4 files changed, 191 insertions(+), 17 deletions(-)
drivers/iommu/arm-smmu.c +38 -2
@@ -389,6 +389,8 @@ struct arm_smmu_device {struct arm_smmu_s2cr *s2crs;struct mutex stream_map_mutex; +u32 ubs; +unsigned long va_size;unsigned long ipa_size;unsigned long pa_size;
@@ -438,6 +440,7 @@ struct arm_smmu_domain {struct mutex init_mutex;/* Protects smmu pointer */ spinlock_t cb_lock;/* Serialises ATS1* ops */ struct iommu_domain domain; +u32 attributes; };struct arm_smmu_option_prop {
@@ -821,7 +824,6 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, }else { reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr; reg2 = pgtbl_cfg->arm_lpae_s1_cfg.tcr >>32 ; - reg2 |=TTBCR2_SEP_UPSTREAM ;if (cfg->fmt ==ARM_SMMU_CTX_FMT_AARCH64 ) reg2 |=TTBCR2_AS ; }
@@ -881,6 +883,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, {int irq, start, ret =0 ;unsigned long ias, oas; +int sep =0 ;struct io_pgtable_ops *pgtbl_ops;struct io_pgtable_cfg pgtbl_cfg;enum io_pgtable_fmt fmt;
@@ -955,6 +958,25 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, oas = smmu->ipa_size;if (cfg->fmt ==ARM_SMMU_CTX_FMT_AARCH64 ) { fmt =ARM_64_LPAE_S1 ; + +if (smmu_domain->attributes & + (1 <<DOMAIN_ATTR_ENABLE_TTBR1 )) { + +/* +* When the UBS id is 5 we know that the bus +* size is 49 bits and that bit 48 is the fixed +* sign extension bit. For any other bus size +* we need to specify the sign extension bit +* and adjust the input size accordingly +*/ + +if (smmu->ubs ==5 ) { + sep =48 ; + }else { + sep = ias -1 ; + ias--; + } + } }else if (cfg->fmt ==ARM_SMMU_CTX_FMT_AARCH32_L ) { fmt =ARM_32_LPAE_S1 ; ias =min (ias,32UL );
@@ -1014,6 +1036,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, .pgsize_bitmap = smmu->pgsize_bitmap, .ias = ias, .oas = oas, + .sep = sep, .tlb = tlb_ops, .iommu_dev = smmu->dev, };
@@ -1021,6 +1044,10 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,if (smmu->features &ARM_SMMU_FEAT_COHERENT_WALK ) pgtbl_cfg.quirks =IO_PGTABLE_QUIRK_NO_DMA ; + +if (smmu_domain->attributes & (1 <<DOMAIN_ATTR_ENABLE_TTBR1 )) + pgtbl_cfg.quirks |=IO_PGTABLE_QUIRK_ARM_TTBR1 ; + smmu_domain->smmu = smmu; pgtbl_ops =alloc_io_pgtable_ops (fmt, &pgtbl_cfg, smmu_domain);if (!pgtbl_ops) {
@@ -1621,6 +1648,10 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,case DOMAIN_ATTR_NESTING : *(int *)data = (smmu_domain->stage ==ARM_SMMU_DOMAIN_NESTED );return 0 ; +case DOMAIN_ATTR_ENABLE_TTBR1 : + *((int *)data) = !!(smmu_domain->attributes + & (1 <<DOMAIN_ATTR_ENABLE_TTBR1 )); +return 0 ;default :return -ENODEV ; }
@@ -1650,6 +1681,11 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, smmu_domain->stage =ARM_SMMU_DOMAIN_S1 ;break ; +case DOMAIN_ATTR_ENABLE_TTBR1 : +if (*((int *)data)) + smmu_domain->attributes |= +1 <<DOMAIN_ATTR_ENABLE_TTBR1 ; +break ;default : ret = -ENODEV ; }
@@ -1991,7 +2027,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)if (smmu->version ==ARM_SMMU_V1_64K ) smmu->features |=ARM_SMMU_FEAT_FMT_AARCH64_64K ; }else { - size = (id >>ID2_UBS_SHIFT ) &ID2_UBS_MASK ; + smmu->ubs = (id >>ID2_UBS_SHIFT ) &ID2_UBS_MASK ; smmu->va_size =arm_smmu_id_size_to_bits (size);if (id &ID2_PTFS_4K ) smmu->features |=ARM_SMMU_FEAT_FMT_AARCH64_4K ;
drivers/iommu/io-pgtable-arm.c +147 -15
269 lines not on this page · raw message
drivers/iommu/io-pgtable.h +5 -0
@@ -70,16 +70,21 @@ struct io_pgtable_cfg {* be accessed by a fully cache-coherent IOMMU or CPU (e.g. for a * software-emulated IOMMU), such that pagetable updates need not * be treated as explicit DMA data. +* +* IO_PGTABLE_QUIRK_ARM_TTBR1: Allocate and configure a supervisor +* (TTBR1) pagetable as well as the user (TTBR0) table */ #define IO_PGTABLE_QUIRK_ARM_NS BIT(0)#define IO_PGTABLE_QUIRK_NO_PERMS BIT(1)#define IO_PGTABLE_QUIRK_TLBI_ON_MAP BIT(2)#define IO_PGTABLE_QUIRK_ARM_MTK_4GB BIT(3)#define IO_PGTABLE_QUIRK_NO_DMA BIT(4) +#define IO_PGTABLE_QUIRK_ARM_TTBR1 BIT(5)/* Allocate TTBR1 PT */ unsigned long quirks;unsigned long pgsize_bitmap;unsigned int ias;unsigned int oas; +int sep;const struct iommu_gather_ops *tlb;struct device *iommu_dev;
include/linux/iommu.h +1 -0
@@ -124,6 +124,7 @@ enum iommu_attr {DOMAIN_ATTR_FSL_PAMU_ENABLE ,DOMAIN_ATTR_FSL_PAMUV1 ,DOMAIN_ATTR_NESTING ,/* two stages of translation */ +DOMAIN_ATTR_ENABLE_TTBR1 , DOMAIN_ATTR_MAX, };
Signature · 6 lines
1.9.1 _______________________________________________ Freedreno mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/freedreno