Skip to content

Commit a375121

Browse files
nxpfranklikwilczynski
authored andcommitted
PCI: Add enable_device() and disable_device() callbacks for bridges
Some PCI host bridges require special handling when enabling or disabling PCI devices. For example, the i.MX95 platform has a lookup table to map Requester IDs to StreamIDs, which the SMMU and MSI controller use to identify the source of DMA accesses. Without this mapping, DMA accesses may target unintended memory, which would corrupt memory or read the wrong data. Add a host bridge enable_device() hook the imx6 driver can use to configure the Requester ID to StreamID mapping. The hardware table isn't big enough to map all possible Requester IDs, so this hook may fail if no table space is available. In that case, return failure from pci_enable_device(). It might make more sense to make pci_set_master() decline to enable bus mastering and return failure, but it currently doesn't have a way to return failure. Link: https://lore.kernel.org/r/[email protected] Tested-by: Marc Zyngier <[email protected]> Signed-off-by: Frank Li <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> [kwilczynski: commit log] Signed-off-by: Krzysztof Wilczyński <[email protected]> Reviewed-by: Marc Zyngier <[email protected]> Acked-by: Manivannan Sadhasivam <[email protected]>
1 parent 40384c8 commit a375121

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

drivers/pci/pci.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,28 @@ int __weak pcibios_enable_device(struct pci_dev *dev, int bars)
20592059
return pci_enable_resources(dev, bars);
20602060
}
20612061

2062+
static int pci_host_bridge_enable_device(struct pci_dev *dev)
2063+
{
2064+
struct pci_host_bridge *host_bridge = pci_find_host_bridge(dev->bus);
2065+
int err;
2066+
2067+
if (host_bridge && host_bridge->enable_device) {
2068+
err = host_bridge->enable_device(host_bridge, dev);
2069+
if (err)
2070+
return err;
2071+
}
2072+
2073+
return 0;
2074+
}
2075+
2076+
static void pci_host_bridge_disable_device(struct pci_dev *dev)
2077+
{
2078+
struct pci_host_bridge *host_bridge = pci_find_host_bridge(dev->bus);
2079+
2080+
if (host_bridge && host_bridge->disable_device)
2081+
host_bridge->disable_device(host_bridge, dev);
2082+
}
2083+
20622084
static int do_pci_enable_device(struct pci_dev *dev, int bars)
20632085
{
20642086
int err;
@@ -2074,9 +2096,13 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
20742096
if (bridge)
20752097
pcie_aspm_powersave_config_link(bridge);
20762098

2099+
err = pci_host_bridge_enable_device(dev);
2100+
if (err)
2101+
return err;
2102+
20772103
err = pcibios_enable_device(dev, bars);
20782104
if (err < 0)
2079-
return err;
2105+
goto err_enable;
20802106
pci_fixup_device(pci_fixup_enable, dev);
20812107

20822108
if (dev->msi_enabled || dev->msix_enabled)
@@ -2091,6 +2117,12 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
20912117
}
20922118

20932119
return 0;
2120+
2121+
err_enable:
2122+
pci_host_bridge_disable_device(dev);
2123+
2124+
return err;
2125+
20942126
}
20952127

20962128
/**
@@ -2274,6 +2306,8 @@ void pci_disable_device(struct pci_dev *dev)
22742306
if (atomic_dec_return(&dev->enable_cnt) != 0)
22752307
return;
22762308

2309+
pci_host_bridge_disable_device(dev);
2310+
22772311
do_pci_disable_device(dev);
22782312

22792313
dev->is_busmaster = 0;

include/linux/pci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,8 @@ struct pci_host_bridge {
595595
u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* Platform IRQ swizzler */
596596
int (*map_irq)(const struct pci_dev *, u8, u8);
597597
void (*release_fn)(struct pci_host_bridge *);
598+
int (*enable_device)(struct pci_host_bridge *bridge, struct pci_dev *dev);
599+
void (*disable_device)(struct pci_host_bridge *bridge, struct pci_dev *dev);
598600
void *release_data;
599601
unsigned int ignore_reset_delay:1; /* For entire hierarchy */
600602
unsigned int no_ext_tags:1; /* No Extended Tags */

0 commit comments

Comments
 (0)