Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Siddharth Vadapalli and committed by
Bjorn Helgaas
bc10d0ad 5aa84c03

+59 -37
+11 -4
drivers/pci/controller/dwc/Kconfig
··· 482 482 to enable device-specific features PCI_DRA7XX_EP must be selected. 483 483 This uses the DesignWare core. 484 484 485 + # ARM32 platforms use hook_fault_code() and cannot support loadable module. 485 486 config PCI_KEYSTONE 486 487 bool 487 488 489 + # On non-ARM32 platforms, loadable module can be supported. 490 + config PCI_KEYSTONE_TRISTATE 491 + tristate 492 + 488 493 config PCI_KEYSTONE_HOST 489 - bool "TI Keystone PCIe controller (host mode)" 494 + tristate "TI Keystone PCIe controller (host mode)" 490 495 depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST 491 496 depends on PCI_MSI 492 497 select PCIE_DW_HOST 493 - select PCI_KEYSTONE 498 + select PCI_KEYSTONE if ARM 499 + select PCI_KEYSTONE_TRISTATE if !ARM 494 500 help 495 501 Enables support for the PCIe controller in the Keystone SoC to 496 502 work in host mode. The PCI controller on Keystone is based on ··· 504 498 DesignWare core functions to implement the driver. 505 499 506 500 config PCI_KEYSTONE_EP 507 - bool "TI Keystone PCIe controller (endpoint mode)" 501 + tristate "TI Keystone PCIe controller (endpoint mode)" 508 502 depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST 509 503 depends on PCI_ENDPOINT 510 504 select PCIE_DW_EP 511 - select PCI_KEYSTONE 505 + select PCI_KEYSTONE if ARM 506 + select PCI_KEYSTONE_TRISTATE if !ARM 512 507 help 513 508 Enables support for the PCIe controller in the Keystone SoC to 514 509 work in endpoint mode. The PCI controller on Keystone is based
+3
drivers/pci/controller/dwc/Makefile
··· 11 11 obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o 12 12 obj-$(CONFIG_PCI_IMX6) += pci-imx6.o 13 13 obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o 14 + # ARM32 platforms use hook_fault_code() and cannot support loadable module. 14 15 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 15 18 obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o 16 19 obj-$(CONFIG_PCI_LAYERSCAPE_EP) += pci-layerscape-ep.o 17 20 obj-$(CONFIG_PCIE_QCOM_COMMON) += pcie-qcom-common.o
+45 -33
drivers/pci/controller/dwc/pci-keystone.c
··· 17 17 #include <linux/irqchip/chained_irq.h> 18 18 #include <linux/irqdomain.h> 19 19 #include <linux/mfd/syscon.h> 20 + #include <linux/module.h> 20 21 #include <linux/msi.h> 21 22 #include <linux/of.h> 22 23 #include <linux/of_irq.h> ··· 778 777 return ret; 779 778 } 780 779 781 - #ifdef CONFIG_ARM 782 - /* 783 - * When a PCI device does not exist during config cycles, keystone host 784 - * gets a bus error instead of returning 0xffffffff (PCI_ERROR_RESPONSE). 785 - * This handler always returns 0 for this kind of fault. 786 - */ 787 - static int ks_pcie_fault(unsigned long addr, unsigned int fsr, 788 - struct pt_regs *regs) 789 - { 790 - unsigned long instr = *(unsigned long *) instruction_pointer(regs); 791 - 792 - if ((instr & 0x0e100090) == 0x00100090) { 793 - int reg = (instr >> 12) & 15; 794 - 795 - regs->uregs[reg] = -1; 796 - regs->ARM_pc += 4; 797 - } 798 - 799 - return 0; 800 - } 801 - #endif 802 - 803 - static int __init ks_pcie_init_id(struct keystone_pcie *ks_pcie) 780 + static int ks_pcie_init_id(struct keystone_pcie *ks_pcie) 804 781 { 805 782 int ret; 806 783 unsigned int id; ··· 810 831 return 0; 811 832 } 812 833 813 - static int __init ks_pcie_host_init(struct dw_pcie_rp *pp) 834 + static int ks_pcie_host_init(struct dw_pcie_rp *pp) 814 835 { 815 836 struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 816 837 struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); ··· 839 860 ret = ks_pcie_init_id(ks_pcie); 840 861 if (ret < 0) 841 862 return ret; 842 - 843 - #ifdef CONFIG_ARM 844 - /* 845 - * PCIe access errors that result into OCP errors are caught by ARM as 846 - * "External aborts" 847 - */ 848 - hook_fault_code(17, ks_pcie_fault, SIGBUS, 0, 849 - "Asynchronous external abort"); 850 - #endif 851 863 852 864 return 0; 853 865 } ··· 1104 1134 }, 1105 1135 { }, 1106 1136 }; 1137 + MODULE_DEVICE_TABLE(of, ks_pcie_of_match); 1107 1138 1108 1139 static int ks_pcie_probe(struct platform_device *pdev) 1109 1140 { ··· 1352 1381 .of_match_table = ks_pcie_of_match, 1353 1382 }, 1354 1383 }; 1384 + 1385 + #ifdef CONFIG_ARM 1386 + /* 1387 + * When a PCI device does not exist during config cycles, keystone host 1388 + * gets a bus error instead of returning 0xffffffff (PCI_ERROR_RESPONSE). 1389 + * This handler always returns 0 for this kind of fault. 1390 + */ 1391 + static int ks_pcie_fault(unsigned long addr, unsigned int fsr, 1392 + struct pt_regs *regs) 1393 + { 1394 + unsigned long instr = *(unsigned long *)instruction_pointer(regs); 1395 + 1396 + if ((instr & 0x0e100090) == 0x00100090) { 1397 + int reg = (instr >> 12) & 15; 1398 + 1399 + regs->uregs[reg] = -1; 1400 + regs->ARM_pc += 4; 1401 + } 1402 + 1403 + return 0; 1404 + } 1405 + 1406 + static int __init ks_pcie_init(void) 1407 + { 1408 + /* 1409 + * PCIe access errors that result into OCP errors are caught by ARM as 1410 + * "External aborts" 1411 + */ 1412 + if (of_find_matching_node(NULL, ks_pcie_of_match)) 1413 + hook_fault_code(17, ks_pcie_fault, SIGBUS, 0, 1414 + "Asynchronous external abort"); 1415 + 1416 + return platform_driver_register(&ks_pcie_driver); 1417 + } 1418 + device_initcall(ks_pcie_init); 1419 + #else 1355 1420 builtin_platform_driver(ks_pcie_driver); 1421 + #endif 1422 + 1423 + MODULE_LICENSE("GPL"); 1424 + MODULE_DESCRIPTION("PCIe controller driver for Texas Instruments Keystone SoCs"); 1425 + MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");