aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/controller/dwc/pcie-designware-host.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-10-06 10:41:03 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2025-10-06 10:41:03 -0700
commit2f2c7254931f41b5736e3ba12aaa9ac1bbeeeb92 (patch)
treee9d9aa57eceb8f57ef3a88ec99a05d34c947ea83 /drivers/pci/controller/dwc/pcie-designware-host.c
parentMerge tag 'dmaengine-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/g... (diff)
parentMerge branch 'pci/misc' (diff)
downloadlinux-2f2c7254931f41b5736e3ba12aaa9ac1bbeeeb92.tar.gz
linux-2f2c7254931f41b5736e3ba12aaa9ac1bbeeeb92.zip
Merge tag 'pci-v6.18-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
Pull pci updates from Bjorn Helgaas: "Enumeration: - Add PCI_FIND_NEXT_CAP() and PCI_FIND_NEXT_EXT_CAP() macros that take config space accessor functions. Implement pci_find_capability(), pci_find_ext_capability(), and dwc, dwc endpoint, and cadence capability search interfaces with them (Hans Zhang) - Leave parent unit address 0 in 'interrupt-map' so that when we build devicetree nodes to describe PCI functions that contain multiple peripherals, we can build this property even when interrupt controllers lack 'reg' properties (Lorenzo Pieralisi) - Add a Xeon 6 quirk to disable Extended Tags and limit Max Read Request Size to 128B to avoid a performance issue (Ilpo Järvinen) - Add sysfs 'serial_number' file to expose the Device Serial Number (Matthew Wood) - Fix pci_acpi_preserve_config() memory leak (Nirmoy Das) Resource management: - Align m68k pcibios_enable_device() with other arches (Ilpo Järvinen) - Remove sparc pcibios_enable_device() implementations that don't do anything beyond what pci_enable_resources() does (Ilpo Järvinen) - Remove mips pcibios_enable_resources() and use pci_enable_resources() instead (Ilpo Järvinen) - Clean up bridge window sizing and assignment (Ilpo Järvinen), including: - Leave non-claimed bridge windows disabled - Enable bridges even if a window wasn't assigned because not all windows are required by downstream devices - Preserve bridge window type when releasing the resource, since the type is needed for reassignment - Consolidate selection of bridge windows into two new interfaces, pbus_select_window() and pbus_select_window_for_type(), so this is done consistently - Compute bridge window start and end earlier to avoid logging stale information MSI: - Add quirk to disable MSI on RDC PCI to PCIe bridges (Marcos Del Sol Vives) Error handling: - Align AER with EEH by allowing drivers to request a Bus Reset on Non-Fatal Errors (in addition to the reset on Fatal Errors that we already do) (Lukas Wunner) - If error recovery fails, emit FAILED_RECOVERY uevents for the devices, not for the bridge leading to them. This makes them correspond to BEGIN_RECOVERY uevents (Lukas Wunner) - Align AER with EEH by calling err_handler.error_detected() callbacks to notify drivers if error recovery fails (Lukas Wunner) - Align AER with EEH by restoring device error_state to pci_channel_io_normal before the err_handler.slot_reset() callback. This is earlier than before the err_handler.resume() callback (Lukas Wunner) - Emit a BEGIN_RECOVERY uevent when driver's err_handler.error_detected() requests a reset, as well as when it says recovery is complete or can be done without a reset (Niklas Schnelle) - Align s390 with AER and EEH by emitting uevents during error recovery (Niklas Schnelle) - Align EEH with AER and s390 by emitting BEGIN_RECOVERY, SUCCESSFUL_RECOVERY, or FAILED_RECOVERY uevents depending on the result of err_handler.error_detected() (Niklas Schnelle) - Fix a NULL pointer dereference in aer_ratelimit() when ACPI GHES error information identifies a device without an AER Capability (Breno Leitao) - Update error decoding and TLP Log printing for new errors in current PCIe base spec (Lukas Wunner) - Update error recovery documentation to match the current code and use consistent nomenclature (Lukas Wunner) ASPM: - Enable all ClockPM and ASPM states for devicetree platforms, since there's typically no firmware that enables ASPM This is a risky change that may uncover hardware or configuration defects at boot-time rather than when users enable ASPM via sysfs later. Booting with "pcie_aspm=off" prevents this enabling (Manivannan Sadhasivam) - Remove the qcom code that enabled ASPM (Manivannan Sadhasivam) Power management: - If a device has already been disconnected, e.g., by a hotplug removal, don't bother trying to resume it to D0 when detaching the driver. This avoids annoying "Unable to change power state from D3cold to D0" messages (Mario Limonciello) - Ensure devices are powered up before config reads for 'max_link_width', 'current_link_speed', 'current_link_width', 'secondary_bus_number', and 'subordinate_bus_number' sysfs files. This prevents using invalid data (~0) in drivers or lspci and, depending on how the PCIe controller reports errors, may avoid error interrupts or crashes (Brian Norris) Virtualization: - Add rescan/remove locking when enabling/disabling SR-IOV, which avoids list corruption on s390, where disabling SR-IOV also generates hotplug events (Niklas Schnelle) Peer-to-peer DMA: - Free struct p2p_pgmap, not a member within it, in the pci_p2pdma_add_resource() error path (Sungho Kim) Endpoint framework: - Document sysfs interface for BAR assignment of vNTB endpoint functions (Jerome Brunet) - Fix array underflow in endpoint BAR test case (Dan Carpenter) - Skip endpoint IRQ test if the IRQ is out of range to avoid false errors (Christian Bruel) - Fix endpoint test case for controllers with fixed-size BARs smaller than requested by the test (Marek Vasut) - Restore inbound translation when disabling doorbell so the endpoint doorbell test case can be run more than once (Niklas Cassel) - Avoid a NULL pointer dereference when releasing DMA channels in endpoint DMA test case (Shin'ichiro Kawasaki) - Convert tegra194 interrupt number to MSI vector to fix endpoint Kselftest MSI_TEST test case (Niklas Cassel) - Reset tegra194 BARs when running in endpoint mode so the BAR tests don't overwrite the ATU settings in BAR4 (Niklas Cassel) - Handle errors in tegra194 BPMP transactions so we don't mistakenly skip future PERST# assertion (Vidya Sagar) AMD MDB PCIe controller driver: - Update DT binding example to separate PERST# to a Root Port stanza to make multiple Root Ports possible in the future (Sai Krishna Musham) - Add driver support for PERST# being described in a Root Port stanza, falling back to the host bridge if not found there (Sai Krishna Musham) Freescale i.MX6 PCIe controller driver: - Enable the 3.3V Vaux supply if available so devices can request wakeup with either Beacon or WAKE# (Richard Zhu) MediaTek PCIe Gen3 controller driver: - Add optional sys clock ready time setting to avoid sys_clk_rdy signal glitching in MT6991 and MT8196 (AngeloGioacchino Del Regno) - Add DT binding and driver support for MT6991 and MT8196 (AngeloGioacchino Del Regno) NVIDIA Tegra PCIe controller driver: - When asserting PERST#, disable the controller instead of mistakenly disabling the PLL twice (Nagarjuna Kristam) - Convert struct tegra_msi mask_lock to raw spinlock to avoid a lock nesting error (Marek Vasut) Qualcomm PCIe controller driver: - Select PCI Power Control Slot driver so slot voltage rails can be turned on/off if described in Root Port devicetree node (Qiang Yu) - Parse only PCI bridge child nodes in devicetree, skipping unrelated nodes such as OPP (Operating Performance Points), which caused probe failures (Krishna Chaitanya Chundru) - Add 8.0 GT/s and 32.0 GT/s equalization settings (Ziyue Zhang) - Consolidate Root Port 'phy' and 'reset' properties in struct qcom_pcie_port, regardless of whether we got them from the Root Port node or the host bridge node (Manivannan Sadhasivam) - Fetch and map the ELBI register space in the DWC core rather than in each driver individually (Krishna Chaitanya Chundru) - Enable ECAM mechanism in DWC core by setting up iATU with 'CFG Shift Feature' and use this in the qcom driver (Krishna Chaitanya Chundru) - Add SM8750 compatible to qcom,pcie-sm8550.yaml (Krishna Chaitanya Chundru) - Update qcom,pcie-x1e80100.yaml to allow fifth PCIe host on Qualcomm Glymur, which is compatible with X1E80100 but doesn't have the cnoc_sf_axi clock (Qiang Yu) Renesas R-Car PCIe controller driver: - Fix a typo that prevented correct PHY initialization (Marek Vasut) - Add a missing 1ms delay after PWR reset assertion as required by the V4H manual (Marek Vasut) - Assure reset has completed before DBI access to avoid SError (Marek Vasut) - Fix inverted PHY initialization check, which sometimes led to timeouts and failure to start the controller (Marek Vasut) - Pass the correct IRQ domain to generic_handle_domain_irq() to fix a regression when converting to msi_create_parent_irq_domain() (Claudiu Beznea) - Drop the spinlock protecting the PMSR register - it's no longer required since pci_lock already serializes accesses (Marek Vasut) - Convert struct rcar_msi mask_lock to raw spinlock to avoid a lock nesting error (Marek Vasut) SOPHGO PCIe controller driver: - Check for existence of struct cdns_pcie.ops before using it to allow Cadence drivers that don't need to supply ops (Chen Wang) - Add DT binding and driver for the SOPHGO SG2042 PCIe controller (Chen Wang) STMicroelectronics STM32MP25 PCIe controller driver: - Update pinctrl documentation of initial states and use in runtime suspend/resume (Christian Bruel) - Add pinctrl_pm_select_init_state() for use by stm32 driver, which needs it during resume (Christian Bruel) - Add devicetree bindings and drivers for the STMicroelectronics STM32MP25 in host and endpoint modes (Christian Bruel) Synopsys DesignWare PCIe controller driver: - Add support for x16 in devicetree 'num-lanes' property (Konrad Dybcio) - Verify that if DT specifies a single IRQ for all eDMA channels, it is named 'dma' (Niklas Cassel) TI J721E PCIe driver: - Add MODULE_DEVICE_TABLE() so driver can be autoloaded (Siddharth Vadapalli) - Power controller off before configuring the glue layer so the controller latches the correct values on power-on (Siddharth Vadapalli) TI Keystone PCIe controller driver: - Use devm_request_irq() so 'ks-pcie-error-irq' is freed when driver exits with error (Siddharth Vadapalli) - Add Peripheral Virtualization Unit (PVU), which restricts DMA from PCIe devices to specific regions of host memory, to the ti,am65 binding (Jan Kiszka) Xilinx NWL PCIe controller driver: - Clear bootloader E_ECAM_CONTROL before merging in the new driver value to avoid writing invalid values (Jani Nurminen)" * tag 'pci-v6.18-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci: (141 commits) PCI/AER: Avoid NULL pointer dereference in aer_ratelimit() MAINTAINERS: Add entry for ST STM32MP25 PCIe drivers PCI: stm32-ep: Add PCIe Endpoint support for STM32MP25 dt-bindings: PCI: Add STM32MP25 PCIe Endpoint bindings PCI: stm32: Add PCIe host support for STM32MP25 PCI: xilinx-nwl: Fix ECAM programming PCI: j721e: Fix incorrect error message in probe() PCI: keystone: Use devm_request_irq() to free "ks-pcie-error-irq" on exit dt-bindings: PCI: qcom,pcie-x1e80100: Set clocks minItems for the fifth Glymur PCIe Controller PCI: dwc: Support 16-lane operation PCI: Add lockdep assertion in pci_stop_and_remove_bus_device() PCI/IOV: Add PCI rescan-remove locking when enabling/disabling SR-IOV PCI: rcar-host: Convert struct rcar_msi mask_lock into raw spinlock PCI: tegra194: Rename 'root_bus' to 'root_port_bus' in tegra_pcie_downstream_dev_to_D0() PCI: tegra: Convert struct tegra_msi mask_lock into raw spinlock PCI: rcar-gen4: Fix inverted break condition in PHY initialization PCI: rcar-gen4: Assure reset occurs before DBI access PCI: rcar-gen4: Add missing 1ms delay after PWR reset assertion PCI: Set up bridge resources earlier PCI: rcar-host: Drop PMSR spinlock ...
Diffstat (limited to 'drivers/pci/controller/dwc/pcie-designware-host.c')
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-host.c148
1 files changed, 134 insertions, 14 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 952f8594b501..20c9333bcb1c 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -8,6 +8,7 @@
* Author: Jingoo Han <jg1.han@samsung.com>
*/
+#include <linux/align.h>
#include <linux/iopoll.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqchip/irq-msi-lib.h>
@@ -32,6 +33,8 @@ static struct pci_ops dw_child_pcie_ops;
MSI_FLAG_PCI_MSIX | \
MSI_GENERIC_FLAGS_MASK)
+#define IS_256MB_ALIGNED(x) IS_ALIGNED(x, SZ_256M)
+
static const struct msi_parent_ops dw_pcie_msi_parent_ops = {
.required_flags = DW_PCIE_MSI_FLAGS_REQUIRED,
.supported_flags = DW_PCIE_MSI_FLAGS_SUPPORTED,
@@ -413,6 +416,95 @@ static void dw_pcie_host_request_msg_tlp_res(struct dw_pcie_rp *pp)
}
}
+static int dw_pcie_config_ecam_iatu(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct dw_pcie_ob_atu_cfg atu = {0};
+ resource_size_t bus_range_max;
+ struct resource_entry *bus;
+ int ret;
+
+ bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS);
+
+ /*
+ * Root bus under the host bridge doesn't require any iATU configuration
+ * as DBI region will be used to access root bus config space.
+ * Immediate bus under Root Bus, needs type 0 iATU configuration and
+ * remaining buses need type 1 iATU configuration.
+ */
+ atu.index = 0;
+ atu.type = PCIE_ATU_TYPE_CFG0;
+ atu.parent_bus_addr = pp->cfg0_base + SZ_1M;
+ /* 1MiB is to cover 1 (bus) * 32 (devices) * 8 (functions) */
+ atu.size = SZ_1M;
+ atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE;
+ ret = dw_pcie_prog_outbound_atu(pci, &atu);
+ if (ret)
+ return ret;
+
+ bus_range_max = resource_size(bus->res);
+
+ if (bus_range_max < 2)
+ return 0;
+
+ /* Configure remaining buses in type 1 iATU configuration */
+ atu.index = 1;
+ atu.type = PCIE_ATU_TYPE_CFG1;
+ atu.parent_bus_addr = pp->cfg0_base + SZ_2M;
+ atu.size = (SZ_1M * bus_range_max) - SZ_2M;
+ atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE;
+
+ return dw_pcie_prog_outbound_atu(pci, &atu);
+}
+
+static int dw_pcie_create_ecam_window(struct dw_pcie_rp *pp, struct resource *res)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct device *dev = pci->dev;
+ struct resource_entry *bus;
+
+ bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS);
+ if (!bus)
+ return -ENODEV;
+
+ pp->cfg = pci_ecam_create(dev, res, bus->res, &pci_generic_ecam_ops);
+ if (IS_ERR(pp->cfg))
+ return PTR_ERR(pp->cfg);
+
+ pci->dbi_base = pp->cfg->win;
+ pci->dbi_phys_addr = res->start;
+
+ return 0;
+}
+
+static bool dw_pcie_ecam_enabled(struct dw_pcie_rp *pp, struct resource *config_res)
+{
+ struct resource *bus_range;
+ u64 nr_buses;
+
+ /* Vendor glue drivers may implement their own ECAM mechanism */
+ if (pp->native_ecam)
+ return false;
+
+ /*
+ * PCIe spec r6.0, sec 7.2.2 mandates the base address used for ECAM to
+ * be aligned on a 2^(n+20) byte boundary, where n is the number of bits
+ * used for representing 'bus' in BDF. Since the DWC cores always use 8
+ * bits for representing 'bus', the base address has to be aligned to
+ * 2^28 byte boundary, which is 256 MiB.
+ */
+ if (!IS_256MB_ALIGNED(config_res->start))
+ return false;
+
+ bus_range = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS)->res;
+ if (!bus_range)
+ return false;
+
+ nr_buses = resource_size(config_res) >> PCIE_ECAM_BUS_SHIFT;
+
+ return nr_buses >= resource_size(bus_range);
+}
+
static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -422,10 +514,6 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp)
struct resource *res;
int ret;
- ret = dw_pcie_get_resources(pci);
- if (ret)
- return ret;
-
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
if (!res) {
dev_err(dev, "Missing \"config\" reg space\n");
@@ -435,9 +523,32 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp)
pp->cfg0_size = resource_size(res);
pp->cfg0_base = res->start;
- pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res);
- if (IS_ERR(pp->va_cfg0_base))
- return PTR_ERR(pp->va_cfg0_base);
+ pp->ecam_enabled = dw_pcie_ecam_enabled(pp, res);
+ if (pp->ecam_enabled) {
+ ret = dw_pcie_create_ecam_window(pp, res);
+ if (ret)
+ return ret;
+
+ pp->bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
+ pp->bridge->sysdata = pp->cfg;
+ pp->cfg->priv = pp;
+ } else {
+ pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res);
+ if (IS_ERR(pp->va_cfg0_base))
+ return PTR_ERR(pp->va_cfg0_base);
+
+ /* Set default bus ops */
+ pp->bridge->ops = &dw_pcie_ops;
+ pp->bridge->child_ops = &dw_child_pcie_ops;
+ pp->bridge->sysdata = pp;
+ }
+
+ ret = dw_pcie_get_resources(pci);
+ if (ret) {
+ if (pp->cfg)
+ pci_ecam_free(pp->cfg);
+ return ret;
+ }
/* Get the I/O range from DT */
win = resource_list_first_type(&pp->bridge->windows, IORESOURCE_IO);
@@ -476,14 +587,10 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
if (ret)
return ret;
- /* Set default bus ops */
- bridge->ops = &dw_pcie_ops;
- bridge->child_ops = &dw_child_pcie_ops;
-
if (pp->ops->init) {
ret = pp->ops->init(pp);
if (ret)
- return ret;
+ goto err_free_ecam;
}
if (pci_msi_enabled()) {
@@ -525,6 +632,14 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
if (ret)
goto err_free_msi;
+ if (pp->ecam_enabled) {
+ ret = dw_pcie_config_ecam_iatu(pp);
+ if (ret) {
+ dev_err(dev, "Failed to configure iATU in ECAM mode\n");
+ goto err_free_msi;
+ }
+ }
+
/*
* Allocate the resource for MSG TLP before programming the iATU
* outbound window in dw_pcie_setup_rc(). Since the allocation depends
@@ -560,8 +675,6 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
/* Ignore errors, the link may come up later */
dw_pcie_wait_for_link(pci);
- bridge->sysdata = pp;
-
ret = pci_host_probe(bridge);
if (ret)
goto err_stop_link;
@@ -587,6 +700,10 @@ err_deinit_host:
if (pp->ops->deinit)
pp->ops->deinit(pp);
+err_free_ecam:
+ if (pp->cfg)
+ pci_ecam_free(pp->cfg);
+
return ret;
}
EXPORT_SYMBOL_GPL(dw_pcie_host_init);
@@ -609,6 +726,9 @@ void dw_pcie_host_deinit(struct dw_pcie_rp *pp)
if (pp->ops->deinit)
pp->ops->deinit(pp);
+
+ if (pp->cfg)
+ pci_ecam_free(pp->cfg);
}
EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);