1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * File: mca.c 3*1da177e4SLinus Torvalds * Purpose: Generic MCA handling layer 4*1da177e4SLinus Torvalds * 5*1da177e4SLinus Torvalds * Updated for latest kernel 6*1da177e4SLinus Torvalds * Copyright (C) 2003 Hewlett-Packard Co 7*1da177e4SLinus Torvalds * David Mosberger-Tang <davidm@hpl.hp.com> 8*1da177e4SLinus Torvalds * 9*1da177e4SLinus Torvalds * Copyright (C) 2002 Dell Inc. 10*1da177e4SLinus Torvalds * Copyright (C) Matt Domsch (Matt_Domsch@dell.com) 11*1da177e4SLinus Torvalds * 12*1da177e4SLinus Torvalds * Copyright (C) 2002 Intel 13*1da177e4SLinus Torvalds * Copyright (C) Jenna Hall (jenna.s.hall@intel.com) 14*1da177e4SLinus Torvalds * 15*1da177e4SLinus Torvalds * Copyright (C) 2001 Intel 16*1da177e4SLinus Torvalds * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com) 17*1da177e4SLinus Torvalds * 18*1da177e4SLinus Torvalds * Copyright (C) 2000 Intel 19*1da177e4SLinus Torvalds * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) 20*1da177e4SLinus Torvalds * 21*1da177e4SLinus Torvalds * Copyright (C) 1999, 2004 Silicon Graphics, Inc. 22*1da177e4SLinus Torvalds * Copyright (C) Vijay Chander(vijay@engr.sgi.com) 23*1da177e4SLinus Torvalds * 24*1da177e4SLinus Torvalds * 03/04/15 D. Mosberger Added INIT backtrace support. 25*1da177e4SLinus Torvalds * 02/03/25 M. Domsch GUID cleanups 26*1da177e4SLinus Torvalds * 27*1da177e4SLinus Torvalds * 02/01/04 J. Hall Aligned MCA stack to 16 bytes, added platform vs. CPU 28*1da177e4SLinus Torvalds * error flag, set SAL default return values, changed 29*1da177e4SLinus Torvalds * error record structure to linked list, added init call 30*1da177e4SLinus Torvalds * to sal_get_state_info_size(). 31*1da177e4SLinus Torvalds * 32*1da177e4SLinus Torvalds * 01/01/03 F. Lewis Added setup of CMCI and CPEI IRQs, logging of corrected 33*1da177e4SLinus Torvalds * platform errors, completed code for logging of 34*1da177e4SLinus Torvalds * corrected & uncorrected machine check errors, and 35*1da177e4SLinus Torvalds * updated for conformance with Nov. 2000 revision of the 36*1da177e4SLinus Torvalds * SAL 3.0 spec. 37*1da177e4SLinus Torvalds * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, 38*1da177e4SLinus Torvalds * added min save state dump, added INIT handler. 39*1da177e4SLinus Torvalds * 40*1da177e4SLinus Torvalds * 2003-12-08 Keith Owens <kaos@sgi.com> 41*1da177e4SLinus Torvalds * smp_call_function() must not be called from interrupt context (can 42*1da177e4SLinus Torvalds * deadlock on tasklist_lock). Use keventd to call smp_call_function(). 43*1da177e4SLinus Torvalds * 44*1da177e4SLinus Torvalds * 2004-02-01 Keith Owens <kaos@sgi.com> 45*1da177e4SLinus Torvalds * Avoid deadlock when using printk() for MCA and INIT records. 46*1da177e4SLinus Torvalds * Delete all record printing code, moved to salinfo_decode in user space. 47*1da177e4SLinus Torvalds * Mark variables and functions static where possible. 48*1da177e4SLinus Torvalds * Delete dead variables and functions. 49*1da177e4SLinus Torvalds * Reorder to remove the need for forward declarations and to consolidate 50*1da177e4SLinus Torvalds * related code. 51*1da177e4SLinus Torvalds */ 52*1da177e4SLinus Torvalds #include <linux/config.h> 53*1da177e4SLinus Torvalds #include <linux/types.h> 54*1da177e4SLinus Torvalds #include <linux/init.h> 55*1da177e4SLinus Torvalds #include <linux/sched.h> 56*1da177e4SLinus Torvalds #include <linux/interrupt.h> 57*1da177e4SLinus Torvalds #include <linux/irq.h> 58*1da177e4SLinus Torvalds #include <linux/kallsyms.h> 59*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 60*1da177e4SLinus Torvalds #include <linux/bootmem.h> 61*1da177e4SLinus Torvalds #include <linux/acpi.h> 62*1da177e4SLinus Torvalds #include <linux/timer.h> 63*1da177e4SLinus Torvalds #include <linux/module.h> 64*1da177e4SLinus Torvalds #include <linux/kernel.h> 65*1da177e4SLinus Torvalds #include <linux/smp.h> 66*1da177e4SLinus Torvalds #include <linux/workqueue.h> 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds #include <asm/delay.h> 69*1da177e4SLinus Torvalds #include <asm/machvec.h> 70*1da177e4SLinus Torvalds #include <asm/meminit.h> 71*1da177e4SLinus Torvalds #include <asm/page.h> 72*1da177e4SLinus Torvalds #include <asm/ptrace.h> 73*1da177e4SLinus Torvalds #include <asm/system.h> 74*1da177e4SLinus Torvalds #include <asm/sal.h> 75*1da177e4SLinus Torvalds #include <asm/mca.h> 76*1da177e4SLinus Torvalds 77*1da177e4SLinus Torvalds #include <asm/irq.h> 78*1da177e4SLinus Torvalds #include <asm/hw_irq.h> 79*1da177e4SLinus Torvalds 80*1da177e4SLinus Torvalds #if defined(IA64_MCA_DEBUG_INFO) 81*1da177e4SLinus Torvalds # define IA64_MCA_DEBUG(fmt...) printk(fmt) 82*1da177e4SLinus Torvalds #else 83*1da177e4SLinus Torvalds # define IA64_MCA_DEBUG(fmt...) 84*1da177e4SLinus Torvalds #endif 85*1da177e4SLinus Torvalds 86*1da177e4SLinus Torvalds /* Used by mca_asm.S */ 87*1da177e4SLinus Torvalds ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; 88*1da177e4SLinus Torvalds ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; 89*1da177e4SLinus Torvalds u64 ia64_mca_serialize; 90*1da177e4SLinus Torvalds DEFINE_PER_CPU(u64, ia64_mca_data); /* == __per_cpu_mca[smp_processor_id()] */ 91*1da177e4SLinus Torvalds DEFINE_PER_CPU(u64, ia64_mca_per_cpu_pte); /* PTE to map per-CPU area */ 92*1da177e4SLinus Torvalds DEFINE_PER_CPU(u64, ia64_mca_pal_pte); /* PTE to map PAL code */ 93*1da177e4SLinus Torvalds DEFINE_PER_CPU(u64, ia64_mca_pal_base); /* vaddr PAL code granule */ 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds unsigned long __per_cpu_mca[NR_CPUS]; 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds /* In mca_asm.S */ 98*1da177e4SLinus Torvalds extern void ia64_monarch_init_handler (void); 99*1da177e4SLinus Torvalds extern void ia64_slave_init_handler (void); 100*1da177e4SLinus Torvalds 101*1da177e4SLinus Torvalds static ia64_mc_info_t ia64_mc_info; 102*1da177e4SLinus Torvalds 103*1da177e4SLinus Torvalds #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ 104*1da177e4SLinus Torvalds #define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */ 105*1da177e4SLinus Torvalds #define CMC_POLL_INTERVAL (1*60*HZ) /* 1 minute */ 106*1da177e4SLinus Torvalds #define CPE_HISTORY_LENGTH 5 107*1da177e4SLinus Torvalds #define CMC_HISTORY_LENGTH 5 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds static struct timer_list cpe_poll_timer; 110*1da177e4SLinus Torvalds static struct timer_list cmc_poll_timer; 111*1da177e4SLinus Torvalds /* 112*1da177e4SLinus Torvalds * This variable tells whether we are currently in polling mode. 113*1da177e4SLinus Torvalds * Start with this in the wrong state so we won't play w/ timers 114*1da177e4SLinus Torvalds * before the system is ready. 115*1da177e4SLinus Torvalds */ 116*1da177e4SLinus Torvalds static int cmc_polling_enabled = 1; 117*1da177e4SLinus Torvalds 118*1da177e4SLinus Torvalds /* 119*1da177e4SLinus Torvalds * Clearing this variable prevents CPE polling from getting activated 120*1da177e4SLinus Torvalds * in mca_late_init. Use it if your system doesn't provide a CPEI, 121*1da177e4SLinus Torvalds * but encounters problems retrieving CPE logs. This should only be 122*1da177e4SLinus Torvalds * necessary for debugging. 123*1da177e4SLinus Torvalds */ 124*1da177e4SLinus Torvalds static int cpe_poll_enabled = 1; 125*1da177e4SLinus Torvalds 126*1da177e4SLinus Torvalds extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); 127*1da177e4SLinus Torvalds 128*1da177e4SLinus Torvalds static int mca_init; 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds /* 131*1da177e4SLinus Torvalds * IA64_MCA log support 132*1da177e4SLinus Torvalds */ 133*1da177e4SLinus Torvalds #define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */ 134*1da177e4SLinus Torvalds #define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */ 135*1da177e4SLinus Torvalds 136*1da177e4SLinus Torvalds typedef struct ia64_state_log_s 137*1da177e4SLinus Torvalds { 138*1da177e4SLinus Torvalds spinlock_t isl_lock; 139*1da177e4SLinus Torvalds int isl_index; 140*1da177e4SLinus Torvalds unsigned long isl_count; 141*1da177e4SLinus Torvalds ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ 142*1da177e4SLinus Torvalds } ia64_state_log_t; 143*1da177e4SLinus Torvalds 144*1da177e4SLinus Torvalds static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds #define IA64_LOG_ALLOCATE(it, size) \ 147*1da177e4SLinus Torvalds {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ 148*1da177e4SLinus Torvalds (ia64_err_rec_t *)alloc_bootmem(size); \ 149*1da177e4SLinus Torvalds ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ 150*1da177e4SLinus Torvalds (ia64_err_rec_t *)alloc_bootmem(size);} 151*1da177e4SLinus Torvalds #define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) 152*1da177e4SLinus Torvalds #define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) 153*1da177e4SLinus Torvalds #define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) 154*1da177e4SLinus Torvalds #define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index 155*1da177e4SLinus Torvalds #define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index 156*1da177e4SLinus Torvalds #define IA64_LOG_INDEX_INC(it) \ 157*1da177e4SLinus Torvalds {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \ 158*1da177e4SLinus Torvalds ia64_state_log[it].isl_count++;} 159*1da177e4SLinus Torvalds #define IA64_LOG_INDEX_DEC(it) \ 160*1da177e4SLinus Torvalds ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index 161*1da177e4SLinus Torvalds #define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) 162*1da177e4SLinus Torvalds #define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) 163*1da177e4SLinus Torvalds #define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds /* 166*1da177e4SLinus Torvalds * ia64_log_init 167*1da177e4SLinus Torvalds * Reset the OS ia64 log buffer 168*1da177e4SLinus Torvalds * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) 169*1da177e4SLinus Torvalds * Outputs : None 170*1da177e4SLinus Torvalds */ 171*1da177e4SLinus Torvalds static void 172*1da177e4SLinus Torvalds ia64_log_init(int sal_info_type) 173*1da177e4SLinus Torvalds { 174*1da177e4SLinus Torvalds u64 max_size = 0; 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds IA64_LOG_NEXT_INDEX(sal_info_type) = 0; 177*1da177e4SLinus Torvalds IA64_LOG_LOCK_INIT(sal_info_type); 178*1da177e4SLinus Torvalds 179*1da177e4SLinus Torvalds // SAL will tell us the maximum size of any error record of this type 180*1da177e4SLinus Torvalds max_size = ia64_sal_get_state_info_size(sal_info_type); 181*1da177e4SLinus Torvalds if (!max_size) 182*1da177e4SLinus Torvalds /* alloc_bootmem() doesn't like zero-sized allocations! */ 183*1da177e4SLinus Torvalds return; 184*1da177e4SLinus Torvalds 185*1da177e4SLinus Torvalds // set up OS data structures to hold error info 186*1da177e4SLinus Torvalds IA64_LOG_ALLOCATE(sal_info_type, max_size); 187*1da177e4SLinus Torvalds memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size); 188*1da177e4SLinus Torvalds memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size); 189*1da177e4SLinus Torvalds } 190*1da177e4SLinus Torvalds 191*1da177e4SLinus Torvalds /* 192*1da177e4SLinus Torvalds * ia64_log_get 193*1da177e4SLinus Torvalds * 194*1da177e4SLinus Torvalds * Get the current MCA log from SAL and copy it into the OS log buffer. 195*1da177e4SLinus Torvalds * 196*1da177e4SLinus Torvalds * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) 197*1da177e4SLinus Torvalds * irq_safe whether you can use printk at this point 198*1da177e4SLinus Torvalds * Outputs : size (total record length) 199*1da177e4SLinus Torvalds * *buffer (ptr to error record) 200*1da177e4SLinus Torvalds * 201*1da177e4SLinus Torvalds */ 202*1da177e4SLinus Torvalds static u64 203*1da177e4SLinus Torvalds ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe) 204*1da177e4SLinus Torvalds { 205*1da177e4SLinus Torvalds sal_log_record_header_t *log_buffer; 206*1da177e4SLinus Torvalds u64 total_len = 0; 207*1da177e4SLinus Torvalds int s; 208*1da177e4SLinus Torvalds 209*1da177e4SLinus Torvalds IA64_LOG_LOCK(sal_info_type); 210*1da177e4SLinus Torvalds 211*1da177e4SLinus Torvalds /* Get the process state information */ 212*1da177e4SLinus Torvalds log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); 213*1da177e4SLinus Torvalds 214*1da177e4SLinus Torvalds total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); 215*1da177e4SLinus Torvalds 216*1da177e4SLinus Torvalds if (total_len) { 217*1da177e4SLinus Torvalds IA64_LOG_INDEX_INC(sal_info_type); 218*1da177e4SLinus Torvalds IA64_LOG_UNLOCK(sal_info_type); 219*1da177e4SLinus Torvalds if (irq_safe) { 220*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: SAL error record type %d retrieved. " 221*1da177e4SLinus Torvalds "Record length = %ld\n", __FUNCTION__, sal_info_type, total_len); 222*1da177e4SLinus Torvalds } 223*1da177e4SLinus Torvalds *buffer = (u8 *) log_buffer; 224*1da177e4SLinus Torvalds return total_len; 225*1da177e4SLinus Torvalds } else { 226*1da177e4SLinus Torvalds IA64_LOG_UNLOCK(sal_info_type); 227*1da177e4SLinus Torvalds return 0; 228*1da177e4SLinus Torvalds } 229*1da177e4SLinus Torvalds } 230*1da177e4SLinus Torvalds 231*1da177e4SLinus Torvalds /* 232*1da177e4SLinus Torvalds * ia64_mca_log_sal_error_record 233*1da177e4SLinus Torvalds * 234*1da177e4SLinus Torvalds * This function retrieves a specified error record type from SAL 235*1da177e4SLinus Torvalds * and wakes up any processes waiting for error records. 236*1da177e4SLinus Torvalds * 237*1da177e4SLinus Torvalds * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) 238*1da177e4SLinus Torvalds */ 239*1da177e4SLinus Torvalds static void 240*1da177e4SLinus Torvalds ia64_mca_log_sal_error_record(int sal_info_type) 241*1da177e4SLinus Torvalds { 242*1da177e4SLinus Torvalds u8 *buffer; 243*1da177e4SLinus Torvalds sal_log_record_header_t *rh; 244*1da177e4SLinus Torvalds u64 size; 245*1da177e4SLinus Torvalds int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA && sal_info_type != SAL_INFO_TYPE_INIT; 246*1da177e4SLinus Torvalds #ifdef IA64_MCA_DEBUG_INFO 247*1da177e4SLinus Torvalds static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" }; 248*1da177e4SLinus Torvalds #endif 249*1da177e4SLinus Torvalds 250*1da177e4SLinus Torvalds size = ia64_log_get(sal_info_type, &buffer, irq_safe); 251*1da177e4SLinus Torvalds if (!size) 252*1da177e4SLinus Torvalds return; 253*1da177e4SLinus Torvalds 254*1da177e4SLinus Torvalds salinfo_log_wakeup(sal_info_type, buffer, size, irq_safe); 255*1da177e4SLinus Torvalds 256*1da177e4SLinus Torvalds if (irq_safe) 257*1da177e4SLinus Torvalds IA64_MCA_DEBUG("CPU %d: SAL log contains %s error record\n", 258*1da177e4SLinus Torvalds smp_processor_id(), 259*1da177e4SLinus Torvalds sal_info_type < ARRAY_SIZE(rec_name) ? rec_name[sal_info_type] : "UNKNOWN"); 260*1da177e4SLinus Torvalds 261*1da177e4SLinus Torvalds /* Clear logs from corrected errors in case there's no user-level logger */ 262*1da177e4SLinus Torvalds rh = (sal_log_record_header_t *)buffer; 263*1da177e4SLinus Torvalds if (rh->severity == sal_log_severity_corrected) 264*1da177e4SLinus Torvalds ia64_sal_clear_state_info(sal_info_type); 265*1da177e4SLinus Torvalds } 266*1da177e4SLinus Torvalds 267*1da177e4SLinus Torvalds /* 268*1da177e4SLinus Torvalds * platform dependent error handling 269*1da177e4SLinus Torvalds */ 270*1da177e4SLinus Torvalds #ifndef PLATFORM_MCA_HANDLERS 271*1da177e4SLinus Torvalds 272*1da177e4SLinus Torvalds #ifdef CONFIG_ACPI 273*1da177e4SLinus Torvalds 274*1da177e4SLinus Torvalds static int cpe_vector = -1; 275*1da177e4SLinus Torvalds 276*1da177e4SLinus Torvalds static irqreturn_t 277*1da177e4SLinus Torvalds ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) 278*1da177e4SLinus Torvalds { 279*1da177e4SLinus Torvalds static unsigned long cpe_history[CPE_HISTORY_LENGTH]; 280*1da177e4SLinus Torvalds static int index; 281*1da177e4SLinus Torvalds static DEFINE_SPINLOCK(cpe_history_lock); 282*1da177e4SLinus Torvalds 283*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n", 284*1da177e4SLinus Torvalds __FUNCTION__, cpe_irq, smp_processor_id()); 285*1da177e4SLinus Torvalds 286*1da177e4SLinus Torvalds /* SAL spec states this should run w/ interrupts enabled */ 287*1da177e4SLinus Torvalds local_irq_enable(); 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds /* Get the CPE error record and log it */ 290*1da177e4SLinus Torvalds ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); 291*1da177e4SLinus Torvalds 292*1da177e4SLinus Torvalds spin_lock(&cpe_history_lock); 293*1da177e4SLinus Torvalds if (!cpe_poll_enabled && cpe_vector >= 0) { 294*1da177e4SLinus Torvalds 295*1da177e4SLinus Torvalds int i, count = 1; /* we know 1 happened now */ 296*1da177e4SLinus Torvalds unsigned long now = jiffies; 297*1da177e4SLinus Torvalds 298*1da177e4SLinus Torvalds for (i = 0; i < CPE_HISTORY_LENGTH; i++) { 299*1da177e4SLinus Torvalds if (now - cpe_history[i] <= HZ) 300*1da177e4SLinus Torvalds count++; 301*1da177e4SLinus Torvalds } 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds IA64_MCA_DEBUG(KERN_INFO "CPE threshold %d/%d\n", count, CPE_HISTORY_LENGTH); 304*1da177e4SLinus Torvalds if (count >= CPE_HISTORY_LENGTH) { 305*1da177e4SLinus Torvalds 306*1da177e4SLinus Torvalds cpe_poll_enabled = 1; 307*1da177e4SLinus Torvalds spin_unlock(&cpe_history_lock); 308*1da177e4SLinus Torvalds disable_irq_nosync(local_vector_to_irq(IA64_CPE_VECTOR)); 309*1da177e4SLinus Torvalds 310*1da177e4SLinus Torvalds /* 311*1da177e4SLinus Torvalds * Corrected errors will still be corrected, but 312*1da177e4SLinus Torvalds * make sure there's a log somewhere that indicates 313*1da177e4SLinus Torvalds * something is generating more than we can handle. 314*1da177e4SLinus Torvalds */ 315*1da177e4SLinus Torvalds printk(KERN_WARNING "WARNING: Switching to polling CPE handler; error records may be lost\n"); 316*1da177e4SLinus Torvalds 317*1da177e4SLinus Torvalds mod_timer(&cpe_poll_timer, jiffies + MIN_CPE_POLL_INTERVAL); 318*1da177e4SLinus Torvalds 319*1da177e4SLinus Torvalds /* lock already released, get out now */ 320*1da177e4SLinus Torvalds return IRQ_HANDLED; 321*1da177e4SLinus Torvalds } else { 322*1da177e4SLinus Torvalds cpe_history[index++] = now; 323*1da177e4SLinus Torvalds if (index == CPE_HISTORY_LENGTH) 324*1da177e4SLinus Torvalds index = 0; 325*1da177e4SLinus Torvalds } 326*1da177e4SLinus Torvalds } 327*1da177e4SLinus Torvalds spin_unlock(&cpe_history_lock); 328*1da177e4SLinus Torvalds return IRQ_HANDLED; 329*1da177e4SLinus Torvalds } 330*1da177e4SLinus Torvalds 331*1da177e4SLinus Torvalds #endif /* CONFIG_ACPI */ 332*1da177e4SLinus Torvalds 333*1da177e4SLinus Torvalds static void 334*1da177e4SLinus Torvalds show_min_state (pal_min_state_area_t *minstate) 335*1da177e4SLinus Torvalds { 336*1da177e4SLinus Torvalds u64 iip = minstate->pmsa_iip + ((struct ia64_psr *)(&minstate->pmsa_ipsr))->ri; 337*1da177e4SLinus Torvalds u64 xip = minstate->pmsa_xip + ((struct ia64_psr *)(&minstate->pmsa_xpsr))->ri; 338*1da177e4SLinus Torvalds 339*1da177e4SLinus Torvalds printk("NaT bits\t%016lx\n", minstate->pmsa_nat_bits); 340*1da177e4SLinus Torvalds printk("pr\t\t%016lx\n", minstate->pmsa_pr); 341*1da177e4SLinus Torvalds printk("b0\t\t%016lx ", minstate->pmsa_br0); print_symbol("%s\n", minstate->pmsa_br0); 342*1da177e4SLinus Torvalds printk("ar.rsc\t\t%016lx\n", minstate->pmsa_rsc); 343*1da177e4SLinus Torvalds printk("cr.iip\t\t%016lx ", iip); print_symbol("%s\n", iip); 344*1da177e4SLinus Torvalds printk("cr.ipsr\t\t%016lx\n", minstate->pmsa_ipsr); 345*1da177e4SLinus Torvalds printk("cr.ifs\t\t%016lx\n", minstate->pmsa_ifs); 346*1da177e4SLinus Torvalds printk("xip\t\t%016lx ", xip); print_symbol("%s\n", xip); 347*1da177e4SLinus Torvalds printk("xpsr\t\t%016lx\n", minstate->pmsa_xpsr); 348*1da177e4SLinus Torvalds printk("xfs\t\t%016lx\n", minstate->pmsa_xfs); 349*1da177e4SLinus Torvalds printk("b1\t\t%016lx ", minstate->pmsa_br1); 350*1da177e4SLinus Torvalds print_symbol("%s\n", minstate->pmsa_br1); 351*1da177e4SLinus Torvalds 352*1da177e4SLinus Torvalds printk("\nstatic registers r0-r15:\n"); 353*1da177e4SLinus Torvalds printk(" r0- 3 %016lx %016lx %016lx %016lx\n", 354*1da177e4SLinus Torvalds 0UL, minstate->pmsa_gr[0], minstate->pmsa_gr[1], minstate->pmsa_gr[2]); 355*1da177e4SLinus Torvalds printk(" r4- 7 %016lx %016lx %016lx %016lx\n", 356*1da177e4SLinus Torvalds minstate->pmsa_gr[3], minstate->pmsa_gr[4], 357*1da177e4SLinus Torvalds minstate->pmsa_gr[5], minstate->pmsa_gr[6]); 358*1da177e4SLinus Torvalds printk(" r8-11 %016lx %016lx %016lx %016lx\n", 359*1da177e4SLinus Torvalds minstate->pmsa_gr[7], minstate->pmsa_gr[8], 360*1da177e4SLinus Torvalds minstate->pmsa_gr[9], minstate->pmsa_gr[10]); 361*1da177e4SLinus Torvalds printk("r12-15 %016lx %016lx %016lx %016lx\n", 362*1da177e4SLinus Torvalds minstate->pmsa_gr[11], minstate->pmsa_gr[12], 363*1da177e4SLinus Torvalds minstate->pmsa_gr[13], minstate->pmsa_gr[14]); 364*1da177e4SLinus Torvalds 365*1da177e4SLinus Torvalds printk("\nbank 0:\n"); 366*1da177e4SLinus Torvalds printk("r16-19 %016lx %016lx %016lx %016lx\n", 367*1da177e4SLinus Torvalds minstate->pmsa_bank0_gr[0], minstate->pmsa_bank0_gr[1], 368*1da177e4SLinus Torvalds minstate->pmsa_bank0_gr[2], minstate->pmsa_bank0_gr[3]); 369*1da177e4SLinus Torvalds printk("r20-23 %016lx %016lx %016lx %016lx\n", 370*1da177e4SLinus Torvalds minstate->pmsa_bank0_gr[4], minstate->pmsa_bank0_gr[5], 371*1da177e4SLinus Torvalds minstate->pmsa_bank0_gr[6], minstate->pmsa_bank0_gr[7]); 372*1da177e4SLinus Torvalds printk("r24-27 %016lx %016lx %016lx %016lx\n", 373*1da177e4SLinus Torvalds minstate->pmsa_bank0_gr[8], minstate->pmsa_bank0_gr[9], 374*1da177e4SLinus Torvalds minstate->pmsa_bank0_gr[10], minstate->pmsa_bank0_gr[11]); 375*1da177e4SLinus Torvalds printk("r28-31 %016lx %016lx %016lx %016lx\n", 376*1da177e4SLinus Torvalds minstate->pmsa_bank0_gr[12], minstate->pmsa_bank0_gr[13], 377*1da177e4SLinus Torvalds minstate->pmsa_bank0_gr[14], minstate->pmsa_bank0_gr[15]); 378*1da177e4SLinus Torvalds 379*1da177e4SLinus Torvalds printk("\nbank 1:\n"); 380*1da177e4SLinus Torvalds printk("r16-19 %016lx %016lx %016lx %016lx\n", 381*1da177e4SLinus Torvalds minstate->pmsa_bank1_gr[0], minstate->pmsa_bank1_gr[1], 382*1da177e4SLinus Torvalds minstate->pmsa_bank1_gr[2], minstate->pmsa_bank1_gr[3]); 383*1da177e4SLinus Torvalds printk("r20-23 %016lx %016lx %016lx %016lx\n", 384*1da177e4SLinus Torvalds minstate->pmsa_bank1_gr[4], minstate->pmsa_bank1_gr[5], 385*1da177e4SLinus Torvalds minstate->pmsa_bank1_gr[6], minstate->pmsa_bank1_gr[7]); 386*1da177e4SLinus Torvalds printk("r24-27 %016lx %016lx %016lx %016lx\n", 387*1da177e4SLinus Torvalds minstate->pmsa_bank1_gr[8], minstate->pmsa_bank1_gr[9], 388*1da177e4SLinus Torvalds minstate->pmsa_bank1_gr[10], minstate->pmsa_bank1_gr[11]); 389*1da177e4SLinus Torvalds printk("r28-31 %016lx %016lx %016lx %016lx\n", 390*1da177e4SLinus Torvalds minstate->pmsa_bank1_gr[12], minstate->pmsa_bank1_gr[13], 391*1da177e4SLinus Torvalds minstate->pmsa_bank1_gr[14], minstate->pmsa_bank1_gr[15]); 392*1da177e4SLinus Torvalds } 393*1da177e4SLinus Torvalds 394*1da177e4SLinus Torvalds static void 395*1da177e4SLinus Torvalds fetch_min_state (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw) 396*1da177e4SLinus Torvalds { 397*1da177e4SLinus Torvalds u64 *dst_banked, *src_banked, bit, shift, nat_bits; 398*1da177e4SLinus Torvalds int i; 399*1da177e4SLinus Torvalds 400*1da177e4SLinus Torvalds /* 401*1da177e4SLinus Torvalds * First, update the pt-regs and switch-stack structures with the contents stored 402*1da177e4SLinus Torvalds * in the min-state area: 403*1da177e4SLinus Torvalds */ 404*1da177e4SLinus Torvalds if (((struct ia64_psr *) &ms->pmsa_ipsr)->ic == 0) { 405*1da177e4SLinus Torvalds pt->cr_ipsr = ms->pmsa_xpsr; 406*1da177e4SLinus Torvalds pt->cr_iip = ms->pmsa_xip; 407*1da177e4SLinus Torvalds pt->cr_ifs = ms->pmsa_xfs; 408*1da177e4SLinus Torvalds } else { 409*1da177e4SLinus Torvalds pt->cr_ipsr = ms->pmsa_ipsr; 410*1da177e4SLinus Torvalds pt->cr_iip = ms->pmsa_iip; 411*1da177e4SLinus Torvalds pt->cr_ifs = ms->pmsa_ifs; 412*1da177e4SLinus Torvalds } 413*1da177e4SLinus Torvalds pt->ar_rsc = ms->pmsa_rsc; 414*1da177e4SLinus Torvalds pt->pr = ms->pmsa_pr; 415*1da177e4SLinus Torvalds pt->r1 = ms->pmsa_gr[0]; 416*1da177e4SLinus Torvalds pt->r2 = ms->pmsa_gr[1]; 417*1da177e4SLinus Torvalds pt->r3 = ms->pmsa_gr[2]; 418*1da177e4SLinus Torvalds sw->r4 = ms->pmsa_gr[3]; 419*1da177e4SLinus Torvalds sw->r5 = ms->pmsa_gr[4]; 420*1da177e4SLinus Torvalds sw->r6 = ms->pmsa_gr[5]; 421*1da177e4SLinus Torvalds sw->r7 = ms->pmsa_gr[6]; 422*1da177e4SLinus Torvalds pt->r8 = ms->pmsa_gr[7]; 423*1da177e4SLinus Torvalds pt->r9 = ms->pmsa_gr[8]; 424*1da177e4SLinus Torvalds pt->r10 = ms->pmsa_gr[9]; 425*1da177e4SLinus Torvalds pt->r11 = ms->pmsa_gr[10]; 426*1da177e4SLinus Torvalds pt->r12 = ms->pmsa_gr[11]; 427*1da177e4SLinus Torvalds pt->r13 = ms->pmsa_gr[12]; 428*1da177e4SLinus Torvalds pt->r14 = ms->pmsa_gr[13]; 429*1da177e4SLinus Torvalds pt->r15 = ms->pmsa_gr[14]; 430*1da177e4SLinus Torvalds dst_banked = &pt->r16; /* r16-r31 are contiguous in struct pt_regs */ 431*1da177e4SLinus Torvalds src_banked = ms->pmsa_bank1_gr; 432*1da177e4SLinus Torvalds for (i = 0; i < 16; ++i) 433*1da177e4SLinus Torvalds dst_banked[i] = src_banked[i]; 434*1da177e4SLinus Torvalds pt->b0 = ms->pmsa_br0; 435*1da177e4SLinus Torvalds sw->b1 = ms->pmsa_br1; 436*1da177e4SLinus Torvalds 437*1da177e4SLinus Torvalds /* construct the NaT bits for the pt-regs structure: */ 438*1da177e4SLinus Torvalds # define PUT_NAT_BIT(dst, addr) \ 439*1da177e4SLinus Torvalds do { \ 440*1da177e4SLinus Torvalds bit = nat_bits & 1; nat_bits >>= 1; \ 441*1da177e4SLinus Torvalds shift = ((unsigned long) addr >> 3) & 0x3f; \ 442*1da177e4SLinus Torvalds dst = ((dst) & ~(1UL << shift)) | (bit << shift); \ 443*1da177e4SLinus Torvalds } while (0) 444*1da177e4SLinus Torvalds 445*1da177e4SLinus Torvalds /* Rotate the saved NaT bits such that bit 0 corresponds to pmsa_gr[0]: */ 446*1da177e4SLinus Torvalds shift = ((unsigned long) &ms->pmsa_gr[0] >> 3) & 0x3f; 447*1da177e4SLinus Torvalds nat_bits = (ms->pmsa_nat_bits >> shift) | (ms->pmsa_nat_bits << (64 - shift)); 448*1da177e4SLinus Torvalds 449*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r1); 450*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r2); 451*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r3); 452*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->ar_unat, &sw->r4); 453*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->ar_unat, &sw->r5); 454*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->ar_unat, &sw->r6); 455*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->ar_unat, &sw->r7); 456*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r8); PUT_NAT_BIT(sw->caller_unat, &pt->r9); 457*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r10); PUT_NAT_BIT(sw->caller_unat, &pt->r11); 458*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r12); PUT_NAT_BIT(sw->caller_unat, &pt->r13); 459*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r14); PUT_NAT_BIT(sw->caller_unat, &pt->r15); 460*1da177e4SLinus Torvalds nat_bits >>= 16; /* skip over bank0 NaT bits */ 461*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r16); PUT_NAT_BIT(sw->caller_unat, &pt->r17); 462*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r18); PUT_NAT_BIT(sw->caller_unat, &pt->r19); 463*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r20); PUT_NAT_BIT(sw->caller_unat, &pt->r21); 464*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r22); PUT_NAT_BIT(sw->caller_unat, &pt->r23); 465*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r24); PUT_NAT_BIT(sw->caller_unat, &pt->r25); 466*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r26); PUT_NAT_BIT(sw->caller_unat, &pt->r27); 467*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r28); PUT_NAT_BIT(sw->caller_unat, &pt->r29); 468*1da177e4SLinus Torvalds PUT_NAT_BIT(sw->caller_unat, &pt->r30); PUT_NAT_BIT(sw->caller_unat, &pt->r31); 469*1da177e4SLinus Torvalds } 470*1da177e4SLinus Torvalds 471*1da177e4SLinus Torvalds static void 472*1da177e4SLinus Torvalds init_handler_platform (pal_min_state_area_t *ms, 473*1da177e4SLinus Torvalds struct pt_regs *pt, struct switch_stack *sw) 474*1da177e4SLinus Torvalds { 475*1da177e4SLinus Torvalds struct unw_frame_info info; 476*1da177e4SLinus Torvalds 477*1da177e4SLinus Torvalds /* if a kernel debugger is available call it here else just dump the registers */ 478*1da177e4SLinus Torvalds 479*1da177e4SLinus Torvalds /* 480*1da177e4SLinus Torvalds * Wait for a bit. On some machines (e.g., HP's zx2000 and zx6000, INIT can be 481*1da177e4SLinus Torvalds * generated via the BMC's command-line interface, but since the console is on the 482*1da177e4SLinus Torvalds * same serial line, the user will need some time to switch out of the BMC before 483*1da177e4SLinus Torvalds * the dump begins. 484*1da177e4SLinus Torvalds */ 485*1da177e4SLinus Torvalds printk("Delaying for 5 seconds...\n"); 486*1da177e4SLinus Torvalds udelay(5*1000000); 487*1da177e4SLinus Torvalds show_min_state(ms); 488*1da177e4SLinus Torvalds 489*1da177e4SLinus Torvalds printk("Backtrace of current task (pid %d, %s)\n", current->pid, current->comm); 490*1da177e4SLinus Torvalds fetch_min_state(ms, pt, sw); 491*1da177e4SLinus Torvalds unw_init_from_interruption(&info, current, pt, sw); 492*1da177e4SLinus Torvalds ia64_do_show_stack(&info, NULL); 493*1da177e4SLinus Torvalds 494*1da177e4SLinus Torvalds #ifdef CONFIG_SMP 495*1da177e4SLinus Torvalds /* read_trylock() would be handy... */ 496*1da177e4SLinus Torvalds if (!tasklist_lock.write_lock) 497*1da177e4SLinus Torvalds read_lock(&tasklist_lock); 498*1da177e4SLinus Torvalds #endif 499*1da177e4SLinus Torvalds { 500*1da177e4SLinus Torvalds struct task_struct *g, *t; 501*1da177e4SLinus Torvalds do_each_thread (g, t) { 502*1da177e4SLinus Torvalds if (t == current) 503*1da177e4SLinus Torvalds continue; 504*1da177e4SLinus Torvalds 505*1da177e4SLinus Torvalds printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); 506*1da177e4SLinus Torvalds show_stack(t, NULL); 507*1da177e4SLinus Torvalds } while_each_thread (g, t); 508*1da177e4SLinus Torvalds } 509*1da177e4SLinus Torvalds #ifdef CONFIG_SMP 510*1da177e4SLinus Torvalds if (!tasklist_lock.write_lock) 511*1da177e4SLinus Torvalds read_unlock(&tasklist_lock); 512*1da177e4SLinus Torvalds #endif 513*1da177e4SLinus Torvalds 514*1da177e4SLinus Torvalds printk("\nINIT dump complete. Please reboot now.\n"); 515*1da177e4SLinus Torvalds while (1); /* hang city if no debugger */ 516*1da177e4SLinus Torvalds } 517*1da177e4SLinus Torvalds 518*1da177e4SLinus Torvalds #ifdef CONFIG_ACPI 519*1da177e4SLinus Torvalds /* 520*1da177e4SLinus Torvalds * ia64_mca_register_cpev 521*1da177e4SLinus Torvalds * 522*1da177e4SLinus Torvalds * Register the corrected platform error vector with SAL. 523*1da177e4SLinus Torvalds * 524*1da177e4SLinus Torvalds * Inputs 525*1da177e4SLinus Torvalds * cpev Corrected Platform Error Vector number 526*1da177e4SLinus Torvalds * 527*1da177e4SLinus Torvalds * Outputs 528*1da177e4SLinus Torvalds * None 529*1da177e4SLinus Torvalds */ 530*1da177e4SLinus Torvalds static void 531*1da177e4SLinus Torvalds ia64_mca_register_cpev (int cpev) 532*1da177e4SLinus Torvalds { 533*1da177e4SLinus Torvalds /* Register the CPE interrupt vector with SAL */ 534*1da177e4SLinus Torvalds struct ia64_sal_retval isrv; 535*1da177e4SLinus Torvalds 536*1da177e4SLinus Torvalds isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0); 537*1da177e4SLinus Torvalds if (isrv.status) { 538*1da177e4SLinus Torvalds printk(KERN_ERR "Failed to register Corrected Platform " 539*1da177e4SLinus Torvalds "Error interrupt vector with SAL (status %ld)\n", isrv.status); 540*1da177e4SLinus Torvalds return; 541*1da177e4SLinus Torvalds } 542*1da177e4SLinus Torvalds 543*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: corrected platform error " 544*1da177e4SLinus Torvalds "vector %#x registered\n", __FUNCTION__, cpev); 545*1da177e4SLinus Torvalds } 546*1da177e4SLinus Torvalds #endif /* CONFIG_ACPI */ 547*1da177e4SLinus Torvalds 548*1da177e4SLinus Torvalds #endif /* PLATFORM_MCA_HANDLERS */ 549*1da177e4SLinus Torvalds 550*1da177e4SLinus Torvalds /* 551*1da177e4SLinus Torvalds * ia64_mca_cmc_vector_setup 552*1da177e4SLinus Torvalds * 553*1da177e4SLinus Torvalds * Setup the corrected machine check vector register in the processor. 554*1da177e4SLinus Torvalds * (The interrupt is masked on boot. ia64_mca_late_init unmask this.) 555*1da177e4SLinus Torvalds * This function is invoked on a per-processor basis. 556*1da177e4SLinus Torvalds * 557*1da177e4SLinus Torvalds * Inputs 558*1da177e4SLinus Torvalds * None 559*1da177e4SLinus Torvalds * 560*1da177e4SLinus Torvalds * Outputs 561*1da177e4SLinus Torvalds * None 562*1da177e4SLinus Torvalds */ 563*1da177e4SLinus Torvalds void 564*1da177e4SLinus Torvalds ia64_mca_cmc_vector_setup (void) 565*1da177e4SLinus Torvalds { 566*1da177e4SLinus Torvalds cmcv_reg_t cmcv; 567*1da177e4SLinus Torvalds 568*1da177e4SLinus Torvalds cmcv.cmcv_regval = 0; 569*1da177e4SLinus Torvalds cmcv.cmcv_mask = 1; /* Mask/disable interrupt at first */ 570*1da177e4SLinus Torvalds cmcv.cmcv_vector = IA64_CMC_VECTOR; 571*1da177e4SLinus Torvalds ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval); 572*1da177e4SLinus Torvalds 573*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: CPU %d corrected " 574*1da177e4SLinus Torvalds "machine check vector %#x registered.\n", 575*1da177e4SLinus Torvalds __FUNCTION__, smp_processor_id(), IA64_CMC_VECTOR); 576*1da177e4SLinus Torvalds 577*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: CPU %d CMCV = %#016lx\n", 578*1da177e4SLinus Torvalds __FUNCTION__, smp_processor_id(), ia64_getreg(_IA64_REG_CR_CMCV)); 579*1da177e4SLinus Torvalds } 580*1da177e4SLinus Torvalds 581*1da177e4SLinus Torvalds /* 582*1da177e4SLinus Torvalds * ia64_mca_cmc_vector_disable 583*1da177e4SLinus Torvalds * 584*1da177e4SLinus Torvalds * Mask the corrected machine check vector register in the processor. 585*1da177e4SLinus Torvalds * This function is invoked on a per-processor basis. 586*1da177e4SLinus Torvalds * 587*1da177e4SLinus Torvalds * Inputs 588*1da177e4SLinus Torvalds * dummy(unused) 589*1da177e4SLinus Torvalds * 590*1da177e4SLinus Torvalds * Outputs 591*1da177e4SLinus Torvalds * None 592*1da177e4SLinus Torvalds */ 593*1da177e4SLinus Torvalds static void 594*1da177e4SLinus Torvalds ia64_mca_cmc_vector_disable (void *dummy) 595*1da177e4SLinus Torvalds { 596*1da177e4SLinus Torvalds cmcv_reg_t cmcv; 597*1da177e4SLinus Torvalds 598*1da177e4SLinus Torvalds cmcv.cmcv_regval = ia64_getreg(_IA64_REG_CR_CMCV); 599*1da177e4SLinus Torvalds 600*1da177e4SLinus Torvalds cmcv.cmcv_mask = 1; /* Mask/disable interrupt */ 601*1da177e4SLinus Torvalds ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval); 602*1da177e4SLinus Torvalds 603*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: CPU %d corrected " 604*1da177e4SLinus Torvalds "machine check vector %#x disabled.\n", 605*1da177e4SLinus Torvalds __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector); 606*1da177e4SLinus Torvalds } 607*1da177e4SLinus Torvalds 608*1da177e4SLinus Torvalds /* 609*1da177e4SLinus Torvalds * ia64_mca_cmc_vector_enable 610*1da177e4SLinus Torvalds * 611*1da177e4SLinus Torvalds * Unmask the corrected machine check vector register in the processor. 612*1da177e4SLinus Torvalds * This function is invoked on a per-processor basis. 613*1da177e4SLinus Torvalds * 614*1da177e4SLinus Torvalds * Inputs 615*1da177e4SLinus Torvalds * dummy(unused) 616*1da177e4SLinus Torvalds * 617*1da177e4SLinus Torvalds * Outputs 618*1da177e4SLinus Torvalds * None 619*1da177e4SLinus Torvalds */ 620*1da177e4SLinus Torvalds static void 621*1da177e4SLinus Torvalds ia64_mca_cmc_vector_enable (void *dummy) 622*1da177e4SLinus Torvalds { 623*1da177e4SLinus Torvalds cmcv_reg_t cmcv; 624*1da177e4SLinus Torvalds 625*1da177e4SLinus Torvalds cmcv.cmcv_regval = ia64_getreg(_IA64_REG_CR_CMCV); 626*1da177e4SLinus Torvalds 627*1da177e4SLinus Torvalds cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ 628*1da177e4SLinus Torvalds ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval); 629*1da177e4SLinus Torvalds 630*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: CPU %d corrected " 631*1da177e4SLinus Torvalds "machine check vector %#x enabled.\n", 632*1da177e4SLinus Torvalds __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector); 633*1da177e4SLinus Torvalds } 634*1da177e4SLinus Torvalds 635*1da177e4SLinus Torvalds /* 636*1da177e4SLinus Torvalds * ia64_mca_cmc_vector_disable_keventd 637*1da177e4SLinus Torvalds * 638*1da177e4SLinus Torvalds * Called via keventd (smp_call_function() is not safe in interrupt context) to 639*1da177e4SLinus Torvalds * disable the cmc interrupt vector. 640*1da177e4SLinus Torvalds */ 641*1da177e4SLinus Torvalds static void 642*1da177e4SLinus Torvalds ia64_mca_cmc_vector_disable_keventd(void *unused) 643*1da177e4SLinus Torvalds { 644*1da177e4SLinus Torvalds on_each_cpu(ia64_mca_cmc_vector_disable, NULL, 1, 0); 645*1da177e4SLinus Torvalds } 646*1da177e4SLinus Torvalds 647*1da177e4SLinus Torvalds /* 648*1da177e4SLinus Torvalds * ia64_mca_cmc_vector_enable_keventd 649*1da177e4SLinus Torvalds * 650*1da177e4SLinus Torvalds * Called via keventd (smp_call_function() is not safe in interrupt context) to 651*1da177e4SLinus Torvalds * enable the cmc interrupt vector. 652*1da177e4SLinus Torvalds */ 653*1da177e4SLinus Torvalds static void 654*1da177e4SLinus Torvalds ia64_mca_cmc_vector_enable_keventd(void *unused) 655*1da177e4SLinus Torvalds { 656*1da177e4SLinus Torvalds on_each_cpu(ia64_mca_cmc_vector_enable, NULL, 1, 0); 657*1da177e4SLinus Torvalds } 658*1da177e4SLinus Torvalds 659*1da177e4SLinus Torvalds /* 660*1da177e4SLinus Torvalds * ia64_mca_wakeup_ipi_wait 661*1da177e4SLinus Torvalds * 662*1da177e4SLinus Torvalds * Wait for the inter-cpu interrupt to be sent by the 663*1da177e4SLinus Torvalds * monarch processor once it is done with handling the 664*1da177e4SLinus Torvalds * MCA. 665*1da177e4SLinus Torvalds * 666*1da177e4SLinus Torvalds * Inputs : None 667*1da177e4SLinus Torvalds * Outputs : None 668*1da177e4SLinus Torvalds */ 669*1da177e4SLinus Torvalds static void 670*1da177e4SLinus Torvalds ia64_mca_wakeup_ipi_wait(void) 671*1da177e4SLinus Torvalds { 672*1da177e4SLinus Torvalds int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6); 673*1da177e4SLinus Torvalds int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f); 674*1da177e4SLinus Torvalds u64 irr = 0; 675*1da177e4SLinus Torvalds 676*1da177e4SLinus Torvalds do { 677*1da177e4SLinus Torvalds switch(irr_num) { 678*1da177e4SLinus Torvalds case 0: 679*1da177e4SLinus Torvalds irr = ia64_getreg(_IA64_REG_CR_IRR0); 680*1da177e4SLinus Torvalds break; 681*1da177e4SLinus Torvalds case 1: 682*1da177e4SLinus Torvalds irr = ia64_getreg(_IA64_REG_CR_IRR1); 683*1da177e4SLinus Torvalds break; 684*1da177e4SLinus Torvalds case 2: 685*1da177e4SLinus Torvalds irr = ia64_getreg(_IA64_REG_CR_IRR2); 686*1da177e4SLinus Torvalds break; 687*1da177e4SLinus Torvalds case 3: 688*1da177e4SLinus Torvalds irr = ia64_getreg(_IA64_REG_CR_IRR3); 689*1da177e4SLinus Torvalds break; 690*1da177e4SLinus Torvalds } 691*1da177e4SLinus Torvalds cpu_relax(); 692*1da177e4SLinus Torvalds } while (!(irr & (1UL << irr_bit))) ; 693*1da177e4SLinus Torvalds } 694*1da177e4SLinus Torvalds 695*1da177e4SLinus Torvalds /* 696*1da177e4SLinus Torvalds * ia64_mca_wakeup 697*1da177e4SLinus Torvalds * 698*1da177e4SLinus Torvalds * Send an inter-cpu interrupt to wake-up a particular cpu 699*1da177e4SLinus Torvalds * and mark that cpu to be out of rendez. 700*1da177e4SLinus Torvalds * 701*1da177e4SLinus Torvalds * Inputs : cpuid 702*1da177e4SLinus Torvalds * Outputs : None 703*1da177e4SLinus Torvalds */ 704*1da177e4SLinus Torvalds static void 705*1da177e4SLinus Torvalds ia64_mca_wakeup(int cpu) 706*1da177e4SLinus Torvalds { 707*1da177e4SLinus Torvalds platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); 708*1da177e4SLinus Torvalds ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; 709*1da177e4SLinus Torvalds 710*1da177e4SLinus Torvalds } 711*1da177e4SLinus Torvalds 712*1da177e4SLinus Torvalds /* 713*1da177e4SLinus Torvalds * ia64_mca_wakeup_all 714*1da177e4SLinus Torvalds * 715*1da177e4SLinus Torvalds * Wakeup all the cpus which have rendez'ed previously. 716*1da177e4SLinus Torvalds * 717*1da177e4SLinus Torvalds * Inputs : None 718*1da177e4SLinus Torvalds * Outputs : None 719*1da177e4SLinus Torvalds */ 720*1da177e4SLinus Torvalds static void 721*1da177e4SLinus Torvalds ia64_mca_wakeup_all(void) 722*1da177e4SLinus Torvalds { 723*1da177e4SLinus Torvalds int cpu; 724*1da177e4SLinus Torvalds 725*1da177e4SLinus Torvalds /* Clear the Rendez checkin flag for all cpus */ 726*1da177e4SLinus Torvalds for(cpu = 0; cpu < NR_CPUS; cpu++) { 727*1da177e4SLinus Torvalds if (!cpu_online(cpu)) 728*1da177e4SLinus Torvalds continue; 729*1da177e4SLinus Torvalds if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE) 730*1da177e4SLinus Torvalds ia64_mca_wakeup(cpu); 731*1da177e4SLinus Torvalds } 732*1da177e4SLinus Torvalds 733*1da177e4SLinus Torvalds } 734*1da177e4SLinus Torvalds 735*1da177e4SLinus Torvalds /* 736*1da177e4SLinus Torvalds * ia64_mca_rendez_interrupt_handler 737*1da177e4SLinus Torvalds * 738*1da177e4SLinus Torvalds * This is handler used to put slave processors into spinloop 739*1da177e4SLinus Torvalds * while the monarch processor does the mca handling and later 740*1da177e4SLinus Torvalds * wake each slave up once the monarch is done. 741*1da177e4SLinus Torvalds * 742*1da177e4SLinus Torvalds * Inputs : None 743*1da177e4SLinus Torvalds * Outputs : None 744*1da177e4SLinus Torvalds */ 745*1da177e4SLinus Torvalds static irqreturn_t 746*1da177e4SLinus Torvalds ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) 747*1da177e4SLinus Torvalds { 748*1da177e4SLinus Torvalds unsigned long flags; 749*1da177e4SLinus Torvalds int cpu = smp_processor_id(); 750*1da177e4SLinus Torvalds 751*1da177e4SLinus Torvalds /* Mask all interrupts */ 752*1da177e4SLinus Torvalds local_irq_save(flags); 753*1da177e4SLinus Torvalds 754*1da177e4SLinus Torvalds ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE; 755*1da177e4SLinus Torvalds /* Register with the SAL monarch that the slave has 756*1da177e4SLinus Torvalds * reached SAL 757*1da177e4SLinus Torvalds */ 758*1da177e4SLinus Torvalds ia64_sal_mc_rendez(); 759*1da177e4SLinus Torvalds 760*1da177e4SLinus Torvalds /* Wait for the wakeup IPI from the monarch 761*1da177e4SLinus Torvalds * This waiting is done by polling on the wakeup-interrupt 762*1da177e4SLinus Torvalds * vector bit in the processor's IRRs 763*1da177e4SLinus Torvalds */ 764*1da177e4SLinus Torvalds ia64_mca_wakeup_ipi_wait(); 765*1da177e4SLinus Torvalds 766*1da177e4SLinus Torvalds /* Enable all interrupts */ 767*1da177e4SLinus Torvalds local_irq_restore(flags); 768*1da177e4SLinus Torvalds return IRQ_HANDLED; 769*1da177e4SLinus Torvalds } 770*1da177e4SLinus Torvalds 771*1da177e4SLinus Torvalds /* 772*1da177e4SLinus Torvalds * ia64_mca_wakeup_int_handler 773*1da177e4SLinus Torvalds * 774*1da177e4SLinus Torvalds * The interrupt handler for processing the inter-cpu interrupt to the 775*1da177e4SLinus Torvalds * slave cpu which was spinning in the rendez loop. 776*1da177e4SLinus Torvalds * Since this spinning is done by turning off the interrupts and 777*1da177e4SLinus Torvalds * polling on the wakeup-interrupt bit in the IRR, there is 778*1da177e4SLinus Torvalds * nothing useful to be done in the handler. 779*1da177e4SLinus Torvalds * 780*1da177e4SLinus Torvalds * Inputs : wakeup_irq (Wakeup-interrupt bit) 781*1da177e4SLinus Torvalds * arg (Interrupt handler specific argument) 782*1da177e4SLinus Torvalds * ptregs (Exception frame at the time of the interrupt) 783*1da177e4SLinus Torvalds * Outputs : None 784*1da177e4SLinus Torvalds * 785*1da177e4SLinus Torvalds */ 786*1da177e4SLinus Torvalds static irqreturn_t 787*1da177e4SLinus Torvalds ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) 788*1da177e4SLinus Torvalds { 789*1da177e4SLinus Torvalds return IRQ_HANDLED; 790*1da177e4SLinus Torvalds } 791*1da177e4SLinus Torvalds 792*1da177e4SLinus Torvalds /* 793*1da177e4SLinus Torvalds * ia64_return_to_sal_check 794*1da177e4SLinus Torvalds * 795*1da177e4SLinus Torvalds * This is function called before going back from the OS_MCA handler 796*1da177e4SLinus Torvalds * to the OS_MCA dispatch code which finally takes the control back 797*1da177e4SLinus Torvalds * to the SAL. 798*1da177e4SLinus Torvalds * The main purpose of this routine is to setup the OS_MCA to SAL 799*1da177e4SLinus Torvalds * return state which can be used by the OS_MCA dispatch code 800*1da177e4SLinus Torvalds * just before going back to SAL. 801*1da177e4SLinus Torvalds * 802*1da177e4SLinus Torvalds * Inputs : None 803*1da177e4SLinus Torvalds * Outputs : None 804*1da177e4SLinus Torvalds */ 805*1da177e4SLinus Torvalds 806*1da177e4SLinus Torvalds static void 807*1da177e4SLinus Torvalds ia64_return_to_sal_check(int recover) 808*1da177e4SLinus Torvalds { 809*1da177e4SLinus Torvalds 810*1da177e4SLinus Torvalds /* Copy over some relevant stuff from the sal_to_os_mca_handoff 811*1da177e4SLinus Torvalds * so that it can be used at the time of os_mca_to_sal_handoff 812*1da177e4SLinus Torvalds */ 813*1da177e4SLinus Torvalds ia64_os_to_sal_handoff_state.imots_sal_gp = 814*1da177e4SLinus Torvalds ia64_sal_to_os_handoff_state.imsto_sal_gp; 815*1da177e4SLinus Torvalds 816*1da177e4SLinus Torvalds ia64_os_to_sal_handoff_state.imots_sal_check_ra = 817*1da177e4SLinus Torvalds ia64_sal_to_os_handoff_state.imsto_sal_check_ra; 818*1da177e4SLinus Torvalds 819*1da177e4SLinus Torvalds if (recover) 820*1da177e4SLinus Torvalds ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; 821*1da177e4SLinus Torvalds else 822*1da177e4SLinus Torvalds ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; 823*1da177e4SLinus Torvalds 824*1da177e4SLinus Torvalds /* Default = tell SAL to return to same context */ 825*1da177e4SLinus Torvalds ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT; 826*1da177e4SLinus Torvalds 827*1da177e4SLinus Torvalds ia64_os_to_sal_handoff_state.imots_new_min_state = 828*1da177e4SLinus Torvalds (u64 *)ia64_sal_to_os_handoff_state.pal_min_state; 829*1da177e4SLinus Torvalds 830*1da177e4SLinus Torvalds } 831*1da177e4SLinus Torvalds 832*1da177e4SLinus Torvalds /* Function pointer for extra MCA recovery */ 833*1da177e4SLinus Torvalds int (*ia64_mca_ucmc_extension) 834*1da177e4SLinus Torvalds (void*,ia64_mca_sal_to_os_state_t*,ia64_mca_os_to_sal_state_t*) 835*1da177e4SLinus Torvalds = NULL; 836*1da177e4SLinus Torvalds 837*1da177e4SLinus Torvalds int 838*1da177e4SLinus Torvalds ia64_reg_MCA_extension(void *fn) 839*1da177e4SLinus Torvalds { 840*1da177e4SLinus Torvalds if (ia64_mca_ucmc_extension) 841*1da177e4SLinus Torvalds return 1; 842*1da177e4SLinus Torvalds 843*1da177e4SLinus Torvalds ia64_mca_ucmc_extension = fn; 844*1da177e4SLinus Torvalds return 0; 845*1da177e4SLinus Torvalds } 846*1da177e4SLinus Torvalds 847*1da177e4SLinus Torvalds void 848*1da177e4SLinus Torvalds ia64_unreg_MCA_extension(void) 849*1da177e4SLinus Torvalds { 850*1da177e4SLinus Torvalds if (ia64_mca_ucmc_extension) 851*1da177e4SLinus Torvalds ia64_mca_ucmc_extension = NULL; 852*1da177e4SLinus Torvalds } 853*1da177e4SLinus Torvalds 854*1da177e4SLinus Torvalds EXPORT_SYMBOL(ia64_reg_MCA_extension); 855*1da177e4SLinus Torvalds EXPORT_SYMBOL(ia64_unreg_MCA_extension); 856*1da177e4SLinus Torvalds 857*1da177e4SLinus Torvalds /* 858*1da177e4SLinus Torvalds * ia64_mca_ucmc_handler 859*1da177e4SLinus Torvalds * 860*1da177e4SLinus Torvalds * This is uncorrectable machine check handler called from OS_MCA 861*1da177e4SLinus Torvalds * dispatch code which is in turn called from SAL_CHECK(). 862*1da177e4SLinus Torvalds * This is the place where the core of OS MCA handling is done. 863*1da177e4SLinus Torvalds * Right now the logs are extracted and displayed in a well-defined 864*1da177e4SLinus Torvalds * format. This handler code is supposed to be run only on the 865*1da177e4SLinus Torvalds * monarch processor. Once the monarch is done with MCA handling 866*1da177e4SLinus Torvalds * further MCA logging is enabled by clearing logs. 867*1da177e4SLinus Torvalds * Monarch also has the duty of sending wakeup-IPIs to pull the 868*1da177e4SLinus Torvalds * slave processors out of rendezvous spinloop. 869*1da177e4SLinus Torvalds * 870*1da177e4SLinus Torvalds * Inputs : None 871*1da177e4SLinus Torvalds * Outputs : None 872*1da177e4SLinus Torvalds */ 873*1da177e4SLinus Torvalds void 874*1da177e4SLinus Torvalds ia64_mca_ucmc_handler(void) 875*1da177e4SLinus Torvalds { 876*1da177e4SLinus Torvalds pal_processor_state_info_t *psp = (pal_processor_state_info_t *) 877*1da177e4SLinus Torvalds &ia64_sal_to_os_handoff_state.proc_state_param; 878*1da177e4SLinus Torvalds int recover; 879*1da177e4SLinus Torvalds 880*1da177e4SLinus Torvalds /* Get the MCA error record and log it */ 881*1da177e4SLinus Torvalds ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); 882*1da177e4SLinus Torvalds 883*1da177e4SLinus Torvalds /* TLB error is only exist in this SAL error record */ 884*1da177e4SLinus Torvalds recover = (psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc)) 885*1da177e4SLinus Torvalds /* other error recovery */ 886*1da177e4SLinus Torvalds || (ia64_mca_ucmc_extension 887*1da177e4SLinus Torvalds && ia64_mca_ucmc_extension( 888*1da177e4SLinus Torvalds IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA), 889*1da177e4SLinus Torvalds &ia64_sal_to_os_handoff_state, 890*1da177e4SLinus Torvalds &ia64_os_to_sal_handoff_state)); 891*1da177e4SLinus Torvalds 892*1da177e4SLinus Torvalds if (recover) { 893*1da177e4SLinus Torvalds sal_log_record_header_t *rh = IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA); 894*1da177e4SLinus Torvalds rh->severity = sal_log_severity_corrected; 895*1da177e4SLinus Torvalds ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); 896*1da177e4SLinus Torvalds } 897*1da177e4SLinus Torvalds /* 898*1da177e4SLinus Torvalds * Wakeup all the processors which are spinning in the rendezvous 899*1da177e4SLinus Torvalds * loop. 900*1da177e4SLinus Torvalds */ 901*1da177e4SLinus Torvalds ia64_mca_wakeup_all(); 902*1da177e4SLinus Torvalds 903*1da177e4SLinus Torvalds /* Return to SAL */ 904*1da177e4SLinus Torvalds ia64_return_to_sal_check(recover); 905*1da177e4SLinus Torvalds } 906*1da177e4SLinus Torvalds 907*1da177e4SLinus Torvalds static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd, NULL); 908*1da177e4SLinus Torvalds static DECLARE_WORK(cmc_enable_work, ia64_mca_cmc_vector_enable_keventd, NULL); 909*1da177e4SLinus Torvalds 910*1da177e4SLinus Torvalds /* 911*1da177e4SLinus Torvalds * ia64_mca_cmc_int_handler 912*1da177e4SLinus Torvalds * 913*1da177e4SLinus Torvalds * This is corrected machine check interrupt handler. 914*1da177e4SLinus Torvalds * Right now the logs are extracted and displayed in a well-defined 915*1da177e4SLinus Torvalds * format. 916*1da177e4SLinus Torvalds * 917*1da177e4SLinus Torvalds * Inputs 918*1da177e4SLinus Torvalds * interrupt number 919*1da177e4SLinus Torvalds * client data arg ptr 920*1da177e4SLinus Torvalds * saved registers ptr 921*1da177e4SLinus Torvalds * 922*1da177e4SLinus Torvalds * Outputs 923*1da177e4SLinus Torvalds * None 924*1da177e4SLinus Torvalds */ 925*1da177e4SLinus Torvalds static irqreturn_t 926*1da177e4SLinus Torvalds ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) 927*1da177e4SLinus Torvalds { 928*1da177e4SLinus Torvalds static unsigned long cmc_history[CMC_HISTORY_LENGTH]; 929*1da177e4SLinus Torvalds static int index; 930*1da177e4SLinus Torvalds static DEFINE_SPINLOCK(cmc_history_lock); 931*1da177e4SLinus Torvalds 932*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n", 933*1da177e4SLinus Torvalds __FUNCTION__, cmc_irq, smp_processor_id()); 934*1da177e4SLinus Torvalds 935*1da177e4SLinus Torvalds /* SAL spec states this should run w/ interrupts enabled */ 936*1da177e4SLinus Torvalds local_irq_enable(); 937*1da177e4SLinus Torvalds 938*1da177e4SLinus Torvalds /* Get the CMC error record and log it */ 939*1da177e4SLinus Torvalds ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC); 940*1da177e4SLinus Torvalds 941*1da177e4SLinus Torvalds spin_lock(&cmc_history_lock); 942*1da177e4SLinus Torvalds if (!cmc_polling_enabled) { 943*1da177e4SLinus Torvalds int i, count = 1; /* we know 1 happened now */ 944*1da177e4SLinus Torvalds unsigned long now = jiffies; 945*1da177e4SLinus Torvalds 946*1da177e4SLinus Torvalds for (i = 0; i < CMC_HISTORY_LENGTH; i++) { 947*1da177e4SLinus Torvalds if (now - cmc_history[i] <= HZ) 948*1da177e4SLinus Torvalds count++; 949*1da177e4SLinus Torvalds } 950*1da177e4SLinus Torvalds 951*1da177e4SLinus Torvalds IA64_MCA_DEBUG(KERN_INFO "CMC threshold %d/%d\n", count, CMC_HISTORY_LENGTH); 952*1da177e4SLinus Torvalds if (count >= CMC_HISTORY_LENGTH) { 953*1da177e4SLinus Torvalds 954*1da177e4SLinus Torvalds cmc_polling_enabled = 1; 955*1da177e4SLinus Torvalds spin_unlock(&cmc_history_lock); 956*1da177e4SLinus Torvalds schedule_work(&cmc_disable_work); 957*1da177e4SLinus Torvalds 958*1da177e4SLinus Torvalds /* 959*1da177e4SLinus Torvalds * Corrected errors will still be corrected, but 960*1da177e4SLinus Torvalds * make sure there's a log somewhere that indicates 961*1da177e4SLinus Torvalds * something is generating more than we can handle. 962*1da177e4SLinus Torvalds */ 963*1da177e4SLinus Torvalds printk(KERN_WARNING "WARNING: Switching to polling CMC handler; error records may be lost\n"); 964*1da177e4SLinus Torvalds 965*1da177e4SLinus Torvalds mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL); 966*1da177e4SLinus Torvalds 967*1da177e4SLinus Torvalds /* lock already released, get out now */ 968*1da177e4SLinus Torvalds return IRQ_HANDLED; 969*1da177e4SLinus Torvalds } else { 970*1da177e4SLinus Torvalds cmc_history[index++] = now; 971*1da177e4SLinus Torvalds if (index == CMC_HISTORY_LENGTH) 972*1da177e4SLinus Torvalds index = 0; 973*1da177e4SLinus Torvalds } 974*1da177e4SLinus Torvalds } 975*1da177e4SLinus Torvalds spin_unlock(&cmc_history_lock); 976*1da177e4SLinus Torvalds return IRQ_HANDLED; 977*1da177e4SLinus Torvalds } 978*1da177e4SLinus Torvalds 979*1da177e4SLinus Torvalds /* 980*1da177e4SLinus Torvalds * ia64_mca_cmc_int_caller 981*1da177e4SLinus Torvalds * 982*1da177e4SLinus Torvalds * Triggered by sw interrupt from CMC polling routine. Calls 983*1da177e4SLinus Torvalds * real interrupt handler and either triggers a sw interrupt 984*1da177e4SLinus Torvalds * on the next cpu or does cleanup at the end. 985*1da177e4SLinus Torvalds * 986*1da177e4SLinus Torvalds * Inputs 987*1da177e4SLinus Torvalds * interrupt number 988*1da177e4SLinus Torvalds * client data arg ptr 989*1da177e4SLinus Torvalds * saved registers ptr 990*1da177e4SLinus Torvalds * Outputs 991*1da177e4SLinus Torvalds * handled 992*1da177e4SLinus Torvalds */ 993*1da177e4SLinus Torvalds static irqreturn_t 994*1da177e4SLinus Torvalds ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs) 995*1da177e4SLinus Torvalds { 996*1da177e4SLinus Torvalds static int start_count = -1; 997*1da177e4SLinus Torvalds unsigned int cpuid; 998*1da177e4SLinus Torvalds 999*1da177e4SLinus Torvalds cpuid = smp_processor_id(); 1000*1da177e4SLinus Torvalds 1001*1da177e4SLinus Torvalds /* If first cpu, update count */ 1002*1da177e4SLinus Torvalds if (start_count == -1) 1003*1da177e4SLinus Torvalds start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CMC); 1004*1da177e4SLinus Torvalds 1005*1da177e4SLinus Torvalds ia64_mca_cmc_int_handler(cmc_irq, arg, ptregs); 1006*1da177e4SLinus Torvalds 1007*1da177e4SLinus Torvalds for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); 1008*1da177e4SLinus Torvalds 1009*1da177e4SLinus Torvalds if (cpuid < NR_CPUS) { 1010*1da177e4SLinus Torvalds platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); 1011*1da177e4SLinus Torvalds } else { 1012*1da177e4SLinus Torvalds /* If no log record, switch out of polling mode */ 1013*1da177e4SLinus Torvalds if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) { 1014*1da177e4SLinus Torvalds 1015*1da177e4SLinus Torvalds printk(KERN_WARNING "Returning to interrupt driven CMC handler\n"); 1016*1da177e4SLinus Torvalds schedule_work(&cmc_enable_work); 1017*1da177e4SLinus Torvalds cmc_polling_enabled = 0; 1018*1da177e4SLinus Torvalds 1019*1da177e4SLinus Torvalds } else { 1020*1da177e4SLinus Torvalds 1021*1da177e4SLinus Torvalds mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL); 1022*1da177e4SLinus Torvalds } 1023*1da177e4SLinus Torvalds 1024*1da177e4SLinus Torvalds start_count = -1; 1025*1da177e4SLinus Torvalds } 1026*1da177e4SLinus Torvalds 1027*1da177e4SLinus Torvalds return IRQ_HANDLED; 1028*1da177e4SLinus Torvalds } 1029*1da177e4SLinus Torvalds 1030*1da177e4SLinus Torvalds /* 1031*1da177e4SLinus Torvalds * ia64_mca_cmc_poll 1032*1da177e4SLinus Torvalds * 1033*1da177e4SLinus Torvalds * Poll for Corrected Machine Checks (CMCs) 1034*1da177e4SLinus Torvalds * 1035*1da177e4SLinus Torvalds * Inputs : dummy(unused) 1036*1da177e4SLinus Torvalds * Outputs : None 1037*1da177e4SLinus Torvalds * 1038*1da177e4SLinus Torvalds */ 1039*1da177e4SLinus Torvalds static void 1040*1da177e4SLinus Torvalds ia64_mca_cmc_poll (unsigned long dummy) 1041*1da177e4SLinus Torvalds { 1042*1da177e4SLinus Torvalds /* Trigger a CMC interrupt cascade */ 1043*1da177e4SLinus Torvalds platform_send_ipi(first_cpu(cpu_online_map), IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); 1044*1da177e4SLinus Torvalds } 1045*1da177e4SLinus Torvalds 1046*1da177e4SLinus Torvalds /* 1047*1da177e4SLinus Torvalds * ia64_mca_cpe_int_caller 1048*1da177e4SLinus Torvalds * 1049*1da177e4SLinus Torvalds * Triggered by sw interrupt from CPE polling routine. Calls 1050*1da177e4SLinus Torvalds * real interrupt handler and either triggers a sw interrupt 1051*1da177e4SLinus Torvalds * on the next cpu or does cleanup at the end. 1052*1da177e4SLinus Torvalds * 1053*1da177e4SLinus Torvalds * Inputs 1054*1da177e4SLinus Torvalds * interrupt number 1055*1da177e4SLinus Torvalds * client data arg ptr 1056*1da177e4SLinus Torvalds * saved registers ptr 1057*1da177e4SLinus Torvalds * Outputs 1058*1da177e4SLinus Torvalds * handled 1059*1da177e4SLinus Torvalds */ 1060*1da177e4SLinus Torvalds #ifdef CONFIG_ACPI 1061*1da177e4SLinus Torvalds 1062*1da177e4SLinus Torvalds static irqreturn_t 1063*1da177e4SLinus Torvalds ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) 1064*1da177e4SLinus Torvalds { 1065*1da177e4SLinus Torvalds static int start_count = -1; 1066*1da177e4SLinus Torvalds static int poll_time = MIN_CPE_POLL_INTERVAL; 1067*1da177e4SLinus Torvalds unsigned int cpuid; 1068*1da177e4SLinus Torvalds 1069*1da177e4SLinus Torvalds cpuid = smp_processor_id(); 1070*1da177e4SLinus Torvalds 1071*1da177e4SLinus Torvalds /* If first cpu, update count */ 1072*1da177e4SLinus Torvalds if (start_count == -1) 1073*1da177e4SLinus Torvalds start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CPE); 1074*1da177e4SLinus Torvalds 1075*1da177e4SLinus Torvalds ia64_mca_cpe_int_handler(cpe_irq, arg, ptregs); 1076*1da177e4SLinus Torvalds 1077*1da177e4SLinus Torvalds for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); 1078*1da177e4SLinus Torvalds 1079*1da177e4SLinus Torvalds if (cpuid < NR_CPUS) { 1080*1da177e4SLinus Torvalds platform_send_ipi(cpuid, IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); 1081*1da177e4SLinus Torvalds } else { 1082*1da177e4SLinus Torvalds /* 1083*1da177e4SLinus Torvalds * If a log was recorded, increase our polling frequency, 1084*1da177e4SLinus Torvalds * otherwise, backoff or return to interrupt mode. 1085*1da177e4SLinus Torvalds */ 1086*1da177e4SLinus Torvalds if (start_count != IA64_LOG_COUNT(SAL_INFO_TYPE_CPE)) { 1087*1da177e4SLinus Torvalds poll_time = max(MIN_CPE_POLL_INTERVAL, poll_time / 2); 1088*1da177e4SLinus Torvalds } else if (cpe_vector < 0) { 1089*1da177e4SLinus Torvalds poll_time = min(MAX_CPE_POLL_INTERVAL, poll_time * 2); 1090*1da177e4SLinus Torvalds } else { 1091*1da177e4SLinus Torvalds poll_time = MIN_CPE_POLL_INTERVAL; 1092*1da177e4SLinus Torvalds 1093*1da177e4SLinus Torvalds printk(KERN_WARNING "Returning to interrupt driven CPE handler\n"); 1094*1da177e4SLinus Torvalds enable_irq(local_vector_to_irq(IA64_CPE_VECTOR)); 1095*1da177e4SLinus Torvalds cpe_poll_enabled = 0; 1096*1da177e4SLinus Torvalds } 1097*1da177e4SLinus Torvalds 1098*1da177e4SLinus Torvalds if (cpe_poll_enabled) 1099*1da177e4SLinus Torvalds mod_timer(&cpe_poll_timer, jiffies + poll_time); 1100*1da177e4SLinus Torvalds start_count = -1; 1101*1da177e4SLinus Torvalds } 1102*1da177e4SLinus Torvalds 1103*1da177e4SLinus Torvalds return IRQ_HANDLED; 1104*1da177e4SLinus Torvalds } 1105*1da177e4SLinus Torvalds 1106*1da177e4SLinus Torvalds #endif /* CONFIG_ACPI */ 1107*1da177e4SLinus Torvalds 1108*1da177e4SLinus Torvalds /* 1109*1da177e4SLinus Torvalds * ia64_mca_cpe_poll 1110*1da177e4SLinus Torvalds * 1111*1da177e4SLinus Torvalds * Poll for Corrected Platform Errors (CPEs), trigger interrupt 1112*1da177e4SLinus Torvalds * on first cpu, from there it will trickle through all the cpus. 1113*1da177e4SLinus Torvalds * 1114*1da177e4SLinus Torvalds * Inputs : dummy(unused) 1115*1da177e4SLinus Torvalds * Outputs : None 1116*1da177e4SLinus Torvalds * 1117*1da177e4SLinus Torvalds */ 1118*1da177e4SLinus Torvalds static void 1119*1da177e4SLinus Torvalds ia64_mca_cpe_poll (unsigned long dummy) 1120*1da177e4SLinus Torvalds { 1121*1da177e4SLinus Torvalds /* Trigger a CPE interrupt cascade */ 1122*1da177e4SLinus Torvalds platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); 1123*1da177e4SLinus Torvalds } 1124*1da177e4SLinus Torvalds 1125*1da177e4SLinus Torvalds /* 1126*1da177e4SLinus Torvalds * C portion of the OS INIT handler 1127*1da177e4SLinus Torvalds * 1128*1da177e4SLinus Torvalds * Called from ia64_monarch_init_handler 1129*1da177e4SLinus Torvalds * 1130*1da177e4SLinus Torvalds * Inputs: pointer to pt_regs where processor info was saved. 1131*1da177e4SLinus Torvalds * 1132*1da177e4SLinus Torvalds * Returns: 1133*1da177e4SLinus Torvalds * 0 if SAL must warm boot the System 1134*1da177e4SLinus Torvalds * 1 if SAL must return to interrupted context using PAL_MC_RESUME 1135*1da177e4SLinus Torvalds * 1136*1da177e4SLinus Torvalds */ 1137*1da177e4SLinus Torvalds void 1138*1da177e4SLinus Torvalds ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) 1139*1da177e4SLinus Torvalds { 1140*1da177e4SLinus Torvalds pal_min_state_area_t *ms; 1141*1da177e4SLinus Torvalds 1142*1da177e4SLinus Torvalds oops_in_progress = 1; /* avoid deadlock in printk, but it makes recovery dodgy */ 1143*1da177e4SLinus Torvalds console_loglevel = 15; /* make sure printks make it to console */ 1144*1da177e4SLinus Torvalds 1145*1da177e4SLinus Torvalds printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n", 1146*1da177e4SLinus Torvalds ia64_sal_to_os_handoff_state.proc_state_param); 1147*1da177e4SLinus Torvalds 1148*1da177e4SLinus Torvalds /* 1149*1da177e4SLinus Torvalds * Address of minstate area provided by PAL is physical, 1150*1da177e4SLinus Torvalds * uncacheable (bit 63 set). Convert to Linux virtual 1151*1da177e4SLinus Torvalds * address in region 6. 1152*1da177e4SLinus Torvalds */ 1153*1da177e4SLinus Torvalds ms = (pal_min_state_area_t *)(ia64_sal_to_os_handoff_state.pal_min_state | (6ul<<61)); 1154*1da177e4SLinus Torvalds 1155*1da177e4SLinus Torvalds init_handler_platform(ms, pt, sw); /* call platform specific routines */ 1156*1da177e4SLinus Torvalds } 1157*1da177e4SLinus Torvalds 1158*1da177e4SLinus Torvalds static int __init 1159*1da177e4SLinus Torvalds ia64_mca_disable_cpe_polling(char *str) 1160*1da177e4SLinus Torvalds { 1161*1da177e4SLinus Torvalds cpe_poll_enabled = 0; 1162*1da177e4SLinus Torvalds return 1; 1163*1da177e4SLinus Torvalds } 1164*1da177e4SLinus Torvalds 1165*1da177e4SLinus Torvalds __setup("disable_cpe_poll", ia64_mca_disable_cpe_polling); 1166*1da177e4SLinus Torvalds 1167*1da177e4SLinus Torvalds static struct irqaction cmci_irqaction = { 1168*1da177e4SLinus Torvalds .handler = ia64_mca_cmc_int_handler, 1169*1da177e4SLinus Torvalds .flags = SA_INTERRUPT, 1170*1da177e4SLinus Torvalds .name = "cmc_hndlr" 1171*1da177e4SLinus Torvalds }; 1172*1da177e4SLinus Torvalds 1173*1da177e4SLinus Torvalds static struct irqaction cmcp_irqaction = { 1174*1da177e4SLinus Torvalds .handler = ia64_mca_cmc_int_caller, 1175*1da177e4SLinus Torvalds .flags = SA_INTERRUPT, 1176*1da177e4SLinus Torvalds .name = "cmc_poll" 1177*1da177e4SLinus Torvalds }; 1178*1da177e4SLinus Torvalds 1179*1da177e4SLinus Torvalds static struct irqaction mca_rdzv_irqaction = { 1180*1da177e4SLinus Torvalds .handler = ia64_mca_rendez_int_handler, 1181*1da177e4SLinus Torvalds .flags = SA_INTERRUPT, 1182*1da177e4SLinus Torvalds .name = "mca_rdzv" 1183*1da177e4SLinus Torvalds }; 1184*1da177e4SLinus Torvalds 1185*1da177e4SLinus Torvalds static struct irqaction mca_wkup_irqaction = { 1186*1da177e4SLinus Torvalds .handler = ia64_mca_wakeup_int_handler, 1187*1da177e4SLinus Torvalds .flags = SA_INTERRUPT, 1188*1da177e4SLinus Torvalds .name = "mca_wkup" 1189*1da177e4SLinus Torvalds }; 1190*1da177e4SLinus Torvalds 1191*1da177e4SLinus Torvalds #ifdef CONFIG_ACPI 1192*1da177e4SLinus Torvalds static struct irqaction mca_cpe_irqaction = { 1193*1da177e4SLinus Torvalds .handler = ia64_mca_cpe_int_handler, 1194*1da177e4SLinus Torvalds .flags = SA_INTERRUPT, 1195*1da177e4SLinus Torvalds .name = "cpe_hndlr" 1196*1da177e4SLinus Torvalds }; 1197*1da177e4SLinus Torvalds 1198*1da177e4SLinus Torvalds static struct irqaction mca_cpep_irqaction = { 1199*1da177e4SLinus Torvalds .handler = ia64_mca_cpe_int_caller, 1200*1da177e4SLinus Torvalds .flags = SA_INTERRUPT, 1201*1da177e4SLinus Torvalds .name = "cpe_poll" 1202*1da177e4SLinus Torvalds }; 1203*1da177e4SLinus Torvalds #endif /* CONFIG_ACPI */ 1204*1da177e4SLinus Torvalds 1205*1da177e4SLinus Torvalds /* Do per-CPU MCA-related initialization. */ 1206*1da177e4SLinus Torvalds 1207*1da177e4SLinus Torvalds void __devinit 1208*1da177e4SLinus Torvalds ia64_mca_cpu_init(void *cpu_data) 1209*1da177e4SLinus Torvalds { 1210*1da177e4SLinus Torvalds void *pal_vaddr; 1211*1da177e4SLinus Torvalds 1212*1da177e4SLinus Torvalds if (smp_processor_id() == 0) { 1213*1da177e4SLinus Torvalds void *mca_data; 1214*1da177e4SLinus Torvalds int cpu; 1215*1da177e4SLinus Torvalds 1216*1da177e4SLinus Torvalds mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) 1217*1da177e4SLinus Torvalds * NR_CPUS); 1218*1da177e4SLinus Torvalds for (cpu = 0; cpu < NR_CPUS; cpu++) { 1219*1da177e4SLinus Torvalds __per_cpu_mca[cpu] = __pa(mca_data); 1220*1da177e4SLinus Torvalds mca_data += sizeof(struct ia64_mca_cpu); 1221*1da177e4SLinus Torvalds } 1222*1da177e4SLinus Torvalds } 1223*1da177e4SLinus Torvalds 1224*1da177e4SLinus Torvalds /* 1225*1da177e4SLinus Torvalds * The MCA info structure was allocated earlier and its 1226*1da177e4SLinus Torvalds * physical address saved in __per_cpu_mca[cpu]. Copy that 1227*1da177e4SLinus Torvalds * address * to ia64_mca_data so we can access it as a per-CPU 1228*1da177e4SLinus Torvalds * variable. 1229*1da177e4SLinus Torvalds */ 1230*1da177e4SLinus Torvalds __get_cpu_var(ia64_mca_data) = __per_cpu_mca[smp_processor_id()]; 1231*1da177e4SLinus Torvalds 1232*1da177e4SLinus Torvalds /* 1233*1da177e4SLinus Torvalds * Stash away a copy of the PTE needed to map the per-CPU page. 1234*1da177e4SLinus Torvalds * We may need it during MCA recovery. 1235*1da177e4SLinus Torvalds */ 1236*1da177e4SLinus Torvalds __get_cpu_var(ia64_mca_per_cpu_pte) = 1237*1da177e4SLinus Torvalds pte_val(mk_pte_phys(__pa(cpu_data), PAGE_KERNEL)); 1238*1da177e4SLinus Torvalds 1239*1da177e4SLinus Torvalds /* 1240*1da177e4SLinus Torvalds * Also, stash away a copy of the PAL address and the PTE 1241*1da177e4SLinus Torvalds * needed to map it. 1242*1da177e4SLinus Torvalds */ 1243*1da177e4SLinus Torvalds pal_vaddr = efi_get_pal_addr(); 1244*1da177e4SLinus Torvalds if (!pal_vaddr) 1245*1da177e4SLinus Torvalds return; 1246*1da177e4SLinus Torvalds __get_cpu_var(ia64_mca_pal_base) = 1247*1da177e4SLinus Torvalds GRANULEROUNDDOWN((unsigned long) pal_vaddr); 1248*1da177e4SLinus Torvalds __get_cpu_var(ia64_mca_pal_pte) = pte_val(mk_pte_phys(__pa(pal_vaddr), 1249*1da177e4SLinus Torvalds PAGE_KERNEL)); 1250*1da177e4SLinus Torvalds } 1251*1da177e4SLinus Torvalds 1252*1da177e4SLinus Torvalds /* 1253*1da177e4SLinus Torvalds * ia64_mca_init 1254*1da177e4SLinus Torvalds * 1255*1da177e4SLinus Torvalds * Do all the system level mca specific initialization. 1256*1da177e4SLinus Torvalds * 1257*1da177e4SLinus Torvalds * 1. Register spinloop and wakeup request interrupt vectors 1258*1da177e4SLinus Torvalds * 1259*1da177e4SLinus Torvalds * 2. Register OS_MCA handler entry point 1260*1da177e4SLinus Torvalds * 1261*1da177e4SLinus Torvalds * 3. Register OS_INIT handler entry point 1262*1da177e4SLinus Torvalds * 1263*1da177e4SLinus Torvalds * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS. 1264*1da177e4SLinus Torvalds * 1265*1da177e4SLinus Torvalds * Note that this initialization is done very early before some kernel 1266*1da177e4SLinus Torvalds * services are available. 1267*1da177e4SLinus Torvalds * 1268*1da177e4SLinus Torvalds * Inputs : None 1269*1da177e4SLinus Torvalds * 1270*1da177e4SLinus Torvalds * Outputs : None 1271*1da177e4SLinus Torvalds */ 1272*1da177e4SLinus Torvalds void __init 1273*1da177e4SLinus Torvalds ia64_mca_init(void) 1274*1da177e4SLinus Torvalds { 1275*1da177e4SLinus Torvalds ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; 1276*1da177e4SLinus Torvalds ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; 1277*1da177e4SLinus Torvalds ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; 1278*1da177e4SLinus Torvalds int i; 1279*1da177e4SLinus Torvalds s64 rc; 1280*1da177e4SLinus Torvalds struct ia64_sal_retval isrv; 1281*1da177e4SLinus Torvalds u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ 1282*1da177e4SLinus Torvalds 1283*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); 1284*1da177e4SLinus Torvalds 1285*1da177e4SLinus Torvalds /* Clear the Rendez checkin flag for all cpus */ 1286*1da177e4SLinus Torvalds for(i = 0 ; i < NR_CPUS; i++) 1287*1da177e4SLinus Torvalds ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; 1288*1da177e4SLinus Torvalds 1289*1da177e4SLinus Torvalds /* 1290*1da177e4SLinus Torvalds * Register the rendezvous spinloop and wakeup mechanism with SAL 1291*1da177e4SLinus Torvalds */ 1292*1da177e4SLinus Torvalds 1293*1da177e4SLinus Torvalds /* Register the rendezvous interrupt vector with SAL */ 1294*1da177e4SLinus Torvalds while (1) { 1295*1da177e4SLinus Torvalds isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, 1296*1da177e4SLinus Torvalds SAL_MC_PARAM_MECHANISM_INT, 1297*1da177e4SLinus Torvalds IA64_MCA_RENDEZ_VECTOR, 1298*1da177e4SLinus Torvalds timeout, 1299*1da177e4SLinus Torvalds SAL_MC_PARAM_RZ_ALWAYS); 1300*1da177e4SLinus Torvalds rc = isrv.status; 1301*1da177e4SLinus Torvalds if (rc == 0) 1302*1da177e4SLinus Torvalds break; 1303*1da177e4SLinus Torvalds if (rc == -2) { 1304*1da177e4SLinus Torvalds printk(KERN_INFO "Increasing MCA rendezvous timeout from " 1305*1da177e4SLinus Torvalds "%ld to %ld milliseconds\n", timeout, isrv.v0); 1306*1da177e4SLinus Torvalds timeout = isrv.v0; 1307*1da177e4SLinus Torvalds continue; 1308*1da177e4SLinus Torvalds } 1309*1da177e4SLinus Torvalds printk(KERN_ERR "Failed to register rendezvous interrupt " 1310*1da177e4SLinus Torvalds "with SAL (status %ld)\n", rc); 1311*1da177e4SLinus Torvalds return; 1312*1da177e4SLinus Torvalds } 1313*1da177e4SLinus Torvalds 1314*1da177e4SLinus Torvalds /* Register the wakeup interrupt vector with SAL */ 1315*1da177e4SLinus Torvalds isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, 1316*1da177e4SLinus Torvalds SAL_MC_PARAM_MECHANISM_INT, 1317*1da177e4SLinus Torvalds IA64_MCA_WAKEUP_VECTOR, 1318*1da177e4SLinus Torvalds 0, 0); 1319*1da177e4SLinus Torvalds rc = isrv.status; 1320*1da177e4SLinus Torvalds if (rc) { 1321*1da177e4SLinus Torvalds printk(KERN_ERR "Failed to register wakeup interrupt with SAL " 1322*1da177e4SLinus Torvalds "(status %ld)\n", rc); 1323*1da177e4SLinus Torvalds return; 1324*1da177e4SLinus Torvalds } 1325*1da177e4SLinus Torvalds 1326*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: registered MCA rendezvous spinloop and wakeup mech.\n", __FUNCTION__); 1327*1da177e4SLinus Torvalds 1328*1da177e4SLinus Torvalds ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); 1329*1da177e4SLinus Torvalds /* 1330*1da177e4SLinus Torvalds * XXX - disable SAL checksum by setting size to 0; should be 1331*1da177e4SLinus Torvalds * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch); 1332*1da177e4SLinus Torvalds */ 1333*1da177e4SLinus Torvalds ia64_mc_info.imi_mca_handler_size = 0; 1334*1da177e4SLinus Torvalds 1335*1da177e4SLinus Torvalds /* Register the os mca handler with SAL */ 1336*1da177e4SLinus Torvalds if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, 1337*1da177e4SLinus Torvalds ia64_mc_info.imi_mca_handler, 1338*1da177e4SLinus Torvalds ia64_tpa(mca_hldlr_ptr->gp), 1339*1da177e4SLinus Torvalds ia64_mc_info.imi_mca_handler_size, 1340*1da177e4SLinus Torvalds 0, 0, 0))) 1341*1da177e4SLinus Torvalds { 1342*1da177e4SLinus Torvalds printk(KERN_ERR "Failed to register OS MCA handler with SAL " 1343*1da177e4SLinus Torvalds "(status %ld)\n", rc); 1344*1da177e4SLinus Torvalds return; 1345*1da177e4SLinus Torvalds } 1346*1da177e4SLinus Torvalds 1347*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: registered OS MCA handler with SAL at 0x%lx, gp = 0x%lx\n", __FUNCTION__, 1348*1da177e4SLinus Torvalds ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp)); 1349*1da177e4SLinus Torvalds 1350*1da177e4SLinus Torvalds /* 1351*1da177e4SLinus Torvalds * XXX - disable SAL checksum by setting size to 0, should be 1352*1da177e4SLinus Torvalds * size of the actual init handler in mca_asm.S. 1353*1da177e4SLinus Torvalds */ 1354*1da177e4SLinus Torvalds ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp); 1355*1da177e4SLinus Torvalds ia64_mc_info.imi_monarch_init_handler_size = 0; 1356*1da177e4SLinus Torvalds ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp); 1357*1da177e4SLinus Torvalds ia64_mc_info.imi_slave_init_handler_size = 0; 1358*1da177e4SLinus Torvalds 1359*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: OS INIT handler at %lx\n", __FUNCTION__, 1360*1da177e4SLinus Torvalds ia64_mc_info.imi_monarch_init_handler); 1361*1da177e4SLinus Torvalds 1362*1da177e4SLinus Torvalds /* Register the os init handler with SAL */ 1363*1da177e4SLinus Torvalds if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, 1364*1da177e4SLinus Torvalds ia64_mc_info.imi_monarch_init_handler, 1365*1da177e4SLinus Torvalds ia64_tpa(ia64_getreg(_IA64_REG_GP)), 1366*1da177e4SLinus Torvalds ia64_mc_info.imi_monarch_init_handler_size, 1367*1da177e4SLinus Torvalds ia64_mc_info.imi_slave_init_handler, 1368*1da177e4SLinus Torvalds ia64_tpa(ia64_getreg(_IA64_REG_GP)), 1369*1da177e4SLinus Torvalds ia64_mc_info.imi_slave_init_handler_size))) 1370*1da177e4SLinus Torvalds { 1371*1da177e4SLinus Torvalds printk(KERN_ERR "Failed to register m/s INIT handlers with SAL " 1372*1da177e4SLinus Torvalds "(status %ld)\n", rc); 1373*1da177e4SLinus Torvalds return; 1374*1da177e4SLinus Torvalds } 1375*1da177e4SLinus Torvalds 1376*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__); 1377*1da177e4SLinus Torvalds 1378*1da177e4SLinus Torvalds /* 1379*1da177e4SLinus Torvalds * Configure the CMCI/P vector and handler. Interrupts for CMC are 1380*1da177e4SLinus Torvalds * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). 1381*1da177e4SLinus Torvalds */ 1382*1da177e4SLinus Torvalds register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); 1383*1da177e4SLinus Torvalds register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction); 1384*1da177e4SLinus Torvalds ia64_mca_cmc_vector_setup(); /* Setup vector on BSP */ 1385*1da177e4SLinus Torvalds 1386*1da177e4SLinus Torvalds /* Setup the MCA rendezvous interrupt vector */ 1387*1da177e4SLinus Torvalds register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction); 1388*1da177e4SLinus Torvalds 1389*1da177e4SLinus Torvalds /* Setup the MCA wakeup interrupt vector */ 1390*1da177e4SLinus Torvalds register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); 1391*1da177e4SLinus Torvalds 1392*1da177e4SLinus Torvalds #ifdef CONFIG_ACPI 1393*1da177e4SLinus Torvalds /* Setup the CPEI/P vector and handler */ 1394*1da177e4SLinus Torvalds cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI); 1395*1da177e4SLinus Torvalds register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); 1396*1da177e4SLinus Torvalds #endif 1397*1da177e4SLinus Torvalds 1398*1da177e4SLinus Torvalds /* Initialize the areas set aside by the OS to buffer the 1399*1da177e4SLinus Torvalds * platform/processor error states for MCA/INIT/CMC 1400*1da177e4SLinus Torvalds * handling. 1401*1da177e4SLinus Torvalds */ 1402*1da177e4SLinus Torvalds ia64_log_init(SAL_INFO_TYPE_MCA); 1403*1da177e4SLinus Torvalds ia64_log_init(SAL_INFO_TYPE_INIT); 1404*1da177e4SLinus Torvalds ia64_log_init(SAL_INFO_TYPE_CMC); 1405*1da177e4SLinus Torvalds ia64_log_init(SAL_INFO_TYPE_CPE); 1406*1da177e4SLinus Torvalds 1407*1da177e4SLinus Torvalds mca_init = 1; 1408*1da177e4SLinus Torvalds printk(KERN_INFO "MCA related initialization done\n"); 1409*1da177e4SLinus Torvalds } 1410*1da177e4SLinus Torvalds 1411*1da177e4SLinus Torvalds /* 1412*1da177e4SLinus Torvalds * ia64_mca_late_init 1413*1da177e4SLinus Torvalds * 1414*1da177e4SLinus Torvalds * Opportunity to setup things that require initialization later 1415*1da177e4SLinus Torvalds * than ia64_mca_init. Setup a timer to poll for CPEs if the 1416*1da177e4SLinus Torvalds * platform doesn't support an interrupt driven mechanism. 1417*1da177e4SLinus Torvalds * 1418*1da177e4SLinus Torvalds * Inputs : None 1419*1da177e4SLinus Torvalds * Outputs : Status 1420*1da177e4SLinus Torvalds */ 1421*1da177e4SLinus Torvalds static int __init 1422*1da177e4SLinus Torvalds ia64_mca_late_init(void) 1423*1da177e4SLinus Torvalds { 1424*1da177e4SLinus Torvalds if (!mca_init) 1425*1da177e4SLinus Torvalds return 0; 1426*1da177e4SLinus Torvalds 1427*1da177e4SLinus Torvalds /* Setup the CMCI/P vector and handler */ 1428*1da177e4SLinus Torvalds init_timer(&cmc_poll_timer); 1429*1da177e4SLinus Torvalds cmc_poll_timer.function = ia64_mca_cmc_poll; 1430*1da177e4SLinus Torvalds 1431*1da177e4SLinus Torvalds /* Unmask/enable the vector */ 1432*1da177e4SLinus Torvalds cmc_polling_enabled = 0; 1433*1da177e4SLinus Torvalds schedule_work(&cmc_enable_work); 1434*1da177e4SLinus Torvalds 1435*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: CMCI/P setup and enabled.\n", __FUNCTION__); 1436*1da177e4SLinus Torvalds 1437*1da177e4SLinus Torvalds #ifdef CONFIG_ACPI 1438*1da177e4SLinus Torvalds /* Setup the CPEI/P vector and handler */ 1439*1da177e4SLinus Torvalds init_timer(&cpe_poll_timer); 1440*1da177e4SLinus Torvalds cpe_poll_timer.function = ia64_mca_cpe_poll; 1441*1da177e4SLinus Torvalds 1442*1da177e4SLinus Torvalds { 1443*1da177e4SLinus Torvalds irq_desc_t *desc; 1444*1da177e4SLinus Torvalds unsigned int irq; 1445*1da177e4SLinus Torvalds 1446*1da177e4SLinus Torvalds if (cpe_vector >= 0) { 1447*1da177e4SLinus Torvalds /* If platform supports CPEI, enable the irq. */ 1448*1da177e4SLinus Torvalds cpe_poll_enabled = 0; 1449*1da177e4SLinus Torvalds for (irq = 0; irq < NR_IRQS; ++irq) 1450*1da177e4SLinus Torvalds if (irq_to_vector(irq) == cpe_vector) { 1451*1da177e4SLinus Torvalds desc = irq_descp(irq); 1452*1da177e4SLinus Torvalds desc->status |= IRQ_PER_CPU; 1453*1da177e4SLinus Torvalds setup_irq(irq, &mca_cpe_irqaction); 1454*1da177e4SLinus Torvalds } 1455*1da177e4SLinus Torvalds ia64_mca_register_cpev(cpe_vector); 1456*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n", __FUNCTION__); 1457*1da177e4SLinus Torvalds } else { 1458*1da177e4SLinus Torvalds /* If platform doesn't support CPEI, get the timer going. */ 1459*1da177e4SLinus Torvalds if (cpe_poll_enabled) { 1460*1da177e4SLinus Torvalds ia64_mca_cpe_poll(0UL); 1461*1da177e4SLinus Torvalds IA64_MCA_DEBUG("%s: CPEP setup and enabled.\n", __FUNCTION__); 1462*1da177e4SLinus Torvalds } 1463*1da177e4SLinus Torvalds } 1464*1da177e4SLinus Torvalds } 1465*1da177e4SLinus Torvalds #endif 1466*1da177e4SLinus Torvalds 1467*1da177e4SLinus Torvalds return 0; 1468*1da177e4SLinus Torvalds } 1469*1da177e4SLinus Torvalds 1470*1da177e4SLinus Torvalds device_initcall(ia64_mca_late_init); 1471