diff options
Diffstat (limited to 'arch/ia64/kernel/mca.c')
-rw-r--r-- | arch/ia64/kernel/mca.c | 90 |
1 files changed, 60 insertions, 30 deletions
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index ee7eec9ee576..b57e723f194c 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c | |||
@@ -281,14 +281,10 @@ ia64_mca_log_sal_error_record(int sal_info_type) | |||
281 | ia64_sal_clear_state_info(sal_info_type); | 281 | ia64_sal_clear_state_info(sal_info_type); |
282 | } | 282 | } |
283 | 283 | ||
284 | /* | ||
285 | * platform dependent error handling | ||
286 | */ | ||
287 | #ifndef PLATFORM_MCA_HANDLERS | ||
288 | |||
289 | #ifdef CONFIG_ACPI | 284 | #ifdef CONFIG_ACPI |
290 | 285 | ||
291 | int cpe_vector = -1; | 286 | int cpe_vector = -1; |
287 | int ia64_cpe_irq = -1; | ||
292 | 288 | ||
293 | static irqreturn_t | 289 | static irqreturn_t |
294 | ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) | 290 | ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) |
@@ -377,8 +373,6 @@ ia64_mca_register_cpev (int cpev) | |||
377 | } | 373 | } |
378 | #endif /* CONFIG_ACPI */ | 374 | #endif /* CONFIG_ACPI */ |
379 | 375 | ||
380 | #endif /* PLATFORM_MCA_HANDLERS */ | ||
381 | |||
382 | /* | 376 | /* |
383 | * ia64_mca_cmc_vector_setup | 377 | * ia64_mca_cmc_vector_setup |
384 | * | 378 | * |
@@ -630,6 +624,32 @@ copy_reg(const u64 *fr, u64 fnat, u64 *tr, u64 *tnat) | |||
630 | *tnat |= (nat << tslot); | 624 | *tnat |= (nat << tslot); |
631 | } | 625 | } |
632 | 626 | ||
627 | /* Change the comm field on the MCA/INT task to include the pid that | ||
628 | * was interrupted, it makes for easier debugging. If that pid was 0 | ||
629 | * (swapper or nested MCA/INIT) then use the start of the previous comm | ||
630 | * field suffixed with its cpu. | ||
631 | */ | ||
632 | |||
633 | static void | ||
634 | ia64_mca_modify_comm(const task_t *previous_current) | ||
635 | { | ||
636 | char *p, comm[sizeof(current->comm)]; | ||
637 | if (previous_current->pid) | ||
638 | snprintf(comm, sizeof(comm), "%s %d", | ||
639 | current->comm, previous_current->pid); | ||
640 | else { | ||
641 | int l; | ||
642 | if ((p = strchr(previous_current->comm, ' '))) | ||
643 | l = p - previous_current->comm; | ||
644 | else | ||
645 | l = strlen(previous_current->comm); | ||
646 | snprintf(comm, sizeof(comm), "%s %*s %d", | ||
647 | current->comm, l, previous_current->comm, | ||
648 | task_thread_info(previous_current)->cpu); | ||
649 | } | ||
650 | memcpy(current->comm, comm, sizeof(current->comm)); | ||
651 | } | ||
652 | |||
633 | /* On entry to this routine, we are running on the per cpu stack, see | 653 | /* On entry to this routine, we are running on the per cpu stack, see |
634 | * mca_asm.h. The original stack has not been touched by this event. Some of | 654 | * mca_asm.h. The original stack has not been touched by this event. Some of |
635 | * the original stack's registers will be in the RBS on this stack. This stack | 655 | * the original stack's registers will be in the RBS on this stack. This stack |
@@ -648,7 +668,7 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
648 | struct ia64_sal_os_state *sos, | 668 | struct ia64_sal_os_state *sos, |
649 | const char *type) | 669 | const char *type) |
650 | { | 670 | { |
651 | char *p, comm[sizeof(current->comm)]; | 671 | char *p; |
652 | ia64_va va; | 672 | ia64_va va; |
653 | extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ | 673 | extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ |
654 | const pal_min_state_area_t *ms = sos->pal_min_state; | 674 | const pal_min_state_area_t *ms = sos->pal_min_state; |
@@ -721,6 +741,10 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
721 | /* Verify the previous stack state before we change it */ | 741 | /* Verify the previous stack state before we change it */ |
722 | if (user_mode(regs)) { | 742 | if (user_mode(regs)) { |
723 | msg = "occurred in user space"; | 743 | msg = "occurred in user space"; |
744 | /* previous_current is guaranteed to be valid when the task was | ||
745 | * in user space, so ... | ||
746 | */ | ||
747 | ia64_mca_modify_comm(previous_current); | ||
724 | goto no_mod; | 748 | goto no_mod; |
725 | } | 749 | } |
726 | if (r13 != sos->prev_IA64_KR_CURRENT) { | 750 | if (r13 != sos->prev_IA64_KR_CURRENT) { |
@@ -750,25 +774,7 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
750 | goto no_mod; | 774 | goto no_mod; |
751 | } | 775 | } |
752 | 776 | ||
753 | /* Change the comm field on the MCA/INT task to include the pid that | 777 | ia64_mca_modify_comm(previous_current); |
754 | * was interrupted, it makes for easier debugging. If that pid was 0 | ||
755 | * (swapper or nested MCA/INIT) then use the start of the previous comm | ||
756 | * field suffixed with its cpu. | ||
757 | */ | ||
758 | if (previous_current->pid) | ||
759 | snprintf(comm, sizeof(comm), "%s %d", | ||
760 | current->comm, previous_current->pid); | ||
761 | else { | ||
762 | int l; | ||
763 | if ((p = strchr(previous_current->comm, ' '))) | ||
764 | l = p - previous_current->comm; | ||
765 | else | ||
766 | l = strlen(previous_current->comm); | ||
767 | snprintf(comm, sizeof(comm), "%s %*s %d", | ||
768 | current->comm, l, previous_current->comm, | ||
769 | task_thread_info(previous_current)->cpu); | ||
770 | } | ||
771 | memcpy(current->comm, comm, sizeof(current->comm)); | ||
772 | 778 | ||
773 | /* Make the original task look blocked. First stack a struct pt_regs, | 779 | /* Make the original task look blocked. First stack a struct pt_regs, |
774 | * describing the state at the time of interrupt. mca_asm.S built a | 780 | * describing the state at the time of interrupt. mca_asm.S built a |
@@ -908,7 +914,7 @@ no_mod: | |||
908 | static void | 914 | static void |
909 | ia64_wait_for_slaves(int monarch) | 915 | ia64_wait_for_slaves(int monarch) |
910 | { | 916 | { |
911 | int c, wait = 0; | 917 | int c, wait = 0, missing = 0; |
912 | for_each_online_cpu(c) { | 918 | for_each_online_cpu(c) { |
913 | if (c == monarch) | 919 | if (c == monarch) |
914 | continue; | 920 | continue; |
@@ -919,15 +925,32 @@ ia64_wait_for_slaves(int monarch) | |||
919 | } | 925 | } |
920 | } | 926 | } |
921 | if (!wait) | 927 | if (!wait) |
922 | return; | 928 | goto all_in; |
923 | for_each_online_cpu(c) { | 929 | for_each_online_cpu(c) { |
924 | if (c == monarch) | 930 | if (c == monarch) |
925 | continue; | 931 | continue; |
926 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { | 932 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) { |
927 | udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */ | 933 | udelay(5*1000000); /* wait 5 seconds for slaves (arbitrary) */ |
934 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) | ||
935 | missing = 1; | ||
928 | break; | 936 | break; |
929 | } | 937 | } |
930 | } | 938 | } |
939 | if (!missing) | ||
940 | goto all_in; | ||
941 | printk(KERN_INFO "OS MCA slave did not rendezvous on cpu"); | ||
942 | for_each_online_cpu(c) { | ||
943 | if (c == monarch) | ||
944 | continue; | ||
945 | if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE) | ||
946 | printk(" %d", c); | ||
947 | } | ||
948 | printk("\n"); | ||
949 | return; | ||
950 | |||
951 | all_in: | ||
952 | printk(KERN_INFO "All OS MCA slaves have reached rendezvous\n"); | ||
953 | return; | ||
931 | } | 954 | } |
932 | 955 | ||
933 | /* | 956 | /* |
@@ -953,6 +976,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
953 | task_t *previous_current; | 976 | task_t *previous_current; |
954 | 977 | ||
955 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ | 978 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ |
979 | console_loglevel = 15; /* make sure printks make it to console */ | ||
980 | printk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d monarch=%ld\n", | ||
981 | sos->proc_state_param, cpu, sos->monarch); | ||
982 | |||
956 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); | 983 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); |
957 | monarch_cpu = cpu; | 984 | monarch_cpu = cpu; |
958 | if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) | 985 | if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) |
@@ -1444,11 +1471,13 @@ void __devinit | |||
1444 | ia64_mca_cpu_init(void *cpu_data) | 1471 | ia64_mca_cpu_init(void *cpu_data) |
1445 | { | 1472 | { |
1446 | void *pal_vaddr; | 1473 | void *pal_vaddr; |
1474 | static int first_time = 1; | ||
1447 | 1475 | ||
1448 | if (smp_processor_id() == 0) { | 1476 | if (first_time) { |
1449 | void *mca_data; | 1477 | void *mca_data; |
1450 | int cpu; | 1478 | int cpu; |
1451 | 1479 | ||
1480 | first_time = 0; | ||
1452 | mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) | 1481 | mca_data = alloc_bootmem(sizeof(struct ia64_mca_cpu) |
1453 | * NR_CPUS + KERNEL_STACK_SIZE); | 1482 | * NR_CPUS + KERNEL_STACK_SIZE); |
1454 | mca_data = (void *)(((unsigned long)mca_data + | 1483 | mca_data = (void *)(((unsigned long)mca_data + |
@@ -1704,6 +1733,7 @@ ia64_mca_late_init(void) | |||
1704 | desc = irq_descp(irq); | 1733 | desc = irq_descp(irq); |
1705 | desc->status |= IRQ_PER_CPU; | 1734 | desc->status |= IRQ_PER_CPU; |
1706 | setup_irq(irq, &mca_cpe_irqaction); | 1735 | setup_irq(irq, &mca_cpe_irqaction); |
1736 | ia64_cpe_irq = irq; | ||
1707 | } | 1737 | } |
1708 | ia64_mca_register_cpev(cpe_vector); | 1738 | ia64_mca_register_cpev(cpe_vector); |
1709 | IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n", __FUNCTION__); | 1739 | IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n", __FUNCTION__); |