|
@@ -83,6 +83,7 @@
|
|
|
#include <asm/irq.h>
|
|
|
#include <asm/hw_irq.h>
|
|
|
|
|
|
+#include "mca_drv.h"
|
|
|
#include "entry.h"
|
|
|
|
|
|
#if defined(IA64_MCA_DEBUG_INFO)
|
|
@@ -133,7 +134,7 @@ static int cpe_poll_enabled = 1;
|
|
|
|
|
|
extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe);
|
|
|
|
|
|
-static int mca_init;
|
|
|
+static int mca_init __initdata;
|
|
|
|
|
|
|
|
|
static void inline
|
|
@@ -184,7 +185,7 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES];
|
|
|
* Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
|
|
|
* Outputs : None
|
|
|
*/
|
|
|
-static void
|
|
|
+static void __init
|
|
|
ia64_log_init(int sal_info_type)
|
|
|
{
|
|
|
u64 max_size = 0;
|
|
@@ -281,6 +282,50 @@ ia64_mca_log_sal_error_record(int sal_info_type)
|
|
|
ia64_sal_clear_state_info(sal_info_type);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * search_mca_table
|
|
|
+ * See if the MCA surfaced in an instruction range
|
|
|
+ * that has been tagged as recoverable.
|
|
|
+ *
|
|
|
+ * Inputs
|
|
|
+ * first First address range to check
|
|
|
+ * last Last address range to check
|
|
|
+ * ip Instruction pointer, address we are looking for
|
|
|
+ *
|
|
|
+ * Return value:
|
|
|
+ * 1 on Success (in the table)/ 0 on Failure (not in the table)
|
|
|
+ */
|
|
|
+int
|
|
|
+search_mca_table (const struct mca_table_entry *first,
|
|
|
+ const struct mca_table_entry *last,
|
|
|
+ unsigned long ip)
|
|
|
+{
|
|
|
+ const struct mca_table_entry *curr;
|
|
|
+ u64 curr_start, curr_end;
|
|
|
+
|
|
|
+ curr = first;
|
|
|
+ while (curr <= last) {
|
|
|
+ curr_start = (u64) &curr->start_addr + curr->start_addr;
|
|
|
+ curr_end = (u64) &curr->end_addr + curr->end_addr;
|
|
|
+
|
|
|
+ if ((ip >= curr_start) && (ip <= curr_end)) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ curr++;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* Given an address, look for it in the mca tables. */
|
|
|
+int mca_recover_range(unsigned long addr)
|
|
|
+{
|
|
|
+ extern struct mca_table_entry __start___mca_table[];
|
|
|
+ extern struct mca_table_entry __stop___mca_table[];
|
|
|
+
|
|
|
+ return search_mca_table(__start___mca_table, __stop___mca_table-1, addr);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(mca_recover_range);
|
|
|
+
|
|
|
#ifdef CONFIG_ACPI
|
|
|
|
|
|
int cpe_vector = -1;
|
|
@@ -355,7 +400,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
|
|
|
* Outputs
|
|
|
* None
|
|
|
*/
|
|
|
-static void
|
|
|
+static void __init
|
|
|
ia64_mca_register_cpev (int cpev)
|
|
|
{
|
|
|
/* Register the CPE interrupt vector with SAL */
|
|
@@ -386,7 +431,7 @@ ia64_mca_register_cpev (int cpev)
|
|
|
* Outputs
|
|
|
* None
|
|
|
*/
|
|
|
-void
|
|
|
+void __cpuinit
|
|
|
ia64_mca_cmc_vector_setup (void)
|
|
|
{
|
|
|
cmcv_reg_t cmcv;
|
|
@@ -747,31 +792,34 @@ ia64_mca_modify_original_stack(struct pt_regs *regs,
|
|
|
ia64_mca_modify_comm(previous_current);
|
|
|
goto no_mod;
|
|
|
}
|
|
|
- if (r13 != sos->prev_IA64_KR_CURRENT) {
|
|
|
- msg = "inconsistent previous current and r13";
|
|
|
- goto no_mod;
|
|
|
- }
|
|
|
- if ((r12 - r13) >= KERNEL_STACK_SIZE) {
|
|
|
- msg = "inconsistent r12 and r13";
|
|
|
- goto no_mod;
|
|
|
- }
|
|
|
- if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) {
|
|
|
- msg = "inconsistent ar.bspstore and r13";
|
|
|
- goto no_mod;
|
|
|
- }
|
|
|
- va.p = old_bspstore;
|
|
|
- if (va.f.reg < 5) {
|
|
|
- msg = "old_bspstore is in the wrong region";
|
|
|
- goto no_mod;
|
|
|
- }
|
|
|
- if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) {
|
|
|
- msg = "inconsistent ar.bsp and r13";
|
|
|
- goto no_mod;
|
|
|
- }
|
|
|
- size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8;
|
|
|
- if (ar_bspstore + size > r12) {
|
|
|
- msg = "no room for blocked state";
|
|
|
- goto no_mod;
|
|
|
+
|
|
|
+ if (!mca_recover_range(ms->pmsa_iip)) {
|
|
|
+ if (r13 != sos->prev_IA64_KR_CURRENT) {
|
|
|
+ msg = "inconsistent previous current and r13";
|
|
|
+ goto no_mod;
|
|
|
+ }
|
|
|
+ if ((r12 - r13) >= KERNEL_STACK_SIZE) {
|
|
|
+ msg = "inconsistent r12 and r13";
|
|
|
+ goto no_mod;
|
|
|
+ }
|
|
|
+ if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) {
|
|
|
+ msg = "inconsistent ar.bspstore and r13";
|
|
|
+ goto no_mod;
|
|
|
+ }
|
|
|
+ va.p = old_bspstore;
|
|
|
+ if (va.f.reg < 5) {
|
|
|
+ msg = "old_bspstore is in the wrong region";
|
|
|
+ goto no_mod;
|
|
|
+ }
|
|
|
+ if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) {
|
|
|
+ msg = "inconsistent ar.bsp and r13";
|
|
|
+ goto no_mod;
|
|
|
+ }
|
|
|
+ size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8;
|
|
|
+ if (ar_bspstore + size > r12) {
|
|
|
+ msg = "no room for blocked state";
|
|
|
+ goto no_mod;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
ia64_mca_modify_comm(previous_current);
|
|
@@ -1443,7 +1491,7 @@ static struct irqaction mca_cpep_irqaction = {
|
|
|
* format most of the fields.
|
|
|
*/
|
|
|
|
|
|
-static void
|
|
|
+static void __cpuinit
|
|
|
format_mca_init_stack(void *mca_data, unsigned long offset,
|
|
|
const char *type, int cpu)
|
|
|
{
|
|
@@ -1467,7 +1515,7 @@ format_mca_init_stack(void *mca_data, unsigned long offset,
|
|
|
|
|
|
/* Do per-CPU MCA-related initialization. */
|
|
|
|
|
|
-void __devinit
|
|
|
+void __cpuinit
|
|
|
ia64_mca_cpu_init(void *cpu_data)
|
|
|
{
|
|
|
void *pal_vaddr;
|