int rpaphp_enable_slot(struct slot *slot) { int rc, level, state; struct pci_bus *bus; struct hotplug_slot_info *info = slot->hotplug_slot->info; info->adapter_status = NOT_VALID; slot->state = EMPTY; /* Find out if the power is turned on for the slot */ rc = rtas_get_power_level(slot->power_domain, &level); if (rc) return rc; info->power_status = level; /* Figure out if there is an adapter in the slot */ rc = rpaphp_get_sensor_state(slot, &state); if (rc) return rc; bus = pcibios_find_pci_bus(slot->dn); if (!bus) { err("%s: no pci_bus for dn %s\n", __func__, slot->dn->full_name); return -EINVAL; } info->adapter_status = EMPTY; slot->bus = bus; slot->pci_devs = &bus->devices; /* if there's an adapter in the slot, go add the pci devices */ if (state == PRESENT) { info->adapter_status = NOT_CONFIGURED; slot->state = NOT_CONFIGURED; /* non-empty slot has to have child */ if (!slot->dn->child) { err("%s: slot[%s]'s device_node doesn't have child for adapter\n", __func__, slot->name); return -EINVAL; } if (list_empty(&bus->devices)) pcibios_add_pci_devices(bus); if (!list_empty(&bus->devices)) { info->adapter_status = CONFIGURED; slot->state = CONFIGURED; } if (rpaphp_debug) { struct pci_dev *dev; dbg("%s: pci_devs of slot[%s]\n", __func__, slot->dn->full_name); list_for_each_entry (dev, &bus->devices, bus_list) dbg("\t%s\n", pci_name(dev)); } } return 0; }
static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) { int cnt, rc; /* pcibios will clear the counter; save the value */ cnt = pe_dn->eeh_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 = rtas_set_slot_reset(pe_dn); if (rc) return rc; /* New-style config addrs might be shared across multiple devices, * Walk over all functions on this device */ if (pe_dn->eeh_pe_config_addr) { struct device_node *pe = pe_dn->node; pe = pe->parent->child; while (pe) { struct pci_dn *ppe = PCI_DN(pe); if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { rtas_configure_bridge(ppe); eeh_restore_bars(ppe); } pe = pe->sibling; } } else { rtas_configure_bridge(pe_dn); eeh_restore_bars(pe_dn); } /* 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); } pe_dn->eeh_freeze_count = cnt; return 0; }
/** * 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; }