aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/mca.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/mca.c')
-rw-r--r--arch/ia64/kernel/mca.c90
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
291int cpe_vector = -1; 286int cpe_vector = -1;
287int ia64_cpe_irq = -1;
292 288
293static irqreturn_t 289static irqreturn_t
294ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) 290ia64_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
633static void
634ia64_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:
908static void 914static void
909ia64_wait_for_slaves(int monarch) 915ia64_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
951all_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
1444ia64_mca_cpu_init(void *cpu_data) 1471ia64_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__);