Skip to content

Commit

Permalink
powerpc/eeh: Use global PCI rescan-remove locking
Browse files Browse the repository at this point in the history
Race conditions are theoretically possible between the PCI device addition
and removal in the PPC64 PCI error recovery driver and the generic PCI bus
rescan and device removal that can be triggered via sysfs.

To avoid those race conditions make PPC64 PCI error recovery driver use
global PCI rescan-remove locking around PCI device addition and removal.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
  • Loading branch information
Rafael J. Wysocki authored and Bjorn Helgaas committed Jan 15, 2014
1 parent 64cdb41 commit 1c2042c
Showing 1 changed file with 16 additions and 3 deletions.
19 changes: 16 additions & 3 deletions arch/powerpc/kernel/eeh_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,9 @@ static void *eeh_rmv_device(void *data, void *userdata)
edev->mode |= EEH_DEV_DISCONNECTED;
(*removed)++;

pci_lock_rescan_remove();
pci_stop_and_remove_bus_device(dev);
pci_unlock_rescan_remove();

return NULL;
}
Expand Down Expand Up @@ -416,10 +418,13 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
* into pcibios_add_pci_devices().
*/
eeh_pe_state_mark(pe, EEH_PE_KEEP);
if (bus)
if (bus) {
pci_lock_rescan_remove();
pcibios_remove_pci_devices(bus);
else if (frozen_bus)
pci_unlock_rescan_remove();
} else if (frozen_bus) {
eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed);
}

/* Reset the pci controller. (Asserts RST#; resets config space).
* Reconfigure bridges and devices. Don't try to bring the system
Expand All @@ -429,6 +434,8 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
if (rc)
return rc;

pci_lock_rescan_remove();

/* Restore PE */
eeh_ops->configure_bridge(pe);
eeh_pe_restore_bars(pe);
Expand Down Expand Up @@ -462,6 +469,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
pe->tstamp = tstamp;
pe->freeze_count = cnt;

pci_unlock_rescan_remove();
return 0;
}

Expand Down Expand Up @@ -618,8 +626,11 @@ static void eeh_handle_normal_event(struct eeh_pe *pe)
eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);

/* Shut down the device drivers for good. */
if (frozen_bus)
if (frozen_bus) {
pci_lock_rescan_remove();
pcibios_remove_pci_devices(frozen_bus);
pci_unlock_rescan_remove();
}
}

static void eeh_handle_special_event(void)
Expand Down Expand Up @@ -692,6 +703,7 @@ static void eeh_handle_special_event(void)
if (rc == 2 || rc == 1)
eeh_handle_normal_event(pe);
else {
pci_lock_rescan_remove();
list_for_each_entry_safe(hose, tmp,
&hose_list, list_node) {
phb_pe = eeh_phb_pe_get(hose);
Expand All @@ -703,6 +715,7 @@ static void eeh_handle_special_event(void)
eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
pcibios_remove_pci_devices(bus);
}
pci_unlock_rescan_remove();
}
}

Expand Down

0 comments on commit 1c2042c

Please sign in to comment.