Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28d6007b authored by Will Deacon's avatar Will Deacon
Browse files

iommu/arm-smmu: don't bother truncating the s1 output size to VA_BITS



In order for nested translation to work correctly, we need to ensure
that the maximum output address size from stage-1 is <= the maximum
supported input address size to stage-2. The latter is currently defined
by VA_BITS, since we make use of the CPU page table functions for
allocating out tables and so the driver currently enforces this
restriction by truncating the stage-1 output size during probe.

In reality, this doesn't make a lot of sense; the guest OS is responsible
for managing the stage-1 page tables, so we actually just need to ensure
that the ID registers of the virtual SMMU interface only advertise the
supported stage-2 input size.

This patch fixes the problem by treating the stage-1 and stage-2 input
address sizes separately.

Reported-by: default avatarTirumalesh Chalamarla <tchalamarla@cavium.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent c757e852
Loading
Loading
Loading
Loading
+22 −23
Original line number Original line Diff line number Diff line
@@ -24,7 +24,7 @@
 *	- v7/v8 long-descriptor format
 *	- v7/v8 long-descriptor format
 *	- Non-secure access to the SMMU
 *	- Non-secure access to the SMMU
 *	- 4k and 64k pages, with contiguous pte hints.
 *	- 4k and 64k pages, with contiguous pte hints.
 *	- Up to 42-bit addressing (dependent on VA_BITS)
 *	- Up to 48-bit addressing (dependent on VA_BITS)
 *	- Context fault reporting
 *	- Context fault reporting
 */
 */


@@ -375,8 +375,9 @@ struct arm_smmu_device {
	u32				num_mapping_groups;
	u32				num_mapping_groups;
	DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);
	DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);


	unsigned long			input_size;
	unsigned long			s1_input_size;
	unsigned long			s1_output_size;
	unsigned long			s1_output_size;
	unsigned long			s2_input_size;
	unsigned long			s2_output_size;
	unsigned long			s2_output_size;


	u32				num_global_irqs;
	u32				num_global_irqs;
@@ -762,7 +763,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
			       gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx));
			       gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx));


		/* TTBCR2 */
		/* TTBCR2 */
		switch (smmu->input_size) {
		switch (smmu->s1_input_size) {
		case 32:
		case 32:
			reg = (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
			reg = (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
			break;
			break;
@@ -831,7 +832,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
			reg = TTBCR_TG0_64K;
			reg = TTBCR_TG0_64K;


		if (!stage1) {
		if (!stage1) {
			reg |= (64 - smmu->s1_output_size) << TTBCR_T0SZ_SHIFT;
			reg |= (64 - smmu->s2_input_size) << TTBCR_T0SZ_SHIFT;


			switch (smmu->s2_output_size) {
			switch (smmu->s2_output_size) {
			case 32:
			case 32:
@@ -854,7 +855,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
				break;
				break;
			}
			}
		} else {
		} else {
			reg |= (64 - smmu->input_size) << TTBCR_T0SZ_SHIFT;
			reg |= (64 - smmu->s1_input_size) << TTBCR_T0SZ_SHIFT;
		}
		}
	} else {
	} else {
		reg = 0;
		reg = 0;
@@ -1454,9 +1455,11 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,


	if (cfg->cbar == CBAR_TYPE_S2_TRANS) {
	if (cfg->cbar == CBAR_TYPE_S2_TRANS) {
		stage = 2;
		stage = 2;
		input_mask = (1ULL << smmu->s2_input_size) - 1;
		output_mask = (1ULL << smmu->s2_output_size) - 1;
		output_mask = (1ULL << smmu->s2_output_size) - 1;
	} else {
	} else {
		stage = 1;
		stage = 1;
		input_mask = (1ULL << smmu->s1_input_size) - 1;
		output_mask = (1ULL << smmu->s1_output_size) - 1;
		output_mask = (1ULL << smmu->s1_output_size) - 1;
	}
	}


@@ -1466,7 +1469,6 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
	if (size & ~PAGE_MASK)
	if (size & ~PAGE_MASK)
		return -EINVAL;
		return -EINVAL;


	input_mask = (1ULL << smmu->input_size) - 1;
	if ((phys_addr_t)iova & ~input_mask)
	if ((phys_addr_t)iova & ~input_mask)
		return -ERANGE;
		return -ERANGE;


@@ -1838,28 +1840,21 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
	/* ID2 */
	/* ID2 */
	id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
	id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
	size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK);
	size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK);
	smmu->s1_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size);


	/*
	/* Stage-2 input size limited due to pgd allocation (PTRS_PER_PGD) */
	 * Stage-1 output limited by stage-2 input size due to pgd
	 * allocation (PTRS_PER_PGD).
	 */
	if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
#ifdef CONFIG_64BIT
#ifdef CONFIG_64BIT
		smmu->s1_output_size = min_t(unsigned long, VA_BITS, size);
	smmu->s2_input_size = min_t(unsigned long, VA_BITS, size);
#else
#else
		smmu->s1_output_size = min(32UL, size);
	smmu->s2_input_size = min(32UL, size);
#endif
#endif
	} else {
		smmu->s1_output_size = min_t(unsigned long, PHYS_MASK_SHIFT,
					     size);
	}


	/* The stage-2 output mask is also applied for bypass */
	/* The stage-2 output mask is also applied for bypass */
	size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
	size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
	smmu->s2_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size);
	smmu->s2_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size);


	if (smmu->version == 1) {
	if (smmu->version == 1) {
		smmu->input_size = 32;
		smmu->s1_input_size = 32;
	} else {
	} else {
#ifdef CONFIG_64BIT
#ifdef CONFIG_64BIT
		size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
		size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
@@ -1867,7 +1862,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
#else
#else
		size = 32;
		size = 32;
#endif
#endif
		smmu->input_size = size;
		smmu->s1_input_size = size;


		if ((PAGE_SIZE == SZ_4K && !(id & ID2_PTFS_4K)) ||
		if ((PAGE_SIZE == SZ_4K && !(id & ID2_PTFS_4K)) ||
		    (PAGE_SIZE == SZ_64K && !(id & ID2_PTFS_64K)) ||
		    (PAGE_SIZE == SZ_64K && !(id & ID2_PTFS_64K)) ||
@@ -1878,10 +1873,14 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
		}
		}
	}
	}


	dev_notice(smmu->dev,
	if (smmu->features & ARM_SMMU_FEAT_TRANS_S1)
		   "\t%lu-bit VA, %lu-bit IPA, %lu-bit PA\n",
		dev_notice(smmu->dev, "\tStage-1: %lu-bit VA -> %lu-bit IPA\n",
		   smmu->input_size, smmu->s1_output_size,
			   smmu->s1_input_size, smmu->s1_output_size);
		   smmu->s2_output_size);

	if (smmu->features & ARM_SMMU_FEAT_TRANS_S2)
		dev_notice(smmu->dev, "\tStage-2: %lu-bit IPA -> %lu-bit PA\n",
			   smmu->s2_input_size, smmu->s2_output_size);

	return 0;
	return 0;
}
}