136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar/*
236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * Machine check exception handling.
336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *
436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * This program is free software; you can redistribute it and/or modify
536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * it under the terms of the GNU General Public License as published by
636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * the Free Software Foundation; either version 2 of the License, or
736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * (at your option) any later version.
836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *
936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * This program is distributed in the hope that it will be useful,
1036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * but WITHOUT ANY WARRANTY; without even the implied warranty of
1136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * GNU General Public License for more details.
1336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *
1436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * You should have received a copy of the GNU General Public License
1536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * along with this program; if not, write to the Free Software
1636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *
1836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * Copyright 2013 IBM Corporation
1936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
2036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar */
2136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
2236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar#undef DEBUG
2336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar#define pr_fmt(fmt) "mce: " fmt
2436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
2536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar#include <linux/types.h>
2636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar#include <linux/ptrace.h>
2736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar#include <linux/percpu.h>
2836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar#include <linux/export.h>
2930c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkar#include <linux/irq_work.h>
3036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar#include <asm/mce.h>
3136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
3236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkarstatic DEFINE_PER_CPU(int, mce_nest_count);
3336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkarstatic DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event);
3436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
35b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar/* Queue for delayed MCE events. */
36b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkarstatic DEFINE_PER_CPU(int, mce_queue_count);
37b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkarstatic DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event_queue);
38b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
3930c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkarstatic void machine_check_process_queued_event(struct irq_work *work);
4030c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkarstruct irq_work mce_event_process_work = {
4130c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkar        .func = machine_check_process_queued_event,
4230c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkar};
4330c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkar
4436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkarstatic void mce_set_error_info(struct machine_check_event *mce,
4536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar			       struct mce_error_info *mce_err)
4636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar{
4736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	mce->error_type = mce_err->error_type;
4836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	switch (mce_err->error_type) {
4936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	case MCE_ERROR_TYPE_UE:
5036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.ue_error.ue_error_type = mce_err->u.ue_error_type;
5136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		break;
5236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	case MCE_ERROR_TYPE_SLB:
5336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.slb_error.slb_error_type = mce_err->u.slb_error_type;
5436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		break;
5536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	case MCE_ERROR_TYPE_ERAT:
5636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.erat_error.erat_error_type = mce_err->u.erat_error_type;
5736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		break;
5836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	case MCE_ERROR_TYPE_TLB:
5936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type;
6036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		break;
6136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	case MCE_ERROR_TYPE_UNKNOWN:
6236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	default:
6336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		break;
6436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	}
6536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar}
6636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
6736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar/*
6836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * Decode and save high level MCE information into per cpu buffer which
6936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * is an array of machine_check_event structure.
7036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar */
7136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkarvoid save_mce_event(struct pt_regs *regs, long handled,
7236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		    struct mce_error_info *mce_err,
7355672ecfa21f23616541c50e0e687f14f9ecf165Mahesh Salgaonkar		    uint64_t nip, uint64_t addr)
7436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar{
7536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	uint64_t srr1;
7636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	int index = __get_cpu_var(mce_nest_count)++;
7736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	struct machine_check_event *mce = &__get_cpu_var(mce_event[index]);
7836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
7936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	/*
8036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	 * Return if we don't have enough space to log mce event.
8136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	 * mce_nest_count may go beyond MAX_MC_EVT but that's ok,
8236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	 * the check below will stop buffer overrun.
8336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	 */
8436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	if (index >= MAX_MC_EVT)
8536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		return;
8636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
8736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	/* Populate generic machine check info */
8836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	mce->version = MCE_V1;
8955672ecfa21f23616541c50e0e687f14f9ecf165Mahesh Salgaonkar	mce->srr0 = nip;
9036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	mce->srr1 = regs->msr;
9136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	mce->gpr3 = regs->gpr[3];
9236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	mce->in_use = 1;
9336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
9436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	mce->initiator = MCE_INITIATOR_CPU;
9536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	if (handled)
9636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->disposition = MCE_DISPOSITION_RECOVERED;
9736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	else
9836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
9936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	mce->severity = MCE_SEV_ERROR_SYNC;
10036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
10136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	srr1 = regs->msr;
10236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
10336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	/*
10436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	 * Populate the mce error_type and type-specific error_type.
10536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	 */
10636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	mce_set_error_info(mce, mce_err);
10736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
10836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	if (!addr)
10936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		return;
11036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
11136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	if (mce->error_type == MCE_ERROR_TYPE_TLB) {
11236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.tlb_error.effective_address_provided = true;
11336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.tlb_error.effective_address = addr;
11436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	} else if (mce->error_type == MCE_ERROR_TYPE_SLB) {
11536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.slb_error.effective_address_provided = true;
11636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.slb_error.effective_address = addr;
11736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	} else if (mce->error_type == MCE_ERROR_TYPE_ERAT) {
11836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.erat_error.effective_address_provided = true;
11936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.erat_error.effective_address = addr;
12036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	} else if (mce->error_type == MCE_ERROR_TYPE_UE) {
12136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.ue_error.effective_address_provided = true;
12236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mce->u.ue_error.effective_address = addr;
12336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	}
12436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	return;
12536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar}
12636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
12736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar/*
12836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * get_mce_event:
12936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *	mce	Pointer to machine_check_event structure to be filled.
13036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *	release Flag to indicate whether to free the event slot or not.
13136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *		0 <= do not release the mce event. Caller will invoke
13236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *		     release_mce_event() once event has been consumed.
13336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *		1 <= release the slot.
13436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *
13536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *	return	1 = success
13636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *		0 = failure
13736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar *
13836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * get_mce_event() will be called by platform specific machine check
13936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * handle routine and in KVM.
14036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * When we call get_mce_event(), we are still in interrupt context and
14136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * preemption will not be scheduled until ret_from_expect() routine
14236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar * is called.
14336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar */
14436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkarint get_mce_event(struct machine_check_event *mce, bool release)
14536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar{
14636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	int index = __get_cpu_var(mce_nest_count) - 1;
14736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	struct machine_check_event *mc_evt;
14836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	int ret = 0;
14936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
15036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	/* Sanity check */
15136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	if (index < 0)
15236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		return ret;
15336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
15436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	/* Check if we have MCE info to process. */
15536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	if (index < MAX_MC_EVT) {
15636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		mc_evt = &__get_cpu_var(mce_event[index]);
15736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		/* Copy the event structure and release the original */
15836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		if (mce)
15936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar			*mce = *mc_evt;
16036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		if (release)
16136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar			mc_evt->in_use = 0;
16236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		ret = 1;
16336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	}
16436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	/* Decrement the count to free the slot. */
16536df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	if (release)
16636df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar		__get_cpu_var(mce_nest_count)--;
16736df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
16836df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	return ret;
16936df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar}
17036df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar
17136df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkarvoid release_mce_event(void)
17236df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar{
17336df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar	get_mce_event(NULL, true);
17436df96f8acaf51992177645eb2d781f766ce97dcMahesh Salgaonkar}
175b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
176b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar/*
177b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar * Queue up the MCE event which then can be handled later.
178b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar */
179b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkarvoid machine_check_queue_event(void)
180b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar{
181b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	int index;
182b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	struct machine_check_event evt;
183b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
184b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
185b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		return;
186b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
187b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	index = __get_cpu_var(mce_queue_count)++;
188b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	/* If queue is full, just return for now. */
189b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	if (index >= MAX_MC_EVT) {
190b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		__get_cpu_var(mce_queue_count)--;
191b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		return;
192b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	}
193b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	__get_cpu_var(mce_event_queue[index]) = evt;
19430c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkar
19530c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkar	/* Queue irq work to process this event later. */
19630c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkar	irq_work_queue(&mce_event_process_work);
197b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar}
198b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
199b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar/*
200b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar * process pending MCE event from the mce event queue. This function will be
201b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar * called during syscall exit.
202b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar */
20330c826358d10c1d6f8147de3310b97488daec830Mahesh Salgaonkarstatic void machine_check_process_queued_event(struct irq_work *work)
204b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar{
205b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	int index;
206b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
207b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	/*
208b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	 * For now just print it to console.
209b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	 * TODO: log this error event to FSP or nvram.
210b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	 */
211b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	while (__get_cpu_var(mce_queue_count) > 0) {
212b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		index = __get_cpu_var(mce_queue_count) - 1;
213b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		machine_check_print_event_info(
214b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar				&__get_cpu_var(mce_event_queue[index]));
215b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		__get_cpu_var(mce_queue_count)--;
216b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	}
217b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar}
218b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
219b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkarvoid machine_check_print_event_info(struct machine_check_event *evt)
220b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar{
221b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	const char *level, *sevstr, *subtype;
222b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	static const char *mc_ue_types[] = {
223b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Indeterminate",
224b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Instruction fetch",
225b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Page table walk ifetch",
226b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Load/Store",
227b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Page table walk Load/Store",
228b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	};
229b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	static const char *mc_slb_types[] = {
230b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Indeterminate",
231b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Parity",
232b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Multihit",
233b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	};
234b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	static const char *mc_erat_types[] = {
235b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Indeterminate",
236b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Parity",
237b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Multihit",
238b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	};
239b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	static const char *mc_tlb_types[] = {
240b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Indeterminate",
241b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Parity",
242b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		"Multihit",
243b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	};
244b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
245b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	/* Print things out */
246b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	if (evt->version != MCE_V1) {
247b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		pr_err("Machine Check Exception, Unknown event version %d !\n",
248b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		       evt->version);
249b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		return;
250b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	}
251b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	switch (evt->severity) {
252b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_SEV_NO_ERROR:
253b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		level = KERN_INFO;
254b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		sevstr = "Harmless";
255b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
256b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_SEV_WARNING:
257b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		level = KERN_WARNING;
258b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		sevstr = "";
259b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
260b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_SEV_ERROR_SYNC:
261b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		level = KERN_ERR;
262b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		sevstr = "Severe";
263b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
264b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_SEV_FATAL:
265b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	default:
266b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		level = KERN_ERR;
267b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		sevstr = "Fatal";
268b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
269b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	}
270b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar
271b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	printk("%s%s Machine check interrupt [%s]\n", level, sevstr,
272b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	       evt->disposition == MCE_DISPOSITION_RECOVERED ?
273b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	       "Recovered" : "[Not recovered");
274b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	printk("%s  Initiator: %s\n", level,
275b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	       evt->initiator == MCE_INITIATOR_CPU ? "CPU" : "Unknown");
276b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	switch (evt->error_type) {
277b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_ERROR_TYPE_UE:
278b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		subtype = evt->u.ue_error.ue_error_type <
279b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			ARRAY_SIZE(mc_ue_types) ?
280b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			mc_ue_types[evt->u.ue_error.ue_error_type]
281b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			: "Unknown";
282b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		printk("%s  Error type: UE [%s]\n", level, subtype);
283b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		if (evt->u.ue_error.effective_address_provided)
284b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			printk("%s    Effective address: %016llx\n",
285b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			       level, evt->u.ue_error.effective_address);
286b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		if (evt->u.ue_error.physical_address_provided)
287b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			printk("%s      Physial address: %016llx\n",
288b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			       level, evt->u.ue_error.physical_address);
289b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
290b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_ERROR_TYPE_SLB:
291b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		subtype = evt->u.slb_error.slb_error_type <
292b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			ARRAY_SIZE(mc_slb_types) ?
293b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			mc_slb_types[evt->u.slb_error.slb_error_type]
294b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			: "Unknown";
295b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		printk("%s  Error type: SLB [%s]\n", level, subtype);
296b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		if (evt->u.slb_error.effective_address_provided)
297b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			printk("%s    Effective address: %016llx\n",
298b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			       level, evt->u.slb_error.effective_address);
299b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
300b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_ERROR_TYPE_ERAT:
301b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		subtype = evt->u.erat_error.erat_error_type <
302b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			ARRAY_SIZE(mc_erat_types) ?
303b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			mc_erat_types[evt->u.erat_error.erat_error_type]
304b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			: "Unknown";
305b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		printk("%s  Error type: ERAT [%s]\n", level, subtype);
306b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		if (evt->u.erat_error.effective_address_provided)
307b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			printk("%s    Effective address: %016llx\n",
308b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			       level, evt->u.erat_error.effective_address);
309b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
310b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_ERROR_TYPE_TLB:
311b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		subtype = evt->u.tlb_error.tlb_error_type <
312b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			ARRAY_SIZE(mc_tlb_types) ?
313b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			mc_tlb_types[evt->u.tlb_error.tlb_error_type]
314b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			: "Unknown";
315b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		printk("%s  Error type: TLB [%s]\n", level, subtype);
316b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		if (evt->u.tlb_error.effective_address_provided)
317b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			printk("%s    Effective address: %016llx\n",
318b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar			       level, evt->u.tlb_error.effective_address);
319b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
320b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	default:
321b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	case MCE_ERROR_TYPE_UNKNOWN:
322b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		printk("%s  Error type: Unknown\n", level);
323b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar		break;
324b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar	}
325b5ff4211a8294be2ddbaf963fa3666fa042292a8Mahesh Salgaonkar}
326b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar
327b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkaruint64_t get_mce_fault_addr(struct machine_check_event *evt)
328b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar{
329b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	switch (evt->error_type) {
330b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	case MCE_ERROR_TYPE_UE:
331b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		if (evt->u.ue_error.effective_address_provided)
332b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar			return evt->u.ue_error.effective_address;
333b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		break;
334b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	case MCE_ERROR_TYPE_SLB:
335b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		if (evt->u.slb_error.effective_address_provided)
336b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar			return evt->u.slb_error.effective_address;
337b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		break;
338b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	case MCE_ERROR_TYPE_ERAT:
339b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		if (evt->u.erat_error.effective_address_provided)
340b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar			return evt->u.erat_error.effective_address;
341b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		break;
342b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	case MCE_ERROR_TYPE_TLB:
343b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		if (evt->u.tlb_error.effective_address_provided)
344b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar			return evt->u.tlb_error.effective_address;
345b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		break;
346b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	default:
347b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	case MCE_ERROR_TYPE_UNKNOWN:
348b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar		break;
349b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	}
350b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar	return 0;
351b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh Salgaonkar}
352b63a0ffe35de7e5f9b907bbc2c783e702f7e15afMahesh SalgaonkarEXPORT_SYMBOL(get_mce_fault_addr);
353