patch-2.4.26 linux-2.4.26/arch/ia64/kernel/mca.c
Next file: linux-2.4.26/arch/ia64/kernel/pci.c
Previous file: linux-2.4.26/arch/ia64/kernel/ia64_ksyms.c
Back to the patch index
Back to the overall index
- Lines: 2313
- Date:
2004-04-14 06:05:26.000000000 -0700
- Orig file:
linux-2.4.25/arch/ia64/kernel/mca.c
- Orig date:
2004-02-18 05:36:30.000000000 -0800
diff -urN linux-2.4.25/arch/ia64/kernel/mca.c linux-2.4.26/arch/ia64/kernel/mca.c
@@ -6,7 +6,7 @@
* Copyright (C) 2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
- * Copyright (C) 2002 Dell Computer Corporation
+ * Copyright (C) 2002 Dell Inc.
* Copyright (C) Matt Domsch (Matt_Domsch@dell.com)
*
* Copyright (C) 2002 Intel
@@ -18,7 +18,7 @@
* Copyright (C) 2000 Intel
* Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com)
*
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1999, 2004 Silicon Graphics, Inc.
* Copyright (C) Vijay Chander(vijay@engr.sgi.com)
*
* 03/04/15 D. Mosberger Added INIT backtrace support.
@@ -40,6 +40,14 @@
* 2003-12-08 Keith Owens <kaos@sgi.com>
* smp_call_function() must not be called from interrupt context (can
* deadlock on tasklist_lock). Use keventd to call smp_call_function().
+ *
+ * 2004-02-01 Keith Owens <kaos@sgi.com>
+ * Avoid deadlock when using printk() for MCA and INIT records.
+ * Delete all record printing code, moved to salinfo_decode in user space.
+ * Mark variables and functions static where possible.
+ * Delete dead variables and functions.
+ * Reorder to remove the need for forward declarations and to consolidate
+ * related code.
*/
#include <linux/config.h>
#include <linux/types.h>
@@ -67,9 +75,12 @@
#include <asm/irq.h>
#include <asm/hw_irq.h>
-#undef MCA_PRT_XTRA_DATA
+#if defined(IA64_MCA_DEBUG_INFO)
+# define IA64_MCA_DEBUG(fmt...) printk(fmt)
+#else
+# define IA64_MCA_DEBUG(fmt...)
+#endif
-#define print_symbol(fmt, addr) printk(fmt, "(no symbol)");
extern void show_stack(struct task_struct *);
typedef struct ia64_fptr {
@@ -77,7 +88,7 @@
unsigned long gp;
} ia64_fptr_t;
-ia64_mc_info_t ia64_mc_info;
+/* Used by mca_asm.S */
ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state;
ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state;
u64 ia64_mca_proc_state_dump[512];
@@ -85,54 +96,17 @@
u64 ia64_mca_stackframe[32];
u64 ia64_mca_bspstore[1024];
u64 ia64_init_stack[INIT_TASK_SIZE/8] __attribute__((aligned(16)));
-u64 ia64_os_mca_recovery_successful;
u64 ia64_mca_serialize;
-static void ia64_mca_wakeup_ipi_wait(void);
-static void ia64_mca_wakeup(int cpu);
-static void ia64_mca_wakeup_all(void);
-static void ia64_log_init(int);
+
+/* In mca_asm.S */
extern void ia64_monarch_init_handler (void);
extern void ia64_slave_init_handler (void);
-static u64 ia64_log_get(int sal_info_type, u8 **buffer);
-extern struct hw_interrupt_type irq_type_iosapic_level;
-
-struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS];
-
-static struct irqaction cmci_irqaction = {
- .handler = ia64_mca_cmc_int_handler,
- .flags = SA_INTERRUPT,
- .name = "cmc_hndlr"
-};
-
-static struct irqaction cmcp_irqaction = {
- .handler = ia64_mca_cmc_int_caller,
- .flags = SA_INTERRUPT,
- .name = "cmc_poll"
-};
-
-static struct irqaction mca_rdzv_irqaction = {
- .handler = ia64_mca_rendez_int_handler,
- .flags = SA_INTERRUPT,
- .name = "mca_rdzv"
-};
-static struct irqaction mca_wkup_irqaction = {
- .handler = ia64_mca_wakeup_int_handler,
- .flags = SA_INTERRUPT,
- .name = "mca_wkup"
-};
+static ia64_mc_info_t ia64_mc_info;
-static struct irqaction mca_cpe_irqaction = {
- .handler = ia64_mca_cpe_int_handler,
- .flags = SA_INTERRUPT,
- .name = "cpe_hndlr"
-};
+extern struct hw_interrupt_type irq_type_iosapic_level;
-static struct irqaction mca_cpep_irqaction = {
- .handler = ia64_mca_cpe_int_caller,
- .flags = SA_INTERRUPT,
- .name = "cpe_poll"
-};
+struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS];
#define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */
#define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */
@@ -156,69 +130,163 @@
*/
static int cpe_poll_enabled = 1;
-extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size);
+extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe);
static struct tq_struct cmc_disable_tq, cmc_enable_tq;
/*
+ * IA64_MCA log support
+ */
+#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */
+#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */
+
+typedef struct ia64_state_log_s
+{
+ spinlock_t isl_lock;
+ int isl_index;
+ unsigned long isl_count;
+ ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */
+} ia64_state_log_t;
+
+static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES];
+
+#define IA64_LOG_ALLOCATE(it, size) \
+ {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \
+ (ia64_err_rec_t *)alloc_bootmem(size); \
+ ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \
+ (ia64_err_rec_t *)alloc_bootmem(size);}
+#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock)
+#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s)
+#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s)
+#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index
+#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index
+#define IA64_LOG_INDEX_INC(it) \
+ {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \
+ ia64_state_log[it].isl_count++;}
+#define IA64_LOG_INDEX_DEC(it) \
+ ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
+#define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)]))
+#define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
+#define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count
+
+/*
+ * ia64_log_init
+ * Reset the OS ia64 log buffer
+ * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
+ * Outputs : None
+ */
+static void
+ia64_log_init(int sal_info_type)
+{
+ u64 max_size = 0;
+
+ IA64_LOG_NEXT_INDEX(sal_info_type) = 0;
+ IA64_LOG_LOCK_INIT(sal_info_type);
+
+ // SAL will tell us the maximum size of any error record of this type
+ max_size = ia64_sal_get_state_info_size(sal_info_type);
+ if (!max_size)
+ /* alloc_bootmem() doesn't like zero-sized allocations! */
+ return;
+
+ // set up OS data structures to hold error info
+ IA64_LOG_ALLOCATE(sal_info_type, max_size);
+ memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size);
+ memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size);
+}
+
+/*
+ * ia64_log_get
+ *
+ * Get the current MCA log from SAL and copy it into the OS log buffer.
+ *
+ * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
+ * irq_safe whether you can use printk at this point
+ * Outputs : size (total record length)
+ * *buffer (ptr to error record)
+ *
+ */
+static u64
+ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe)
+{
+ sal_log_record_header_t *log_buffer;
+ u64 total_len = 0;
+ int s;
+
+ IA64_LOG_LOCK(sal_info_type);
+
+ /* Get the process state information */
+ log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type);
+
+ total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer);
+
+ if (total_len) {
+ IA64_LOG_INDEX_INC(sal_info_type);
+ IA64_LOG_UNLOCK(sal_info_type);
+ if (irq_safe) {
+ IA64_MCA_DEBUG("%s: SAL error record type %d retrieved. "
+ "Record length = %ld\n", __FUNCTION__, sal_info_type, total_len);
+ }
+ *buffer = (u8 *) log_buffer;
+ return total_len;
+ } else {
+ IA64_LOG_UNLOCK(sal_info_type);
+ return 0;
+ }
+}
+
+/*
* ia64_mca_log_sal_error_record
*
- * This function retrieves a specified error record type from SAL,
- * wakes up any processes waiting for error records, and sends it to
- * the system log.
+ * This function retrieves a specified error record type from SAL
+ * and wakes up any processes waiting for error records.
*
* Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT)
- * Outputs : platform error status
*/
-int
-ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init)
+static void
+ia64_mca_log_sal_error_record(int sal_info_type)
{
u8 *buffer;
u64 size;
- int platform_err;
+ int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA && sal_info_type != SAL_INFO_TYPE_INIT;
+ static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" };
- size = ia64_log_get(sal_info_type, &buffer);
+ size = ia64_log_get(sal_info_type, &buffer, irq_safe);
if (!size)
- return 0;
+ return;
- /* TODO:
- * 1. analyze error logs to determine recoverability
- * 2. perform error recovery procedures, if applicable
- * 3. set ia64_os_mca_recovery_successful flag, if applicable
- */
+ salinfo_log_wakeup(sal_info_type, buffer, size, irq_safe);
+
+ if (irq_safe)
+ printk(KERN_INFO "CPU %d: SAL log contains %s error record\n",
+ smp_processor_id(),
+ sal_info_type < ARRAY_SIZE(rec_name) ? rec_name[sal_info_type] : "UNKNOWN");
- salinfo_log_wakeup(sal_info_type, buffer, size);
- platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk);
/* Clear logs from corrected errors in case there's no user-level logger */
if (sal_info_type == SAL_INFO_TYPE_CPE || sal_info_type == SAL_INFO_TYPE_CMC)
ia64_sal_clear_state_info(sal_info_type);
-
- return platform_err;
}
/*
* platform dependent error handling
*/
#ifndef PLATFORM_MCA_HANDLERS
-void
-mca_handler_platform (void)
-{
-
-}
-void
+static void
ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
{
- IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. CPU:%d vector = %#x\n",
- smp_processor_id(), cpe_irq);
+ IA64_MCA_DEBUG("%s: received interrupt. CPU:%d vector = %#x\n",
+ __FUNCTION__, smp_processor_id(), cpe_irq);
/* SAL spec states this should run w/ interrupts enabled */
local_irq_enable();
/* Get the CMC error record and log it */
- ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0);
+ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
}
+#define print_symbol(fmt, addr) printk(fmt, "(no symbol)");
+
static void
show_min_state (pal_min_state_area_t *minstate)
{
@@ -357,7 +425,7 @@
PUT_NAT_BIT(sw->caller_unat, &pt->r30); PUT_NAT_BIT(sw->caller_unat, &pt->r31);
}
-void
+static void
init_handler_platform (pal_min_state_area_t *ms,
struct pt_regs *pt, struct switch_stack *sw)
{
@@ -404,45 +472,7 @@
while (1); /* hang city if no debugger */
}
-/*
- * ia64_mca_init_platform
- *
- * External entry for platform specific MCA initialization.
- *
- * Inputs
- * None
- *
- * Outputs
- * None
- */
-void
-ia64_mca_init_platform (void)
-{
-
-}
-
-/*
- * ia64_mca_check_errors
- *
- * External entry to check for error records which may have been posted by SAL
- * for a prior failure.
- *
- * Inputs : None
- *
- * Outputs : None
- */
-int
-ia64_mca_check_errors (void)
-{
- /*
- * If there is an MCA error record pending, get it and log it.
- */
- printk("CPU %d: checking for saved MCA error records\n", smp_processor_id());
- ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1);
-
- return 0;
-}
-
+#ifdef CONFIG_ACPI
/*
* ia64_mca_register_cpev
*
@@ -462,14 +492,15 @@
isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0);
if (isrv.status) {
- printk(KERN_ERR "ia64_mca_platform_init: failed to register Corrected "
- "Platform Error interrupt vector with SAL.\n");
+ printk(KERN_ERR "Failed to register Corrected Platform "
+ "Error interrupt vector with SAL (status %ld)\n", isrv.status);
return;
}
- IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error "
- "vector %#x setup and enabled\n", cpev);
+ IA64_MCA_DEBUG("%s: corrected platform error "
+ "vector %#x setup and enabled\n", __FUNCTION__, cpev);
}
+#endif /* CONFIG_ACPI */
#endif /* PLATFORM_MCA_HANDLERS */
@@ -495,12 +526,12 @@
cmcv.cmcv_vector = IA64_CMC_VECTOR;
ia64_set_cmcv(cmcv.cmcv_regval);
- IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected "
+ IA64_MCA_DEBUG("%s: CPU %d corrected "
"machine check vector %#x setup and enabled.\n",
- smp_processor_id(), IA64_CMC_VECTOR);
+ __FUNCTION__, smp_processor_id(), IA64_CMC_VECTOR);
- IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n",
- smp_processor_id(), ia64_get_cmcv());
+ IA64_MCA_DEBUG("%s: CPU %d CMCV = %#016lx\n",
+ __FUNCTION__, smp_processor_id(), ia64_get_cmcv());
}
/*
@@ -515,7 +546,7 @@
* Outputs
* None
*/
-void
+static void
ia64_mca_cmc_vector_disable (void *dummy)
{
cmcv_reg_t cmcv;
@@ -525,9 +556,9 @@
cmcv.cmcv_mask = 1; /* Mask/disable interrupt */
ia64_set_cmcv(cmcv.cmcv_regval);
- IA64_MCA_DEBUG("ia64_mca_cmc_vector_disable: CPU %d corrected "
+ IA64_MCA_DEBUG("%s: CPU %d corrected "
"machine check vector %#x disabled.\n",
- smp_processor_id(), cmcv.cmcv_vector);
+ __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector);
}
/*
@@ -542,7 +573,7 @@
* Outputs
* None
*/
-void
+static void
ia64_mca_cmc_vector_enable (void *dummy)
{
cmcv_reg_t cmcv;
@@ -552,63 +583,9 @@
cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */
ia64_set_cmcv(cmcv.cmcv_regval);
- IA64_MCA_DEBUG("ia64_mca_cmc_vector_enable: CPU %d corrected "
+ IA64_MCA_DEBUG("%s: CPU %d corrected "
"machine check vector %#x enabled.\n",
- smp_processor_id(), cmcv.cmcv_vector);
-}
-
-
-#if defined(MCA_TEST)
-
-sal_log_processor_info_t slpi_buf;
-
-void
-mca_test(void)
-{
- slpi_buf.valid.psi_static_struct = 1;
- slpi_buf.valid.num_cache_check = 1;
- slpi_buf.valid.num_tlb_check = 1;
- slpi_buf.valid.num_bus_check = 1;
- slpi_buf.valid.processor_static_info.minstate = 1;
- slpi_buf.valid.processor_static_info.br = 1;
- slpi_buf.valid.processor_static_info.cr = 1;
- slpi_buf.valid.processor_static_info.ar = 1;
- slpi_buf.valid.processor_static_info.rr = 1;
- slpi_buf.valid.processor_static_info.fr = 1;
-
- ia64_os_mca_dispatch();
-}
-
-#endif /* #if defined(MCA_TEST) */
-
-
-/*
- * verify_guid
- *
- * Compares a test guid to a target guid and returns result.
- *
- * Inputs
- * test_guid * (ptr to guid to be verified)
- * target_guid * (ptr to standard guid to be verified against)
- *
- * Outputs
- * 0 (test verifies against target)
- * non-zero (test guid does not verify)
- */
-static int
-verify_guid (efi_guid_t *test, efi_guid_t *target)
-{
- int rc;
-#ifdef IA64_MCA_DEBUG_INFO
- char out[40];
-#endif
-
- if ((rc = efi_guidcmp(*test, *target))) {
- IA64_MCA_DEBUG(KERN_DEBUG
- "verify_guid: invalid GUID = %s\n",
- efi_guid_unparse(test, out));
- }
- return rc;
+ __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector);
}
/*
@@ -642,225 +619,39 @@
}
/*
- * ia64_mca_init
- *
- * Do all the system level mca specific initialization.
- *
- * 1. Register spinloop and wakeup request interrupt vectors
- *
- * 2. Register OS_MCA handler entry point
- *
- * 3. Register OS_INIT handler entry point
- *
- * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
+ * ia64_mca_wakeup_ipi_wait
*
- * Note that this initialization is done very early before some kernel
- * services are available.
+ * Wait for the inter-cpu interrupt to be sent by the
+ * monarch processor once it is done with handling the
+ * MCA.
*
* Inputs : None
- *
* Outputs : None
*/
-void __init
-ia64_mca_init(void)
+static void
+ia64_mca_wakeup_ipi_wait(void)
{
- ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler;
- ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler;
- ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch;
- int i;
- s64 rc;
- struct ia64_sal_retval isrv;
- u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */
+ int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6);
+ int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f);
+ u64 irr = 0;
- IA64_MCA_DEBUG("ia64_mca_init: begin\n");
-
- INIT_TQUEUE(&cmc_disable_tq, ia64_mca_cmc_vector_disable_keventd, NULL);
- INIT_TQUEUE(&cmc_enable_tq, ia64_mca_cmc_vector_enable_keventd, NULL);
-
- /* initialize recovery success indicator */
- ia64_os_mca_recovery_successful = 0;
-
- /* Clear the Rendez checkin flag for all cpus */
- for(i = 0 ; i < NR_CPUS; i++)
- ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
-
- /*
- * Register the rendezvous spinloop and wakeup mechanism with SAL
- */
-
- /* Register the rendezvous interrupt vector with SAL */
- while (1) {
- isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
- SAL_MC_PARAM_MECHANISM_INT,
- IA64_MCA_RENDEZ_VECTOR,
- timeout,
- SAL_MC_PARAM_RZ_ALWAYS);
- rc = isrv.status;
- if (rc == 0)
- break;
- if (rc == -2) {
- printk(KERN_INFO "ia64_mca_init: increasing MCA rendezvous timeout from "
- "%ld to %ld\n", timeout, isrv.v0);
- timeout = isrv.v0;
- continue;
- }
- printk(KERN_ERR "ia64_mca_init: Failed to register rendezvous interrupt "
- "with SAL. rc = %ld\n", rc);
- return;
- }
-
- /* Register the wakeup interrupt vector with SAL */
- isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
- SAL_MC_PARAM_MECHANISM_INT,
- IA64_MCA_WAKEUP_VECTOR,
- 0, 0);
- rc = isrv.status;
- if (rc) {
- printk(KERN_ERR "ia64_mca_init: Failed to register wakeup interrupt with SAL. "
- "rc = %ld\n", rc);
- return;
- }
-
- IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n");
-
- ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp);
- /*
- * XXX - disable SAL checksum by setting size to 0; should be
- * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch);
- */
- ia64_mc_info.imi_mca_handler_size = 0;
-
- /* Register the os mca handler with SAL */
- if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
- ia64_mc_info.imi_mca_handler,
- ia64_tpa(mca_hldlr_ptr->gp),
- ia64_mc_info.imi_mca_handler_size,
- 0, 0, 0)))
- {
- printk(KERN_ERR "ia64_mca_init: Failed to register os mca handler with SAL. "
- "rc = %ld\n", rc);
- return;
- }
-
- IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n",
- ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp));
-
- /*
- * XXX - disable SAL checksum by setting size to 0, should be
- * IA64_INIT_HANDLER_SIZE
- */
- ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp);
- ia64_mc_info.imi_monarch_init_handler_size = 0;
- ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp);
- ia64_mc_info.imi_slave_init_handler_size = 0;
-
- IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n",
- ia64_mc_info.imi_monarch_init_handler);
-
- /* Register the os init handler with SAL */
- if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
- ia64_mc_info.imi_monarch_init_handler,
- ia64_tpa(ia64_get_gp()),
- ia64_mc_info.imi_monarch_init_handler_size,
- ia64_mc_info.imi_slave_init_handler,
- ia64_tpa(ia64_get_gp()),
- ia64_mc_info.imi_slave_init_handler_size)))
- {
- printk(KERN_ERR "ia64_mca_init: Failed to register m/s init handlers with SAL. "
- "rc = %ld\n", rc);
- return;
- }
-
- IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n");
-
- /*
- * Configure the CMCI/P vector and handler. Interrupts for CMC are
- * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
- */
- register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
- register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
- ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */
-
- /* Setup the MCA rendezvous interrupt vector */
- register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
-
- /* Setup the MCA wakeup interrupt vector */
- register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
-
- /* Setup the CPE interrupt vector */
- {
- irq_desc_t *desc;
- unsigned int irq;
- int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI);
-
- if (cpev >= 0) {
- for (irq = 0; irq < NR_IRQS; ++irq)
- if (irq_to_vector(irq) == cpev) {
- desc = irq_desc(irq);
- desc->status |= IRQ_PER_CPU;
- desc->handler = &irq_type_iosapic_level;
- setup_irq(irq, &mca_cpe_irqaction);
- }
- ia64_mca_register_cpev(cpev);
- }
- }
-
- /* Initialize the areas set aside by the OS to buffer the
- * platform/processor error states for MCA/INIT/CMC
- * handling.
- */
- ia64_log_init(SAL_INFO_TYPE_MCA);
- ia64_log_init(SAL_INFO_TYPE_INIT);
- ia64_log_init(SAL_INFO_TYPE_CMC);
- ia64_log_init(SAL_INFO_TYPE_CPE);
-
-#if defined(MCA_TEST)
- mca_test();
-#endif /* #if defined(MCA_TEST) */
-
- printk(KERN_INFO "Mca related initialization done\n");
-
- /* commented out because this is done elsewhere */
-#if 0
- /* Do post-failure MCA error logging */
- ia64_mca_check_errors();
-#endif
-}
-
-/*
- * ia64_mca_wakeup_ipi_wait
- *
- * Wait for the inter-cpu interrupt to be sent by the
- * monarch processor once it is done with handling the
- * MCA.
- *
- * Inputs : None
- * Outputs : None
- */
-void
-ia64_mca_wakeup_ipi_wait(void)
-{
- int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6);
- int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f);
- u64 irr = 0;
-
- do {
- switch(irr_num) {
- case 0:
- irr = ia64_get_irr0();
- break;
- case 1:
- irr = ia64_get_irr1();
- break;
- case 2:
- irr = ia64_get_irr2();
- break;
- case 3:
- irr = ia64_get_irr3();
- break;
- }
- } while (!(irr & (1UL << irr_bit))) ;
-}
+ do {
+ switch(irr_num) {
+ case 0:
+ irr = ia64_get_irr0();
+ break;
+ case 1:
+ irr = ia64_get_irr1();
+ break;
+ case 2:
+ irr = ia64_get_irr2();
+ break;
+ case 3:
+ irr = ia64_get_irr3();
+ break;
+ }
+ } while (!(irr & (1UL << irr_bit))) ;
+}
/*
* ia64_mca_wakeup
@@ -871,7 +662,7 @@
* Inputs : cpuid
* Outputs : None
*/
-void
+static void
ia64_mca_wakeup(int cpu)
{
platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
@@ -887,7 +678,7 @@
* Inputs : None
* Outputs : None
*/
-void
+static void
ia64_mca_wakeup_all(void)
{
int cpu;
@@ -912,7 +703,7 @@
* Inputs : None
* Outputs : None
*/
-void
+static void
ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
{
unsigned long flags;
@@ -937,7 +728,6 @@
local_irq_restore(flags);
}
-
/*
* ia64_mca_wakeup_int_handler
*
@@ -953,7 +743,7 @@
* Outputs : None
*
*/
-void
+static void
ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
{
}
@@ -972,11 +762,9 @@
* Outputs : None
*/
-void
-ia64_return_to_sal_check(void)
+static void
+ia64_return_to_sal_check(int recover)
{
- pal_processor_state_info_t *psp = (pal_processor_state_info_t *)
- &ia64_sal_to_os_handoff_state.proc_state_param;
/* Copy over some relevant stuff from the sal_to_os_mca_handoff
* so that it can be used at the time of os_mca_to_sal_handoff
@@ -987,15 +775,10 @@
ia64_os_to_sal_handoff_state.imots_sal_check_ra =
ia64_sal_to_os_handoff_state.imsto_sal_check_ra;
- /*
- * Did we correct the error? At the moment the only error that
- * we fix is a TLB error, if any other kind of error occurred
- * we must reboot.
- */
- if (psp->cc == 1 && psp->bc == 1 && psp->rc == 1 && psp->uc == 1)
- ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
- else
+ if (recover)
ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED;
+ else
+ ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
/* Default = tell SAL to return to same context */
ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
@@ -1024,16 +807,12 @@
void
ia64_mca_ucmc_handler(void)
{
- int platform_err = 0;
+ pal_processor_state_info_t *psp = (pal_processor_state_info_t *)
+ &ia64_sal_to_os_handoff_state.proc_state_param;
+ int recover = psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc);
/* Get the MCA error record and log it */
- platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0);
-
- /*
- * Do Platform-specific mca error handling if required.
- */
- if (platform_err)
- mca_handler_platform();
+ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
/*
* Wakeup all the processors which are spinning in the rendezvous
@@ -1042,7 +821,7 @@
ia64_mca_wakeup_all();
/* Return to SAL */
- ia64_return_to_sal_check();
+ ia64_return_to_sal_check(recover);
}
/*
@@ -1060,21 +839,21 @@
* Outputs
* None
*/
-void
+static void
ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
{
static unsigned long cmc_history[CMC_HISTORY_LENGTH];
static int index;
static spinlock_t cmc_history_lock = SPIN_LOCK_UNLOCKED;
- IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n",
- cmc_irq, smp_processor_id());
+ IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n",
+ __FUNCTION__, cmc_irq, smp_processor_id());
/* SAL spec states this should run w/ interrupts enabled */
local_irq_enable();
/* Get the CMC error record and log it */
- ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0);
+ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
spin_lock(&cmc_history_lock);
if (!cmc_polling_enabled) {
@@ -1098,7 +877,7 @@
* make sure there's a log somewhere that indicates
* something is generating more than we can handle.
*/
- printk(KERN_WARNING "%s: WARNING: Switching to polling CMC handler, error records may be lost\n", __FUNCTION__);
+ printk(KERN_WARNING "WARNING: Switching to polling CMC handler; error records may be lost\n");
mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL);
@@ -1114,41 +893,6 @@
}
/*
- * IA64_MCA log support
- */
-#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */
-#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */
-
-typedef struct ia64_state_log_s
-{
- spinlock_t isl_lock;
- int isl_index;
- unsigned long isl_count;
- ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */
-} ia64_state_log_t;
-
-static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES];
-
-#define IA64_LOG_ALLOCATE(it, size) \
- {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \
- (ia64_err_rec_t *)alloc_bootmem(size); \
- ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \
- (ia64_err_rec_t *)alloc_bootmem(size);}
-#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock)
-#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s)
-#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s)
-#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index
-#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index
-#define IA64_LOG_INDEX_INC(it) \
- {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \
- ia64_state_log[it].isl_count++;}
-#define IA64_LOG_INDEX_DEC(it) \
- ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
-#define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)]))
-#define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
-#define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count
-
-/*
* ia64_mca_cmc_int_caller
*
* Triggered by sw interrupt from CMC polling routine. Calls
@@ -1162,7 +906,7 @@
* Outputs
* None
*/
-void
+static void
ia64_mca_cmc_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
{
static int start_count = -1;
@@ -1177,14 +921,14 @@
ia64_mca_cmc_int_handler(cpe_irq, arg, ptregs);
for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
-
+
if (cpuid < NR_CPUS) {
platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0);
} else {
- /* If no log recored, switch out of polling mode */
+ /* If no log record, switch out of polling mode */
if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) {
- printk(KERN_WARNING "%s: Returning to interrupt driven CMC handler\n", __FUNCTION__);
+ printk(KERN_WARNING "Returning to interrupt driven CMC handler\n");
schedule_task(&cmc_enable_tq);
cmc_polling_enabled = 0;
@@ -1227,7 +971,7 @@
* Outputs
* None
*/
-void
+static void
ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
{
static int start_count = -1;
@@ -1279,57 +1023,26 @@
}
/*
- * ia64_mca_late_init
+ * C portion of the OS INIT handler
*
- * Opportunity to setup things that require initialization later
- * than ia64_mca_init. Setup a timer to poll for CPEs if the
- * platform doesn't support an interrupt driven mechanism.
+ * Called from ia64_monarch_init_handler
+ *
+ * Inputs: pointer to pt_regs where processor info was saved.
+ *
+ * Returns:
+ * 0 if SAL must warm boot the System
+ * 1 if SAL must return to interrupted context using PAL_MC_RESUME
*
- * Inputs : None
- * Outputs : Status
*/
-static int __init
-ia64_mca_late_init(void)
+void
+ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw)
{
- init_timer(&cmc_poll_timer);
- cmc_poll_timer.function = ia64_mca_cmc_poll;
+ pal_min_state_area_t *ms;
- /* Reset to the correct state */
- cmc_polling_enabled = 0;
+ oops_in_progress = 1; /* avoid deadlock in printk, but it makes recovery dodgy */
- init_timer(&cpe_poll_timer);
- cpe_poll_timer.function = ia64_mca_cpe_poll;
-
- /* If platform doesn't support CPEI, get the timer going. */
- if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0 && cpe_poll_enabled) {
- register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
- ia64_mca_cpe_poll(0UL);
- }
-
- return 0;
-}
-
-module_init(ia64_mca_late_init);
-
-/*
- * C portion of the OS INIT handler
- *
- * Called from ia64_monarch_init_handler
- *
- * Inputs: pointer to pt_regs where processor info was saved.
- *
- * Returns:
- * 0 if SAL must warm boot the System
- * 1 if SAL must return to interrupted context using PAL_MC_RESUME
- *
- */
-void
-ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw)
-{
- pal_min_state_area_t *ms;
-
- printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n",
- ia64_sal_to_os_handoff_state.proc_state_param);
+ printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n",
+ ia64_sal_to_os_handoff_state.proc_state_param);
/*
* Address of minstate area provided by PAL is physical,
@@ -1341,1080 +1054,259 @@
init_handler_platform(ms, pt, sw); /* call platform specific routines */
}
-/*
- * ia64_log_prt_guid
- *
- * Print a formatted GUID.
- *
- * Inputs : p_guid (ptr to the GUID)
- * prfunc (print function)
- * Outputs : None
- *
- */
-void
-ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc)
-{
- char out[40];
- printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out));
-}
-
-static void
-ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc)
+static int __init
+ia64_mca_disable_cpe_polling(char *str)
{
- unsigned long i;
- int j;
-
- if (!p)
- return;
-
- for (i = 0; i < n_ch;) {
- prfunc("%p ", (void *)p);
- for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) {
- prfunc("%02x ", *p);
- }
- prfunc("\n");
- }
+ cpe_poll_enabled = 0;
+ return 1;
}
-#ifdef MCA_PRT_XTRA_DATA // for test only @FVL
+__setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
-static void
-ia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc)
-{
- prfunc("SAL RECORD HEADER: Record buffer = %p, header size = %ld\n",
- (void *)rh, sizeof(sal_log_record_header_t));
- ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t),
- (prfunc_t)prfunc);
- prfunc("Total record length = %d\n", rh->len);
- ia64_log_prt_guid(&rh->platform_guid, prfunc);
- prfunc("End of SAL RECORD HEADER\n");
-}
+static struct irqaction cmci_irqaction = {
+ .handler = ia64_mca_cmc_int_handler,
+ .flags = SA_INTERRUPT,
+ .name = "cmc_hndlr"
+};
-static void
-ia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc)
-{
- prfunc("SAL SECTION HEADER: Record buffer = %p, header size = %ld\n",
- (void *)sh, sizeof(sal_log_section_hdr_t));
- ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t),
- (prfunc_t)prfunc);
- prfunc("Length of section & header = %d\n", sh->len);
- ia64_log_prt_guid(&sh->guid, prfunc);
- prfunc("End of SAL SECTION HEADER\n");
-}
-#endif // MCA_PRT_XTRA_DATA for test only @FVL
+static struct irqaction cmcp_irqaction = {
+ .handler = ia64_mca_cmc_int_caller,
+ .flags = SA_INTERRUPT,
+ .name = "cmc_poll"
+};
-/*
- * ia64_log_init
- * Reset the OS ia64 log buffer
- * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
- * Outputs : None
- */
-void
-ia64_log_init(int sal_info_type)
-{
- u64 max_size = 0;
+static struct irqaction mca_rdzv_irqaction = {
+ .handler = ia64_mca_rendez_int_handler,
+ .flags = SA_INTERRUPT,
+ .name = "mca_rdzv"
+};
- IA64_LOG_NEXT_INDEX(sal_info_type) = 0;
- IA64_LOG_LOCK_INIT(sal_info_type);
+static struct irqaction mca_wkup_irqaction = {
+ .handler = ia64_mca_wakeup_int_handler,
+ .flags = SA_INTERRUPT,
+ .name = "mca_wkup"
+};
- // SAL will tell us the maximum size of any error record of this type
- max_size = ia64_sal_get_state_info_size(sal_info_type);
+#ifdef CONFIG_ACPI
+static struct irqaction mca_cpe_irqaction = {
+ .handler = ia64_mca_cpe_int_handler,
+ .flags = SA_INTERRUPT,
+ .name = "cpe_hndlr"
+};
- // set up OS data structures to hold error info
- IA64_LOG_ALLOCATE(sal_info_type, max_size);
- memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size);
- memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size);
-}
+static struct irqaction mca_cpep_irqaction = {
+ .handler = ia64_mca_cpe_int_caller,
+ .flags = SA_INTERRUPT,
+ .name = "cpe_poll"
+};
+#endif /* CONFIG_ACPI */
/*
- * ia64_log_get
+ * ia64_mca_init
*
- * Get the current MCA log from SAL and copy it into the OS log buffer.
+ * Do all the system level mca specific initialization.
*
- * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
- * Outputs : size (total record length)
- * *buffer (ptr to error record)
+ * 1. Register spinloop and wakeup request interrupt vectors
*
- */
-u64
-ia64_log_get(int sal_info_type, u8 **buffer)
-{
- sal_log_record_header_t *log_buffer;
- u64 total_len = 0;
- int s;
-
- IA64_LOG_LOCK(sal_info_type);
-
- /* Get the process state information */
- log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type);
-
- total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer);
-
- if (total_len) {
- IA64_LOG_INDEX_INC(sal_info_type);
- IA64_LOG_UNLOCK(sal_info_type);
- IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. "
- "Record length = %ld\n", sal_info_type, total_len);
- *buffer = (u8 *) log_buffer;
- return total_len;
- } else {
- IA64_LOG_UNLOCK(sal_info_type);
- return 0;
- }
-}
-
-/*
- * ia64_log_prt_oem_data
+ * 2. Register OS_MCA handler entry point
*
- * Print OEM specific data if included.
+ * 3. Register OS_INIT handler entry point
*
- * Inputs : header_len (length passed in section header)
- * sect_len (default length of section type)
- * p_data (ptr to data)
- * prfunc (print function)
- * Outputs : None
+ * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
*
- */
-void
-ia64_log_prt_oem_data (int header_len, int sect_len, u8 *p_data, prfunc_t prfunc)
-{
- int oem_data_len, i;
-
- if ((oem_data_len = header_len - sect_len) > 0) {
- prfunc(" OEM Specific Data:");
- for (i = 0; i < oem_data_len; i++, p_data++)
- prfunc(" %02x", *p_data);
- }
- prfunc("\n");
-}
-
-/*
- * ia64_log_rec_header_print
+ * Note that this initialization is done very early before some kernel
+ * services are available.
*
- * Log info from the SAL error record header.
+ * Inputs : None
*
- * Inputs : lh * (ptr to SAL log error record header)
- * prfunc (fn ptr of log output function to use)
* Outputs : None
*/
-void
-ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc)
-{
- prfunc("+Err Record ID: %ld SAL Rev: %2x.%02x\n", lh->id,
- lh->revision.major, lh->revision.minor);
- prfunc("+Time: %02x/%02x/%02x%02x %02x:%02x:%02x Severity %d\n",
- lh->timestamp.slh_month, lh->timestamp.slh_day,
- lh->timestamp.slh_century, lh->timestamp.slh_year,
- lh->timestamp.slh_hour, lh->timestamp.slh_minute,
- lh->timestamp.slh_second, lh->severity);
-}
-
-/*
- * ia64_log_processor_regs_print
- * Print the contents of the saved processor register(s) in the format
- * <reg_prefix>[<index>] <value>
- *
- * Inputs : regs (Register save buffer)
- * reg_num (# of registers)
- * reg_class (application/banked/control/bank1_general)
- * reg_prefix (ar/br/cr/b1_gr)
- * Outputs : None
- *
- */
-void
-ia64_log_processor_regs_print(u64 *regs,
- int reg_num,
- char *reg_class,
- char *reg_prefix,
- prfunc_t prfunc)
-{
- int i;
-
- prfunc("+%s Registers\n", reg_class);
- for (i = 0; i < reg_num; i++)
- prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]);
-}
-
-/*
- * ia64_log_processor_fp_regs_print
- * Print the contents of the saved floating page register(s) in the format
- * <reg_prefix>[<index>] <value>
- *
- * Inputs: ia64_fpreg (Register save buffer)
- * reg_num (# of registers)
- * reg_class (application/banked/control/bank1_general)
- * reg_prefix (ar/br/cr/b1_gr)
- * Outputs: None
- *
- */
-void
-ia64_log_processor_fp_regs_print (struct ia64_fpreg *regs,
- int reg_num,
- char *reg_class,
- char *reg_prefix,
- prfunc_t prfunc)
+void __init
+ia64_mca_init(void)
{
+ ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler;
+ ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler;
+ ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch;
int i;
+ s64 rc;
+ struct ia64_sal_retval isrv;
+ u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */
- prfunc("+%s Registers\n", reg_class);
- for (i = 0; i < reg_num; i++)
- prfunc("+ %s[%d] 0x%lx%016lx\n", reg_prefix, i, regs[i].u.bits[1],
- regs[i].u.bits[0]);
-}
-
-static char *pal_mesi_state[] = {
- "Invalid",
- "Shared",
- "Exclusive",
- "Modified",
- "Reserved1",
- "Reserved2",
- "Reserved3",
- "Reserved4"
-};
-
-static char *pal_cache_op[] = {
- "Unknown",
- "Move in",
- "Cast out",
- "Coherency check",
- "Internal",
- "Instruction fetch",
- "Implicit Writeback",
- "Reserved"
-};
-
-/*
- * ia64_log_cache_check_info_print
- * Display the machine check information related to cache error(s).
- * Inputs: i (Multiple errors are logged, i - index of logged error)
- * cc_info * (Ptr to cache check info logged by the PAL and later
- * captured by the SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_cache_check_info_print (int i,
- sal_log_mod_error_info_t *cache_check_info,
- prfunc_t prfunc)
-{
- pal_cache_check_info_t *info;
- u64 target_addr;
-
- if (!cache_check_info->valid.check_info) {
- IA64_MCA_DEBUG("ia64_mca_log_print: invalid cache_check_info[%d]\n",i);
- return; /* If check info data not valid, skip it */
- }
-
- info = (pal_cache_check_info_t *)&cache_check_info->check_info;
- target_addr = cache_check_info->target_identifier;
-
- prfunc("+ Cache check info[%d]\n+", i);
- prfunc(" Level: L%d,",info->level);
- if (info->mv)
- prfunc(" Mesi: %s,",pal_mesi_state[info->mesi]);
- prfunc(" Index: %d,", info->index);
- if (info->ic)
- prfunc(" Cache: Instruction,");
- if (info->dc)
- prfunc(" Cache: Data,");
- if (info->tl)
- prfunc(" Line: Tag,");
- if (info->dl)
- prfunc(" Line: Data,");
- prfunc(" Operation: %s,", pal_cache_op[info->op]);
- if (info->wiv)
- prfunc(" Way: %d,", info->way);
- if (cache_check_info->valid.target_identifier)
- /* Hope target address is saved in target_identifier */
- if (info->tv)
- prfunc(" Target Addr: 0x%lx,", target_addr);
- if (info->mcc)
- prfunc(" MC: Corrected");
- prfunc("\n");
-}
-
-/*
- * ia64_log_tlb_check_info_print
- * Display the machine check information related to tlb error(s).
- * Inputs: i (Multiple errors are logged, i - index of logged error)
- * tlb_info * (Ptr to machine check info logged by the PAL and later
- * captured by the SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_tlb_check_info_print (int i,
- sal_log_mod_error_info_t *tlb_check_info,
- prfunc_t prfunc)
-
-{
- pal_tlb_check_info_t *info;
-
- if (!tlb_check_info->valid.check_info) {
- IA64_MCA_DEBUG("ia64_mca_log_print: invalid tlb_check_info[%d]\n", i);
- return; /* If check info data not valid, skip it */
- }
-
- info = (pal_tlb_check_info_t *)&tlb_check_info->check_info;
-
- prfunc("+ TLB Check Info [%d]\n+", i);
- if (info->itc)
- prfunc(" Failure: Instruction Translation Cache");
- if (info->dtc)
- prfunc(" Failure: Data Translation Cache");
- if (info->itr) {
- prfunc(" Failure: Instruction Translation Register");
- prfunc(" ,Slot: %ld", info->tr_slot);
- }
- if (info->dtr) {
- prfunc(" Failure: Data Translation Register");
- prfunc(" ,Slot: %ld", info->tr_slot);
- }
- if (info->mcc)
- prfunc(" ,MC: Corrected");
- prfunc("\n");
-}
-
-/*
- * ia64_log_bus_check_info_print
- * Display the machine check information related to bus error(s).
- * Inputs: i (Multiple errors are logged, i - index of logged error)
- * bus_info * (Ptr to machine check info logged by the PAL and later
- * captured by the SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_bus_check_info_print (int i,
- sal_log_mod_error_info_t *bus_check_info,
- prfunc_t prfunc)
-{
- pal_bus_check_info_t *info;
- u64 req_addr; /* Address of the requestor of the transaction */
- u64 resp_addr; /* Address of the responder of the transaction */
- u64 targ_addr; /* Address where the data was to be delivered to */
- /* or obtained from */
-
- if (!bus_check_info->valid.check_info) {
- IA64_MCA_DEBUG("ia64_mca_log_print: invalid bus_check_info[%d]\n", i);
- return; /* If check info data not valid, skip it */
- }
+ IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__);
- info = (pal_bus_check_info_t *)&bus_check_info->check_info;
- req_addr = bus_check_info->requestor_identifier;
- resp_addr = bus_check_info->responder_identifier;
- targ_addr = bus_check_info->target_identifier;
-
- prfunc("+ BUS Check Info [%d]\n+", i);
- prfunc(" Status Info: %d", info->bsi);
- prfunc(" ,Severity: %d", info->sev);
- prfunc(" ,Transaction Type: %d", info->type);
- prfunc(" ,Transaction Size: %d", info->size);
- if (info->cc)
- prfunc(" ,Cache-cache-transfer");
- if (info->ib)
- prfunc(" ,Error: Internal");
- if (info->eb)
- prfunc(" ,Error: External");
- if (info->mcc)
- prfunc(" ,MC: Corrected");
- if (info->tv)
- prfunc(" ,Target Address: 0x%lx", targ_addr);
- if (info->rq)
- prfunc(" ,Requestor Address: 0x%lx", req_addr);
- if (info->tv)
- prfunc(" ,Responder Address: 0x%lx", resp_addr);
- prfunc("\n");
-}
+ INIT_TQUEUE(&cmc_disable_tq, ia64_mca_cmc_vector_disable_keventd, NULL);
+ INIT_TQUEUE(&cmc_enable_tq, ia64_mca_cmc_vector_enable_keventd, NULL);
-/*
- * ia64_log_mem_dev_err_info_print
- *
- * Format and log the platform memory device error record section data.
- *
- * Inputs: mem_dev_err_info * (Ptr to memory device error record section
- * returned by SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_mem_dev_err_info_print (sal_log_mem_dev_err_info_t *mdei,
- prfunc_t prfunc)
-{
- prfunc("+ Mem Error Detail: ");
+ /* Clear the Rendez checkin flag for all cpus */
+ for(i = 0 ; i < NR_CPUS; i++)
+ ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
- if (mdei->valid.error_status)
- prfunc(" Error Status: %#lx,", mdei->error_status);
- if (mdei->valid.physical_addr)
- prfunc(" Physical Address: %#lx,", mdei->physical_addr);
- if (mdei->valid.addr_mask)
- prfunc(" Address Mask: %#lx,", mdei->addr_mask);
- if (mdei->valid.node)
- prfunc(" Node: %d,", mdei->node);
- if (mdei->valid.card)
- prfunc(" Card: %d,", mdei->card);
- if (mdei->valid.module)
- prfunc(" Module: %d,", mdei->module);
- if (mdei->valid.bank)
- prfunc(" Bank: %d,", mdei->bank);
- if (mdei->valid.device)
- prfunc(" Device: %d,", mdei->device);
- if (mdei->valid.row)
- prfunc(" Row: %d,", mdei->row);
- if (mdei->valid.column)
- prfunc(" Column: %d,", mdei->column);
- if (mdei->valid.bit_position)
- prfunc(" Bit Position: %d,", mdei->bit_position);
- if (mdei->valid.target_id)
- prfunc(" ,Target Address: %#lx,", mdei->target_id);
- if (mdei->valid.requestor_id)
- prfunc(" ,Requestor Address: %#lx,", mdei->requestor_id);
- if (mdei->valid.responder_id)
- prfunc(" ,Responder Address: %#lx,", mdei->responder_id);
- if (mdei->valid.bus_spec_data)
- prfunc(" Bus Specific Data: %#lx,", mdei->bus_spec_data);
- prfunc("\n");
-
- if (mdei->valid.oem_id) {
- u8 *p_data = &(mdei->oem_id[0]);
- int i;
-
- prfunc(" OEM Memory Controller ID:");
- for (i = 0; i < 16; i++, p_data++)
- prfunc(" %02x", *p_data);
- prfunc("\n");
- }
+ /*
+ * Register the rendezvous spinloop and wakeup mechanism with SAL
+ */
- if (mdei->valid.oem_data) {
- platform_mem_dev_err_print((int)mdei->header.len,
- (int)sizeof(sal_log_mem_dev_err_info_t) - 1,
- &(mdei->oem_data[0]), prfunc);
+ /* Register the rendezvous interrupt vector with SAL */
+ while (1) {
+ isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
+ SAL_MC_PARAM_MECHANISM_INT,
+ IA64_MCA_RENDEZ_VECTOR,
+ timeout,
+ SAL_MC_PARAM_RZ_ALWAYS);
+ rc = isrv.status;
+ if (rc == 0)
+ break;
+ if (rc == -2) {
+ printk(KERN_INFO "Increasing MCA rendezvous timeout from "
+ "%ld to %ld milliseconds\n", timeout, isrv.v0);
+ timeout = isrv.v0;
+ continue;
+ }
+ printk(KERN_ERR "Failed to register rendezvous interrupt "
+ "with SAL (status %ld)\n", rc);
+ return;
}
-}
-/*
- * ia64_log_sel_dev_err_info_print
- *
- * Format and log the platform SEL device error record section data.
- *
- * Inputs: sel_dev_err_info * (Ptr to the SEL device error record section
- * returned by SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_sel_dev_err_info_print (sal_log_sel_dev_err_info_t *sdei,
- prfunc_t prfunc)
-{
- int i;
-
- prfunc("+ SEL Device Error Detail: ");
-
- if (sdei->valid.record_id)
- prfunc(" Record ID: %#x", sdei->record_id);
- if (sdei->valid.record_type)
- prfunc(" Record Type: %#x", sdei->record_type);
- prfunc(" Time Stamp: ");
- for (i = 0; i < 4; i++)
- prfunc("%1d", sdei->timestamp[i]);
- if (sdei->valid.generator_id)
- prfunc(" Generator ID: %#x", sdei->generator_id);
- if (sdei->valid.evm_rev)
- prfunc(" Message Format Version: %#x", sdei->evm_rev);
- if (sdei->valid.sensor_type)
- prfunc(" Sensor Type: %#x", sdei->sensor_type);
- if (sdei->valid.sensor_num)
- prfunc(" Sensor Number: %#x", sdei->sensor_num);
- if (sdei->valid.event_dir)
- prfunc(" Event Direction Type: %#x", sdei->event_dir);
- if (sdei->valid.event_data1)
- prfunc(" Data1: %#x", sdei->event_data1);
- if (sdei->valid.event_data2)
- prfunc(" Data2: %#x", sdei->event_data2);
- if (sdei->valid.event_data3)
- prfunc(" Data3: %#x", sdei->event_data3);
- prfunc("\n");
-
-}
-
-/*
- * ia64_log_pci_bus_err_info_print
- *
- * Format and log the platform PCI bus error record section data.
- *
- * Inputs: pci_bus_err_info * (Ptr to the PCI bus error record section
- * returned by SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_pci_bus_err_info_print (sal_log_pci_bus_err_info_t *pbei,
- prfunc_t prfunc)
-{
- prfunc("+ PCI Bus Error Detail: ");
-
- if (pbei->valid.err_status)
- prfunc(" Error Status: %#lx", pbei->err_status);
- if (pbei->valid.err_type)
- prfunc(" Error Type: %#x", pbei->err_type);
- if (pbei->valid.bus_id)
- prfunc(" Bus ID: %#x", pbei->bus_id);
- if (pbei->valid.bus_address)
- prfunc(" Bus Address: %#lx", pbei->bus_address);
- if (pbei->valid.bus_data)
- prfunc(" Bus Data: %#lx", pbei->bus_data);
- if (pbei->valid.bus_cmd)
- prfunc(" Bus Command: %#lx", pbei->bus_cmd);
- if (pbei->valid.requestor_id)
- prfunc(" Requestor ID: %#lx", pbei->requestor_id);
- if (pbei->valid.responder_id)
- prfunc(" Responder ID: %#lx", pbei->responder_id);
- if (pbei->valid.target_id)
- prfunc(" Target ID: %#lx", pbei->target_id);
- if (pbei->valid.oem_data)
- prfunc("\n");
-
- if (pbei->valid.oem_data) {
- platform_pci_bus_err_print((int)pbei->header.len,
- (int)sizeof(sal_log_pci_bus_err_info_t) - 1,
- &(pbei->oem_data[0]), prfunc);
+ /* Register the wakeup interrupt vector with SAL */
+ isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
+ SAL_MC_PARAM_MECHANISM_INT,
+ IA64_MCA_WAKEUP_VECTOR,
+ 0, 0);
+ rc = isrv.status;
+ if (rc) {
+ printk(KERN_ERR "Failed to register wakeup interrupt with SAL "
+ "(status %ld)\n", rc);
+ return;
}
-}
-/*
- * ia64_log_smbios_dev_err_info_print
- *
- * Format and log the platform SMBIOS device error record section data.
- *
- * Inputs: smbios_dev_err_info * (Ptr to the SMBIOS device error record
- * section returned by SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_smbios_dev_err_info_print (sal_log_smbios_dev_err_info_t *sdei,
- prfunc_t prfunc)
-{
- u8 i;
+ IA64_MCA_DEBUG("%s: registered MCA rendezvous spinloop and wakeup mech.\n", __FUNCTION__);
- prfunc("+ SMBIOS Device Error Detail: ");
-
- if (sdei->valid.event_type)
- prfunc(" Event Type: %#x", sdei->event_type);
- if (sdei->valid.time_stamp) {
- prfunc(" Time Stamp: ");
- for (i = 0; i < 6; i++)
- prfunc("%d", sdei->time_stamp[i]);
- }
- if ((sdei->valid.data) && (sdei->valid.length)) {
- prfunc(" Data: ");
- for (i = 0; i < sdei->length; i++)
- prfunc(" %02x", sdei->data[i]);
- }
- prfunc("\n");
-}
+ ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp);
+ /*
+ * XXX - disable SAL checksum by setting size to 0; should be
+ * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch);
+ */
+ ia64_mc_info.imi_mca_handler_size = 0;
-/*
- * ia64_log_pci_comp_err_info_print
- *
- * Format and log the platform PCI component error record section data.
- *
- * Inputs: pci_comp_err_info * (Ptr to the PCI component error record section
- * returned by SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_pci_comp_err_info_print(sal_log_pci_comp_err_info_t *pcei,
- prfunc_t prfunc)
-{
- u32 n_mem_regs, n_io_regs;
- u64 i, n_pci_data;
- u64 *p_reg_data;
- u8 *p_oem_data;
-
- prfunc("+ PCI Component Error Detail: ");
-
- if (pcei->valid.err_status)
- prfunc(" Error Status: %#lx\n", pcei->err_status);
- if (pcei->valid.comp_info)
- prfunc(" Component Info: Vendor Id = %#x, Device Id = %#x,"
- " Class Code = %#x, Seg/Bus/Dev/Func = %d/%d/%d/%d\n",
- pcei->comp_info.vendor_id, pcei->comp_info.device_id,
- pcei->comp_info.class_code, pcei->comp_info.seg_num,
- pcei->comp_info.bus_num, pcei->comp_info.dev_num,
- pcei->comp_info.func_num);
-
- n_mem_regs = (pcei->valid.num_mem_regs) ? pcei->num_mem_regs : 0;
- n_io_regs = (pcei->valid.num_io_regs) ? pcei->num_io_regs : 0;
- p_reg_data = &(pcei->reg_data_pairs[0]);
- p_oem_data = (u8 *)p_reg_data +
- (n_mem_regs + n_io_regs) * 2 * sizeof(u64);
- n_pci_data = p_oem_data - (u8 *)pcei;
-
- if (n_pci_data > pcei->header.len) {
- prfunc(" Invalid PCI Component Error Record format: length = %ld, "
- " Size PCI Data = %d, Num Mem-Map/IO-Map Regs = %ld/%ld\n",
- pcei->header.len, n_pci_data, n_mem_regs, n_io_regs);
+ /* Register the os mca handler with SAL */
+ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
+ ia64_mc_info.imi_mca_handler,
+ ia64_tpa(mca_hldlr_ptr->gp),
+ ia64_mc_info.imi_mca_handler_size,
+ 0, 0, 0)))
+ {
+ printk(KERN_ERR "Failed to register OS MCA handler with SAL "
+ "(status %ld)\n", rc);
return;
}
- if (n_mem_regs) {
- prfunc(" Memory Mapped Registers\n Address \tValue\n");
- for (i = 0; i < pcei->num_mem_regs; i++) {
- prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]);
- p_reg_data += 2;
- }
- }
- if (n_io_regs) {
- prfunc(" I/O Mapped Registers\n Address \tValue\n");
- for (i = 0; i < pcei->num_io_regs; i++) {
- prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]);
- p_reg_data += 2;
- }
- }
- if (pcei->valid.oem_data) {
- platform_pci_comp_err_print((int)pcei->header.len, n_pci_data,
- p_oem_data, prfunc);
- prfunc("\n");
- }
-}
-
-/*
- * ia64_log_plat_specific_err_info_print
- *
- * Format and log the platform specifie error record section data.
- *
- * Inputs: sel_dev_err_info * (Ptr to the platform specific error record
- * section returned by SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_plat_specific_err_info_print (sal_log_plat_specific_err_info_t *psei,
- prfunc_t prfunc)
-{
- prfunc("+ Platform Specific Error Detail: ");
+ IA64_MCA_DEBUG("%s: registered OS MCA handler with SAL at 0x%lx, gp = 0x%lx\n", __FUNCTION__,
+ ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp));
- if (psei->valid.err_status)
- prfunc(" Error Status: %#lx", psei->err_status);
- if (psei->valid.guid) {
- prfunc(" GUID: ");
- ia64_log_prt_guid(&psei->guid, prfunc);
- }
- if (psei->valid.oem_data) {
- platform_plat_specific_err_print((int) psei->header.len,
- (char *) psei->oem_data - (char *) psei,
- &psei->oem_data[0], prfunc);
- }
- prfunc("\n");
-}
+ /*
+ * XXX - disable SAL checksum by setting size to 0, should be
+ * size of the actual init handler in mca_asm.S.
+ */
+ ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp);
+ ia64_mc_info.imi_monarch_init_handler_size = 0;
+ ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp);
+ ia64_mc_info.imi_slave_init_handler_size = 0;
-/*
- * ia64_log_host_ctlr_err_info_print
- *
- * Format and log the platform host controller error record section data.
- *
- * Inputs: host_ctlr_err_info * (Ptr to the host controller error record
- * section returned by SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_host_ctlr_err_info_print (sal_log_host_ctlr_err_info_t *hcei,
- prfunc_t prfunc)
-{
- prfunc("+ Host Controller Error Detail: ");
+ IA64_MCA_DEBUG("%s: OS INIT handler at %lx\n", __FUNCTION__,
+ ia64_mc_info.imi_monarch_init_handler);
- if (hcei->valid.err_status)
- prfunc(" Error Status: %#lx", hcei->err_status);
- if (hcei->valid.requestor_id)
- prfunc(" Requestor ID: %#lx", hcei->requestor_id);
- if (hcei->valid.responder_id)
- prfunc(" Responder ID: %#lx", hcei->responder_id);
- if (hcei->valid.target_id)
- prfunc(" Target ID: %#lx", hcei->target_id);
- if (hcei->valid.bus_spec_data)
- prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data);
- if (hcei->valid.oem_data) {
- platform_host_ctlr_err_print((int)hcei->header.len,
- (int)sizeof(sal_log_host_ctlr_err_info_t) - 1,
- &(hcei->oem_data[0]), prfunc);
+ /* Register the os init handler with SAL */
+ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
+ ia64_mc_info.imi_monarch_init_handler,
+ ia64_tpa(ia64_get_gp()),
+ ia64_mc_info.imi_monarch_init_handler_size,
+ ia64_mc_info.imi_slave_init_handler,
+ ia64_tpa(ia64_get_gp()),
+ ia64_mc_info.imi_slave_init_handler_size)))
+ {
+ printk(KERN_ERR "Failed to register m/s INIT handlers with SAL "
+ "(status %ld)\n", rc);
+ return;
}
- prfunc("\n");
-}
-/*
- * ia64_log_plat_bus_err_info_print
- *
- * Format and log the platform bus error record section data.
- *
- * Inputs: plat_bus_err_info * (Ptr to the platform bus error record section
- * returned by SAL)
- * prfunc (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_plat_bus_err_info_print (sal_log_plat_bus_err_info_t *pbei,
- prfunc_t prfunc)
-{
- prfunc("+ Platform Bus Error Detail: ");
+ IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__);
- if (pbei->valid.err_status)
- prfunc(" Error Status: %#lx", pbei->err_status);
- if (pbei->valid.requestor_id)
- prfunc(" Requestor ID: %#lx", pbei->requestor_id);
- if (pbei->valid.responder_id)
- prfunc(" Responder ID: %#lx", pbei->responder_id);
- if (pbei->valid.target_id)
- prfunc(" Target ID: %#lx", pbei->target_id);
- if (pbei->valid.bus_spec_data)
- prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data);
- if (pbei->valid.oem_data) {
- platform_plat_bus_err_print((int)pbei->header.len,
- (int)sizeof(sal_log_plat_bus_err_info_t) - 1,
- &(pbei->oem_data[0]), prfunc);
- }
- prfunc("\n");
-}
+ /*
+ * Configure the CMCI/P vector and handler. Interrupts for CMC are
+ * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
+ */
+ register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
+ register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
+ ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */
-/*
- * ia64_log_proc_dev_err_info_print
- *
- * Display the processor device error record.
- *
- * Inputs: sal_log_processor_info_t * (Ptr to processor device error record
- * section body).
- * prfunc (fn ptr of print function to be used
- * for output).
- * Outputs: None
- */
-void
-ia64_log_proc_dev_err_info_print (sal_log_processor_info_t *slpi,
- prfunc_t prfunc)
-{
-#ifdef MCA_PRT_XTRA_DATA
- size_t d_len = slpi->header.len - sizeof(sal_log_section_hdr_t);
-#endif
- sal_processor_static_info_t *spsi;
- int i;
- sal_log_mod_error_info_t *p_data;
+ /* Setup the MCA rendezvous interrupt vector */
+ register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
- prfunc("+Processor Device Error Info Section\n");
+ /* Setup the MCA wakeup interrupt vector */
+ register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
-#ifdef MCA_PRT_XTRA_DATA // for test only @FVL
+#ifdef CONFIG_ACPI
+ /* Setup the CPE interrupt vector */
{
- char *p_data = (char *)&slpi->valid;
+ irq_desc_t *desc;
+ unsigned int irq;
+ int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI);
- prfunc("SAL_PROC_DEV_ERR SECTION DATA: Data buffer = %p, "
- "Data size = %ld\n", (void *)p_data, d_len);
- ia64_log_hexdump(p_data, d_len, prfunc);
- prfunc("End of SAL_PROC_DEV_ERR SECTION DATA\n");
+ if (cpev >= 0) {
+ for (irq = 0; irq < NR_IRQS; ++irq)
+ if (irq_to_vector(irq) == cpev) {
+ desc = irq_desc(irq);
+ desc->status |= IRQ_PER_CPU;
+ desc->handler = &irq_type_iosapic_level;
+ setup_irq(irq, &mca_cpe_irqaction);
+ }
+ ia64_mca_register_cpev(cpev);
+ }
}
-#endif // MCA_PRT_XTRA_DATA for test only @FVL
-
- if (slpi->valid.proc_error_map)
- prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map);
-
- if (slpi->valid.proc_state_param)
- prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter);
-
- if (slpi->valid.proc_cr_lid)
- prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid);
+#endif
- /*
- * Note: March 2001 SAL spec states that if the number of elements in any
- * of the MOD_ERROR_INFO_STRUCT arrays is zero, the entire array is
- * absent. Also, current implementations only allocate space for number of
- * elements used. So we walk the data pointer from here on.
+ /* Initialize the areas set aside by the OS to buffer the
+ * platform/processor error states for MCA/INIT/CMC
+ * handling.
*/
- p_data = &slpi->info[0];
-
- /* Print the cache check information if any*/
- for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++)
- ia64_log_cache_check_info_print(i, p_data, prfunc);
-
- /* Print the tlb check information if any*/
- for (i = 0 ; i < slpi->valid.num_tlb_check; i++, p_data++)
- ia64_log_tlb_check_info_print(i, p_data, prfunc);
-
- /* Print the bus check information if any*/
- for (i = 0 ; i < slpi->valid.num_bus_check; i++, p_data++)
- ia64_log_bus_check_info_print(i, p_data, prfunc);
-
- /* Print the reg file check information if any*/
- for (i = 0 ; i < slpi->valid.num_reg_file_check; i++, p_data++)
- ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t),
- prfunc); /* Just hex dump for now */
-
- /* Print the ms check information if any*/
- for (i = 0 ; i < slpi->valid.num_ms_check; i++, p_data++)
- ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t),
- prfunc); /* Just hex dump for now */
-
- /* Print CPUID registers if any*/
- if (slpi->valid.cpuid_info) {
- u64 *p = (u64 *)p_data;
-
- prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]);
- p_data++;
- }
+ ia64_log_init(SAL_INFO_TYPE_MCA);
+ ia64_log_init(SAL_INFO_TYPE_INIT);
+ ia64_log_init(SAL_INFO_TYPE_CMC);
+ ia64_log_init(SAL_INFO_TYPE_CPE);
- /* Print processor static info if any */
- if (slpi->valid.psi_static_struct) {
- spsi = (sal_processor_static_info_t *)p_data;
-
- /* Print branch register contents if valid */
- if (spsi->valid.br)
- ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
- prfunc);
-
- /* Print control register contents if valid */
- if (spsi->valid.cr)
- ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr",
- prfunc);
-
- /* Print application register contents if valid */
- if (spsi->valid.ar)
- ia64_log_processor_regs_print(spsi->ar, 128, "Application",
- "ar", prfunc);
-
- /* Print region register contents if valid */
- if (spsi->valid.rr)
- ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr",
- prfunc);
-
- /* Print floating-point register contents if valid */
- if (spsi->valid.fr)
- ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr",
- prfunc);
- }
+ printk(KERN_INFO "MCA related initialization done\n");
}
/*
- * ia64_log_processor_info_print
+ * ia64_mca_late_init
*
- * Display the processor-specific information logged by PAL as a part
- * of MCA or INIT or CMC.
+ * Opportunity to setup things that require initialization later
+ * than ia64_mca_init. Setup a timer to poll for CPEs if the
+ * platform doesn't support an interrupt driven mechanism.
*
- * Inputs : lh (Pointer of the sal log header which specifies the
- * format of SAL state info as specified by the SAL spec).
- * prfunc (fn ptr of print function to be used for output).
- * Outputs : None
+ * Inputs : None
+ * Outputs : Status
*/
-void
-ia64_log_processor_info_print(sal_log_record_header_t *lh, prfunc_t prfunc)
+static int __init
+ia64_mca_late_init(void)
{
- sal_log_section_hdr_t *slsh;
- int n_sects;
- u32 ercd_pos;
-
- if (!lh)
- return;
-
-#ifdef MCA_PRT_XTRA_DATA // for test only @FVL
- ia64_log_prt_record_header(lh, prfunc);
-#endif // MCA_PRT_XTRA_DATA for test only @FVL
-
- if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) {
- IA64_MCA_DEBUG("ia64_mca_log_print: "
- "truncated SAL CMC error record. len = %d\n",
- lh->len);
- return;
- }
-
- /* Print record header info */
- ia64_log_rec_header_print(lh, prfunc);
-
- for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) {
- /* point to next section header */
- slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos);
-
-#ifdef MCA_PRT_XTRA_DATA // for test only @FVL
- ia64_log_prt_section_header(slsh, prfunc);
-#endif // MCA_PRT_XTRA_DATA for test only @FVL
-
- if (verify_guid(&slsh->guid, &(SAL_PROC_DEV_ERR_SECT_GUID))) {
- IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
- continue;
- }
-
- /*
- * Now process processor device error record section
- */
- ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, printk);
- }
-
- IA64_MCA_DEBUG("ia64_mca_log_print: "
- "found %d sections in SAL CMC error record. len = %d\n",
- n_sects, lh->len);
- if (!n_sects) {
- prfunc("No Processor Device Error Info Section found\n");
- return;
- }
-}
-
-/*
- * ia64_log_platform_info_print
- *
- * Format and Log the SAL Platform Error Record.
- *
- * Inputs : lh (Pointer to the sal error record header with format
- * specified by the SAL spec).
- * prfunc (fn ptr of log output function to use)
- * Outputs : platform error status
- */
-int
-ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc)
-{
- sal_log_section_hdr_t *slsh;
- int n_sects;
- u32 ercd_pos;
- int platform_err = 0;
-
- if (!lh)
- return platform_err;
-
-#ifdef MCA_PRT_XTRA_DATA // for test only @FVL
- ia64_log_prt_record_header(lh, prfunc);
-#endif // MCA_PRT_XTRA_DATA for test only @FVL
-
- if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) {
- IA64_MCA_DEBUG("ia64_mca_log_print: "
- "truncated SAL error record. len = %d\n",
- lh->len);
- return platform_err;
- }
-
- /* Print record header info */
- ia64_log_rec_header_print(lh, prfunc);
-
- for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) {
- /* point to next section header */
- slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos);
-
-#ifdef MCA_PRT_XTRA_DATA // for test only @FVL
- ia64_log_prt_section_header(slsh, prfunc);
-
- if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) != 0) {
- size_t d_len = slsh->len - sizeof(sal_log_section_hdr_t);
- char *p_data = (char *)&((sal_log_mem_dev_err_info_t *)slsh)->valid;
-
- prfunc("Start of Platform Err Data Section: Data buffer = %p, "
- "Data size = %ld\n", (void *)p_data, d_len);
- ia64_log_hexdump(p_data, d_len, prfunc);
- prfunc("End of Platform Err Data Section\n");
- }
-#endif // MCA_PRT_XTRA_DATA for test only @FVL
+ init_timer(&cmc_poll_timer);
+ cmc_poll_timer.function = ia64_mca_cmc_poll;
- /*
- * Now process CPE error record section
- */
- if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) == 0) {
- ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh,
- prfunc);
- } else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) {
- platform_err = 1;
- prfunc("+Platform Memory Device Error Info Section\n");
- ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh,
- prfunc);
- } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) == 0) {
- platform_err = 1;
- prfunc("+Platform SEL Device Error Info Section\n");
- ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh,
- prfunc);
- } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) == 0) {
- platform_err = 1;
- prfunc("+Platform PCI Bus Error Info Section\n");
- ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh,
- prfunc);
- } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) == 0) {
- platform_err = 1;
- prfunc("+Platform SMBIOS Device Error Info Section\n");
- ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh,
- prfunc);
- } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) == 0) {
- platform_err = 1;
- prfunc("+Platform PCI Component Error Info Section\n");
- ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh,
- prfunc);
- } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) {
- platform_err = 1;
- prfunc("+Platform Specific Error Info Section\n");
- ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *)
- slsh,
- prfunc);
- } else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) == 0) {
- platform_err = 1;
- prfunc("+Platform Host Controller Error Info Section\n");
- ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh,
- prfunc);
- } else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) == 0) {
- platform_err = 1;
- prfunc("+Platform Bus Error Info Section\n");
- ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh,
- prfunc);
- } else {
- IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
- continue;
- }
- }
+ /* Reset to the correct state */
+ cmc_polling_enabled = 0;
- IA64_MCA_DEBUG("ia64_mca_log_print: found %d sections in SAL error record. len = %d\n",
- n_sects, lh->len);
- if (!n_sects) {
- prfunc("No Platform Error Info Sections found\n");
- return platform_err;
- }
- return platform_err;
-}
+ init_timer(&cpe_poll_timer);
+ cpe_poll_timer.function = ia64_mca_cpe_poll;
-/*
- * ia64_log_print
- *
- * Displays the contents of the OS error log information
- *
- * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
- * prfunc (fn ptr of log output function to use)
- * Outputs : platform error status
- */
-int
-ia64_log_print(int sal_info_type, prfunc_t prfunc)
-{
- int platform_err = 0;
-
- switch(sal_info_type) {
- case SAL_INFO_TYPE_MCA:
- prfunc("+CPU %d: SAL log contains MCA error record\n", smp_processor_id());
- ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
- break;
- case SAL_INFO_TYPE_INIT:
- prfunc("+CPU %d: SAL log contains INIT error record\n", smp_processor_id());
- ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
- break;
- case SAL_INFO_TYPE_CMC:
- prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n");
- ia64_log_processor_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
- prfunc("+END HARDWARE ERROR STATE AT CMC\n");
- break;
- case SAL_INFO_TYPE_CPE:
- prfunc("+BEGIN HARDWARE ERROR STATE AT CPE\n");
- ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
- prfunc("+END HARDWARE ERROR STATE AT CPE\n");
- break;
- default:
- prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n");
- break;
+#ifdef CONFIG_ACPI
+ /* If platform doesn't support CPEI, get the timer going. */
+ if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0 && cpe_poll_enabled) {
+ register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
+ ia64_mca_cpe_poll(0UL);
}
- return platform_err;
-}
+#endif
-static int __init
-ia64_mca_disable_cpe_polling(char *str)
-{
- cpe_poll_enabled = 0;
- return 1;
+ return 0;
}
-__setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
+module_init(ia64_mca_late_init);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)