/** * eeh_slot_error_detail - Generate combined log including driver log and error log * @pe: EEH PE * @severity: temporary or permanent error log * * This routine should be called to generate the combined log, which * is comprised of driver log and error log. The driver log is figured * out from the config space of the corresponding PCI device, while * the error log is fetched through platform dependent function call. */ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) { size_t loglen = 0; struct eeh_dev *edev, *tmp; /* * When the PHB is fenced or dead, it's pointless to collect * the data from PCI config space because it should return * 0xFF's. For ER, we still retrieve the data from the PCI * config space. * * For pHyp, we have to enable IO for log retrieval. Otherwise, * 0xFF's is always returned from PCI config space. */ if (!(pe->type & EEH_PE_PHB)) { if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG)) eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); eeh_ops->configure_bridge(pe); eeh_pe_restore_bars(pe); pci_regs_buf[0] = 0; eeh_pe_for_each_dev(pe, edev, tmp) { loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen, EEH_PCI_REGS_LOG_LEN - loglen); } }
/** * eeh_slot_error_detail - Generate combined log including driver log and error log * @pe: EEH PE * @severity: temporary or permanent error log * * This routine should be called to generate the combined log, which * is comprised of driver log and error log. The driver log is figured * out from the config space of the corresponding PCI device, while * the error log is fetched through platform dependent function call. */ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) { size_t loglen = 0; /* * When the PHB is fenced or dead, it's pointless to collect * the data from PCI config space because it should return * 0xFF's. For ER, we still retrieve the data from the PCI * config space. * * For pHyp, we have to enable IO for log retrieval. Otherwise, * 0xFF's is always returned from PCI config space. */ if (!(pe->type & EEH_PE_PHB)) { if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG)) eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); /* * The config space of some PCI devices can't be accessed * when their PEs are in frozen state. Otherwise, fenced * PHB might be seen. Those PEs are identified with flag * EEH_PE_CFG_RESTRICTED, indicating EEH_PE_CFG_BLOCKED * is set automatically when the PE is put to EEH_PE_ISOLATED. * * Restoring BARs possibly triggers PCI config access in * (OPAL) firmware and then causes fenced PHB. If the * PCI config is blocked with flag EEH_PE_CFG_BLOCKED, it's * pointless to restore BARs and dump config space. */ eeh_ops->configure_bridge(pe); if (!(pe->state & EEH_PE_CFG_BLOCKED)) { eeh_pe_restore_bars(pe); pci_regs_buf[0] = 0; eeh_pe_traverse(pe, eeh_dump_pe_log, &loglen); } } eeh_ops->get_log(pe, severity, pci_regs_buf, loglen); }
/** * 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; }