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

Commit bae2c2d4 authored by Robin Murphy's avatar Robin Murphy Committed by Will Deacon
Browse files

iommu/arm-smmu: Sort out coherency



Currently, we detect whether the SMMU has coherent page table walk
capability from the IDR0.CTTW field, and base our cache maintenance
decisions on that. In preparation for fixing the bogus DMA API usage,
however, we need to ensure that the DMA API agrees about this, which
necessitates deferring to the dma-coherent property in the device tree
for the final say.

As an added bonus, since systems exist where an external CTTW signal
has been tied off incorrectly at integration, allowing DT to override
it offers a neat workaround for coherency issues with such SMMUs.

Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 28c8b404
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -43,6 +43,12 @@ conditions.


** System MMU optional properties:
** System MMU optional properties:


- dma-coherent  : Present if page table walks made by the SMMU are
                  cache coherent with the CPU.

                  NOTE: this only applies to the SMMU itself, not
                  masters connected upstream of the SMMU.

- calxeda,smmu-secure-config-access : Enable proper handling of buggy
- calxeda,smmu-secure-config-access : Enable proper handling of buggy
                  implementations that always use secure access to
                  implementations that always use secure access to
                  SMMU configuration registers. In this case non-secure
                  SMMU configuration registers. In this case non-secure
+17 −3
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/iopoll.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/slab.h>
@@ -1532,6 +1533,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
	unsigned long size;
	unsigned long size;
	void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
	void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
	u32 id;
	u32 id;
	bool cttw_dt, cttw_reg;


	dev_notice(smmu->dev, "probing hardware configuration...\n");
	dev_notice(smmu->dev, "probing hardware configuration...\n");
	dev_notice(smmu->dev, "SMMUv%d with:\n", smmu->version);
	dev_notice(smmu->dev, "SMMUv%d with:\n", smmu->version);
@@ -1571,10 +1573,22 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
		dev_notice(smmu->dev, "\taddress translation ops\n");
		dev_notice(smmu->dev, "\taddress translation ops\n");
	}
	}


	if (id & ID0_CTTW) {
	/*
	 * In order for DMA API calls to work properly, we must defer to what
	 * the DT says about coherency, regardless of what the hardware claims.
	 * Fortunately, this also opens up a workaround for systems where the
	 * ID register value has ended up configured incorrectly.
	 */
	cttw_dt = of_dma_is_coherent(smmu->dev->of_node);
	cttw_reg = !!(id & ID0_CTTW);
	if (cttw_dt)
		smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
		smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
		dev_notice(smmu->dev, "\tcoherent table walk\n");
	if (cttw_dt || cttw_reg)
	}
		dev_notice(smmu->dev, "\t%scoherent table walk\n",
			   cttw_dt ? "" : "non-");
	if (cttw_dt != cttw_reg)
		dev_notice(smmu->dev,
			   "\t(IDR0.CTTW overridden by dma-coherent property)\n");


	if (id & ID0_SMS) {
	if (id & ID0_SMS) {
		u32 smr, sid, mask;
		u32 smr, sid, mask;