Merge branch 'pci/controller/keystone'

- Fail the probe instead of silently succeeding if ks_pcie_of_data
  didn't specify Root Complex or Endpoint mode (Siddharth Vadapalli)

- Make keystone buildable as a loadable module, except on ARM32 where
  hook_fault_code() is __init (Siddharth Vadapalli)

* pci/controller/keystone:
  PCI: keystone: Add support to build as a loadable module
  PCI: dwc: Export dw_pcie_allocate_domains() and dw_pcie_ep_raise_msix_irq()
  PCI: Export pci_get_host_bridge_device() for use by pci-keystone
  PCI: keystone: Exit ks_pcie_probe() for invalid mode
This commit is contained in:
Bjorn Helgaas 2025-12-03 14:18:38 -06:00
commit 5606b7bad0
7 changed files with 65 additions and 37 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
{ {
@ -1337,6 +1308,8 @@ static int ks_pcie_probe(struct platform_device *pdev)
break; break;
default: default:
dev_err(dev, "INVALID device type %d\n", mode); dev_err(dev, "INVALID device type %d\n", mode);
ret = -EINVAL;
goto err_get_sync;
} }
ks_pcie_enable_error_irq(ks_pcie); ks_pcie_enable_error_irq(ks_pcie);
@ -1379,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>");

View File

@ -797,6 +797,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_msix_irq);
/** /**
* dw_pcie_ep_cleanup - Cleanup DWC EP resources after fundamental reset * dw_pcie_ep_cleanup - Cleanup DWC EP resources after fundamental reset

View File

@ -232,6 +232,7 @@ int dw_pcie_allocate_domains(struct dw_pcie_rp *pp)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(dw_pcie_allocate_domains);
void dw_pcie_free_msi(struct dw_pcie_rp *pp) void dw_pcie_free_msi(struct dw_pcie_rp *pp)
{ {

View File

@ -33,6 +33,7 @@ struct device *pci_get_host_bridge_device(struct pci_dev *dev)
kobject_get(&bridge->kobj); kobject_get(&bridge->kobj);
return bridge; return bridge;
} }
EXPORT_SYMBOL_GPL(pci_get_host_bridge_device);
void pci_put_host_bridge_device(struct device *dev) void pci_put_host_bridge_device(struct device *dev)
{ {

View File

@ -648,6 +648,7 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv);
struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev, struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev,
size_t priv); size_t priv);
void pci_free_host_bridge(struct pci_host_bridge *bridge); void pci_free_host_bridge(struct pci_host_bridge *bridge);
struct device *pci_get_host_bridge_device(struct pci_dev *dev);
struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus); struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
void pci_set_host_bridge_release(struct pci_host_bridge *bridge, void pci_set_host_bridge_release(struct pci_host_bridge *bridge,