|
@@ -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;
|
|
|
-
|
|
|
- cpu_hotplug_disable();
|
|
|
+ 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);
|
|
|
- cpu_hotplug_enable();
|
|
|
- } 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;
|
|
|
}
|
|
|
|