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

Commit b94df6fa authored by Robin Murphy's avatar Robin Murphy Committed by Patrick Daly
Browse files

iommu/arm-smmu: Support v7s context format



Fill in the last bits of machinery required to drive a stage 1 context
bank in v7 short descriptor format. By default we'll prefer to use it
only when the CPUs are also using the same format, such that we're
guaranteed that everything will be strictly 32-bit.

Change-Id: I49925ef37271707338ee84f179ac6bc6cb8289e5
Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Git-commit: 6070529b
Git-repo: https://source.codeaurora.org/quic/la/kernel/msm-4.4


Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent 2a637601
Loading
Loading
Loading
Loading
+46 −23
Original line number Diff line number Diff line
@@ -248,7 +248,6 @@
#define SCTLR_AFE			(1 << 2)
#define SCTLR_TRE			(1 << 1)
#define SCTLR_M				(1 << 0)
#define SCTLR_EAE_SBOP			(SCTLR_AFE | SCTLR_TRE)

#define ARM_MMU500_ACTLR_CPRE		(1 << 1)

@@ -1431,7 +1430,7 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
				       struct io_pgtable_cfg *pgtbl_cfg)
{
	u32 reg;
	u32 reg, reg2;
	u64 reg64;
	bool stage1;
	struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
@@ -1474,14 +1473,22 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,

	/* TTBRs */
	if (stage1) {
		u16 asid = ARM_SMMU_CB_ASID(smmu, cfg);

		if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
			reg = pgtbl_cfg->arm_v7s_cfg.ttbr[0];
			writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0);
			reg = pgtbl_cfg->arm_v7s_cfg.ttbr[1];
			writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1);
			writel_relaxed(asid, cb_base + ARM_SMMU_CB_CONTEXTIDR);
		} else {
			reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];

		reg64 |= ((u64)ARM_SMMU_CB_ASID(smmu, cfg)) << TTBRn_ASID_SHIFT;
			reg64 |= (u64)asid << TTBRn_ASID_SHIFT;
			writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0);

			reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1];
		reg64 |= ((u64)ARM_SMMU_CB_ASID(smmu, cfg)) << TTBRn_ASID_SHIFT;
			reg64 |= (u64)asid << TTBRn_ASID_SHIFT;
			writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR1);
		}
	} else {
		reg64 = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
		writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0);
@@ -1489,29 +1496,36 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,

	/* TTBCR */
	if (stage1) {
		if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
			reg = pgtbl_cfg->arm_v7s_cfg.tcr;
			reg2 = 0;
		} else {
			reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr;
		writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
		if (smmu->version > ARM_SMMU_V1) {
			reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32;
			reg |= TTBCR2_SEP_UPSTREAM;
			writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2);
			reg2 = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32;
			reg2 |= TTBCR2_SEP_UPSTREAM;
		}
		if (smmu->version > ARM_SMMU_V1)
			writel_relaxed(reg2, cb_base + ARM_SMMU_CB_TTBCR2);
	} else {
		reg = pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
		writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
	}
	writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);

	/* MAIRs (stage-1 only) */
	if (stage1) {
		if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
			reg = pgtbl_cfg->arm_v7s_cfg.prrr;
			reg2 = pgtbl_cfg->arm_v7s_cfg.nmrr;
		} else {
			reg = pgtbl_cfg->arm_lpae_s1_cfg.mair[0];
			reg2 = pgtbl_cfg->arm_lpae_s1_cfg.mair[1];
		}
		writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0);
		reg = pgtbl_cfg->arm_lpae_s1_cfg.mair[1];
		writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR1);
		writel_relaxed(reg2, cb_base + ARM_SMMU_CB_S1_MAIR1);
	}

	/* SCTLR */
	reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_EAE_SBOP;

	reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE;
	if (!(smmu_domain->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) ||
	    !stage1)
		reg |= SCTLR_M;
@@ -1631,6 +1645,11 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
	 */
	if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH32_L)
		cfg->fmt = ARM_SMMU_CTX_FMT_AARCH32_L;
	if (IS_ENABLED(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) &&
	    !IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_ARM_LPAE) &&
	    (smmu->features & ARM_SMMU_FEAT_FMT_AARCH32_S) &&
	    (smmu_domain->stage == ARM_SMMU_DOMAIN_S1))
		cfg->fmt = ARM_SMMU_CTX_FMT_AARCH32_S;
	if ((IS_ENABLED(CONFIG_64BIT) || cfg->fmt == ARM_SMMU_CTX_FMT_NONE) &&
	    (smmu->features & (ARM_SMMU_FEAT_FMT_AARCH64_64K |
			       ARM_SMMU_FEAT_FMT_AARCH64_16K |
@@ -1650,10 +1669,14 @@ 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;
		} else {
		} else if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_L) {
			fmt = ARM_32_LPAE_S1;
			ias = min(ias, 32UL);
			oas = min(oas, 40UL);
		} else {
			fmt = ARM_V7S;
			ias = min(ias, 32UL);
			oas = min(oas, 32UL);
		}
		break;
	case ARM_SMMU_DOMAIN_NESTED: