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