aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/mce.c
diff options
context:
space:
mode:
authorMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>2013-10-30 10:35:49 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-12-05 00:05:21 -0500
commitb5ff4211a8294be2ddbaf963fa3666fa042292a8 (patch)
treec87b212ebfddc4c42c54c61ee1b3fb3d49e0c941 /arch/powerpc/kernel/mce.c
parent36df96f8acaf51992177645eb2d781f766ce97dc (diff)
powerpc/book3s: Queue up and process delayed MCE events.
When machine check real mode handler can not continue into host kernel in V mode, it returns from the interrupt and we loose MCE event which never gets logged. In such a situation queue up the MCE event so that we can log it later when we get back into host kernel with r1 pointing to kernel stack e.g. during syscall exit. Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/mce.c')
-rw-r--r--arch/powerpc/kernel/mce.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index aeecdf1ba897..1c6d15701c56 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -31,6 +31,10 @@
31static DEFINE_PER_CPU(int, mce_nest_count); 31static DEFINE_PER_CPU(int, mce_nest_count);
32static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event); 32static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event);
33 33
34/* Queue for delayed MCE events. */
35static DEFINE_PER_CPU(int, mce_queue_count);
36static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event_queue);
37
34static void mce_set_error_info(struct machine_check_event *mce, 38static void mce_set_error_info(struct machine_check_event *mce,
35 struct mce_error_info *mce_err) 39 struct mce_error_info *mce_err)
36{ 40{
@@ -162,3 +166,153 @@ void release_mce_event(void)
162{ 166{
163 get_mce_event(NULL, true); 167 get_mce_event(NULL, true);
164} 168}
169
170/*
171 * Queue up the MCE event which then can be handled later.
172 */
173void machine_check_queue_event(void)
174{
175 int index;
176 struct machine_check_event evt;
177
178 if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
179 return;
180
181 index = __get_cpu_var(mce_queue_count)++;
182 /* If queue is full, just return for now. */
183 if (index >= MAX_MC_EVT) {
184 __get_cpu_var(mce_queue_count)--;
185 return;
186 }
187 __get_cpu_var(mce_event_queue[index]) = evt;
188}
189
190/*
191 * process pending MCE event from the mce event queue. This function will be
192 * called during syscall exit.
193 */
194void machine_check_process_queued_event(void)
195{
196 int index;
197
198 preempt_disable();
199 /*
200 * For now just print it to console.
201 * TODO: log this error event to FSP or nvram.
202 */
203 while (__get_cpu_var(mce_queue_count) > 0) {
204 index = __get_cpu_var(mce_queue_count) - 1;
205 machine_check_print_event_info(
206 &__get_cpu_var(mce_event_queue[index]));
207 __get_cpu_var(mce_queue_count)--;
208 }
209 preempt_enable();
210}
211
212void machine_check_print_event_info(struct machine_check_event *evt)
213{
214 const char *level, *sevstr, *subtype;
215 static const char *mc_ue_types[] = {
216 "Indeterminate",
217 "Instruction fetch",
218 "Page table walk ifetch",
219 "Load/Store",
220 "Page table walk Load/Store",
221 };
222 static const char *mc_slb_types[] = {
223 "Indeterminate",
224 "Parity",
225 "Multihit",
226 };
227 static const char *mc_erat_types[] = {
228 "Indeterminate",
229 "Parity",
230 "Multihit",
231 };
232 static const char *mc_tlb_types[] = {
233 "Indeterminate",
234 "Parity",
235 "Multihit",
236 };
237
238 /* Print things out */
239 if (evt->version != MCE_V1) {
240 pr_err("Machine Check Exception, Unknown event version %d !\n",
241 evt->version);
242 return;
243 }
244 switch (evt->severity) {
245 case MCE_SEV_NO_ERROR:
246 level = KERN_INFO;
247 sevstr = "Harmless";
248 break;
249 case MCE_SEV_WARNING:
250 level = KERN_WARNING;
251 sevstr = "";
252 break;
253 case MCE_SEV_ERROR_SYNC:
254 level = KERN_ERR;
255 sevstr = "Severe";
256 break;
257 case MCE_SEV_FATAL:
258 default:
259 level = KERN_ERR;
260 sevstr = "Fatal";
261 break;
262 }
263
264 printk("%s%s Machine check interrupt [%s]\n", level, sevstr,
265 evt->disposition == MCE_DISPOSITION_RECOVERED ?
266 "Recovered" : "[Not recovered");
267 printk("%s Initiator: %s\n", level,
268 evt->initiator == MCE_INITIATOR_CPU ? "CPU" : "Unknown");
269 switch (evt->error_type) {
270 case MCE_ERROR_TYPE_UE:
271 subtype = evt->u.ue_error.ue_error_type <
272 ARRAY_SIZE(mc_ue_types) ?
273 mc_ue_types[evt->u.ue_error.ue_error_type]
274 : "Unknown";
275 printk("%s Error type: UE [%s]\n", level, subtype);
276 if (evt->u.ue_error.effective_address_provided)
277 printk("%s Effective address: %016llx\n",
278 level, evt->u.ue_error.effective_address);
279 if (evt->u.ue_error.physical_address_provided)
280 printk("%s Physial address: %016llx\n",
281 level, evt->u.ue_error.physical_address);
282 break;
283 case MCE_ERROR_TYPE_SLB:
284 subtype = evt->u.slb_error.slb_error_type <
285 ARRAY_SIZE(mc_slb_types) ?
286 mc_slb_types[evt->u.slb_error.slb_error_type]
287 : "Unknown";
288 printk("%s Error type: SLB [%s]\n", level, subtype);
289 if (evt->u.slb_error.effective_address_provided)
290 printk("%s Effective address: %016llx\n",
291 level, evt->u.slb_error.effective_address);
292 break;
293 case MCE_ERROR_TYPE_ERAT:
294 subtype = evt->u.erat_error.erat_error_type <
295 ARRAY_SIZE(mc_erat_types) ?
296 mc_erat_types[evt->u.erat_error.erat_error_type]
297 : "Unknown";
298 printk("%s Error type: ERAT [%s]\n", level, subtype);
299 if (evt->u.erat_error.effective_address_provided)
300 printk("%s Effective address: %016llx\n",
301 level, evt->u.erat_error.effective_address);
302 break;
303 case MCE_ERROR_TYPE_TLB:
304 subtype = evt->u.tlb_error.tlb_error_type <
305 ARRAY_SIZE(mc_tlb_types) ?
306 mc_tlb_types[evt->u.tlb_error.tlb_error_type]
307 : "Unknown";
308 printk("%s Error type: TLB [%s]\n", level, subtype);
309 if (evt->u.tlb_error.effective_address_provided)
310 printk("%s Effective address: %016llx\n",
311 level, evt->u.tlb_error.effective_address);
312 break;
313 default:
314 case MCE_ERROR_TYPE_UNKNOWN:
315 printk("%s Error type: Unknown\n", level);
316 break;
317 }
318}