diff options
-rw-r--r-- | arch/ia64/kernel/mca.c | 84 |
1 files changed, 55 insertions, 29 deletions
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 87fb7cecead0..b57e723f194c 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c | |||
@@ -281,11 +281,6 @@ 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; |
@@ -378,8 +373,6 @@ ia64_mca_register_cpev (int cpev) | |||
378 | } | 373 | } |
379 | #endif /* CONFIG_ACPI */ | 374 | #endif /* CONFIG_ACPI */ |
380 | 375 | ||
381 | #endif /* PLATFORM_MCA_HANDLERS */ | ||
382 | |||
383 | /* | 376 | /* |
384 | * ia64_mca_cmc_vector_setup | 377 | * ia64_mca_cmc_vector_setup |
385 | * | 378 | * |
@@ -631,6 +624,32 @@ copy_reg(const u64 *fr, u64 fnat, u64 *tr, u64 *tnat) | |||
631 | *tnat |= (nat << tslot); | 624 | *tnat |= (nat << tslot); |
632 | } | 625 | } |
633 | 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 | |||
634 | /* 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 |
635 | * 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 |
636 | * 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 |
@@ -649,7 +668,7 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
649 | struct ia64_sal_os_state *sos, | 668 | struct ia64_sal_os_state *sos, |
650 | const char *type) | 669 | const char *type) |
651 | { | 670 | { |
652 | char *p, comm[sizeof(current->comm)]; | 671 | char *p; |
653 | ia64_va va; | 672 | ia64_va va; |
654 | extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ | 673 | extern char ia64_leave_kernel[]; /* Need asm address, not function descriptor */ |
655 | const pal_min_state_area_t *ms = sos->pal_min_state; | 674 | const pal_min_state_area_t *ms = sos->pal_min_state; |
@@ -722,6 +741,10 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
722 | /* Verify the previous stack state before we change it */ | 741 | /* Verify the previous stack state before we change it */ |
723 | if (user_mode(regs)) { | 742 | if (user_mode(regs)) { |
724 | 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); | ||
725 | goto no_mod; | 748 | goto no_mod; |
726 | } | 749 | } |
727 | if (r13 != sos->prev_IA64_KR_CURRENT) { | 750 | if (r13 != sos->prev_IA64_KR_CURRENT) { |
@@ -751,25 +774,7 @@ ia64_mca_modify_original_stack(struct pt_regs *regs, | |||
751 | goto no_mod; | 774 | goto no_mod; |
752 | } | 775 | } |
753 | 776 | ||
754 | /* Change the comm field on the MCA/INT task to include the pid that | 777 | ia64_mca_modify_comm(previous_current); |
755 | * was interrupted, it makes for easier debugging. If that pid was 0 | ||
756 | * (swapper or nested MCA/INIT) then use the start of the previous comm | ||
757 | * field suffixed with its cpu. | ||
758 | */ | ||
759 | if (previous_current->pid) | ||
760 | snprintf(comm, sizeof(comm), "%s %d", | ||
761 | current->comm, previous_current->pid); | ||
762 | else { | ||
763 | int l; | ||
764 | if ((p = strchr(previous_current->comm, ' '))) | ||
765 | l = p - previous_current->comm; | ||
766 | else | ||
767 | l = strlen(previous_current->comm); | ||
768 | snprintf(comm, sizeof(comm), "%s %*s %d", | ||
769 | current->comm, l, previous_current->comm, | ||
770 | task_thread_info(previous_current)->cpu); | ||
771 | } | ||
772 | memcpy(current->comm, comm, sizeof(current->comm)); | ||
773 | 778 | ||
774 | /* 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, |
775 | * 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 |
@@ -909,7 +914,7 @@ no_mod: | |||
909 | static void | 914 | static void |
910 | ia64_wait_for_slaves(int monarch) | 915 | ia64_wait_for_slaves(int monarch) |
911 | { | 916 | { |
912 | int c, wait = 0; | 917 | int c, wait = 0, missing = 0; |
913 | for_each_online_cpu(c) { | 918 | for_each_online_cpu(c) { |
914 | if (c == monarch) | 919 | if (c == monarch) |
915 | continue; | 920 | continue; |
@@ -920,15 +925,32 @@ ia64_wait_for_slaves(int monarch) | |||
920 | } | 925 | } |
921 | } | 926 | } |
922 | if (!wait) | 927 | if (!wait) |
923 | return; | 928 | goto all_in; |
924 | for_each_online_cpu(c) { | 929 | for_each_online_cpu(c) { |
925 | if (c == monarch) | 930 | if (c == monarch) |
926 | continue; | 931 | continue; |
927 | 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) { |
928 | 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; | ||
929 | break; | 936 | break; |
930 | } | 937 | } |
931 | } | 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; | ||
932 | } | 954 | } |
933 | 955 | ||
934 | /* | 956 | /* |
@@ -954,6 +976,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
954 | task_t *previous_current; | 976 | task_t *previous_current; |
955 | 977 | ||
956 | 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 | |||
957 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); | 983 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); |
958 | monarch_cpu = cpu; | 984 | monarch_cpu = cpu; |
959 | 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) |