diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/Kconfig | 3 | ||||
-rw-r--r-- | drivers/pci/access.c | 16 | ||||
-rw-r--r-- | drivers/pci/host/vmd.c | 8 | ||||
-rw-r--r-- | drivers/pci/msi.c | 2 | ||||
-rw-r--r-- | drivers/pci/pci-driver.c | 55 |
5 files changed, 52 insertions, 32 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index e0cacb7b8563..c32a77fc8b03 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -86,6 +86,9 @@ config PCI_ATS config PCI_ECAM bool +config PCI_LOCKLESS_CONFIG + bool + config PCI_IOV bool "PCI IOV support" depends on PCI diff --git a/drivers/pci/access.c b/drivers/pci/access.c index c80e37a69305..913d6722ece9 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -25,6 +25,14 @@ DEFINE_RAW_SPINLOCK(pci_lock); #define PCI_word_BAD (pos & 1) #define PCI_dword_BAD (pos & 3) +#ifdef CONFIG_PCI_LOCKLESS_CONFIG +# define pci_lock_config(f) do { (void)(f); } while (0) +# define pci_unlock_config(f) do { (void)(f); } while (0) +#else +# define pci_lock_config(f) raw_spin_lock_irqsave(&pci_lock, f) +# define pci_unlock_config(f) raw_spin_unlock_irqrestore(&pci_lock, f) +#endif + #define PCI_OP_READ(size, type, len) \ int pci_bus_read_config_##size \ (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ @@ -33,10 +41,10 @@ int pci_bus_read_config_##size \ unsigned long flags; \ u32 data = 0; \ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ - raw_spin_lock_irqsave(&pci_lock, flags); \ + pci_lock_config(flags); \ res = bus->ops->read(bus, devfn, pos, len, &data); \ *value = (type)data; \ - raw_spin_unlock_irqrestore(&pci_lock, flags); \ + pci_unlock_config(flags); \ return res; \ } @@ -47,9 +55,9 @@ int pci_bus_write_config_##size \ int res; \ unsigned long flags; \ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ - raw_spin_lock_irqsave(&pci_lock, flags); \ + pci_lock_config(flags); \ res = bus->ops->write(bus, devfn, pos, len, value); \ - raw_spin_unlock_irqrestore(&pci_lock, flags); \ + pci_unlock_config(flags); \ return res; \ } diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c index e27ad2a3bd33..31203d69616d 100644 --- a/drivers/pci/host/vmd.c +++ b/drivers/pci/host/vmd.c @@ -554,6 +554,7 @@ static int vmd_find_free_domain(void) static int vmd_enable_domain(struct vmd_dev *vmd) { struct pci_sysdata *sd = &vmd->sysdata; + struct fwnode_handle *fn; struct resource *res; u32 upper_bits; unsigned long flags; @@ -617,8 +618,13 @@ static int vmd_enable_domain(struct vmd_dev *vmd) sd->node = pcibus_to_node(vmd->dev->bus); - vmd->irq_domain = pci_msi_create_irq_domain(NULL, &vmd_msi_domain_info, + fn = irq_domain_alloc_named_id_fwnode("VMD-MSI", vmd->sysdata.domain); + if (!fn) + return -ENODEV; + + vmd->irq_domain = pci_msi_create_irq_domain(fn, &vmd_msi_domain_info, x86_vector_domain); + irq_domain_free_fwnode(fn); if (!vmd->irq_domain) return -ENODEV; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ba44fdfda66b..fbad5dca3219 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1463,7 +1463,7 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, if (!domain) return NULL; - domain->bus_token = DOMAIN_BUS_PCI_MSI; + irq_domain_update_bus_token(domain, DOMAIN_BUS_PCI_MSI); return domain; } EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain); diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index ffe7d54d9328..df4aead394f2 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -96,7 +96,7 @@ static void pci_free_dynids(struct pci_driver *drv) * * Allow PCI IDs to be added to an existing driver via sysfs. */ -static ssize_t store_new_id(struct device_driver *driver, const char *buf, +static ssize_t new_id_store(struct device_driver *driver, const char *buf, size_t count) { struct pci_driver *pdrv = to_pci_driver(driver); @@ -154,7 +154,7 @@ static ssize_t store_new_id(struct device_driver *driver, const char *buf, return retval; return count; } -static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); +static DRIVER_ATTR_WO(new_id); /** * store_remove_id - remove a PCI device ID from this driver @@ -164,7 +164,7 @@ static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); * * Removes a dynamic pci device ID to this driver. */ -static ssize_t store_remove_id(struct device_driver *driver, const char *buf, +static ssize_t remove_id_store(struct device_driver *driver, const char *buf, size_t count) { struct pci_dynid *dynid, *n; @@ -198,7 +198,7 @@ static ssize_t store_remove_id(struct device_driver *driver, const char *buf, return retval; } -static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); +static DRIVER_ATTR_WO(remove_id); static struct attribute *pci_drv_attrs[] = { &driver_attr_new_id.attr, @@ -320,10 +320,19 @@ static long local_pci_probe(void *_ddi) return 0; } +static bool pci_physfn_is_probed(struct pci_dev *dev) +{ +#ifdef CONFIG_PCI_IOV + return dev->is_virtfn && dev->physfn->is_probed; +#else + return false; +#endif +} + static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, const struct pci_device_id *id) { - int error, node; + int error, node, cpu; struct drv_dev_and_id ddi = { drv, dev, id }; /* @@ -332,33 +341,27 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, * on the right node. */ node = dev_to_node(&dev->dev); + dev->is_probed = 1; + + cpu_hotplug_disable(); /* - * On NUMA systems, we are likely to call a PF probe function using - * work_on_cpu(). If that probe calls pci_enable_sriov() (which - * adds the VF devices via pci_bus_add_device()), we may re-enter - * this function to call the VF probe function. Calling - * work_on_cpu() again will cause a lockdep warning. Since VFs are - * always on the same node as the PF, we can work around this by - * avoiding work_on_cpu() when we're already on the correct node. - * - * Preemption is enabled, so it's theoretically unsafe to use - * numa_node_id(), but even if we run the probe function on the - * wrong node, it should be functionally correct. + * Prevent nesting work_on_cpu() for the case where a Virtual Function + * device is probed from work_on_cpu() of the Physical device. */ - if (node >= 0 && node != numa_node_id()) { - int cpu; - - get_online_cpus(); + if (node < 0 || node >= MAX_NUMNODES || !node_online(node) || + pci_physfn_is_probed(dev)) + cpu = nr_cpu_ids; + else cpu = cpumask_any_and(cpumask_of_node(node), cpu_online_mask); - if (cpu < nr_cpu_ids) - error = work_on_cpu(cpu, local_pci_probe, &ddi); - else - error = local_pci_probe(&ddi); - put_online_cpus(); - } else + + if (cpu < nr_cpu_ids) + error = work_on_cpu(cpu, local_pci_probe, &ddi); + else error = local_pci_probe(&ddi); + dev->is_probed = 0; + cpu_hotplug_enable(); return error; } |