Skip to content

Instantly share code, notes, and snippets.

@nuumio
Created December 1, 2020 16:14
Show Gist options
  • Save nuumio/30ce03e967204693ac791b0d294913fb to your computer and use it in GitHub Desktop.
Save nuumio/30ce03e967204693ac791b0d294913fb to your computer and use it in GitHub Desktop.
From ceae51b1cc0e5a5b42999274657bd55606193661 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jari=20H=C3=A4m=C3=A4l=C3=A4inen?= <[email protected]>
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/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi
index 6e553ff47534..9ec248d1c4c3 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi
@@ -548,6 +548,7 @@ &pcie0 {
pinctrl-0 = <&pcie_perst>;
vpcie12v-supply = <&vcc12v_dcin>;
vpcie3v3-supply = <&vcc3v3_pcie>;
+ bus-scan-delay-ms = <1000>;
status = "okay";
};
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 <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_pci.h>
@@ -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
@leiless
Copy link

leiless commented Nov 28, 2023

I'd like to know how to pass this parameter to kernel command line?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment