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

Commit ef6c1dc3 authored by Patrick Daly's avatar Patrick Daly
Browse files

iommu/arm-smmu: support mapping before enabling S1 translations



For performance reasons there are clients who would like to move
from stage 1 bypass to stage 1 enabled without having to stop their
device.

Currently clients need to stop their device because they have to
create the required stage 1 mappings before re-enabling the device.
Add the new DOMAIN_ATTR_EARLY_MAP domain attribute to allow clients
to create stage 1 mappings after attaching but before enabling
stage 1 translations.

If the clients set the DOMAIN_ATTR_EARLY_MAP domain attribute to 1
before attaching then then once they attach the SMMU driver won't
enable stage 1 translations. This gives the client the opportunity to
create the required early mappings (for example using iommu_map).
When the client has finished creating the necessary early mappings
the client can then set the DOMAIN_ATTR_EARLY_MAP domain attribute
to 0, this will in turn enable stage 1 translations.

Change-Id: I9e95c5d2130f1d371e201eac69dec140cc773b1f
Signed-off-by: default avatarLiam Mark <lmark@codeaurora.org>
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent ef8bd289
Loading
Loading
Loading
Loading
+50 −2
Original line number Diff line number Diff line
@@ -548,6 +548,8 @@ static void arm_smmu_unassign_table(struct arm_smmu_domain *smmu_domain);
static int arm_smmu_arch_init(struct arm_smmu_device *smmu);
static void arm_smmu_arch_device_reset(struct arm_smmu_device *smmu);

static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain);

static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
{
	return container_of(dom, struct arm_smmu_domain, domain);
@@ -1424,7 +1426,9 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,

	/* SCTLR */
	reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE;
	if (!(smmu_domain->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) ||

	if ((!(smmu_domain->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) &&
	     !(smmu_domain->attributes & (1 << DOMAIN_ATTR_EARLY_MAP))) ||
								!stage1)
		reg |= SCTLR_M;
	if (stage1)
@@ -2578,6 +2582,11 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
				   (1 << DOMAIN_ATTR_USE_UPSTREAM_HINT));
		ret = 0;
		break;
	case DOMAIN_ATTR_EARLY_MAP:
		*((int *)data) = !!(smmu_domain->attributes
				    & (1 << DOMAIN_ATTR_EARLY_MAP));
		ret = 0;
		break;
	default:
		return -ENODEV;
	}
@@ -2716,6 +2725,24 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
				1 << DOMAIN_ATTR_USE_UPSTREAM_HINT;
		ret = 0;
		break;
	case DOMAIN_ATTR_EARLY_MAP: {
		int early_map = *((int *)data);

		ret = 0;
		if (early_map) {
			smmu_domain->attributes |=
						1 << DOMAIN_ATTR_EARLY_MAP;
		} else {
			if (smmu_domain->smmu)
				ret = arm_smmu_enable_s1_translations(
								smmu_domain);

			if (!ret)
				smmu_domain->attributes &=
					~(1 << DOMAIN_ATTR_EARLY_MAP);
		}
		break;
	}
	default:
		ret = -ENODEV;
	}
@@ -2738,6 +2765,27 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
	return iommu_fwspec_add_ids(dev, &fwid, 1);
}

static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain)
{
	struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
	struct arm_smmu_device *smmu = smmu_domain->smmu;
	void __iomem *cb_base;
	u32 reg;
	int ret;

	cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
	ret = arm_smmu_power_on(smmu->pwr);
	if (ret)
		return ret;

	reg = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR);
	reg |= SCTLR_M;

	writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR);
	arm_smmu_power_off(smmu->pwr);
	return ret;
}

static void arm_smmu_trigger_fault(struct iommu_domain *domain,
					unsigned long flags)
{
+2 −0
Original line number Diff line number Diff line
@@ -69,6 +69,8 @@ static const char *iommu_debug_attr_to_string(enum iommu_attr attr)
		return "DOMAIN_ATTR_S1_BYPASS";
	case DOMAIN_ATTR_FAST:
		return "DOMAIN_ATTR_FAST";
	case DOMAIN_ATTR_EARLY_MAP:
		return "DOMAIN_ATTR_EARLY_MAP";
	default:
		return "Unknown attr!";
	}
+1 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ enum iommu_attr {
	DOMAIN_ATTR_FAST,
	DOMAIN_ATTR_PGTBL_INFO,
	DOMAIN_ATTR_USE_UPSTREAM_HINT,
	DOMAIN_ATTR_EARLY_MAP,
	DOMAIN_ATTR_MAX,
};