@@ -310,6 +310,7 @@ struct pci_dev_reset_method {
u16 vendor;
u16 device;
int (*reset)(struct pci_dev *dev, int probe);
+ struct list_head node;
};
#ifdef CONFIG_PCI_QUIRKS
@@ -3508,20 +3508,44 @@ static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
#define PCI_DEVICE_ID_INTEL_IVB_M_VGA 0x0156
#define PCI_DEVICE_ID_INTEL_IVB_M2_VGA 0x0166
-static const struct pci_dev_reset_method pci_dev_reset_methods[] = {
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
- reset_intel_82599_sfp_virtfn },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M_VGA,
- reset_ivb_igd },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M2_VGA,
- reset_ivb_igd },
- { PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
- reset_intel_generic_dev },
- { PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
- reset_chelsio_generic_dev },
- { 0 }
+static LIST_HEAD(pci_dev_reset_list);
+static DEFINE_MUTEX(pci_dev_reset_mutex);
+static bool pci_dev_reset_populated = false;
+static struct pci_dev_reset_method pci_dev_reset_methods[] = {
+ { .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_82599_SFP_VF,
+ .reset = reset_intel_82599_sfp_virtfn
+ },
+ { .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_IVB_M_VGA,
+ .reset = reset_ivb_igd
+ },
+ { .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_IVB_M2_VGA,
+ .reset =reset_ivb_igd
+ },
+ { .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_ANY_ID,
+ .reset = reset_intel_generic_dev
+ },
+ { .vendor = PCI_VENDOR_ID_CHELSIO,
+ .device = PCI_ANY_ID,
+ .reset = reset_chelsio_generic_dev
+ }
};
+static void pci_dev_populate_reset(void)
+{
+ struct pci_dev_reset_method *m;
+ int i;
+
+ for (i = ARRAY_SIZE(pci_dev_reset_methods) - 1; i >= 0; i--) {
+ m = &pci_dev_reset_methods[i];
+ INIT_LIST_HEAD(&m->node);
+ list_add(&m->node, &pci_dev_reset_list);
+ }
+}
+
/*
* These device-specific reset methods are here rather than in a driver
* because when a host assigns a device to a guest VM, the host may need
@@ -3529,16 +3553,29 @@ static const struct pci_dev_reset_method pci_dev_reset_methods[] = {
*/
int pci_dev_specific_reset(struct pci_dev *dev, int probe)
{
- const struct pci_dev_reset_method *i;
+ struct pci_dev_reset_method *m;
+ int ret;
- for (i = pci_dev_reset_methods; i->reset; i++) {
- if ((i->vendor == dev->vendor ||
- i->vendor == (u16)PCI_ANY_ID) &&
- (i->device == dev->device ||
- i->device == (u16)PCI_ANY_ID))
- return i->reset(dev, probe);
+ mutex_lock(&pci_dev_reset_mutex);
+
+ if (!pci_dev_reset_populated) {
+ pci_dev_populate_reset();
+ pci_dev_reset_populated = true;
}
+ list_for_each_entry(m, &pci_dev_reset_list, node) {
+ if ((m->vendor == dev->vendor ||
+ m->vendor == (u16)PCI_ANY_ID) &&
+ (m->device == dev->device ||
+ m->device == (u16)PCI_ANY_ID)) {
+ ret = m->reset(dev, probe);
+ mutex_unlock(&pci_dev_reset_mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&pci_dev_reset_mutex);
+
return -ENOTTY;
}
The patch introduces list to hold the PCI device specific reset methods. With help of the list, we can register PCI device specific reset method dynamically as we do in next one patch. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> --- drivers/pci/pci.h | 1 + drivers/pci/quirks.c | 75 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 19 deletions(-)