From ceae51b1cc0e5a5b42999274657bd55606193661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jari=20H=C3=A4m=C3=A4l=C3=A4inen?= Date: Sun, 22 Nov 2020 15:24:49 +0200 Subject: [PATCH] nuumio: pcie: Reimplement rockchip PCIe bus scan delay Reimplementation of my old Rockchip PCIe bus scan delay patch for kernels >= 5.9. Delay may fix panix with some PCIe devices, like LSI SAS 9201-8i with SAS2008 chipset in my case. Crash dump (customized Manjaro kernel before this patch): [ 1.229856] SError Interrupt on CPU4, code 0xbf000002 -- SError [ 1.229860] CPU: 4 PID: 1 Comm: swapper/0 Not tainted 5.9.9-2.0-MANJARO-ARM #1 [ 1.229862] Hardware name: Pine64 RockPro64 v2.1 (DT) [ 1.229864] pstate: 60000085 (nZCv daIf -PAN -UAO BTYPE=--) [ 1.229866] pc : rockchip_pcie_rd_conf+0xb4/0x270 [ 1.229868] lr : rockchip_pcie_rd_conf+0x1b4/0x270 [ 1.229870] sp : ffff80001004b850 [ 1.229872] x29: ffff80001004b850 x28: 0000000000000001 [ 1.229877] x27: 0000000000000000 x26: ffff00007a795000 [ 1.229882] x25: ffff00007a7910b0 x24: 0000000000000000 [ 1.229887] x23: 0000000000000000 x22: ffff00007b3a4380 [ 1.229891] x21: ffff80001004b8c4 x20: 0000000000000004 [ 1.229895] x19: 0000000000100000 x18: 0000000000000020 [ 1.229900] x17: 0000000000000001 x16: 0000000000000019 [ 1.229904] x15: ffff00007b222fd8 x14: ffffffffffffffff [ 1.229908] x13: ffff00007a79ba1c x12: ffff00007a79b290 [ 1.229912] x11: 0101010101010101 x10: 7f7f7f7f7f7f7f7f [ 1.229917] x9 : ff72646268756463 x8 : 0000000000000391 [ 1.229921] x7 : ffff80001004b880 x6 : 0000000000000001 [ 1.229925] x5 : 0000000000000000 x4 : 0000000000000000 [ 1.229930] x3 : 0000000000c00008 x2 : 000000000080000a [ 1.229934] x1 : 0000000000000000 x0 : ffff800014000000 [ 1.229939] Kernel panic - not syncing: Asynchronous SError Interrupt [ 1.229942] CPU: 4 PID: 1 Comm: swapper/0 Not tainted 5.9.9-2.0-MANJARO-ARM #1 [ 1.229944] Hardware name: Pine64 RockPro64 v2.1 (DT) [ 1.229946] Call trace: [ 1.229948] dump_backtrace+0x0/0x1d0 [ 1.229949] show_stack+0x18/0x24 [ 1.229951] dump_stack+0xc0/0x118 [ 1.229953] panic+0x148/0x320 [ 1.229955] nmi_panic+0x8c/0x90 [ 1.229956] arm64_serror_panic+0x78/0x84 [ 1.229958] do_serror+0x15c/0x160 [ 1.229960] el1_error+0x84/0x100 [ 1.229962] rockchip_pcie_rd_conf+0xb4/0x270 [ 1.229964] pci_bus_read_config_dword+0x6c/0xd0 [ 1.229966] pci_bus_generic_read_dev_vendor_id+0x34/0x1b0 [ 1.229968] pci_scan_single_device+0xa4/0x144 [ 1.229970] pci_scan_slot+0x40/0x12c [ 1.229972] pci_scan_child_bus_extend+0x58/0x34c [ 1.229974] pci_scan_bridge_extend+0x310/0x590 [ 1.229976] pci_scan_child_bus_extend+0x210/0x34c [ 1.229978] pci_scan_root_bus_bridge+0x68/0xdc [ 1.229980] pci_host_probe+0x18/0xc4 [ 1.229981] rockchip_pcie_probe+0x204/0x330 [ 1.229984] platform_drv_probe+0x54/0xb0 [ 1.229985] really_probe+0xe8/0x500 [ 1.229987] driver_probe_device+0xd8/0xf0 [ 1.229989] device_driver_attach+0xc0/0xcc [ 1.229991] __driver_attach+0xa4/0x170 [ 1.229993] bus_for_each_dev+0x70/0xc0 [ 1.229994] driver_attach+0x24/0x30 [ 1.229996] bus_add_driver+0x140/0x234 [ 1.229998] driver_register+0x78/0x130 [ 1.230000] __platform_driver_register+0x4c/0x60 [ 1.230002] rockchip_pcie_driver_init+0x1c/0x28 [ 1.230004] do_one_initcall+0x54/0x1c0 [ 1.230005] do_initcalls+0xf4/0x130 [ 1.230007] kernel_init_freeable+0x144/0x19c [ 1.230009] kernel_init+0x14/0x11c [ 1.230011] ret_from_fork+0x10/0x34 [ 1.230035] SMP: stopping secondary CPUs [ 1.230037] Kernel Offset: disabled [ 1.230039] CPU features: 0x0240022,2100200c [ 1.230041] Memory Limit: none --- .../admin-guide/kernel-parameters.txt | 8 ++++++ .../boot/dts/rockchip/rk3399-rockpro64.dtsi | 1 + drivers/pci/controller/pcie-rockchip-host.c | 25 +++++++++++++++++++ drivers/pci/controller/pcie-rockchip.c | 6 +++++ drivers/pci/controller/pcie-rockchip.h | 2 ++ 5 files changed, 42 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 44fde25bb221..941dc943eb84 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3816,6 +3816,14 @@ nomsi Do not use MSI for native PCIe PME signaling (this makes all PCIe root ports use INTx for all services). + pcie_rockchip_host.bus_scan_delay= [PCIE] Delay in ms before + scanning PCIe bus in Rockchip PCIe host driver. Some PCIe + cards seem to need delays that can be several hundred ms. + If set to greater than or equal to 0 this parameter will + override delay that can be set in device tree. + Values less than 0 mean that this parameter is ignored. + default=-1 + pcmv= [HW,PCMCIA] BadgePAD 4 pd_ignore_unused diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index 9705059523a6..632dac43a037 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,9 @@ #include "../pci.h" #include "pcie-rockchip.h" +static int bus_scan_delay = -1; +module_param_named(bus_scan_delay, bus_scan_delay, int, S_IRUGO); + static void rockchip_pcie_enable_bw_int(struct rockchip_pcie *rockchip) { u32 status; @@ -942,6 +946,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct pci_host_bridge *bridge; int err; + u32 delay = 0; if (!dev->of_node) return -ENODEV; @@ -993,6 +998,26 @@ static int rockchip_pcie_probe(struct platform_device *pdev) bridge->sysdata = rockchip; bridge->ops = &rockchip_pcie_ops; + /* Checking if bus scan delay was given from command line and prefer + * that over the value in device tree (which defaults to 0 if not set). + */ + if (bus_scan_delay >= 0) { + delay = bus_scan_delay; + dev_info(dev, "wait %u ms (from command-line) before bus scan\n", delay); + } else { + delay = rockchip->bus_scan_delay; + dev_info(dev, "wait %u ms (from device tree) before bus scan\n", delay); + } + /* Workaround for some devices crashing on pci_host_probe / pci_scan_root_bus_bridge + * calls: sleep a bit before bus scan. Call trace gets to rockchip_pcie_rd_conf when + * trying to read vendor id (pci_bus_generic_read_dev_vendor_id is in call stack) + * before panicing. I have no idea why this works or what causes the panic. I just + * found this hack by luck when trying to "make it break differently if possible". + */ + if (delay > 0) { + msleep(delay); + } + err = pci_host_probe(bridge); if (err < 0) goto err_remove_irq_domain; diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c index 904dec0d3a88..e6c97f9944ba 100644 --- a/drivers/pci/controller/pcie-rockchip.c +++ b/drivers/pci/controller/pcie-rockchip.c @@ -149,6 +149,12 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) return PTR_ERR(rockchip->clk_pcie_pm); } + err = of_property_read_u32(node, "bus-scan-delay-ms", &rockchip->bus_scan_delay); + if (err) { + dev_info(dev, "no bus scan delay, default to 0 ms\n"); + rockchip->bus_scan_delay = 0; + } + return 0; } EXPORT_SYMBOL_GPL(rockchip_pcie_parse_dt); diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h index c7d0178fc8c2..52fd2108b704 100644 --- a/drivers/pci/controller/pcie-rockchip.h +++ b/drivers/pci/controller/pcie-rockchip.h @@ -306,6 +306,8 @@ struct rockchip_pcie { phys_addr_t msg_bus_addr; bool is_rc; struct resource *mem_res; + /* Bus scan delay is a workaround for some pcie devices causing crashes */ + u32 bus_scan_delay; }; static u32 rockchip_pcie_read(struct rockchip_pcie *rockchip, u32 reg) -- 2.29.2