mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	iommu/io-pgtable-arm: Prepare for TTBR1 usage
Now that we can correctly extract top-level indices without relying on the remaining upper bits being zero, the only remaining impediments to using a given table for TTBR1 are the address validation on map/unmap and the awkward TCR translation granule format. Add a quirk so that we can do the right thing at those points. Tested-by: Jordan Crouse <jcrouse@codeaurora.org> Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
		
							parent
							
								
									ac4b80e5b9
								
							
						
					
					
						commit
						db6903010a
					
				
					 2 changed files with 23 additions and 6 deletions
				
			
		| 
						 | 
				
			
			@ -104,6 +104,10 @@
 | 
			
		|||
#define ARM_LPAE_TCR_TG0_64K		1
 | 
			
		||||
#define ARM_LPAE_TCR_TG0_16K		2
 | 
			
		||||
 | 
			
		||||
#define ARM_LPAE_TCR_TG1_16K		1
 | 
			
		||||
#define ARM_LPAE_TCR_TG1_4K		2
 | 
			
		||||
#define ARM_LPAE_TCR_TG1_64K		3
 | 
			
		||||
 | 
			
		||||
#define ARM_LPAE_TCR_SH_NS		0
 | 
			
		||||
#define ARM_LPAE_TCR_SH_OS		2
 | 
			
		||||
#define ARM_LPAE_TCR_SH_IS		3
 | 
			
		||||
| 
						 | 
				
			
			@ -464,6 +468,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
 | 
			
		|||
	arm_lpae_iopte *ptep = data->pgd;
 | 
			
		||||
	int ret, lvl = data->start_level;
 | 
			
		||||
	arm_lpae_iopte prot;
 | 
			
		||||
	long iaext = (long)iova >> cfg->ias;
 | 
			
		||||
 | 
			
		||||
	/* If no access, then nothing to do */
 | 
			
		||||
	if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
 | 
			
		||||
| 
						 | 
				
			
			@ -472,7 +477,9 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
 | 
			
		|||
	if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(iova >> data->iop.cfg.ias || paddr >> data->iop.cfg.oas))
 | 
			
		||||
	if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)
 | 
			
		||||
		iaext = ~iaext;
 | 
			
		||||
	if (WARN_ON(iaext || paddr >> cfg->oas))
 | 
			
		||||
		return -ERANGE;
 | 
			
		||||
 | 
			
		||||
	prot = arm_lpae_prot_to_pte(data, iommu_prot);
 | 
			
		||||
| 
						 | 
				
			
			@ -638,11 +645,14 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
 | 
			
		|||
	struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
 | 
			
		||||
	struct io_pgtable_cfg *cfg = &data->iop.cfg;
 | 
			
		||||
	arm_lpae_iopte *ptep = data->pgd;
 | 
			
		||||
	long iaext = (long)iova >> cfg->ias;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (WARN_ON(iova >> data->iop.cfg.ias))
 | 
			
		||||
	if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)
 | 
			
		||||
		iaext = ~iaext;
 | 
			
		||||
	if (WARN_ON(iaext))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	return __arm_lpae_unmap(data, gather, iova, size, data->start_level, ptep);
 | 
			
		||||
| 
						 | 
				
			
			@ -778,9 +788,11 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
 | 
			
		|||
	u64 reg;
 | 
			
		||||
	struct arm_lpae_io_pgtable *data;
 | 
			
		||||
	typeof(&cfg->arm_lpae_s1_cfg.tcr) tcr = &cfg->arm_lpae_s1_cfg.tcr;
 | 
			
		||||
	bool tg1;
 | 
			
		||||
 | 
			
		||||
	if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS |
 | 
			
		||||
			    IO_PGTABLE_QUIRK_NON_STRICT))
 | 
			
		||||
			    IO_PGTABLE_QUIRK_NON_STRICT |
 | 
			
		||||
			    IO_PGTABLE_QUIRK_ARM_TTBR1))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	data = arm_lpae_alloc_pgtable(cfg);
 | 
			
		||||
| 
						 | 
				
			
			@ -798,15 +810,16 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
 | 
			
		|||
		tcr->orgn = ARM_LPAE_TCR_RGN_NC;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tg1 = cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1;
 | 
			
		||||
	switch (ARM_LPAE_GRANULE(data)) {
 | 
			
		||||
	case SZ_4K:
 | 
			
		||||
		tcr->tg = ARM_LPAE_TCR_TG0_4K;
 | 
			
		||||
		tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_4K : ARM_LPAE_TCR_TG0_4K;
 | 
			
		||||
		break;
 | 
			
		||||
	case SZ_16K:
 | 
			
		||||
		tcr->tg = ARM_LPAE_TCR_TG0_16K;
 | 
			
		||||
		tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_16K : ARM_LPAE_TCR_TG0_16K;
 | 
			
		||||
		break;
 | 
			
		||||
	case SZ_64K:
 | 
			
		||||
		tcr->tg = ARM_LPAE_TCR_TG0_64K;
 | 
			
		||||
		tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_64K : ARM_LPAE_TCR_TG0_64K;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,12 +83,16 @@ struct io_pgtable_cfg {
 | 
			
		|||
	 * IO_PGTABLE_QUIRK_NON_STRICT: Skip issuing synchronous leaf TLBIs
 | 
			
		||||
	 *	on unmap, for DMA domains using the flush queue mechanism for
 | 
			
		||||
	 *	delayed invalidation.
 | 
			
		||||
	 *
 | 
			
		||||
	 * IO_PGTABLE_QUIRK_ARM_TTBR1: (ARM LPAE format) Configure the table
 | 
			
		||||
	 *	for use in the upper half of a split address space.
 | 
			
		||||
	 */
 | 
			
		||||
	#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_EXT	BIT(3)
 | 
			
		||||
	#define IO_PGTABLE_QUIRK_NON_STRICT	BIT(4)
 | 
			
		||||
	#define IO_PGTABLE_QUIRK_ARM_TTBR1	BIT(5)
 | 
			
		||||
	unsigned long			quirks;
 | 
			
		||||
	unsigned long			pgsize_bitmap;
 | 
			
		||||
	unsigned int			ias;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue