diff options
Diffstat (limited to 'arch/ia64/kernel/mca.c')
-rw-r--r-- | arch/ia64/kernel/mca.c | 98 |
1 files changed, 73 insertions, 25 deletions
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index cedcae713e9f..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) |
@@ -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; |
@@ -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); |