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

Commit 8696005a authored by Patrick Daly's avatar Patrick Daly
Browse files

iommu: arm-smmu: Update safe errata sequence



Under certain circumstatnces, TLB invalidate operations were timing
out with the previous sequence. Make an scm call to disable the SAFE
errata after the first timeout.

Change-Id: Id2ca71bb3f308396eded69ebf8fc35fe80c443da
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent b14f1bf3
Loading
Loading
Loading
Loading
+40 −13
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/secure_buffer.h>
#include <linux/of_platform.h>
#include <linux/msm-bus.h>
@@ -4446,34 +4447,60 @@ qsmmuv500_errata1_required(struct arm_smmu_domain *smmu_domain,
	return ret;
}

#define SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2
#define SCM_CONFIG_ERRATA1 0x3
static void __qsmmuv500_errata1_tlbiall(struct arm_smmu_domain *smmu_domain)
{
	struct arm_smmu_device *smmu = smmu_domain->smmu;
	struct device *dev = smmu_domain->dev;
	struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
	void __iomem *base;
	int ret;
	ktime_t cur;
	u32 val;
	struct scm_desc desc = {
		.args[0] = SCM_CONFIG_ERRATA1_CLIENT_ALL,
		.args[1] = false,
		.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL),
	};

	base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
	writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
	writel_relaxed(0, base + ARM_SMMU_CB_TLBSYNC);
	if (readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val,
				      !(val & TLBSTATUS_SACTIVE), 0, 100)) {
	if (!readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val,
				      !(val & TLBSTATUS_SACTIVE), 0, 100))
		return;

	ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_SMMU_PROGRAM,
					    SCM_CONFIG_ERRATA1),
			       &desc);
	if (ret) {
		dev_err(smmu->dev, "Calling into TZ to disable ERRATA1 failed - IOMMU hardware in bad state\n");
		BUG();
		return;
	}

	cur = ktime_get();
	trace_tlbi_throttle_start(dev, 0);

	msm_bus_noc_throttle_wa(true);

	if (readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val,
			      !(val & TLBSTATUS_SACTIVE), 0, 10000)) {
			dev_err(smmu->dev, "ERRATA1 TLBSYNC timeout");
		dev_err(smmu->dev, "ERRATA1 TLBSYNC timeout - IOMMU hardware in bad state");
		trace_tlbsync_timeout(dev, 0);
		BUG();
	}

	msm_bus_noc_throttle_wa(false);
	trace_tlbi_throttle_end(dev, ktime_us_delta(ktime_get(), cur));

		trace_tlbi_throttle_end(
				dev, ktime_us_delta(ktime_get(), cur));
	desc.args[1] = true;
	ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_SMMU_PROGRAM,
					    SCM_CONFIG_ERRATA1),
			       &desc);
	if (ret) {
		dev_err(smmu->dev, "Calling into TZ to reenable ERRATA1 failed - IOMMU hardware in bad state\n");
		BUG();
	}
}