diff options
Diffstat (limited to 'arch/ia64/kernel/mca.c')
-rw-r--r-- | arch/ia64/kernel/mca.c | 110 |
1 files changed, 79 insertions, 31 deletions
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index b57e723f194c..87ff7fe33cfb 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c | |||
@@ -83,6 +83,7 @@ | |||
83 | #include <asm/irq.h> | 83 | #include <asm/irq.h> |
84 | #include <asm/hw_irq.h> | 84 | #include <asm/hw_irq.h> |
85 | 85 | ||
86 | #include "mca_drv.h" | ||
86 | #include "entry.h" | 87 | #include "entry.h" |
87 | 88 | ||
88 | #if defined(IA64_MCA_DEBUG_INFO) | 89 | #if defined(IA64_MCA_DEBUG_INFO) |
@@ -133,7 +134,7 @@ static int cpe_poll_enabled = 1; | |||
133 | 134 | ||
134 | extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); | 135 | extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); |
135 | 136 | ||
136 | static int mca_init; | 137 | static int mca_init __initdata; |
137 | 138 | ||
138 | 139 | ||
139 | static void inline | 140 | static void inline |
@@ -184,7 +185,7 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; | |||
184 | * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) | 185 | * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) |
185 | * Outputs : None | 186 | * Outputs : None |
186 | */ | 187 | */ |
187 | static void | 188 | static void __init |
188 | ia64_log_init(int sal_info_type) | 189 | ia64_log_init(int sal_info_type) |
189 | { | 190 | { |
190 | u64 max_size = 0; | 191 | u64 max_size = 0; |
@@ -281,6 +282,50 @@ ia64_mca_log_sal_error_record(int sal_info_type) | |||
281 | ia64_sal_clear_state_info(sal_info_type); | 282 | ia64_sal_clear_state_info(sal_info_type); |
282 | } | 283 | } |
283 | 284 | ||
285 | /* | ||
286 | * search_mca_table | ||
287 | * See if the MCA surfaced in an instruction range | ||
288 | * that has been tagged as recoverable. | ||
289 | * | ||
290 | * Inputs | ||
291 | * first First address range to check | ||
292 | * last Last address range to check | ||
293 | * ip Instruction pointer, address we are looking for | ||
294 | * | ||
295 | * Return value: | ||
296 | * 1 on Success (in the table)/ 0 on Failure (not in the table) | ||
297 | */ | ||
298 | int | ||
299 | search_mca_table (const struct mca_table_entry *first, | ||
300 | const struct mca_table_entry *last, | ||
301 | unsigned long ip) | ||
302 | { | ||
303 | const struct mca_table_entry *curr; | ||
304 | u64 curr_start, curr_end; | ||
305 | |||
306 | curr = first; | ||
307 | while (curr <= last) { | ||
308 | curr_start = (u64) &curr->start_addr + curr->start_addr; | ||
309 | curr_end = (u64) &curr->end_addr + curr->end_addr; | ||
310 | |||
311 | if ((ip >= curr_start) && (ip <= curr_end)) { | ||
312 | return 1; | ||
313 | } | ||
314 | curr++; | ||
315 | } | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | /* Given an address, look for it in the mca tables. */ | ||
320 | int mca_recover_range(unsigned long addr) | ||
321 | { | ||
322 | extern struct mca_table_entry __start___mca_table[]; | ||
323 | extern struct mca_table_entry __stop___mca_table[]; | ||
324 | |||
325 | return search_mca_table(__start___mca_table, __stop___mca_table-1, addr); | ||
326 | } | ||
327 | EXPORT_SYMBOL_GPL(mca_recover_range); | ||
328 | |||
284 | #ifdef CONFIG_ACPI | 329 | #ifdef CONFIG_ACPI |
285 | 330 | ||
286 | int cpe_vector = -1; | 331 | int cpe_vector = -1; |
@@ -355,7 +400,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) | |||
355 | * Outputs | 400 | * Outputs |
356 | * None | 401 | * None |
357 | */ | 402 | */ |
358 | static void | 403 | static void __init |
359 | ia64_mca_register_cpev (int cpev) | 404 | ia64_mca_register_cpev (int cpev) |
360 | { | 405 | { |
361 | /* Register the CPE interrupt vector with SAL */ | 406 | /* Register the CPE interrupt vector with SAL */ |
@@ -386,7 +431,7 @@ ia64_mca_register_cpev (int cpev) | |||
386 | * Outputs | 431 | * Outputs |
387 | * None | 432 | * None |
388 | */ | 433 | */ |
389 | void | 434 | void __cpuinit |
390 | ia64_mca_cmc_vector_setup (void) | 435 | ia64_mca_cmc_vector_setup (void) |
391 | { | 436 | { |
392 | cmcv_reg_t cmcv; | 437 | cmcv_reg_t cmcv; |
@@ -747,31 +792,34 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
747 | ia64_mca_modify_comm(previous_current); | 792 | ia64_mca_modify_comm(previous_current); |
748 | goto no_mod; | 793 | goto no_mod; |
749 | } | 794 | } |
750 | if (r13 != sos->prev_IA64_KR_CURRENT) { | 795 | |
751 | msg = "inconsistent previous current and r13"; | 796 | if (!mca_recover_range(ms->pmsa_iip)) { |
752 | goto no_mod; | 797 | if (r13 != sos->prev_IA64_KR_CURRENT) { |
753 | } | 798 | msg = "inconsistent previous current and r13"; |
754 | if ((r12 - r13) >= KERNEL_STACK_SIZE) { | 799 | goto no_mod; |
755 | msg = "inconsistent r12 and r13"; | 800 | } |
756 | goto no_mod; | 801 | if ((r12 - r13) >= KERNEL_STACK_SIZE) { |
757 | } | 802 | msg = "inconsistent r12 and r13"; |
758 | if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) { | 803 | goto no_mod; |
759 | msg = "inconsistent ar.bspstore and r13"; | 804 | } |
760 | goto no_mod; | 805 | if ((ar_bspstore - r13) >= KERNEL_STACK_SIZE) { |
761 | } | 806 | msg = "inconsistent ar.bspstore and r13"; |
762 | va.p = old_bspstore; | 807 | goto no_mod; |
763 | if (va.f.reg < 5) { | 808 | } |
764 | msg = "old_bspstore is in the wrong region"; | 809 | va.p = old_bspstore; |
765 | goto no_mod; | 810 | if (va.f.reg < 5) { |
766 | } | 811 | msg = "old_bspstore is in the wrong region"; |
767 | if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) { | 812 | goto no_mod; |
768 | msg = "inconsistent ar.bsp and r13"; | 813 | } |
769 | goto no_mod; | 814 | if ((ar_bsp - r13) >= KERNEL_STACK_SIZE) { |
770 | } | 815 | msg = "inconsistent ar.bsp and r13"; |
771 | size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8; | 816 | goto no_mod; |
772 | if (ar_bspstore + size > r12) { | 817 | } |
773 | msg = "no room for blocked state"; | 818 | size += (ia64_rse_skip_regs(old_bspstore, slots) - old_bspstore) * 8; |
774 | goto no_mod; | 819 | if (ar_bspstore + size > r12) { |
820 | msg = "no room for blocked state"; | ||
821 | goto no_mod; | ||
822 | } | ||
775 | } | 823 | } |
776 | 824 | ||
777 | ia64_mca_modify_comm(previous_current); | 825 | ia64_mca_modify_comm(previous_current); |
@@ -1443,7 +1491,7 @@ static struct irqaction mca_cpep_irqaction = { | |||
1443 | * format most of the fields. | 1491 | * format most of the fields. |
1444 | */ | 1492 | */ |
1445 | 1493 | ||
1446 | static void | 1494 | static void __cpuinit |
1447 | format_mca_init_stack(void *mca_data, unsigned long offset, | 1495 | format_mca_init_stack(void *mca_data, unsigned long offset, |
1448 | const char *type, int cpu) | 1496 | const char *type, int cpu) |
1449 | { | 1497 | { |
@@ -1467,7 +1515,7 @@ format_mca_init_stack(void *mca_data, unsigned long offset, | |||
1467 | 1515 | ||
1468 | /* Do per-CPU MCA-related initialization. */ | 1516 | /* Do per-CPU MCA-related initialization. */ |
1469 | 1517 | ||
1470 | void __devinit | 1518 | void __cpuinit |
1471 | ia64_mca_cpu_init(void *cpu_data) | 1519 | ia64_mca_cpu_init(void *cpu_data) |
1472 | { | 1520 | { |
1473 | void *pal_vaddr; | 1521 | void *pal_vaddr; |