aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@rjwysocki.net>2014-01-15 08:33:20 -0500
committerBjorn Helgaas <bhelgaas@google.com>2014-01-15 12:31:29 -0500
commit1c2042c83aa7af10579b71a1fe5e22bbae69f08c (patch)
treedaba13b2d79d608c8d3cf28ca183eb0cc879c8d3 /arch
parent64cdb4181d87900c6560f8c72d02c7ccf75c9070 (diff)
powerpc/eeh: Use global PCI rescan-remove locking
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kernel/eeh_driver.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 36bed5a12750..c17f90d0f73c 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -369,7 +369,9 @@ static void *eeh_rmv_device(void *data, void *userdata)
369 edev->mode |= EEH_DEV_DISCONNECTED; 369 edev->mode |= EEH_DEV_DISCONNECTED;
370 (*removed)++; 370 (*removed)++;
371 371
372 pci_lock_rescan_remove();
372 pci_stop_and_remove_bus_device(dev); 373 pci_stop_and_remove_bus_device(dev);
374 pci_unlock_rescan_remove();
373 375
374 return NULL; 376 return NULL;
375} 377}
@@ -416,10 +418,13 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
416 * into pcibios_add_pci_devices(). 418 * into pcibios_add_pci_devices().
417 */ 419 */
418 eeh_pe_state_mark(pe, EEH_PE_KEEP); 420 eeh_pe_state_mark(pe, EEH_PE_KEEP);
419 if (bus) 421 if (bus) {
422 pci_lock_rescan_remove();
420 pcibios_remove_pci_devices(bus); 423 pcibios_remove_pci_devices(bus);
421 else if (frozen_bus) 424 pci_unlock_rescan_remove();
425 } else if (frozen_bus) {
422 eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed); 426 eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed);
427 }
423 428
424 /* Reset the pci controller. (Asserts RST#; resets config space). 429 /* Reset the pci controller. (Asserts RST#; resets config space).
425 * Reconfigure bridges and devices. Don't try to bring the system 430 * Reconfigure bridges and devices. Don't try to bring the system
@@ -429,6 +434,8 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
429 if (rc) 434 if (rc)
430 return rc; 435 return rc;
431 436
437 pci_lock_rescan_remove();
438
432 /* Restore PE */ 439 /* Restore PE */
433 eeh_ops->configure_bridge(pe); 440 eeh_ops->configure_bridge(pe);
434 eeh_pe_restore_bars(pe); 441 eeh_pe_restore_bars(pe);
@@ -462,6 +469,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
462 pe->tstamp = tstamp; 469 pe->tstamp = tstamp;
463 pe->freeze_count = cnt; 470 pe->freeze_count = cnt;
464 471
472 pci_unlock_rescan_remove();
465 return 0; 473 return 0;
466} 474}
467 475
@@ -618,8 +626,11 @@ perm_error:
618 eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); 626 eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
619 627
620 /* Shut down the device drivers for good. */ 628 /* Shut down the device drivers for good. */
621 if (frozen_bus) 629 if (frozen_bus) {
630 pci_lock_rescan_remove();
622 pcibios_remove_pci_devices(frozen_bus); 631 pcibios_remove_pci_devices(frozen_bus);
632 pci_unlock_rescan_remove();
633 }
623} 634}
624 635
625static void eeh_handle_special_event(void) 636static void eeh_handle_special_event(void)
@@ -692,6 +703,7 @@ static void eeh_handle_special_event(void)
692 if (rc == 2 || rc == 1) 703 if (rc == 2 || rc == 1)
693 eeh_handle_normal_event(pe); 704 eeh_handle_normal_event(pe);
694 else { 705 else {
706 pci_lock_rescan_remove();
695 list_for_each_entry_safe(hose, tmp, 707 list_for_each_entry_safe(hose, tmp,
696 &hose_list, list_node) { 708 &hose_list, list_node) {
697 phb_pe = eeh_phb_pe_get(hose); 709 phb_pe = eeh_phb_pe_get(hose);
@@ -703,6 +715,7 @@ static void eeh_handle_special_event(void)
703 eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); 715 eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
704 pcibios_remove_pci_devices(bus); 716 pcibios_remove_pci_devices(bus);
705 } 717 }
718 pci_unlock_rescan_remove();
706 } 719 }
707} 720}
708 721