/* Mark it recovered if we have handled it and MSR(RI=1). */ if (handled && (regs->msr & MSR_RI))
mce->disposition = MCE_DISPOSITION_RECOVERED; else
mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
/* *get_mce_event: *mcePointertomachine_check_eventstructuretobefilled. *releaseFlagtoindicatewhethertofreetheeventslotornot. *0<=donotreleasethemceevent.Callerwillinvoke *release_mce_event()onceeventhasbeenconsumed. *1<=releasetheslot. * *return1=success *0=failure * *get_mce_event()willbecalledbyplatformspecificmachinecheck *handleroutineandinKVM. *Whenwecallget_mce_event(),wearestillininterruptcontextand *preemptionwillnotbescheduleduntilret_from_expect()routine *iscalled.
*/ int get_mce_event(struct machine_check_event *mce, bool release)
{ int index = local_paca->mce_info->mce_nest_count - 1; struct machine_check_event *mc_evt; int ret = 0;
/* Sanity check */ if (index < 0) return ret;
/* Check if we have MCE info to process. */ if (index < MAX_MC_EVT) {
mc_evt = &local_paca->mce_info->mce_event[index]; /* Copy the event structure and release the original */ if (mce)
*mce = *mc_evt; if (release)
mc_evt->in_use = 0;
ret = 1;
} /* Decrement the count to free the slot. */ if (release)
local_paca->mce_info->mce_nest_count--;
/* *QueueuptheMCEeventwhichthencanbehandledlater.
*/ staticvoid machine_check_ue_event(struct machine_check_event *evt)
{ int index;
index = local_paca->mce_info->mce_ue_count++; /* If queue is full, just return for now. */ if (index >= MAX_MC_EVT) {
local_paca->mce_info->mce_ue_count--; return;
}
memcpy(&local_paca->mce_info->mce_ue_event_queue[index],
evt, sizeof(*evt));
}
if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) return;
index = local_paca->mce_info->mce_queue_count++; /* If queue is full, just return for now. */ if (index >= MAX_MC_EVT) {
local_paca->mce_info->mce_queue_count--; return;
}
memcpy(&local_paca->mce_info->mce_event_queue[index],
&evt, sizeof(evt));
/* *Seeifplatformiscapableofhandlingmachinecheck.
*/ if (ppc_md.machine_check_early)
handled = ppc_md.machine_check_early(regs);
return handled;
}
/* Possible meanings for HMER_DEBUG_TRIG bit being set on POWER9 */ staticenum {
DTRIG_UNKNOWN,
DTRIG_VECTOR_CI, /* need to emulate vector CI load instr */
DTRIG_SUSPEND_ESCAPE, /* need to escape from TM suspend mode */
} hmer_debug_trig_function;
/* First look in the device tree */
preempt_disable();
cpun = of_get_cpu_node(smp_processor_id(), NULL); if (cpun) {
of_property_for_each_string(cpun, "ibm,hmi-special-triggers",
prop, str) { if (strcmp(str, "bit17-vector-ci-load") == 0)
hmer_debug_trig_function = DTRIG_VECTOR_CI; elseif (strcmp(str, "bit17-tm-suspend-escape") == 0)
hmer_debug_trig_function = DTRIG_SUSPEND_ESCAPE;
}
of_node_put(cpun);
}
preempt_enable();
/* If we found the property, don't look at PVR */ if (prop) goto out;
pvr = mfspr(SPRN_PVR); /* Check for POWER9 Nimbus (scale-out) */ if ((PVR_VER(pvr) == PVR_POWER9) && (pvr & 0xe000) == 0) { /* DD2.2 and later */ if ((pvr & 0xfff) >= 0x202)
hmer_debug_trig_function = DTRIG_SUSPEND_ESCAPE; /* DD2.0 and DD2.1 - used for vector CI load emulation */ elseif ((pvr & 0xfff) >= 0x200)
hmer_debug_trig_function = DTRIG_VECTOR_CI;
}
out: switch (hmer_debug_trig_function) { case DTRIG_VECTOR_CI:
pr_debug("HMI debug trigger used for vector CI load\n"); break; case DTRIG_SUSPEND_ESCAPE:
pr_debug("HMI debug trigger used for TM suspend escape\n"); break; default: break;
} return0;
}
__initcall(init_debug_trig_function);
/* *HandleHMIsthatoccurasaresultofadebugtrigger. *Returnvalues: *-1meansthisisnotaHMIcausethatweknowabout *0meansnofurtherhandlingisrequired *1meansfurtherhandlingisrequired
*/ long hmi_handle_debugtrig(struct pt_regs *regs)
{ unsignedlong hmer = mfspr(SPRN_HMER); long ret = 0;
/* HMER_DEBUG_TRIG bit is used for various workarounds on P9 */ if (!((hmer & HMER_DEBUG_TRIG)
&& hmer_debug_trig_function != DTRIG_UNKNOWN)) return -1;
hmer &= ~HMER_DEBUG_TRIG; /* HMER is a write-AND register */
mtspr(SPRN_HMER, ~HMER_DEBUG_TRIG);
switch (hmer_debug_trig_function) { case DTRIG_VECTOR_CI: /* *Nowtoavoidproblemswithsoft-disablewe *onlydotheemulationifwearecomingfrom *hostuserspace
*/ if (regs && user_mode(regs))
ret = local_paca->hmi_p9_special_emu = 1;
break;
default: break;
}
/* *SeeifanyotherHMIcausesremaintobehandled
*/ if (hmer & mfspr(SPRN_HMEER)) return -1;
return ret;
}
/* *Returnvalues:
*/
DEFINE_INTERRUPT_HANDLER_NMI(hmi_exception_realmode)
{ int ret;
local_paca->hmi_irqs++;
ret = hmi_handle_debugtrig(regs); if (ret >= 0) return ret;
wait_for_subcore_guest_exit();
if (ppc_md.hmi_exception_early)
ppc_md.hmi_exception_early(regs);
¤ 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.0.16Bemerkung:
(vorverarbeitet am 2026-09-29)
¤
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.