From 0a901afa5052bc6bba850738069c2c1e5c4d6a96 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 3 Jun 2020 15:34:01 +0100 Subject: PCI: mobiveil: fix 5.7 merge errors Fix errors in the mobiveil version that was merged in 5.7 kernels: - the type of "root_bus_nr" was changed from "u8" to "char", but it is compared to values that are typed as "unsigned char". Depending whether a platform has "char" as signed or unsigned, this may not do what is intended. - ls_g4_pcie_reinit_hw() now returns a success/failure value, and follows the Linux style of return 0 on success and -ve errno on failure. However, the testing in ls_pcie_g4_reset() expects 0 on failure, so we won't call ls_ig4_pcie_enable_interrupt() except if ls_g4_pcie_reinit_hw() has failed - which is likely not what was intended. Fixes: d29ad70a813b ("PCI: mobiveil: Add PCIe Gen4 RC driver for Layerscape SoCs") Signed-off-by: Russell King --- drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c index d7b7350f02dd..1b32c37c06e3 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -53,6 +53,17 @@ static inline void ls_g4_pcie_pf_writel(struct ls_g4_pcie *pcie, iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off); } +static bool ls_g4_pcie_is_bridge(struct ls_g4_pcie *pcie) +{ + struct mobiveil_pcie *mv_pci = &pcie->pci; + u32 header_type; + + header_type = mobiveil_csr_readb(mv_pci, PCI_HEADER_TYPE); + header_type &= 0x7f; + + return header_type == PCI_HEADER_TYPE_BRIDGE; +} + static int ls_g4_pcie_link_up(struct mobiveil_pcie *pci) { struct ls_g4_pcie *pcie = to_ls_g4_pcie(pci); @@ -184,7 +195,7 @@ static void ls_g4_pcie_reset(struct work_struct *work) ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; mobiveil_csr_writew(mv_pci, ctrl, PCI_BRIDGE_CONTROL); - if (!ls_g4_pcie_reinit_hw(pcie)) + if (ls_g4_pcie_reinit_hw(pcie)) return; ls_g4_pcie_enable_interrupt(pcie); @@ -234,6 +245,9 @@ static int __init ls_g4_pcie_probe(struct platform_device *pdev) return ret; } + if (!ls_g4_pcie_is_bridge(pcie)) + return -ENODEV; + ls_g4_pcie_enable_interrupt(pcie); return 0; -- cgit From 6056bc876a7bc9f336bacfd917732674442ca2b9 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 17 Sep 2021 19:21:18 +0100 Subject: Revert "PCI: mobiveil: Remove unused readl and writel functions" This reverts commit 42d7a8dc195f99e2e99d8f38a683e0852a29f6af. --- drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c index 1b32c37c06e3..f35464653f34 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -42,6 +42,17 @@ struct ls_g4_pcie { int irq; }; +static inline u32 ls_g4_pcie_lut_readl(struct ls_g4_pcie *pcie, u32 off) +{ + return ioread32(pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off); +} + +static inline void ls_g4_pcie_lut_writel(struct ls_g4_pcie *pcie, + u32 off, u32 val) +{ + iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off); +} + static inline u32 ls_g4_pcie_pf_readl(struct ls_g4_pcie *pcie, u32 off) { return ioread32(pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off); -- cgit From f15f6cfed67170b9c3999ee4784531a145e45ee3 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Wed, 25 Sep 2019 10:21:28 +0100 Subject: PCI: mobiveil: ls_pcie_g4: add Workaround for A-011577 PCIe configuration access to non-existent function triggered SERROR interrupt exception. Workaround: Disable error reporting on AXI bus during the Vendor ID read transactions in enumeration. This ERRATA is only for LX2160A Rev1.0, and it will be fixed in Rev2.0. Signed-off-by: Hou Zhiqiang Signed-off-by: Russell King --- .../pci/controller/mobiveil/pcie-layerscape-gen4.c | 37 ++++++++++++++++++++++ .../pci/controller/mobiveil/pcie-mobiveil-host.c | 18 ++++++++++- drivers/pci/controller/mobiveil/pcie-mobiveil.h | 3 ++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c index f35464653f34..43dede26cc7c 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -22,8 +22,13 @@ #include "pcie-mobiveil.h" +#define REV_1_0 (0x10) + /* LUT and PF control registers */ #define PCIE_LUT_OFF 0x80000 +#define PCIE_LUT_GCR 0x28 +#define PCIE_LUT_GCR_RRE 0 + #define PCIE_PF_OFF 0xc0000 #define PCIE_PF_INT_STAT 0x18 #define PF_INT_STAT_PABRST BIT(31) @@ -40,6 +45,7 @@ struct ls_g4_pcie { struct mobiveil_pcie pci; struct delayed_work dwork; int irq; + u8 rev; }; static inline u32 ls_g4_pcie_lut_readl(struct ls_g4_pcie *pcie, u32 off) @@ -75,6 +81,15 @@ static bool ls_g4_pcie_is_bridge(struct ls_g4_pcie *pcie) return header_type == PCI_HEADER_TYPE_BRIDGE; } +static int ls_g4_pcie_host_init(struct mobiveil_pcie *pci) +{ + struct ls_g4_pcie *pcie = to_ls_g4_pcie(pci); + + pcie->rev = mobiveil_csr_readb(pci, PCI_REVISION_ID); + + return 0; +} + static int ls_g4_pcie_link_up(struct mobiveil_pcie *pci) { struct ls_g4_pcie *pcie = to_ls_g4_pcie(pci); @@ -212,12 +227,34 @@ static void ls_g4_pcie_reset(struct work_struct *work) ls_g4_pcie_enable_interrupt(pcie); } +static int ls_g4_pcie_read_other_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct mobiveil_pcie *pci = bus->sysdata; + struct ls_g4_pcie *pcie = to_ls_g4_pcie(pci); + int ret; + + if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID) + ls_g4_pcie_lut_writel(pcie, PCIE_LUT_GCR, + 0 << PCIE_LUT_GCR_RRE); + + ret = pci_generic_config_read(bus, devfn, where, size, val); + + if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID) + ls_g4_pcie_lut_writel(pcie, PCIE_LUT_GCR, + 1 << PCIE_LUT_GCR_RRE); + + return ret; +} + static struct mobiveil_rp_ops ls_g4_pcie_rp_ops = { .interrupt_init = ls_g4_pcie_interrupt_init, + .read_other_conf = ls_g4_pcie_read_other_conf, }; static const struct mobiveil_pab_ops ls_g4_pcie_pab_ops = { .link_up = ls_g4_pcie_link_up, + .host_init = ls_g4_pcie_host_init, }; static int __init ls_g4_pcie_probe(struct platform_device *pdev) diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c index f3547aa60140..bd6da925e546 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c @@ -76,9 +76,21 @@ static void __iomem *mobiveil_pcie_map_bus(struct pci_bus *bus, return rp->config_axi_slave_base + where; } +static int mobiveil_pcie_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct mobiveil_pcie *pcie = bus->sysdata; + struct mobiveil_root_port *rp = &pcie->rp; + + if (bus->number > to_pci_host_bridge(bus->bridge)->busnr && + rp->ops->read_other_conf) + return rp->ops->read_other_conf(bus, devfn, where, size, val); + + return pci_generic_config_read(bus, devfn, where, size, val); +} static struct pci_ops mobiveil_pcie_ops = { .map_bus = mobiveil_pcie_map_bus, - .read = pci_generic_config_read, + .read = mobiveil_pcie_config_read, .write = pci_generic_config_write, }; @@ -298,6 +310,10 @@ int mobiveil_host_init(struct mobiveil_pcie *pcie, bool reinit) value |= (PCI_CLASS_BRIDGE_PCI << 16); mobiveil_csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS); + /* Platform specific host init */ + if (pcie->ops->host_init) + return pcie->ops->host_init(pcie); + return 0; } diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.h b/drivers/pci/controller/mobiveil/pcie-mobiveil.h index 6082b8afbc31..ec5f1104a9e4 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h @@ -146,6 +146,8 @@ struct mobiveil_pcie; struct mobiveil_rp_ops { int (*interrupt_init)(struct mobiveil_pcie *pcie); + int (*read_other_conf)(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val); }; struct mobiveil_root_port { @@ -161,6 +163,7 @@ struct mobiveil_root_port { struct mobiveil_pab_ops { int (*link_up)(struct mobiveil_pcie *pcie); + int (*host_init)(struct mobiveil_pcie *pcie); }; struct mobiveil_pcie { -- cgit From 686326ba48bb0ec855ab9bc191fa3e437e8ff462 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Tue, 6 Nov 2018 10:14:57 +0800 Subject: PCI: mobiveil: ls_pcie_g4: add Workaround for A-011451 When LX2 PCIe controller is sending multiple split completions and ACK latency expires indicating that ACK should be send at priority. But because of large number of split completions and FC update DLLP, the controller does not give priority to ACK transmission. This results into ACK latency timer timeout error at the link partner and the pending TLPs are replayed by the link partner again. Workaround: 1. Reduce the ACK latency timeout value to a very small value. 2. Restrict the number of completions from the LX2 PCIe controller to 1, by changing the Max Read Request Size (MRRS) of link partner to the same value as Max Packet size (MPS). This patch implemented part 1, the part 2 can be set by kernel parameter 'pci=pcie_bus_perf' This ERRATA is only for LX2160A Rev1.0, and it will be fixed in Rev2.0. Signed-off-by: Hou Zhiqiang [fixed up for mainline -- rmk] Signed-off-by: Russell King --- drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c | 15 +++++++++++++++ drivers/pci/controller/mobiveil/pcie-mobiveil.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c index 43dede26cc7c..d07cddb9c404 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -81,12 +81,27 @@ static bool ls_g4_pcie_is_bridge(struct ls_g4_pcie *pcie) return header_type == PCI_HEADER_TYPE_BRIDGE; } +static void workaround_A011451(struct ls_g4_pcie *pcie) +{ + struct mobiveil_pcie *mv_pci = &pcie->pci; + u32 val; + + /* Set ACK latency timeout */ + val = mobiveil_csr_readl(mv_pci, GPEX_ACK_REPLAY_TO); + val &= ~(ACK_LAT_TO_VAL_MASK << ACK_LAT_TO_VAL_SHIFT); + val |= (4 << ACK_LAT_TO_VAL_SHIFT); + mobiveil_csr_writel(mv_pci, val, GPEX_ACK_REPLAY_TO); +} + static int ls_g4_pcie_host_init(struct mobiveil_pcie *pci) { struct ls_g4_pcie *pcie = to_ls_g4_pcie(pci); pcie->rev = mobiveil_csr_readb(pci, PCI_REVISION_ID); + if (pcie->rev == REV_1_0) + workaround_A011451(pcie); + return 0; } diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil.h b/drivers/pci/controller/mobiveil/pcie-mobiveil.h index ec5f1104a9e4..e03cc8e1399a 100644 --- a/drivers/pci/controller/mobiveil/pcie-mobiveil.h +++ b/drivers/pci/controller/mobiveil/pcie-mobiveil.h @@ -86,6 +86,10 @@ #define PAB_AXI_AMAP_PEX_WIN_H(win) PAB_REG_ADDR(0x0bac, win) #define PAB_INTP_AXI_PIO_CLASS 0x474 +#define GPEX_ACK_REPLAY_TO 0x438 +#define ACK_LAT_TO_VAL_MASK 0x1fff +#define ACK_LAT_TO_VAL_SHIFT 0 + #define PAB_PEX_AMAP_CTRL(win) PAB_REG_ADDR(0x4ba0, win) #define AMAP_CTRL_EN_SHIFT 0 #define AMAP_CTRL_TYPE_SHIFT 1 -- cgit From 017a20b3b1b344b949473fc09edbe626aa325dd4 Mon Sep 17 00:00:00 2001 From: Xiaowei Bao Date: Wed, 25 Sep 2019 22:55:17 +0100 Subject: PCI: mobiveil: ls_pcie_g4: fix SError when accessing config space While the Mellanox driver is binding, the following kernel panic occurred: SError Interrupt on CPU1, code 0xbf000002 -- SError CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.3.0+ #392 Hardware name: SolidRun LX2160A COM express type 7 module (DT) pstate: 60400085 (nZCv daIf +PAN -UAO) pc : pci_generic_config_read+0xb0/0xc0 lr : pci_generic_config_read+0x1c/0xc0 sp : ffffff8010f9baf0 x29: ffffff8010f9baf0 x28: ffffff8010d620a0 x27: ffffff8010d79000 x26: ffffff8010d62000 x25: ffffff8010cb06d4 x24: 0000000000000000 x23: ffffff8010e499b8 x22: ffffff8010f9bbaf x21: 0000000000000000 x20: ffffffe2eda11800 x19: ffffff8010f62158 x18: ffffff8010bdede0 x17: ffffff8010bdede8 x16: ffffff8010b96970 x15: ffffffffffffffff x14: ffffffffff000000 x13: ffffffffffffffff x12: 0000000000000030 x11: 0101010101010101 x10: 7f7f7f7f7f7f7f7f x9 : 2dff716475687163 x8 : ffffffffffffffff x7 : fefefefefefefefe x6 : 0000000000000000 x5 : 0000000000000000 x4 : ffffff8010f9bb6c x3 : 0000000000000001 x2 : 0000000000000003 x1 : 0000000000000000 x0 : 0000000000000000 Kernel panic - not syncing: Asynchronous SError Interrupt CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.3.0+ #392 Hardware name: SolidRun LX2160A COM express type 7 module (DT) Call trace: dump_backtrace+0x0/0x120 show_stack+0x14/0x1c dump_stack+0x9c/0xc0 panic+0x148/0x34c print_tainted+0x0/0xa8 arm64_serror_panic+0x74/0x80 do_serror+0x8c/0x13c el1_error+0xbc/0x160 pci_generic_config_read+0xb0/0xc0 pci_bus_read_config_byte+0x64/0x90 pci_read_config_byte+0x40/0x48 pci_assign_irq+0x34/0xc8 pci_device_probe+0x28/0x148 really_probe+0x1c4/0x2d0 driver_probe_device+0x58/0xfc device_driver_attach+0x68/0x70 __driver_attach+0x94/0xdc bus_for_each_dev+0x50/0xa0 driver_attach+0x20/0x28 bus_add_driver+0x14c/0x200 driver_register+0x6c/0x124 __pci_register_driver+0x48/0x50 mlx4_init+0x154/0x180 do_one_initcall+0x30/0x250 kernel_init_freeable+0x23c/0x32c kernel_init+0x10/0xfc ret_from_fork+0x10/0x18 SMP: stopping secondary CPUs Kernel Offset: disabled CPU features: 0x0002,21006008 Memory Limit: none which appears to be due to: pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); in pci_assign_irq(). Avoiding that access just moves the SError later (e.g. while accessing the command register in pci_enable_device() instead.) This patch resolves the SError problem by preventing configuration accesses triggering a SError interrupt. Reported-by: Russell King Tested-by: Russell King Signed-off-by: Xiaowei Bao [description modified -- rmk] Signed-off-by: Russell King --- drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c index d07cddb9c404..7348a4cd0901 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -249,13 +249,13 @@ static int ls_g4_pcie_read_other_conf(struct pci_bus *bus, unsigned int devfn, struct ls_g4_pcie *pcie = to_ls_g4_pcie(pci); int ret; - if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID) + if (pcie->rev == REV_1_0) ls_g4_pcie_lut_writel(pcie, PCIE_LUT_GCR, 0 << PCIE_LUT_GCR_RRE); ret = pci_generic_config_read(bus, devfn, where, size, val); - if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID) + if (pcie->rev == REV_1_0) ls_g4_pcie_lut_writel(pcie, PCIE_LUT_GCR, 1 << PCIE_LUT_GCR_RRE); -- cgit