From a0ccb3b5994dd1a96a0a152d4bfaad3b90268b97 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_pcie_g4_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_pcie_g4_enable_interrupt() except if ls_pcie_g4_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 ee0156921ebc..e00ed73c2355 100644 --- a/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c +++ b/drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c @@ -64,6 +64,17 @@ static inline void ls_pcie_g4_pf_writel(struct ls_pcie_g4 *pcie, iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off); } +static bool ls_pcie_g4_is_bridge(struct ls_pcie_g4 *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_pcie_g4_link_up(struct mobiveil_pcie *pci) { struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci); @@ -195,7 +206,7 @@ static void ls_pcie_g4_reset(struct work_struct *work) ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; mobiveil_csr_writew(mv_pci, ctrl, PCI_BRIDGE_CONTROL); - if (!ls_pcie_g4_reinit_hw(pcie)) + if (ls_pcie_g4_reinit_hw(pcie)) return; ls_pcie_g4_enable_interrupt(pcie); @@ -245,6 +256,9 @@ static int __init ls_pcie_g4_probe(struct platform_device *pdev) return ret; } + if (!ls_pcie_g4_is_bridge(pcie)) + return -ENODEV; + ls_pcie_g4_enable_interrupt(pcie); return 0; -- cgit From 2bc5fcc38900a31408a432c22cdb76230c8d855d 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 e00ed73c2355..366adf3f1d4b 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_pcie_g4 { struct mobiveil_pcie pci; struct delayed_work dwork; int irq; + u8 rev; }; static inline u32 ls_pcie_g4_lut_readl(struct ls_pcie_g4 *pcie, u32 off) @@ -75,6 +81,15 @@ static bool ls_pcie_g4_is_bridge(struct ls_pcie_g4 *pcie) return header_type == PCI_HEADER_TYPE_BRIDGE; } +static int ls_pcie_g4_host_init(struct mobiveil_pcie *pci) +{ + struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci); + + pcie->rev = mobiveil_csr_readb(pci, PCI_REVISION_ID); + + return 0; +} + static int ls_pcie_g4_link_up(struct mobiveil_pcie *pci) { struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci); @@ -212,12 +227,34 @@ static void ls_pcie_g4_reset(struct work_struct *work) ls_pcie_g4_enable_interrupt(pcie); } +static int ls_pcie_g4_read_other_conf(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct mobiveil_pcie *pci = bus->sysdata; + struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci); + int ret; + + if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID) + ls_pcie_g4_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_pcie_g4_lut_writel(pcie, PCIE_LUT_GCR, + 1 << PCIE_LUT_GCR_RRE); + + return ret; +} + static struct mobiveil_rp_ops ls_pcie_g4_rp_ops = { .interrupt_init = ls_pcie_g4_interrupt_init, + .read_other_conf = ls_pcie_g4_read_other_conf, }; static const struct mobiveil_pab_ops ls_pcie_g4_pab_ops = { .link_up = ls_pcie_g4_link_up, + .host_init = ls_pcie_g4_host_init, }; static int __init ls_pcie_g4_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 c637de3a389b..267b83b809f7 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, }; @@ -301,6 +313,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 b8f2afe3eb468e1c8b136a52a688e9018af58b9c 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 366adf3f1d4b..80150fa2e344 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_pcie_g4_is_bridge(struct ls_pcie_g4 *pcie) return header_type == PCI_HEADER_TYPE_BRIDGE; } +static void workaround_A011451(struct ls_pcie_g4 *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_pcie_g4_host_init(struct mobiveil_pcie *pci) { struct ls_pcie_g4 *pcie = to_ls_pcie_g4(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 75374e81a463f70716f32973a530db07a0a34360 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 80150fa2e344..abbbd70c0401 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_pcie_g4_read_other_conf(struct pci_bus *bus, unsigned int devfn, struct ls_pcie_g4 *pcie = to_ls_pcie_g4(pci); int ret; - if (pcie->rev == REV_1_0 && where == PCI_VENDOR_ID) + if (pcie->rev == REV_1_0) ls_pcie_g4_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_pcie_g4_lut_writel(pcie, PCIE_LUT_GCR, 1 << PCIE_LUT_GCR_RRE); -- cgit