107 lines
3.9 KiB
Diff
107 lines
3.9 KiB
Diff
|
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
|
||
|
index 1396fd2d9..4d583446c 100644
|
||
|
--- a/Documentation/admin-guide/kernel-parameters.txt
|
||
|
+++ b/Documentation/admin-guide/kernel-parameters.txt
|
||
|
@@ -4079,6 +4079,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 c52316d0b..a7974007d 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;
|
||
|
@@ -935,6 +939,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;
|
||
|
@@ -984,6 +989,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 = rockchip_pcie_setup_irq(rockchip);
|
||
|
if (err)
|
||
|
goto err_remove_irq_domain;
|
||
|
diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
|
||
|
index 193d26562..ec6cbaadd 100644
|
||
|
--- a/drivers/pci/controller/pcie-rockchip.c
|
||
|
+++ b/drivers/pci/controller/pcie-rockchip.c
|
||
|
@@ -148,6 +148,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 1650a5087..35a8cf157 100644
|
||
|
--- a/drivers/pci/controller/pcie-rockchip.h
|
||
|
+++ b/drivers/pci/controller/pcie-rockchip.h
|
||
|
@@ -300,6 +300,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)
|