diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/endpoint/functions/pci-epf-test.c | 1 | ||||
-rw-r--r-- | drivers/pci/mmap.c | 44 | ||||
-rw-r--r-- | drivers/pci/pci.c | 6 | ||||
-rw-r--r-- | drivers/pci/pci.h | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aer.c | 15 | ||||
-rw-r--r-- | drivers/pci/pcie/aspm.c | 20 | ||||
-rw-r--r-- | drivers/pci/pcie/err.c | 12 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 9 | ||||
-rw-r--r-- | drivers/pci/probe.c | 90 | ||||
-rw-r--r-- | drivers/pci/proc.c | 7 |
10 files changed, 70 insertions, 136 deletions
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 5b833f00e980..a5ed779b0a51 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -627,7 +627,6 @@ static void pci_epf_test_unbind(struct pci_epf *epf) cancel_delayed_work(&epf_test->cmd_handler); pci_epf_test_clean_dma_chan(epf_test); - pci_epc_stop(epc); for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { epf_bar = &epf->bar[bar]; diff --git a/drivers/pci/mmap.c b/drivers/pci/mmap.c index b8c9011987f4..4504039056d1 100644 --- a/drivers/pci/mmap.c +++ b/drivers/pci/mmap.c @@ -13,27 +13,6 @@ #ifdef ARCH_GENERIC_PCI_MMAP_RESOURCE -/* - * Modern setup: generic pci_mmap_resource_range(), and implement the legacy - * pci_mmap_page_range() (if needed) as a wrapper round it. - */ - -#ifdef HAVE_PCI_MMAP -int pci_mmap_page_range(struct pci_dev *pdev, int bar, - struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, int write_combine) -{ - resource_size_t start, end; - - pci_resource_to_user(pdev, bar, &pdev->resource[bar], &start, &end); - - /* Adjust vm_pgoff to be the offset within the resource */ - vma->vm_pgoff -= start >> PAGE_SHIFT; - return pci_mmap_resource_range(pdev, bar, vma, mmap_state, - write_combine); -} -#endif - static const struct vm_operations_struct pci_phys_vm_ops = { #ifdef CONFIG_HAVE_IOREMAP_PROT .access = generic_access_phys, @@ -70,27 +49,4 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar, vma->vm_page_prot); } -#elif defined(HAVE_PCI_MMAP) /* && !ARCH_GENERIC_PCI_MMAP_RESOURCE */ - -/* - * Legacy setup: Implement pci_mmap_resource_range() as a wrapper around - * the architecture's pci_mmap_page_range(), converting to "user visible" - * addresses as necessary. - */ - -int pci_mmap_resource_range(struct pci_dev *pdev, int bar, - struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, int write_combine) -{ - resource_size_t start, end; - - /* - * pci_mmap_page_range() expects the same kind of entry as coming - * from /proc/bus/pci/ which is a "user visible" value. If this is - * different from the resource itself, arch will do necessary fixup. - */ - pci_resource_to_user(pdev, bar, &pdev->resource[bar], &start, &end); - vma->vm_pgoff += start >> PAGE_SHIFT; - return pci_mmap_page_range(pdev, bar, vma, mmap_state, write_combine); -} #endif diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cfaf40a540a8..093303c27ea8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1293,9 +1293,6 @@ static int pci_set_full_power_state(struct pci_dev *dev) pci_restore_bars(dev); } - if (dev->bus->self) - pcie_aspm_pm_state_change(dev->bus->self); - return 0; } @@ -1390,9 +1387,6 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state) pci_power_name(dev->current_state), pci_power_name(state)); - if (dev->bus->self) - pcie_aspm_pm_state_change(dev->bus->self); - return 0; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index e10cdec6c56e..785f31086313 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -560,12 +560,10 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active); #ifdef CONFIG_PCIEASPM void pcie_aspm_init_link_state(struct pci_dev *pdev); void pcie_aspm_exit_link_state(struct pci_dev *pdev); -void pcie_aspm_pm_state_change(struct pci_dev *pdev); void pcie_aspm_powersave_config_link(struct pci_dev *pdev); #else static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { } static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { } -static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { } static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { } #endif diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 7952e5efd6cf..e2d8a74f83c3 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -392,6 +392,11 @@ void pci_aer_init(struct pci_dev *dev) pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_ERR, sizeof(u32) * n); pci_aer_clear_status(dev); + + if (pci_aer_available()) + pci_enable_pcie_error_reporting(dev); + + pcie_set_ecrc_checking(dev); } void pci_aer_exit(struct pci_dev *dev) @@ -538,7 +543,7 @@ static const char *aer_agent_string[] = { u64 *stats = pdev->aer_stats->stats_array; \ size_t len = 0; \ \ - for (i = 0; i < ARRAY_SIZE(strings_array); i++) { \ + for (i = 0; i < ARRAY_SIZE(pdev->aer_stats->stats_array); i++) {\ if (strings_array[i]) \ len += sysfs_emit_at(buf, len, "%s %llu\n", \ strings_array[i], \ @@ -1228,9 +1233,6 @@ static int set_device_error_reporting(struct pci_dev *dev, void *data) pci_disable_pcie_error_reporting(dev); } - if (enable) - pcie_set_ecrc_checking(dev); - return 0; } @@ -1347,6 +1349,11 @@ static int aer_probe(struct pcie_device *dev) struct device *device = &dev->device; struct pci_dev *port = dev->port; + BUILD_BUG_ON(ARRAY_SIZE(aer_correctable_error_string) < + AER_MAX_TYPEOF_COR_ERRS); + BUILD_BUG_ON(ARRAY_SIZE(aer_uncorrectable_error_string) < + AER_MAX_TYPEOF_UNCOR_ERRS); + /* Limit to Root Ports or Root Complex Event Collectors */ if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) && (pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT)) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index a96b7424c9bc..a8aec190986c 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -1012,25 +1012,6 @@ out: up_read(&pci_bus_sem); } -/* @pdev: the root port or switch downstream port */ -void pcie_aspm_pm_state_change(struct pci_dev *pdev) -{ - struct pcie_link_state *link = pdev->link_state; - - if (aspm_disabled || !link) - return; - /* - * Devices changed PM state, we should recheck if latency - * meets all functions' requirement - */ - down_read(&pci_bus_sem); - mutex_lock(&aspm_lock); - pcie_update_aspm_capable(link->root); - pcie_config_aspm_path(link); - mutex_unlock(&aspm_lock); - up_read(&pci_bus_sem); -} - void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { struct pcie_link_state *link = pdev->link_state; @@ -1366,4 +1347,3 @@ bool pcie_aspm_support_enabled(void) { return aspm_support_enabled; } -EXPORT_SYMBOL(pcie_aspm_support_enabled); diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c index 0c5a143025af..59c90d04a609 100644 --- a/drivers/pci/pcie/err.c +++ b/drivers/pci/pcie/err.c @@ -55,10 +55,14 @@ static int report_error_detected(struct pci_dev *dev, device_lock(&dev->dev); pdrv = dev->driver; - if (!pci_dev_set_io_state(dev, state) || - !pdrv || - !pdrv->err_handler || - !pdrv->err_handler->error_detected) { + if (pci_dev_is_disconnected(dev)) { + vote = PCI_ERS_RESULT_DISCONNECT; + } else if (!pci_dev_set_io_state(dev, state)) { + pci_info(dev, "can't recover (state transition %u -> %u invalid)\n", + dev->error_state, state); + vote = PCI_ERS_RESULT_NONE; + } else if (!pdrv || !pdrv->err_handler || + !pdrv->err_handler->error_detected) { /* * If any device in the subtree does not have an error_detected * callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 604feeb84ee4..1ac7fec47d6f 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -222,15 +222,8 @@ static int get_port_device_capability(struct pci_dev *dev) #ifdef CONFIG_PCIEAER if (dev->aer_cap && pci_aer_available() && - (pcie_ports_native || host->native_aer)) { + (pcie_ports_native || host->native_aer)) services |= PCIE_PORT_SERVICE_AER; - - /* - * Disable AER on this port in case it's been enabled by the - * BIOS (the AER service driver will enable it when necessary). - */ - pci_disable_pcie_error_reporting(dev); - } #endif /* Root Ports and Root Complex Event Collectors may generate PMEs */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 17a969942d37..9884d8b29d3b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1890,6 +1890,9 @@ int pci_setup_device(struct pci_dev *dev) dev->broken_intx_masking = pci_intx_mask_broken(dev); + /* Clear errors left from system firmware */ + pci_write_config_word(dev, PCI_STATUS, 0xffff); + switch (dev->hdr_type) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ if (class == PCI_CLASS_BRIDGE_PCI) @@ -2579,33 +2582,39 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) } EXPORT_SYMBOL(pci_scan_single_device); -static unsigned int next_fn(struct pci_bus *bus, struct pci_dev *dev, - unsigned int fn) +static int next_ari_fn(struct pci_bus *bus, struct pci_dev *dev, int fn) { int pos; u16 cap = 0; unsigned int next_fn; - if (pci_ari_enabled(bus)) { - if (!dev) - return 0; - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); - if (!pos) - return 0; + if (!dev) + return -ENODEV; - pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap); - next_fn = PCI_ARI_CAP_NFN(cap); - if (next_fn <= fn) - return 0; /* protect against malformed list */ + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); + if (!pos) + return -ENODEV; - return next_fn; - } + pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap); + next_fn = PCI_ARI_CAP_NFN(cap); + if (next_fn <= fn) + return -ENODEV; /* protect against malformed list */ - /* dev may be NULL for non-contiguous multifunction devices */ - if (!dev || dev->multifunction) - return (fn + 1) % 8; + return next_fn; +} - return 0; +static int next_fn(struct pci_bus *bus, struct pci_dev *dev, int fn) +{ + if (pci_ari_enabled(bus)) + return next_ari_fn(bus, dev, fn); + + if (fn >= 7) + return -ENODEV; + /* only multifunction devices may have more functions */ + if (dev && !dev->multifunction) + return -ENODEV; + + return fn + 1; } static int only_one_child(struct pci_bus *bus) @@ -2643,26 +2652,30 @@ static int only_one_child(struct pci_bus *bus) */ int pci_scan_slot(struct pci_bus *bus, int devfn) { - unsigned int fn, nr = 0; struct pci_dev *dev; + int fn = 0, nr = 0; if (only_one_child(bus) && (devfn > 0)) return 0; /* Already scanned the entire slot */ - dev = pci_scan_single_device(bus, devfn); - if (!dev) - return 0; - if (!pci_dev_is_added(dev)) - nr++; - - for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) { + do { dev = pci_scan_single_device(bus, devfn + fn); if (dev) { if (!pci_dev_is_added(dev)) nr++; - dev->multifunction = 1; + if (fn > 0) + dev->multifunction = 1; + } else if (fn == 0) { + /* + * Function 0 is required unless we are running on + * a hypervisor that passes through individual PCI + * functions. + */ + if (!hypervisor_isolated_pci_functions()) + break; } - } + fn = next_fn(bus, dev, fn); + } while (fn >= 0); /* Only one slot has PCIe device */ if (bus->self && nr) @@ -2858,29 +2871,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus, { unsigned int used_buses, normal_bridges = 0, hotplug_bridges = 0; unsigned int start = bus->busn_res.start; - unsigned int devfn, fn, cmax, max = start; + unsigned int devfn, cmax, max = start; struct pci_dev *dev; - int nr_devs; dev_dbg(&bus->dev, "scanning bus\n"); /* Go find them, Rover! */ - for (devfn = 0; devfn < 256; devfn += 8) { - nr_devs = pci_scan_slot(bus, devfn); - - /* - * The Jailhouse hypervisor may pass individual functions of a - * multi-function device to a guest without passing function 0. - * Look for them as well. - */ - if (jailhouse_paravirt() && nr_devs == 0) { - for (fn = 1; fn < 8; fn++) { - dev = pci_scan_single_device(bus, devfn + fn); - if (dev) - dev->multifunction = 1; - } - } - } + for (devfn = 0; devfn < 256; devfn += 8) + pci_scan_slot(bus, devfn); /* Reserve buses for SR-IOV capability */ used_buses = pci_iov_bus_range(bus); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 31b26d8ea6cc..f967709082d6 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -244,6 +244,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) { struct pci_dev *dev = pde_data(file_inode(file)); struct pci_filp_private *fpriv = file->private_data; + resource_size_t start, end; int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM; if (!capable(CAP_SYS_RAWIO) || @@ -278,7 +279,11 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) iomem_is_exclusive(dev->resource[i].start)) return -EINVAL; - ret = pci_mmap_page_range(dev, i, vma, + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); + + /* Adjust vm_pgoff to be the offset within the resource */ + vma->vm_pgoff -= start >> PAGE_SHIFT; + ret = pci_mmap_resource_range(dev, i, vma, fpriv->mmap_state, write_combine); if (ret < 0) return ret; |