From: Sunil Goutham <sgout...@marvell.com>

commit cff5676836acd0f92cc7b72b8965f1201ff42278 from
g...@git.assembla.com:cavium/WindRiver.linux.git

This patch adds workaround for config space write's
byte enables issue in the PEM generated TLPs.

Issue: In the TLPs generated by PEM for config space
writes to offsets > 8, byte enables are zeros. So
end-point ignores these writes.

Fix: Use RAS error injection feature to change byte
enables in TLP to correct values.

Change-Id: Ic98a085b4b4ffa0da46c6d052024437474e05c13
Signed-off-by: Sunil Goutham <sgout...@marvell.com>
Reviewed-on: https://sj1git1.cavium.com/7379
Reviewed-by: Sunil Kovvuri Goutham <sunil.gout...@cavium.com>
Tested-by: Sunil Kovvuri Goutham <sunil.gout...@cavium.com>
[RQ: This patch is ported from SDK10, branch is linux-4.18.20-devel.]
Signed-off-by: Ruiqiang Hao <ruiqiang....@windriver.com>
---
 drivers/pci/controller/pci-octeontx2-pem.c | 116 ++++++++++++++++++++-
 1 file changed, 114 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/pci-octeontx2-pem.c 
b/drivers/pci/controller/pci-octeontx2-pem.c
index e0c53230b0c5..85cb892d2e6b 100644
--- a/drivers/pci/controller/pci-octeontx2-pem.c
+++ b/drivers/pci/controller/pci-octeontx2-pem.c
@@ -23,8 +23,17 @@
 /* Bridge config space reads/writes done using
  * these registers.
  */
-#define PEM_CFG_WR     0x18
-#define PEM_CFG_RD     0x20
+#define PEM_CFG_WR                     0x18
+#define PEM_CFG_RD                     0x20
+
+#define PCIERC_RAS_EINJ_EN             0x348
+#define PCIERC_RAS_EINJ_CTL6CMPP0      0x364
+#define PCIERC_RAS_EINJ_CTL6CMPV0      0x374
+#define PCIERC_RAS_EINJ_CTL6CHGP1      0x388
+#define PCIERC_RAS_EINJ_CTL6CHGV1      0x398
+#define PCIERC_RAS_EINJ_CTL6PE         0x3A4
+#define PCIERC_RASDP_EP_CTL            0x420
+#define PCIERC_RASDP_DE_ME             0x440
 
 struct octeontx2_pem_pci {
        u32             ea_entry[3];
@@ -261,6 +270,107 @@ static int octeontx2_pem_bridge_write(struct pci_bus 
*bus, unsigned int devfn,
        return PCIBIOS_SUCCESSFUL;
 }
 
+static void octeontx2_be_workaround_init(struct pci_bus *bus)
+{
+       u32 val;
+
+       /* Ensure that PCIERC_RASDP_DE_ME.ERR_MODE is set to 0 */
+       octeontx2_pem_bridge_read(bus, 0x00,
+                                 PCIERC_RASDP_DE_ME, 4, &val);
+       octeontx2_pem_bridge_write(bus, 0x00,
+                                  PCIERC_RASDP_DE_ME, 4, val & ~BIT(0));
+
+       /* Disable parity error correction */
+       octeontx2_pem_bridge_read(bus, 0x00,
+                                 PCIERC_RASDP_EP_CTL, 4, &val);
+       octeontx2_pem_bridge_write(bus, 0x00,
+                                  PCIERC_RASDP_EP_CTL, 4, val | BIT(0));
+
+       /* Enable RAS to change header
+        * PCIERC_RAS_EINJ_EN.EINJ0_EN.set(0);
+        * PCIERC_RAS_EINJ_EN.EINJ1_EN.set(0);
+        * PCIERC_RAS_EINJ_EN.EINJ2_EN.set(0);
+        * PCIERC_RAS_EINJ_EN.EINJ3_EN.set(0);
+        * PCIERC_RAS_EINJ_EN.EINJ4_EN.set(0);
+        * PCIERC_RAS_EINJ_EN.EINJ5_EN.set(0);
+        * PCIERC_RAS_EINJ_EN.EINJ6_EN.set(1);
+        */
+       octeontx2_pem_bridge_write(bus, 0x00,
+                                  PCIERC_RAS_EINJ_EN, 4, BIT(6));
+
+       /* Set up error injection count to 1 and
+        * set type to TLP and INV_CNTRL must be 0.
+        */
+       octeontx2_pem_bridge_write(bus, 0x00,
+                                  PCIERC_RAS_EINJ_CTL6PE, 4, 1);
+
+       /* Set up compare point to compare Fmt/Type field in TLP Header word 0
+        * Where bits[31:0] = tlp_dw[7:0], tlp_dw[15:18],
+        * tlp_dw[23:16], tlp_dw[31:24].
+        *
+        * PCIERC_RAS_EINJ_CTL6CMPP0.EINJ6_COM_PT_H0.set(32'hfe00_0000);
+        */
+       octeontx2_pem_bridge_write(bus, 0x00,
+                                  PCIERC_RAS_EINJ_CTL6CMPP0, 4, 0xFE000000);
+
+       /* Set up the value to compare against,
+        * look for Fmt/Type to indicate CfgRd/CfWr - both type 0 or 1.
+        * Where bits[31:0] = tlp_dw[7:0], tlp_dw[15:18],
+        * tlp_dw[23:16], tlp_dw[31:24]
+        */
+       octeontx2_pem_bridge_write(bus, 0x00,
+                                  PCIERC_RAS_EINJ_CTL6CMPV0, 4, 0x44000000);
+
+       /* Set up the bit position in TLP Header word 1 to replace
+        * (LBE is bits 7:4, FBE is bits 3:0).
+        *
+        * Where bits[31:0] = tlp_dw[7:0], tlp_dw[15:18],
+        * tlp_dw[23:16], tlp_dw[31:24].
+        */
+       octeontx2_pem_bridge_write(bus, 0x00,
+                                  PCIERC_RAS_EINJ_CTL6CHGP1, 4, 0xFF);
+}
+
+static void octeontx2_be_workaround(struct pci_bus *bus, int where,
+                                   int size, u32 val)
+{
+       struct pci_dev *rc;
+       u32 reg, be = 0;
+
+       rc = pci_get_domain_bus_and_slot(pci_domain_nr(bus), 0, 0);
+
+       /* Setup RAS to inject one error */
+       octeontx2_be_workaround_init(rc->bus);
+
+       /* Get byte-enable to inject into TLP */
+       where &= 0x03;
+       switch (size) {
+       case 1:
+               be = 1 << where;
+               break;
+       case 2:
+               be = 3 << where;
+               break;
+       case 4:
+               be = 0xF;
+       }
+
+       /* Set up the value you'd like to use for FBE (Cfg ops must have LBE==0)
+        * Where bits[31:0] = tlp_dw[7:0], tlp_dw[15:18],
+        * tlp_dw[23:16], tlp_dw[31:24].
+        */
+       octeontx2_pem_bridge_write(rc->bus, 0x00,
+                                  PCIERC_RAS_EINJ_CTL6CHGV1, 4, be);
+
+       /* To be absolutely sure that the ECAM access does not get to
+        * the MAC prior to the PCIERC register updates that are setting
+        * up for that ECAM access, SW should read back one of the
+        * registers it wrote before launching the ECAM access.
+        */
+       octeontx2_pem_bridge_read(rc->bus, 0x00,
+                                 PCIERC_RAS_EINJ_CTL6CHGV1, 4, &reg);
+}
+
 static int octeontx2_pem_config_write(struct pci_bus *bus, unsigned int devfn,
                                    int where, int size, u32 val)
 {
@@ -276,6 +386,8 @@ static int octeontx2_pem_config_write(struct pci_bus *bus, 
unsigned int devfn,
        if (bus->number == cfg->busr.start)
                return octeontx2_pem_bridge_write(bus, devfn, where, size, val);
 
+       octeontx2_be_workaround(bus, where, size, val);
+
        return pci_generic_config_write(bus, devfn, where, size, val);
 }
 
-- 
2.29.2

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#10112): 
https://lists.yoctoproject.org/g/linux-yocto/message/10112
Mute This Topic: https://lists.yoctoproject.org/mt/84169730/21656
Group Owner: linux-yocto+ow...@lists.yoctoproject.org
Unsubscribe: https://lists.yoctoproject.org/g/linux-yocto/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to