diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/p2pdma.c | 10 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 16 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 5 | ||||
-rw-r--r-- | drivers/pci/pci.c | 4 | ||||
-rw-r--r-- | drivers/pci/probe.c | 2 | ||||
-rw-r--r-- | drivers/pci/proc.c | 2 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 110 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 60 | ||||
-rw-r--r-- | drivers/pci/slot.c | 1 |
9 files changed, 151 insertions, 59 deletions
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 742928d0053e..1940a7a0a684 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -468,6 +468,14 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients, return -1; for (i = 0; i < num_clients; i++) { + if (IS_ENABLED(CONFIG_DMA_VIRT_OPS) && + clients[i]->dma_ops == &dma_virt_ops) { + if (verbose) + dev_warn(clients[i], + "cannot be used for peer-to-peer DMA because the driver makes use of dma_virt_ops\n"); + return -1; + } + pci_client = find_parent_pci_dev(clients[i]); if (!pci_client) { if (verbose) @@ -732,7 +740,7 @@ int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents, * p2pdma mappings are not compatible with devices that use * dma_virt_ops. If the upper layers do the right thing * this should never happen because it will be prevented - * by the check in pci_p2pdma_add_client() + * by the check in pci_p2pdma_distance_many() */ if (WARN_ON_ONCE(IS_ENABLED(CONFIG_DMA_VIRT_OPS) && dev->dma_ops == &dma_virt_ops)) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index cae630fe6387..b6a3a51801f0 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -399,7 +399,8 @@ void __weak pcibios_free_irq(struct pci_dev *dev) #ifdef CONFIG_PCI_IOV static inline bool pci_device_can_probe(struct pci_dev *pdev) { - return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe); + return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe || + pdev->driver_override); } #else static inline bool pci_device_can_probe(struct pci_dev *pdev) @@ -414,6 +415,9 @@ static int pci_device_probe(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_driver *drv = to_pci_driver(dev->driver); + if (!pci_device_can_probe(pci_dev)) + return -ENODEV; + pci_assign_irq(pci_dev); error = pcibios_alloc_irq(pci_dev); @@ -421,12 +425,10 @@ static int pci_device_probe(struct device *dev) return error; pci_dev_get(pci_dev); - if (pci_device_can_probe(pci_dev)) { - error = __pci_device_probe(drv, pci_dev); - if (error) { - pcibios_free_irq(pci_dev); - pci_dev_put(pci_dev); - } + error = __pci_device_probe(drv, pci_dev); + if (error) { + pcibios_free_irq(pci_dev); + pci_dev_put(pci_dev); } return error; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 6d27475e39b2..965c72104150 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -182,6 +182,9 @@ static ssize_t current_link_speed_show(struct device *dev, return -EINVAL; switch (linkstat & PCI_EXP_LNKSTA_CLS) { + case PCI_EXP_LNKSTA_CLS_32_0GB: + speed = "32 GT/s"; + break; case PCI_EXP_LNKSTA_CLS_16_0GB: speed = "16 GT/s"; break; @@ -477,7 +480,7 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr, pci_stop_and_remove_bus_device_locked(to_pci_dev(dev)); return count; } -static struct device_attribute dev_remove_attr = __ATTR(remove, +static struct device_attribute dev_remove_attr = __ATTR_IGNORE_LOCKDEP(remove, (S_IWUSR|S_IWGRP), NULL, remove_store); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8abc843b1615..4729a7c7a9d9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5621,7 +5621,9 @@ enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev) */ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2); if (lnkcap2) { /* PCIe r3.0-compliant */ - if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB) + if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_32_0GB) + return PCIE_SPEED_32_0GT; + else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB) return PCIE_SPEED_16_0GT; else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) return PCIE_SPEED_8_0GT; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 439244ff8f09..5a0b07428425 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -668,7 +668,7 @@ const unsigned char pcie_link_speed[] = { PCIE_SPEED_5_0GT, /* 2 */ PCIE_SPEED_8_0GT, /* 3 */ PCIE_SPEED_16_0GT, /* 4 */ - PCI_SPEED_UNKNOWN, /* 5 */ + PCIE_SPEED_32_0GT, /* 5 */ PCI_SPEED_UNKNOWN, /* 6 */ PCI_SPEED_UNKNOWN, /* 7 */ PCI_SPEED_UNKNOWN, /* 8 */ diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 445b51db75b0..fe7fe678965b 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -377,7 +377,7 @@ static int show_device(struct seq_file *m, void *v) } seq_putc(m, '\t'); if (drv) - seq_printf(m, "%s", drv->name); + seq_puts(m, drv->name); seq_putc(m, '\n'); return 0; } diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0f16acc323c6..208aacf39329 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4934,35 +4934,49 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi); /* - * GPUs with integrated HDA controller for streaming audio to attached displays - * need a device link from the HDA controller (consumer) to the GPU (supplier) - * so that the GPU is powered up whenever the HDA controller is accessed. - * The GPU and HDA controller are functions 0 and 1 of the same PCI device. - * The device link stays in place until shutdown (or removal of the PCI device - * if it's hotplugged). Runtime PM is allowed by default on the HDA controller - * to prevent it from permanently keeping the GPU awake. + * Although not allowed by the spec, some multi-function devices have + * dependencies of one function (consumer) on another (supplier). For the + * consumer to work in D0, the supplier must also be in D0. Create a + * device link from the consumer to the supplier to enforce this + * dependency. Runtime PM is allowed by default on the consumer to prevent + * it from permanently keeping the supplier awake. */ -static void quirk_gpu_hda(struct pci_dev *hda) +static void pci_create_device_link(struct pci_dev *pdev, unsigned int consumer, + unsigned int supplier, unsigned int class, + unsigned int class_shift) { - struct pci_dev *gpu; + struct pci_dev *supplier_pdev; - if (PCI_FUNC(hda->devfn) != 1) + if (PCI_FUNC(pdev->devfn) != consumer) return; - gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus), - hda->bus->number, - PCI_DEVFN(PCI_SLOT(hda->devfn), 0)); - if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) { - pci_dev_put(gpu); + supplier_pdev = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), + pdev->bus->number, + PCI_DEVFN(PCI_SLOT(pdev->devfn), supplier)); + if (!supplier_pdev || (supplier_pdev->class >> class_shift) != class) { + pci_dev_put(supplier_pdev); return; } - if (!device_link_add(&hda->dev, &gpu->dev, - DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) - pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu)); + if (device_link_add(&pdev->dev, &supplier_pdev->dev, + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) + pci_info(pdev, "D0 power state depends on %s\n", + pci_name(supplier_pdev)); + else + pci_err(pdev, "Cannot enforce power dependency on %s\n", + pci_name(supplier_pdev)); + + pm_runtime_allow(&pdev->dev); + pci_dev_put(supplier_pdev); +} - pm_runtime_allow(&hda->dev); - pci_dev_put(gpu); +/* + * Create device link for GPUs with integrated HDA controller for streaming + * audio to attached displays. + */ +static void quirk_gpu_hda(struct pci_dev *hda) +{ + pci_create_device_link(hda, 1, 0, PCI_BASE_CLASS_DISPLAY, 16); } DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); @@ -4972,6 +4986,62 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda); /* + * Create device link for NVIDIA GPU with integrated USB xHCI Host + * controller to VGA. + */ +static void quirk_gpu_usb(struct pci_dev *usb) +{ + pci_create_device_link(usb, 2, 0, PCI_BASE_CLASS_DISPLAY, 16); +} +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_CLASS_SERIAL_USB, 8, quirk_gpu_usb); + +/* + * Create device link for NVIDIA GPU with integrated Type-C UCSI controller + * to VGA. Currently there is no class code defined for UCSI device over PCI + * so using UNKNOWN class for now and it will be updated when UCSI + * over PCI gets a class code. + */ +#define PCI_CLASS_SERIAL_UNKNOWN 0x0c80 +static void quirk_gpu_usb_typec_ucsi(struct pci_dev *ucsi) +{ + pci_create_device_link(ucsi, 3, 0, PCI_BASE_CLASS_DISPLAY, 16); +} +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_CLASS_SERIAL_UNKNOWN, 8, + quirk_gpu_usb_typec_ucsi); + +/* + * Enable the NVIDIA GPU integrated HDA controller if the BIOS left it + * disabled. https://devtalk.nvidia.com/default/topic/1024022 + */ +static void quirk_nvidia_hda(struct pci_dev *gpu) +{ + u8 hdr_type; + u32 val; + + /* There was no integrated HDA controller before MCP89 */ + if (gpu->device < PCI_DEVICE_ID_NVIDIA_GEFORCE_320M) + return; + + /* Bit 25 at offset 0x488 enables the HDA controller */ + pci_read_config_dword(gpu, 0x488, &val); + if (val & BIT(25)) + return; + + pci_info(gpu, "Enabling HDA controller\n"); + pci_write_config_dword(gpu, 0x488, val | BIT(25)); + + /* The GPU becomes a multi-function device when the HDA is enabled */ + pci_read_config_byte(gpu, PCI_HEADER_TYPE, &hdr_type); + gpu->multifunction = !!(hdr_type & 0x80); +} +DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_BASE_CLASS_DISPLAY, 16, quirk_nvidia_hda); +DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_BASE_CLASS_DISPLAY, 16, quirk_nvidia_hda); + +/* * Some IDT switches incorrectly flag an ACS Source Validation error on * completions for config read requests even though PCIe r4.0, sec * 6.12.1.1, says that completions are never affected by ACS Source diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 0cdd5ff389de..79b1fa6519be 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1684,10 +1684,15 @@ static enum enable_type pci_realloc_detect(struct pci_bus *bus, enum enable_type enable_local) { bool unassigned = false; + struct pci_host_bridge *host; if (enable_local != undefined) return enable_local; + host = pci_find_host_bridge(bus); + if (host->preserve_config) + return auto_disabled; + pci_walk_bus(bus, iov_resources_unassigned, &unassigned); if (unassigned) return auto_enabled; @@ -1861,16 +1866,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, available_mmio_pref); /* - * Calculate the total amount of extra resource space we can - * pass to bridges below this one. This is basically the - * extra space reduced by the minimal required space for the - * non-hotplug bridges. - */ - remaining_io = available_io; - remaining_mmio = available_mmio; - remaining_mmio_pref = available_mmio_pref; - - /* * Calculate how many hotplug bridges and normal bridges there * are on this bus. We will distribute the additional available * resources between hotplug bridges. @@ -1882,6 +1877,34 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, normal_bridges++; } + /* + * There is only one bridge on the bus so it gets all available + * resources which it can then distribute to the possible hotplug + * bridges below. + */ + if (hotplug_bridges + normal_bridges == 1) { + dev = list_first_entry(&bus->devices, struct pci_dev, bus_list); + if (dev->subordinate) { + pci_bus_distribute_available_resources(dev->subordinate, + add_list, available_io, available_mmio, + available_mmio_pref); + } + return; + } + + if (hotplug_bridges == 0) + return; + + /* + * Calculate the total amount of extra resource space we can + * pass to bridges below this one. This is basically the + * extra space reduced by the minimal required space for the + * non-hotplug bridges. + */ + remaining_io = available_io; + remaining_mmio = available_mmio; + remaining_mmio_pref = available_mmio_pref; + for_each_pci_bridge(dev, bus) { const struct resource *res; @@ -1906,21 +1929,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, } /* - * There is only one bridge on the bus so it gets all available - * resources which it can then distribute to the possible hotplug - * bridges below. - */ - if (hotplug_bridges + normal_bridges == 1) { - dev = list_first_entry(&bus->devices, struct pci_dev, bus_list); - if (dev->subordinate) { - pci_bus_distribute_available_resources(dev->subordinate, - add_list, available_io, available_mmio, - available_mmio_pref); - } - return; - } - - /* * Go over devices on this bus and distribute the remaining * resource space between hotplug bridges. */ @@ -1936,8 +1944,6 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, * Distribute available extra resources equally between * hotplug-capable downstream ports taking alignment into * account. - * - * Here hotplug_bridges is always != 0. */ align = pci_resource_alignment(bridge, io_res); io = div64_ul(available_io, hotplug_bridges); diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index f4d92b1afe7b..ae4aa0e1f2f4 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -75,6 +75,7 @@ static const char *pci_bus_speed_strings[] = { "5.0 GT/s PCIe", /* 0x15 */ "8.0 GT/s PCIe", /* 0x16 */ "16.0 GT/s PCIe", /* 0x17 */ + "32.0 GT/s PCIe", /* 0x18 */ }; static ssize_t bus_speed_read(enum pci_bus_speed speed, char *buf) |