From: Tirumalesh Chalamarla <[email protected]>

  This patch implements Cavium ThunderX erratum 28168.

  PCI requires stores complete in order. Due to erratum #28168
  PCI-inbound MSI-X store to the interrupt controller are delivered
  to the interrupt controller before older PCI-inbound memory stores
  are committed.
  Doing a sync on SMMU will make sure all prior data transfers are
  completed before invoking ISR.

Signed-off-by: Tirumalesh Chalamarla <[email protected]>
Signed-off-by: Geetha sowjanya <[email protected]>
---
 arch/arm64/Kconfig                  |   11 +++++++++++
 arch/arm64/Kconfig.platforms        |    1 +
 arch/arm64/include/asm/cpufeature.h |    3 ++-
 arch/arm64/kernel/cpu_errata.c      |   16 ++++++++++++++++
 drivers/iommu/arm-smmu.c            |   24 ++++++++++++++++++++++++
 drivers/irqchip/irq-gic-common.h    |    1 +
 drivers/irqchip/irq-gic-v3.c        |   19 +++++++++++++++++++
 7 files changed, 74 insertions(+), 1 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 30398db..751972c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -474,6 +474,17 @@ config CAVIUM_ERRATUM_27456
 
          If unsure, say Y.
 
+config CAVIUM_ERRATUM_28168
+       bool "Cavium erratum 28168: Make sure DMA data transfer is done before 
MSIX"
+       depends on ARCH_THUNDER && ARM64
+       default y
+       help
+        Due to erratum #28168 PCI-inbound MSI-X store to the interrupt
+        controller are delivered to the interrupt controller before older
+        PCI-inbound memory stores are committed. Doing a sync on SMMU
+        will make sure all prior data transfers are done before invoking ISR.
+
+        If unsure, say Y.
 endmenu
 
 
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index cfbdf02..2ac4ac6 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -185,6 +185,7 @@ config ARCH_SPRD
 
 config ARCH_THUNDER
        bool "Cavium Inc. Thunder SoC Family"
+       select IRQ_PREFLOW_FASTEOI
        help
          This enables support for Cavium's Thunder Family of SoCs.
 
diff --git a/arch/arm64/include/asm/cpufeature.h 
b/arch/arm64/include/asm/cpufeature.h
index 758d74f..821fc3c 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -40,8 +40,9 @@
 #define ARM64_HAS_32BIT_EL0                    13
 #define ARM64_HYP_OFFSET_LOW                   14
 #define ARM64_MISMATCHED_CACHE_LINE_SIZE       15
+#define ARM64_WORKAROUND_CAVIUM_28168          16
 
-#define ARM64_NCAPS                            16
+#define ARM64_NCAPS                            17
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 0150394..0841a12 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -122,6 +122,22 @@ static void cpu_enable_trap_ctr_access(void *__unused)
                MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
        },
 #endif
+#ifdef CONFIG_CAVIUM_ERRATUM_28168
+       {
+       /* Cavium ThunderX, T88 pass 1.x - 2.1 */
+               .desc = "Cavium erratum 28168",
+               .capability = ARM64_WORKAROUND_CAVIUM_28168,
+               MIDR_RANGE(MIDR_THUNDERX, 0x00,
+                          (1 << MIDR_VARIANT_SHIFT) | 1),
+       },
+       {
+       /* Cavium ThunderX, T81 pass 1.0 */
+               .desc = "Cavium erratum 28168",
+               .capability = ARM64_WORKAROUND_CAVIUM_28168,
+               MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
+       },
+#endif
+
        {
                .desc = "Mismatched cache line size",
                .capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index c841eb7..1b4555c 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -570,6 +570,30 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device 
*smmu)
        }
 }
 
+/*
+ * Cavium ThunderX erratum 28168
+ *
+ * Due to erratum #28168 PCI-inbound MSI-X store to the interrupt
+ * controller are delivered to the interrupt controller before older
+ * PCI-inbound memory stores are committed. Doing a sync on SMMU
+ * will make sure all prior data transfers are completed before
+ * invoking ISR.
+ *
+ */
+void cavium_arm_smmu_tlb_sync(struct device *dev)
+{
+       struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+       struct arm_smmu_device *smmu;
+
+       smmu = fwspec_smmu(fwspec);
+       if (!smmu)
+               return;
+       __arm_smmu_tlb_sync(smmu);
+
+}
+EXPORT_SYMBOL(cavium_arm_smmu_tlb_sync);
+
+
 static void arm_smmu_tlb_sync(void *cookie)
 {
        struct arm_smmu_domain *smmu_domain = cookie;
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index 205e5fd..4e88f55 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -38,4 +38,5 @@ void gic_enable_quirks(u32 iidr, const struct gic_quirk 
*quirks,
 
 void gic_set_kvm_info(const struct gic_kvm_info *info);
 
+void cavium_arm_smmu_tlb_sync(struct device *dev);
 #endif /* _IRQ_GIC_COMMON_H */
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 19d642e..723cebe 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -28,6 +28,8 @@
 #include <linux/of_irq.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
 
 #include <linux/irqchip.h>
 #include <linux/irqchip/arm-gic-common.h>
@@ -736,6 +738,20 @@ static inline void gic_cpu_pm_init(void) { }
 
 #define GIC_ID_NR              (1U << gic_data.rdists.id_bits)
 
+/*
+ * Due to #28168 erratum in ThunderX,
+ * we need to make sure DMA data transfer is done before MSIX.
+ */
+static void cavium_irq_perflow_handler(struct irq_data *data)
+{
+       struct pci_dev *pdev;
+
+       pdev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data));
+       if ((pdev->vendor != 0x177d) &&
+                       ((pdev->device & 0xA000) != 0xA000))
+               cavium_arm_smmu_tlb_sync(&pdev->dev);
+}
+
 static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                              irq_hw_number_t hw)
 {
@@ -773,6 +789,9 @@ static int gic_irq_domain_map(struct irq_domain *d, 
unsigned int irq,
                        return -EPERM;
                irq_domain_set_info(d, irq, hw, chip, d->host_data,
                                    handle_fasteoi_irq, NULL, NULL);
+               if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_28168))
+                       __irq_set_preflow_handler(irq,
+                                                 cavium_irq_perflow_handler);
        }
 
        return 0;
-- 
1.7.1

_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to