mirror of
https://github.com/torvalds/linux.git
synced 2026-09-26 01:52:03 +02:00
PCI: keystone: Add support to build as a loadable module
The 'pci-keystone.c' driver is the application/glue/wrapper driver for the Designware PCIe Controllers on TI SoCs. Now that all of the helper APIs that the 'pci-keystone.c' driver depends upon have been exported for use, enable support to build the driver as a loadable module. When building the driver as a module, the functions marked by the '__init' keyword may be invoked after the init memory has been freed by the kernel. This results will result in an exception of the form: Unable to handle kernel paging request at virtual address ... Mem abort info: ... pc : ks_pcie_host_init+0x0/0x540 lr : dw_pcie_host_init+0x170/0x498 ... ks_pcie_host_init+0x0/0x540 (P) ks_pcie_probe+0x728/0x84c platform_probe+0x5c/0x98 really_probe+0xbc/0x29c __driver_probe_device+0x78/0x12c driver_probe_device+0xd8/0x15c To address this, introduce a new function namely 'ks_pcie_init()' to register the 'fault handler' while removing the '__init' keyword from existing functions. Note that hook_fault_code() is defined as '__init' function. Since the init functions should never be called during runtime (after init memory freeing stage), the driver is made as a built-in if CONFIG_ARM (where hook_fault_code() is used) is selected. Signed-off-by: Siddharth Vadapalli <s-vadapalli@ti.com> [mani: added a note about hook_fault_code()] Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Link: https://patch.msgid.link/20251029080547.1253757-5-s-vadapalli@ti.com
This commit is contained in:
parent
5aa84c034a
commit
bc10d0ad54
|
|
@ -482,15 +482,21 @@ config PCI_DRA7XX_EP
|
||||||
to enable device-specific features PCI_DRA7XX_EP must be selected.
|
to enable device-specific features PCI_DRA7XX_EP must be selected.
|
||||||
This uses the DesignWare core.
|
This uses the DesignWare core.
|
||||||
|
|
||||||
|
# ARM32 platforms use hook_fault_code() and cannot support loadable module.
|
||||||
config PCI_KEYSTONE
|
config PCI_KEYSTONE
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
# On non-ARM32 platforms, loadable module can be supported.
|
||||||
|
config PCI_KEYSTONE_TRISTATE
|
||||||
|
tristate
|
||||||
|
|
||||||
config PCI_KEYSTONE_HOST
|
config PCI_KEYSTONE_HOST
|
||||||
bool "TI Keystone PCIe controller (host mode)"
|
tristate "TI Keystone PCIe controller (host mode)"
|
||||||
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
|
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
|
||||||
depends on PCI_MSI
|
depends on PCI_MSI
|
||||||
select PCIE_DW_HOST
|
select PCIE_DW_HOST
|
||||||
select PCI_KEYSTONE
|
select PCI_KEYSTONE if ARM
|
||||||
|
select PCI_KEYSTONE_TRISTATE if !ARM
|
||||||
help
|
help
|
||||||
Enables support for the PCIe controller in the Keystone SoC to
|
Enables support for the PCIe controller in the Keystone SoC to
|
||||||
work in host mode. The PCI controller on Keystone is based on
|
work in host mode. The PCI controller on Keystone is based on
|
||||||
|
|
@ -498,11 +504,12 @@ config PCI_KEYSTONE_HOST
|
||||||
DesignWare core functions to implement the driver.
|
DesignWare core functions to implement the driver.
|
||||||
|
|
||||||
config PCI_KEYSTONE_EP
|
config PCI_KEYSTONE_EP
|
||||||
bool "TI Keystone PCIe controller (endpoint mode)"
|
tristate "TI Keystone PCIe controller (endpoint mode)"
|
||||||
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
|
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
|
||||||
depends on PCI_ENDPOINT
|
depends on PCI_ENDPOINT
|
||||||
select PCIE_DW_EP
|
select PCIE_DW_EP
|
||||||
select PCI_KEYSTONE
|
select PCI_KEYSTONE if ARM
|
||||||
|
select PCI_KEYSTONE_TRISTATE if !ARM
|
||||||
help
|
help
|
||||||
Enables support for the PCIe controller in the Keystone SoC to
|
Enables support for the PCIe controller in the Keystone SoC to
|
||||||
work in endpoint mode. The PCI controller on Keystone is based
|
work in endpoint mode. The PCI controller on Keystone is based
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,10 @@ obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
|
||||||
obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
|
obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
|
||||||
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
|
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
|
||||||
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
|
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
|
||||||
|
# ARM32 platforms use hook_fault_code() and cannot support loadable module.
|
||||||
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
|
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
|
||||||
|
# On non-ARM32 platforms, loadable module can be supported.
|
||||||
|
obj-$(CONFIG_PCI_KEYSTONE_TRISTATE) += pci-keystone.o
|
||||||
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
|
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
|
||||||
obj-$(CONFIG_PCI_LAYERSCAPE_EP) += pci-layerscape-ep.o
|
obj-$(CONFIG_PCI_LAYERSCAPE_EP) += pci-layerscape-ep.o
|
||||||
obj-$(CONFIG_PCIE_QCOM_COMMON) += pcie-qcom-common.o
|
obj-$(CONFIG_PCIE_QCOM_COMMON) += pcie-qcom-common.o
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/irqchip/chained_irq.h>
|
#include <linux/irqchip/chained_irq.h>
|
||||||
#include <linux/irqdomain.h>
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
|
|
@ -777,29 +778,7 @@ static int ks_pcie_config_intx_irq(struct keystone_pcie *ks_pcie)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ARM
|
static int ks_pcie_init_id(struct keystone_pcie *ks_pcie)
|
||||||
/*
|
|
||||||
* When a PCI device does not exist during config cycles, keystone host
|
|
||||||
* gets a bus error instead of returning 0xffffffff (PCI_ERROR_RESPONSE).
|
|
||||||
* This handler always returns 0 for this kind of fault.
|
|
||||||
*/
|
|
||||||
static int ks_pcie_fault(unsigned long addr, unsigned int fsr,
|
|
||||||
struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
unsigned long instr = *(unsigned long *) instruction_pointer(regs);
|
|
||||||
|
|
||||||
if ((instr & 0x0e100090) == 0x00100090) {
|
|
||||||
int reg = (instr >> 12) & 15;
|
|
||||||
|
|
||||||
regs->uregs[reg] = -1;
|
|
||||||
regs->ARM_pc += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
|
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
|
|
@ -831,7 +810,7 @@ static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init ks_pcie_host_init(struct dw_pcie_rp *pp)
|
static int ks_pcie_host_init(struct dw_pcie_rp *pp)
|
||||||
{
|
{
|
||||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||||
|
|
@ -861,15 +840,6 @@ static int __init ks_pcie_host_init(struct dw_pcie_rp *pp)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
#ifdef CONFIG_ARM
|
|
||||||
/*
|
|
||||||
* PCIe access errors that result into OCP errors are caught by ARM as
|
|
||||||
* "External aborts"
|
|
||||||
*/
|
|
||||||
hook_fault_code(17, ks_pcie_fault, SIGBUS, 0,
|
|
||||||
"Asynchronous external abort");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1134,6 +1104,7 @@ static const struct of_device_id ks_pcie_of_match[] = {
|
||||||
},
|
},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
|
||||||
|
|
||||||
static int ks_pcie_probe(struct platform_device *pdev)
|
static int ks_pcie_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
|
@ -1381,4 +1352,45 @@ static struct platform_driver ks_pcie_driver = {
|
||||||
.of_match_table = ks_pcie_of_match,
|
.of_match_table = ks_pcie_of_match,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARM
|
||||||
|
/*
|
||||||
|
* When a PCI device does not exist during config cycles, keystone host
|
||||||
|
* gets a bus error instead of returning 0xffffffff (PCI_ERROR_RESPONSE).
|
||||||
|
* This handler always returns 0 for this kind of fault.
|
||||||
|
*/
|
||||||
|
static int ks_pcie_fault(unsigned long addr, unsigned int fsr,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
unsigned long instr = *(unsigned long *)instruction_pointer(regs);
|
||||||
|
|
||||||
|
if ((instr & 0x0e100090) == 0x00100090) {
|
||||||
|
int reg = (instr >> 12) & 15;
|
||||||
|
|
||||||
|
regs->uregs[reg] = -1;
|
||||||
|
regs->ARM_pc += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init ks_pcie_init(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* PCIe access errors that result into OCP errors are caught by ARM as
|
||||||
|
* "External aborts"
|
||||||
|
*/
|
||||||
|
if (of_find_matching_node(NULL, ks_pcie_of_match))
|
||||||
|
hook_fault_code(17, ks_pcie_fault, SIGBUS, 0,
|
||||||
|
"Asynchronous external abort");
|
||||||
|
|
||||||
|
return platform_driver_register(&ks_pcie_driver);
|
||||||
|
}
|
||||||
|
device_initcall(ks_pcie_init);
|
||||||
|
#else
|
||||||
builtin_platform_driver(ks_pcie_driver);
|
builtin_platform_driver(ks_pcie_driver);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_DESCRIPTION("PCIe controller driver for Texas Instruments Keystone SoCs");
|
||||||
|
MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user