mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 15:12:13 +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.
|
||||
This uses the DesignWare core.
|
||||
|
||||
# ARM32 platforms use hook_fault_code() and cannot support loadable module.
|
||||
config PCI_KEYSTONE
|
||||
bool
|
||||
|
||||
# On non-ARM32 platforms, loadable module can be supported.
|
||||
config PCI_KEYSTONE_TRISTATE
|
||||
tristate
|
||||
|
||||
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 PCI_MSI
|
||||
select PCIE_DW_HOST
|
||||
select PCI_KEYSTONE
|
||||
select PCI_KEYSTONE if ARM
|
||||
select PCI_KEYSTONE_TRISTATE if !ARM
|
||||
help
|
||||
Enables support for the PCIe controller in the Keystone SoC to
|
||||
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.
|
||||
|
||||
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 PCI_ENDPOINT
|
||||
select PCIE_DW_EP
|
||||
select PCI_KEYSTONE
|
||||
select PCI_KEYSTONE if ARM
|
||||
select PCI_KEYSTONE_TRISTATE if !ARM
|
||||
help
|
||||
Enables support for the PCIe controller in the Keystone SoC to
|
||||
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_PCI_IMX6) += pci-imx6.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
|
||||
# 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_EP) += pci-layerscape-ep.o
|
||||
obj-$(CONFIG_PCIE_QCOM_COMMON) += pcie-qcom-common.o
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
|
@ -777,29 +778,7 @@ static int ks_pcie_config_intx_irq(struct keystone_pcie *ks_pcie)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
|
||||
static int ks_pcie_init_id(struct keystone_pcie *ks_pcie)
|
||||
{
|
||||
int ret;
|
||||
unsigned int id;
|
||||
|
|
@ -831,7 +810,7 @@ static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
|
|||
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 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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
@ -1381,4 +1352,45 @@ static struct platform_driver ks_pcie_driver = {
|
|||
.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);
|
||||
#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