staticinline u8 rtas_mc_error_sub_type(conststruct pseries_mc_errorlog *mlog)
{ switch (mlog->error_type) { case MC_ERROR_TYPE_UE: return (mlog->sub_err_type & 0x07); case MC_ERROR_TYPE_SLB: case MC_ERROR_TYPE_ERAT: case MC_ERROR_TYPE_TLB: return (mlog->sub_err_type & 0x03); case MC_ERROR_TYPE_CTRL_MEM_ACCESS: return (mlog->sub_err_type & 0x70) >> 4; default: return 0;
}
}
/* * Enable the hotplug interrupt late because processing them may touch other * devices or systems (e.g. hugepages) that have not been initialized at the * subsys stage.
*/ staticint __init init_ras_hotplug_IRQ(void)
{ struct device_node *np;
/* * Initialize handlers for the set of interrupts caused by hardware errors * and power system events.
*/ staticint __init init_ras_IRQ(void)
{ struct device_node *np;
staticvoid handle_system_shutdown(char event_modifier)
{ switch (event_modifier) { case EPOW_SHUTDOWN_NORMAL:
pr_emerg("Power off requested\n");
orderly_poweroff(true); break;
case EPOW_SHUTDOWN_ON_UPS:
pr_emerg("Loss of system power detected. System is running on" " UPS/battery. Check RTAS error log for details\n"); break;
case EPOW_SHUTDOWN_LOSS_OF_CRITICAL_FUNCTIONS:
pr_emerg("Loss of system critical functions detected. Check" " RTAS error log for details\n");
orderly_poweroff(true); break;
case EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH:
pr_emerg("High ambient temperature detected. Check RTAS" " error log for details\n");
orderly_poweroff(true); break;
switch (action_code) { case EPOW_RESET: if (num_epow_events) {
pr_info("Non critical power/cooling issue cleared\n");
num_epow_events--;
} break;
case EPOW_WARN_COOLING:
pr_info("Non-critical cooling issue detected. Check RTAS error" " log for details\n"); break;
case EPOW_WARN_POWER:
pr_info("Non-critical power issue detected. Check RTAS error" " log for details\n"); break;
case EPOW_SYSTEM_SHUTDOWN:
handle_system_shutdown(modifier); break;
case EPOW_SYSTEM_HALT:
pr_emerg("Critical power/cooling issue detected. Check RTAS" " error log for details. Powering off.\n");
orderly_poweroff(true); break;
case EPOW_MAIN_ENCLOSURE: case EPOW_POWER_OFF:
pr_emerg("System about to lose power. Check RTAS error log " " for details. Powering off immediately.\n");
emergency_sync();
kernel_power_off(); break;
/* * Since PCI hotplug is not currently supported on pseries, put PCI * hotplug events on the ras_log_buf to be handled by rtas_errd.
*/ if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM ||
hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU ||
hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_PMEM)
queue_hotplug_event(hp_elog); else
log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);
/* Handle environmental and power warning (EPOW) interrupts. */ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
{ int state; int critical;
/* * Handle hardware error interrupts. * * RTAS check-exception is called to collect data on the exception. If * the error is deemed recoverable, we log a warning and return. * For nonrecoverable errors, an error is logged and we stop all processing * as quickly as possible in order to prevent propagation of the failure.
*/ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
{ struct rtas_error_log *rtas_elog; int status; int fatal;
spin_lock(&ras_log_buf_lock);
status = rtas_call(ras_check_exception_token, 6, 1, NULL,
RTAS_VECTOR_EXTERNAL_INTERRUPT,
virq_to_hw(irq),
RTAS_INTERNAL_ERROR, 1 /* Time Critical */,
__pa(&ras_log_buf),
rtas_get_error_log_max());
/* * Some versions of FWNMI place the buffer inside the 4kB page starting at * 0x7000. Other versions place it inside the rtas buffer. We check both. * Minimum size of the buffer is 16 bytes.
*/ #define VALID_FWNMI_BUFFER(A) \
((((A) >= 0x7000) && ((A) <= 0x8000 - 16)) || \
(((A) >= rtas.base) && ((A) <= (rtas.base + rtas.size - 16))))
/* Mask top two bits */
savep_ra = regs->gpr[3] & ~(0x3UL << 62); if (!VALID_FWNMI_BUFFER(savep_ra)) {
printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]); return NULL;
}
return __va(savep_ra);
}
/* * Get the error information for errors coming through the * FWNMI vectors. The pt_regs' r3 will be updated to reflect * the actual r3 if possible, and a ptr to the error log entry * will be returned if found. * * Use one buffer mce_data_buf per cpu to store RTAS error. * * The mce_data_buf does not have any locks or protection around it, * if a second machine check comes in, or a system reset is done * before we have logged the error, then we will get corruption in the * error log. This is preferable over holding off on calling * ibm,nmi-interlock which would result in us checkstopping if a * second machine check did come in.
*/ staticstruct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
{ struct rtas_error_log *h;
__be64 *savep;
savep = fwnmi_get_savep(regs); if (!savep) return NULL;
regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
h = (struct rtas_error_log *)&savep[1]; /* Use the per cpu buffer from paca to store rtas error log */
memset(local_paca->mce_data_buf, 0, RTAS_ERROR_LOG_MAX); if (!rtas_error_extended(h)) {
memcpy(local_paca->mce_data_buf, h, sizeof(__u64));
} else { int len, error_log_length;
/* Call this when done with the data returned by FWNMI_get_errinfo. * It will release the saved data area for other CPUs in the * partition to receive FWNMI errors.
*/ staticvoid fwnmi_release_errinfo(void)
{ struct rtas_args rtas_args; int ret;
/* * On pseries, the machine check stack is limited to under 4GB, so * args can be on-stack.
*/
rtas_call_unlocked(&rtas_args, ibm_nmi_interlock_token, 0, 1, NULL);
ret = be32_to_cpu(rtas_args.rets[0]); if (ret != 0)
printk(KERN_ERR "FWNMI: nmi-interlock failed: %d\n", ret);
}
int pSeries_system_reset_exception(struct pt_regs *regs)
{ #ifdef __LITTLE_ENDIAN__ /* * Some firmware byteswaps SRR registers and gives incorrect SRR1. Try * to detect the bad SRR1 pattern here. Flip the NIP back to correct * endian for reporting purposes. Unfortunately the MSR can't be fixed, * so clear it. It will be missing MSR_RI so we won't try to recover.
*/ if ((be64_to_cpu(regs->msr) &
(MSR_LE|MSR_RI|MSR_DR|MSR_IR|MSR_ME|MSR_PR|
MSR_ILE|MSR_HV|MSR_SF)) == (MSR_DR|MSR_SF)) {
regs_set_return_ip(regs, be64_to_cpu((__be64)regs->nip));
regs_set_return_msr(regs, 0);
} #endif
if (fwnmi_active) {
__be64 *savep;
/* * Firmware (PowerVM and KVM) saves r3 to a save area like * machine check, which is not exactly what PAPR (2.9) * suggests but there is no way to detect otherwise, so this * is the interface now. * * System resets do not save any error log or require an * "ibm,nmi-interlock" rtas call to release.
*/
savep = fwnmi_get_savep(regs); if (savep)
regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
}
if (smp_handle_nmi_ipi(regs)) return 1;
return 0; /* need to perform reset */
}
staticint mce_handle_err_realmode(int disposition, u8 error_type)
{ #ifdef CONFIG_PPC_BOOK3S_64 if (disposition == RTAS_DISP_NOT_RECOVERED) { switch (error_type) { case MC_ERROR_TYPE_ERAT:
flush_erat();
disposition = RTAS_DISP_FULLY_RECOVERED; break; case MC_ERROR_TYPE_SLB: #ifdef CONFIG_PPC_64S_HASH_MMU /* * Store the old slb content in paca before flushing. * Print this when we go to virtual mode. * There are chances that we may hit MCE again if there * is a parity error on the SLB entry we trying to read * for saving. Hence limit the slb saving to single * level of recursion.
*/ if (local_paca->in_mce == 1)
slb_save_contents(local_paca->mce_faulty_slbs);
flush_and_reload_slb();
disposition = RTAS_DISP_FULLY_RECOVERED; #endif break; default: break;
}
} elseif (disposition == RTAS_DISP_LIMITED_RECOVERY) { /* Platform corrected itself but could be degraded */
pr_err("MCE: limited recovery, system may be degraded\n");
disposition = RTAS_DISP_FULLY_RECOVERED;
} #endif return disposition;
}
/* * See if we can recover from a machine check exception. * This is only called on power4 (or above) and only via * the Firmware Non-Maskable Interrupts (fwnmi) handler * which provides the error analysis for us. * * Return 1 if corrected (or delivered a signal). * Return 0 if there is nothing we can do.
*/ staticint recover_mce(struct pt_regs *regs, struct machine_check_event *evt)
{ int recovered = 0;
if (!recovered && evt->sync_error) { /* * Try to kill processes if we get a synchronous machine check * (e.g., one caused by execution of this instruction). This * will devolve into a panic if we try to kill init or are in * an interrupt etc. * * TODO: Queue up this address for hwpoisioning later. * TODO: This is not quite right for d-side machine * checks ->nip is not necessarily the important * address.
*/ if ((user_mode(regs))) {
_exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
recovered = 1;
} elseif (die_will_crash()) { /* * die() would kill the kernel, so better to go via * the platform reboot code that will log the * machine check.
*/
recovered = 0;
} else {
die_mce("Machine check", regs, SIGBUS);
recovered = 1;
}
}
return recovered;
}
/* * Handle a machine check. * * Note that on Power 4 and beyond Firmware Non-Maskable Interrupts (fwnmi) * should be present. If so the handler which called us tells us if the * error was recovered (never true if RI=0). * * On hardware prior to Power 4 these exceptions were asynchronous which * means we can't tell exactly where it occurred and so we can't recover.
*/ int pSeries_machine_check_exception(struct pt_regs *regs)
{ struct machine_check_event evt;
if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) return 0;
/* Print things out */ if (evt.version != MCE_V1) {
pr_err("Machine Check Exception, Unknown event version %d !\n",
evt.version); return 0;
}
machine_check_print_event_info(&evt, user_mode(regs), false);
if (recover_mce(regs, &evt)) return 1;
return 0;
}
long pseries_machine_check_realmode(struct pt_regs *regs)
{ struct rtas_error_log *errp; int disposition;
if (fwnmi_active) {
errp = fwnmi_get_errinfo(regs); /* * Call to fwnmi_release_errinfo() in real mode causes kernel * to panic. Hence we will call it as soon as we go into * virtual mode.
*/
disposition = mce_handle_error(regs, errp);
fwnmi_release_errinfo();
if (disposition == RTAS_DISP_FULLY_RECOVERED) return 1;
}
return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.