]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/pci/pci-driver.c
Merge tag 'pci-v4.13-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[karo-tx-linux.git] / drivers / pci / pci-driver.c
index 50f93a3bc4c08392f0ffd7d3afd7f0666fc1f748..607f677f48d21f7b7f1b938ec39c11034c4dac17 100644 (file)
@@ -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;
 }
 
@@ -1219,7 +1222,7 @@ static int pci_pm_runtime_resume(struct device *dev)
 
        pci_restore_standard_config(pci_dev);
        pci_fixup_device(pci_fixup_resume_early, pci_dev);
-       __pci_enable_wake(pci_dev, PCI_D0, true, false);
+       pci_enable_wake(pci_dev, PCI_D0, false);
        pci_fixup_device(pci_fixup_resume, pci_dev);
 
        rc = pm->runtime_resume(dev);