aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64')
-rw-r--r--arch/ia64/kernel/ivt.S1
-rw-r--r--arch/ia64/kernel/mca.c98
-rw-r--r--arch/ia64/kernel/mca_drv.c22
-rw-r--r--arch/ia64/kernel/mca_drv.h7
-rw-r--r--arch/ia64/kernel/mca_drv_asm.S13
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S9
6 files changed, 109 insertions, 41 deletions
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index dcd906fe5749..829a43cab797 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -865,6 +865,7 @@ ENTRY(interrupt)
865 ;; 865 ;;
866 SAVE_REST 866 SAVE_REST
867 ;; 867 ;;
868 MCA_RECOVER_RANGE(interrupt)
868 alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group 869 alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group
869 mov out0=cr.ivr // pass cr.ivr as first arg 870 mov out0=cr.ivr // pass cr.ivr as first arg
870 add out1=16,sp // pass pointer to pt_regs as second arg 871 add out1=16,sp // pass pointer to pt_regs as second arg
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 */
298int
299search_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. */
320int 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}
327EXPORT_SYMBOL_GPL(mca_recover_range);
328
284#ifdef CONFIG_ACPI 329#ifdef CONFIG_ACPI
285 330
286int cpe_vector = -1; 331int 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);
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index e883d85906db..37c88eb55873 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -6,6 +6,7 @@
6 * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) 6 * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com)
7 * Copyright (C) 2005 Silicon Graphics, Inc 7 * Copyright (C) 2005 Silicon Graphics, Inc
8 * Copyright (C) 2005 Keith Owens <kaos@sgi.com> 8 * Copyright (C) 2005 Keith Owens <kaos@sgi.com>
9 * Copyright (C) 2006 Russ Anderson <rja@sgi.com>
9 */ 10 */
10#include <linux/config.h> 11#include <linux/config.h>
11#include <linux/types.h> 12#include <linux/types.h>
@@ -121,11 +122,12 @@ mca_page_isolate(unsigned long paddr)
121 */ 122 */
122 123
123void 124void
124mca_handler_bh(unsigned long paddr) 125mca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr)
125{ 126{
126 printk(KERN_ERR 127 printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, "
127 "OS_MCA: process [pid: %d](%s) encounters MCA (paddr=%lx)\n", 128 "iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n",
128 current->pid, current->comm, paddr); 129 raw_smp_processor_id(), current->pid, current->uid,
130 iip, ipsr, paddr, current->comm);
129 131
130 spin_lock(&mca_bh_lock); 132 spin_lock(&mca_bh_lock);
131 switch (mca_page_isolate(paddr)) { 133 switch (mca_page_isolate(paddr)) {
@@ -442,21 +444,26 @@ recover_from_read_error(slidx_table_t *slidx,
442 if (!peidx_bottom(peidx) || !(peidx_bottom(peidx)->valid.minstate)) 444 if (!peidx_bottom(peidx) || !(peidx_bottom(peidx)->valid.minstate))
443 return 0; 445 return 0;
444 psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr); 446 psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr);
447 psr2 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_xpsr);
445 448
446 /* 449 /*
447 * Check the privilege level of interrupted context. 450 * Check the privilege level of interrupted context.
448 * If it is user-mode, then terminate affected process. 451 * If it is user-mode, then terminate affected process.
449 */ 452 */
450 if (psr1->cpl != 0) { 453
454 pmsa = sos->pal_min_state;
455 if (psr1->cpl != 0 ||
456 ((psr2->cpl != 0) && mca_recover_range(pmsa->pmsa_iip))) {
451 smei = peidx_bus_check(peidx, 0); 457 smei = peidx_bus_check(peidx, 0);
452 if (smei->valid.target_identifier) { 458 if (smei->valid.target_identifier) {
453 /* 459 /*
454 * setup for resume to bottom half of MCA, 460 * setup for resume to bottom half of MCA,
455 * "mca_handler_bhhook" 461 * "mca_handler_bhhook"
456 */ 462 */
457 pmsa = sos->pal_min_state; 463 /* pass to bhhook as argument (gr8, ...) */
458 /* pass to bhhook as 1st argument (gr8) */
459 pmsa->pmsa_gr[8-1] = smei->target_identifier; 464 pmsa->pmsa_gr[8-1] = smei->target_identifier;
465 pmsa->pmsa_gr[9-1] = pmsa->pmsa_iip;
466 pmsa->pmsa_gr[10-1] = pmsa->pmsa_ipsr;
460 /* set interrupted return address (but no use) */ 467 /* set interrupted return address (but no use) */
461 pmsa->pmsa_br0 = pmsa->pmsa_iip; 468 pmsa->pmsa_br0 = pmsa->pmsa_iip;
462 /* change resume address to bottom half */ 469 /* change resume address to bottom half */
@@ -466,6 +473,7 @@ recover_from_read_error(slidx_table_t *slidx,
466 psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr; 473 psr2 = (struct ia64_psr *)&pmsa->pmsa_ipsr;
467 psr2->cpl = 0; 474 psr2->cpl = 0;
468 psr2->ri = 0; 475 psr2->ri = 0;
476 psr2->bn = 1;
469 psr2->i = 0; 477 psr2->i = 0;
470 478
471 return 1; 479 return 1;
diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h
index e2f6fa1e0ef6..31a2e52bb16f 100644
--- a/arch/ia64/kernel/mca_drv.h
+++ b/arch/ia64/kernel/mca_drv.h
@@ -111,3 +111,10 @@ typedef struct slidx_table {
111 slidx_foreach_entry(__pos, &((slidx)->sec)) { __count++; }\ 111 slidx_foreach_entry(__pos, &((slidx)->sec)) { __count++; }\
112 __count; }) 112 __count; })
113 113
114struct mca_table_entry {
115 int start_addr; /* location-relative starting address of MCA recoverable range */
116 int end_addr; /* location-relative ending address of MCA recoverable range */
117};
118
119extern const struct mca_table_entry *search_mca_tables (unsigned long addr);
120extern int mca_recover_range(unsigned long);
diff --git a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S
index 3f298ee4d00c..e6a580d354b9 100644
--- a/arch/ia64/kernel/mca_drv_asm.S
+++ b/arch/ia64/kernel/mca_drv_asm.S
@@ -14,15 +14,12 @@
14 14
15GLOBAL_ENTRY(mca_handler_bhhook) 15GLOBAL_ENTRY(mca_handler_bhhook)
16 invala // clear RSE ? 16 invala // clear RSE ?
17 ;;
18 cover 17 cover
19 ;; 18 ;;
20 clrrrb 19 clrrrb
21 ;; 20 ;;
22 alloc r16=ar.pfs,0,2,1,0 // make a new frame 21 alloc r16=ar.pfs,0,2,3,0 // make a new frame
23 ;;
24 mov ar.rsc=0 22 mov ar.rsc=0
25 ;;
26 mov r13=IA64_KR(CURRENT) // current task pointer 23 mov r13=IA64_KR(CURRENT) // current task pointer
27 ;; 24 ;;
28 mov r2=r13 25 mov r2=r13
@@ -30,7 +27,6 @@ GLOBAL_ENTRY(mca_handler_bhhook)
30 addl r22=IA64_RBS_OFFSET,r2 27 addl r22=IA64_RBS_OFFSET,r2
31 ;; 28 ;;
32 mov ar.bspstore=r22 29 mov ar.bspstore=r22
33 ;;
34 addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 30 addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2
35 ;; 31 ;;
36 adds r2=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 32 adds r2=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13
@@ -40,12 +36,12 @@ GLOBAL_ENTRY(mca_handler_bhhook)
40 movl loc1=mca_handler_bh // recovery C function 36 movl loc1=mca_handler_bh // recovery C function
41 ;; 37 ;;
42 mov out0=r8 // poisoned address 38 mov out0=r8 // poisoned address
39 mov out1=r9 // iip
40 mov out2=r10 // psr
43 mov b6=loc1 41 mov b6=loc1
44 ;; 42 ;;
45 mov loc1=rp 43 mov loc1=rp
46 ;; 44 ssm psr.i | psr.ic
47 ssm psr.i
48 ;;
49 br.call.sptk.many rp=b6 // does not return ... 45 br.call.sptk.many rp=b6 // does not return ...
50 ;; 46 ;;
51 mov ar.pfs=loc0 47 mov ar.pfs=loc0
@@ -53,5 +49,4 @@ GLOBAL_ENTRY(mca_handler_bhhook)
53 ;; 49 ;;
54 mov r8=r0 50 mov r8=r0
55 br.ret.sptk.many rp 51 br.ret.sptk.many rp
56 ;;
57END(mca_handler_bhhook) 52END(mca_handler_bhhook)
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 632d65cc0685..0b9e56dd7f05 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -130,6 +130,15 @@ SECTIONS
130 __initcall_end = .; 130 __initcall_end = .;
131 } 131 }
132 132
133 /* MCA table */
134 . = ALIGN(16);
135 __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET)
136 {
137 __start___mca_table = .;
138 *(__mca_table)
139 __stop___mca_table = .;
140 }
141
133 .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) 142 .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET)
134 { 143 {
135 __start___vtop_patchlist = .; 144 __start___vtop_patchlist = .;