diff mbox

[5/6] iommu/arm-smmu: support buggy implementations with invalidate-on-map

Message ID 1407891099-24641-6-git-send-email-mitchelh@codeaurora.org (mailing list archive)
State New, archived
Headers show

Commit Message

Mitchel Humpherys Aug. 13, 2014, 12:51 a.m. UTC
Add a workaround for some buggy hardware that requires a TLB invalidate
operation to occur at map time. Activate the feature with the
qcom,smmu-invalidate-on-map boolean DT property.

Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
---
 Documentation/devicetree/bindings/iommu/arm,smmu.txt |  4 ++++
 drivers/iommu/arm-smmu.c                             | 14 +++++++++++++-
 2 files changed, 17 insertions(+), 1 deletion(-)

Comments

Will Deacon Nov. 12, 2014, 6:26 p.m. UTC | #1
Hi Mitch,

On Wed, Aug 13, 2014 at 01:51:38AM +0100, Mitchel Humpherys wrote:
> Add a workaround for some buggy hardware that requires a TLB invalidate
> operation to occur at map time. Activate the feature with the
> qcom,smmu-invalidate-on-map boolean DT property.

I'm digging up an old thread here, but I've been working on a new page-table
allocator for the SMMU and looked into implementing this workaround for you
in there. When I do the TLBI on map after installing the new PTE, can I just
invalidate the range mapped by that PTE, or does it need to be a full TLBI?

Will
Mitchel Humpherys Nov. 12, 2014, 6:58 p.m. UTC | #2
On Wed, Nov 12 2014 at 10:26:43 AM, Will Deacon <will.deacon@arm.com> wrote:
> Hi Mitch,
>
> On Wed, Aug 13, 2014 at 01:51:38AM +0100, Mitchel Humpherys wrote:
>> Add a workaround for some buggy hardware that requires a TLB invalidate
>> operation to occur at map time. Activate the feature with the
>> qcom,smmu-invalidate-on-map boolean DT property.
>
> I'm digging up an old thread here, but I've been working on a new page-table
> allocator for the SMMU and looked into implementing this workaround for you
> in there. When I do the TLBI on map after installing the new PTE, can I just
> invalidate the range mapped by that PTE, or does it need to be a full TLBI?

I'm not totally sure on the history of the hardware errata but I believe
it's just the range mapped by that pte.  We use SMMU_CBn_TLBIVA in the
our smmu driver.

However, let's actually just drop this...  It's looking like the targets
we have that will use the arm-smmu driver thankfully won't need this
workaround.  Thanks for keeping this in mind though :)


-Mitch
Will Deacon Nov. 13, 2014, 9:48 a.m. UTC | #3
On Wed, Nov 12, 2014 at 06:58:17PM +0000, Mitchel Humpherys wrote:
> On Wed, Nov 12 2014 at 10:26:43 AM, Will Deacon <will.deacon@arm.com> wrote:
> > On Wed, Aug 13, 2014 at 01:51:38AM +0100, Mitchel Humpherys wrote:
> >> Add a workaround for some buggy hardware that requires a TLB invalidate
> >> operation to occur at map time. Activate the feature with the
> >> qcom,smmu-invalidate-on-map boolean DT property.
> >
> > I'm digging up an old thread here, but I've been working on a new page-table
> > allocator for the SMMU and looked into implementing this workaround for you
> > in there. When I do the TLBI on map after installing the new PTE, can I just
> > invalidate the range mapped by that PTE, or does it need to be a full TLBI?
> 
> I'm not totally sure on the history of the hardware errata but I believe
> it's just the range mapped by that pte.  We use SMMU_CBn_TLBIVA in the
> our smmu driver.
> 
> However, let's actually just drop this...  It's looking like the targets
> we have that will use the arm-smmu driver thankfully won't need this
> workaround.  Thanks for keeping this in mind though :)

Ha, damn, then I don't have a user of the shiny new quirks field I added!
I don't think I'll go as far as removing it altogether though...

Cheers,

Will
Mitchel Humpherys Nov. 14, 2014, 11:08 p.m. UTC | #4
On Thu, Nov 13 2014 at 01:48:26 AM, Will Deacon <will.deacon@arm.com> wrote:
> Ha, damn, then I don't have a user of the shiny new quirks field I added!
> I don't think I'll go as far as removing it altogether though...

I'm sure we'll be making liberal use of that field soon enough ;)



-Mitch
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index dbc1ddad79..aaebeaeda0 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -48,6 +48,10 @@  conditions.
                   aliases of secure registers have to be used during
                   SMMU configuration.
 
+- qcom,smmu-invalidate-on-map : Enable proper handling of buggy
+                  implementations that require a TLB invalidate
+                  operation to occur at map time.
+
 - clocks        : List of clocks to be used during SMMU register access. See
                   Documentation/devicetree/bindings/clock/clock-bindings.txt
                   for information about the format. For each clock specified
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 22e25f3172..73d056668b 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -389,6 +389,7 @@  struct arm_smmu_device {
 	u32				features;
 
 #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
+#define ARM_SMMU_OPT_INVALIDATE_ON_MAP (1 << 1)
 	u32				options;
 	int				version;
 
@@ -455,6 +456,7 @@  struct arm_smmu_option_prop {
 
 static struct arm_smmu_option_prop arm_smmu_options[] = {
 	{ ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" },
+	{ ARM_SMMU_OPT_INVALIDATE_ON_MAP, "qcom,smmu-invalidate-on-map" },
 	{ 0, NULL},
 };
 
@@ -1693,12 +1695,22 @@  out_unlock:
 static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
 			phys_addr_t paddr, size_t size, int prot)
 {
+	int ret;
 	struct arm_smmu_domain *smmu_domain = domain->priv;
 
 	if (!smmu_domain)
 		return -ENODEV;
 
-	return arm_smmu_handle_mapping(smmu_domain, iova, paddr, size, prot);
+	ret = arm_smmu_handle_mapping(smmu_domain, iova, paddr, size, prot);
+
+	if (!ret &&
+		(smmu_domain->smmu->options & ARM_SMMU_OPT_INVALIDATE_ON_MAP)) {
+		arm_smmu_enable_clocks(smmu_domain->smmu);
+		arm_smmu_tlb_inv_context(smmu_domain);
+		arm_smmu_disable_clocks(smmu_domain->smmu);
+	}
+
+	return ret;
 }
 
 static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,