Skip to content

Commit bc10d0a

Browse files
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
1 parent 5aa84c0 commit bc10d0a

3 files changed

Lines changed: 59 additions & 37 deletions

File tree

drivers/pci/controller/dwc/Kconfig

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,27 +482,34 @@ config PCI_DRA7XX_EP
482482
to enable device-specific features PCI_DRA7XX_EP must be selected.
483483
This uses the DesignWare core.
484484

485+
# ARM32 platforms use hook_fault_code() and cannot support loadable module.
485486
config PCI_KEYSTONE
486487
bool
487488

489+
# On non-ARM32 platforms, loadable module can be supported.
490+
config PCI_KEYSTONE_TRISTATE
491+
tristate
492+
488493
config PCI_KEYSTONE_HOST
489-
bool "TI Keystone PCIe controller (host mode)"
494+
tristate "TI Keystone PCIe controller (host mode)"
490495
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
491496
depends on PCI_MSI
492497
select PCIE_DW_HOST
493-
select PCI_KEYSTONE
498+
select PCI_KEYSTONE if ARM
499+
select PCI_KEYSTONE_TRISTATE if !ARM
494500
help
495501
Enables support for the PCIe controller in the Keystone SoC to
496502
work in host mode. The PCI controller on Keystone is based on
497503
DesignWare hardware and therefore the driver re-uses the
498504
DesignWare core functions to implement the driver.
499505

500506
config PCI_KEYSTONE_EP
501-
bool "TI Keystone PCIe controller (endpoint mode)"
507+
tristate "TI Keystone PCIe controller (endpoint mode)"
502508
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
503509
depends on PCI_ENDPOINT
504510
select PCIE_DW_EP
505-
select PCI_KEYSTONE
511+
select PCI_KEYSTONE if ARM
512+
select PCI_KEYSTONE_TRISTATE if !ARM
506513
help
507514
Enables support for the PCIe controller in the Keystone SoC to
508515
work in endpoint mode. The PCI controller on Keystone is based

drivers/pci/controller/dwc/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
1111
obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
1212
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
1313
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
14+
# ARM32 platforms use hook_fault_code() and cannot support loadable module.
1415
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
16+
# On non-ARM32 platforms, loadable module can be supported.
17+
obj-$(CONFIG_PCI_KEYSTONE_TRISTATE) += pci-keystone.o
1518
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
1619
obj-$(CONFIG_PCI_LAYERSCAPE_EP) += pci-layerscape-ep.o
1720
obj-$(CONFIG_PCIE_QCOM_COMMON) += pcie-qcom-common.o

drivers/pci/controller/dwc/pci-keystone.c

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/irqchip/chained_irq.h>
1818
#include <linux/irqdomain.h>
1919
#include <linux/mfd/syscon.h>
20+
#include <linux/module.h>
2021
#include <linux/msi.h>
2122
#include <linux/of.h>
2223
#include <linux/of_irq.h>
@@ -777,29 +778,7 @@ static int ks_pcie_config_intx_irq(struct keystone_pcie *ks_pcie)
777778
return ret;
778779
}
779780

780-
#ifdef CONFIG_ARM
781-
/*
782-
* When a PCI device does not exist during config cycles, keystone host
783-
* gets a bus error instead of returning 0xffffffff (PCI_ERROR_RESPONSE).
784-
* This handler always returns 0 for this kind of fault.
785-
*/
786-
static int ks_pcie_fault(unsigned long addr, unsigned int fsr,
787-
struct pt_regs *regs)
788-
{
789-
unsigned long instr = *(unsigned long *) instruction_pointer(regs);
790-
791-
if ((instr & 0x0e100090) == 0x00100090) {
792-
int reg = (instr >> 12) & 15;
793-
794-
regs->uregs[reg] = -1;
795-
regs->ARM_pc += 4;
796-
}
797-
798-
return 0;
799-
}
800-
#endif
801-
802-
static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
781+
static int ks_pcie_init_id(struct keystone_pcie *ks_pcie)
803782
{
804783
int ret;
805784
unsigned int id;
@@ -831,7 +810,7 @@ static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie)
831810
return 0;
832811
}
833812

834-
static int __init ks_pcie_host_init(struct dw_pcie_rp *pp)
813+
static int ks_pcie_host_init(struct dw_pcie_rp *pp)
835814
{
836815
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
837816
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)
861840
if (ret < 0)
862841
return ret;
863842

864-
#ifdef CONFIG_ARM
865-
/*
866-
* PCIe access errors that result into OCP errors are caught by ARM as
867-
* "External aborts"
868-
*/
869-
hook_fault_code(17, ks_pcie_fault, SIGBUS, 0,
870-
"Asynchronous external abort");
871-
#endif
872-
873843
return 0;
874844
}
875845

@@ -1134,6 +1104,7 @@ static const struct of_device_id ks_pcie_of_match[] = {
11341104
},
11351105
{ },
11361106
};
1107+
MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
11371108

11381109
static int ks_pcie_probe(struct platform_device *pdev)
11391110
{
@@ -1381,4 +1352,45 @@ static struct platform_driver ks_pcie_driver = {
13811352
.of_match_table = ks_pcie_of_match,
13821353
},
13831354
};
1355+
1356+
#ifdef CONFIG_ARM
1357+
/*
1358+
* When a PCI device does not exist during config cycles, keystone host
1359+
* gets a bus error instead of returning 0xffffffff (PCI_ERROR_RESPONSE).
1360+
* This handler always returns 0 for this kind of fault.
1361+
*/
1362+
static int ks_pcie_fault(unsigned long addr, unsigned int fsr,
1363+
struct pt_regs *regs)
1364+
{
1365+
unsigned long instr = *(unsigned long *)instruction_pointer(regs);
1366+
1367+
if ((instr & 0x0e100090) == 0x00100090) {
1368+
int reg = (instr >> 12) & 15;
1369+
1370+
regs->uregs[reg] = -1;
1371+
regs->ARM_pc += 4;
1372+
}
1373+
1374+
return 0;
1375+
}
1376+
1377+
static int __init ks_pcie_init(void)
1378+
{
1379+
/*
1380+
* PCIe access errors that result into OCP errors are caught by ARM as
1381+
* "External aborts"
1382+
*/
1383+
if (of_find_matching_node(NULL, ks_pcie_of_match))
1384+
hook_fault_code(17, ks_pcie_fault, SIGBUS, 0,
1385+
"Asynchronous external abort");
1386+
1387+
return platform_driver_register(&ks_pcie_driver);
1388+
}
1389+
device_initcall(ks_pcie_init);
1390+
#else
13841391
builtin_platform_driver(ks_pcie_driver);
1392+
#endif
1393+
1394+
MODULE_LICENSE("GPL");
1395+
MODULE_DESCRIPTION("PCIe controller driver for Texas Instruments Keystone SoCs");
1396+
MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");

0 commit comments

Comments
 (0)