From d3a78d8bf759d8848339dcc367c4c1678b57a08b Mon Sep 17 00:00:00 2001 From: Long Li Date: Thu, 23 Mar 2017 14:58:10 -0700 Subject: PCI: hv: Properly handle PCI bus remove hv_pci_devices_present() is called in hv_pci_remove() when we remove a PCI device from the host, e.g., by disabling SR-IOV on a device. In hv_pci_remove(), the bus is already removed before the call, so we don't need to rescan the bus in the workqueue scheduled from hv_pci_devices_present(). By introducing bus state hv_pcibus_removed, we can avoid this situation. Reported-by: Xiaofeng Wang Signed-off-by: Long Li Signed-off-by: Bjorn Helgaas Acked-by: K. Y. Srinivasan --- drivers/pci/host/pci-hyperv.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers/pci/host/pci-hyperv.c') diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index ada98569b78e..39fafda4deff 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -350,6 +350,7 @@ enum hv_pcibus_state { hv_pcibus_init = 0, hv_pcibus_probed, hv_pcibus_installed, + hv_pcibus_removed, hv_pcibus_maximum }; @@ -1504,13 +1505,24 @@ static void pci_devices_present_work(struct work_struct *work) put_pcichild(hpdev, hv_pcidev_ref_initial); } - /* Tell the core to rescan bus because there may have been changes. */ - if (hbus->state == hv_pcibus_installed) { + switch(hbus->state) { + case hv_pcibus_installed: + /* + * Tell the core to rescan bus + * because there may have been changes. + */ pci_lock_rescan_remove(); pci_scan_child_bus(hbus->pci_bus); pci_unlock_rescan_remove(); - } else { + break; + + case hv_pcibus_init: + case hv_pcibus_probed: survey_child_resources(hbus); + break; + + default: + break; } up(&hbus->enum_sem); @@ -2185,6 +2197,7 @@ static int hv_pci_probe(struct hv_device *hdev, hbus = kzalloc(sizeof(*hbus), GFP_KERNEL); if (!hbus) return -ENOMEM; + hbus->state = hv_pcibus_init; /* * The PCI bus "domain" is what is called "segment" in ACPI and @@ -2348,6 +2361,7 @@ static int hv_pci_remove(struct hv_device *hdev) pci_stop_root_bus(hbus->pci_bus); pci_remove_root_bus(hbus->pci_bus); pci_unlock_rescan_remove(); + hbus->state = hv_pcibus_removed; } hv_pci_bus_exit(hdev); -- cgit