/** * eeh_reset_device - Perform actual reset of a pci slot * @edev: PE associated EEH device * @bus: PCI bus corresponding to the isolcated slot * * This routine must be called to do reset on the indicated PE. * During the reset, udev might be invoked because those affected * PCI devices will be removed and then added. */ static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) { struct device_node *dn; int cnt, rc; /* pcibios will clear the counter; save the value */ cnt = edev->freeze_count; if (bus) pcibios_remove_pci_devices(bus); /* Reset the pci controller. (Asserts RST#; resets config space). * Reconfigure bridges and devices. Don't try to bring the system * up if the reset failed for some reason. */ rc = eeh_reset_pe(edev); if (rc) return rc; /* Walk over all functions on this device. */ dn = eeh_dev_to_of_node(edev); if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) dn = dn->parent->child; while (dn) { struct eeh_dev *pedev = of_node_to_eeh_dev(dn); /* On Power4, always true because eeh_pe_config_addr=0 */ if (edev->pe_config_addr == pedev->pe_config_addr) { eeh_ops->configure_bridge(dn); eeh_restore_bars(pedev); } dn = dn->sibling; } /* Give the system 5 seconds to finish running the user-space * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes, * this is a hack, but if we don't do this, and try to bring * the device up before the scripts have taken it down, * potentially weird things happen. */ if (bus) { ssleep(5); pcibios_add_pci_devices(bus); } edev->freeze_count = cnt; return 0; }
static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) { struct device_node *dn; int cnt, rc; cnt = edev->freeze_count; if (bus) pcibios_remove_pci_devices(bus); rc = eeh_reset_pe(edev); if (rc) return rc; dn = eeh_dev_to_of_node(edev); if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) dn = dn->parent->child; while (dn) { struct eeh_dev *pedev = of_node_to_eeh_dev(dn); if (edev->pe_config_addr == pedev->pe_config_addr) { eeh_ops->configure_bridge(dn); eeh_restore_bars(pedev); } dn = dn->sibling; } if (bus) { ssleep(5); pcibios_add_pci_devices(bus); } edev->freeze_count = cnt; return 0; }
/** * eeh_reset_device - Perform actual reset of a pci slot * @pe: EEH PE * @bus: PCI bus corresponding to the isolcated slot * * This routine must be called to do reset on the indicated PE. * During the reset, udev might be invoked because those affected * PCI devices will be removed and then added. */ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus) { struct pci_bus *frozen_bus = eeh_pe_bus_get(pe); struct timeval tstamp; int cnt, rc, removed = 0; /* pcibios will clear the counter; save the value */ cnt = pe->freeze_count; tstamp = pe->tstamp; /* * We don't remove the corresponding PE instances because * we need the information afterwords. The attached EEH * devices are expected to be attached soon when calling * into pcibios_add_pci_devices(). */ eeh_pe_state_mark(pe, EEH_PE_KEEP); if (bus) { pci_lock_rescan_remove(); pcibios_remove_pci_devices(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 * up if the reset failed for some reason. * * During the reset, it's very dangerous to have uncontrolled PCI * config accesses. So we prefer to block them. However, controlled * PCI config accesses initiated from EEH itself are allowed. */ eeh_pe_state_mark(pe, EEH_PE_RESET); rc = eeh_reset_pe(pe); if (rc) { eeh_pe_state_clear(pe, EEH_PE_RESET); return rc; } pci_lock_rescan_remove(); /* Restore PE */ eeh_ops->configure_bridge(pe); eeh_pe_restore_bars(pe); eeh_pe_state_clear(pe, EEH_PE_RESET); /* Clear frozen state */ rc = eeh_clear_pe_frozen_state(pe); if (rc) return rc; /* Give the system 5 seconds to finish running the user-space * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes, * this is a hack, but if we don't do this, and try to bring * the device up before the scripts have taken it down, * potentially weird things happen. */ if (bus) { pr_info("EEH: Sleep 5s ahead of complete hotplug\n"); ssleep(5); /* * The EEH device is still connected with its parent * PE. We should disconnect it so the binding can be * rebuilt when adding PCI devices. */ eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); pcibios_add_pci_devices(bus); } else if (frozen_bus && removed) { pr_info("EEH: Sleep 5s ahead of partial hotplug\n"); ssleep(5); eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); pcibios_add_pci_devices(frozen_bus); } eeh_pe_state_clear(pe, EEH_PE_KEEP); pe->tstamp = tstamp; pe->freeze_count = cnt; pci_unlock_rescan_remove(); return 0; }