diff options
Diffstat (limited to 'arch/ia64/kernel/mca.c')
-rw-r--r-- | arch/ia64/kernel/mca.c | 120 |
1 files changed, 95 insertions, 25 deletions
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 52c47da17246..355af15287c7 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c | |||
@@ -51,6 +51,9 @@ | |||
51 | * | 51 | * |
52 | * 2005-08-12 Keith Owens <kaos@sgi.com> | 52 | * 2005-08-12 Keith Owens <kaos@sgi.com> |
53 | * Convert MCA/INIT handlers to use per event stacks and SAL/OS state. | 53 | * Convert MCA/INIT handlers to use per event stacks and SAL/OS state. |
54 | * | ||
55 | * 2005-10-07 Keith Owens <kaos@sgi.com> | ||
56 | * Add notify_die() hooks. | ||
54 | */ | 57 | */ |
55 | #include <linux/config.h> | 58 | #include <linux/config.h> |
56 | #include <linux/types.h> | 59 | #include <linux/types.h> |
@@ -58,7 +61,6 @@ | |||
58 | #include <linux/sched.h> | 61 | #include <linux/sched.h> |
59 | #include <linux/interrupt.h> | 62 | #include <linux/interrupt.h> |
60 | #include <linux/irq.h> | 63 | #include <linux/irq.h> |
61 | #include <linux/kallsyms.h> | ||
62 | #include <linux/smp_lock.h> | 64 | #include <linux/smp_lock.h> |
63 | #include <linux/bootmem.h> | 65 | #include <linux/bootmem.h> |
64 | #include <linux/acpi.h> | 66 | #include <linux/acpi.h> |
@@ -69,6 +71,7 @@ | |||
69 | #include <linux/workqueue.h> | 71 | #include <linux/workqueue.h> |
70 | 72 | ||
71 | #include <asm/delay.h> | 73 | #include <asm/delay.h> |
74 | #include <asm/kdebug.h> | ||
72 | #include <asm/machvec.h> | 75 | #include <asm/machvec.h> |
73 | #include <asm/meminit.h> | 76 | #include <asm/meminit.h> |
74 | #include <asm/page.h> | 77 | #include <asm/page.h> |
@@ -132,6 +135,14 @@ extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); | |||
132 | 135 | ||
133 | static int mca_init; | 136 | static int mca_init; |
134 | 137 | ||
138 | |||
139 | static void inline | ||
140 | ia64_mca_spin(const char *func) | ||
141 | { | ||
142 | printk(KERN_EMERG "%s: spinning here, not returning to SAL\n", func); | ||
143 | while (1) | ||
144 | cpu_relax(); | ||
145 | } | ||
135 | /* | 146 | /* |
136 | * IA64_MCA log support | 147 | * IA64_MCA log support |
137 | */ | 148 | */ |
@@ -526,13 +537,16 @@ ia64_mca_wakeup_all(void) | |||
526 | * Outputs : None | 537 | * Outputs : None |
527 | */ | 538 | */ |
528 | static irqreturn_t | 539 | static irqreturn_t |
529 | ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) | 540 | ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs) |
530 | { | 541 | { |
531 | unsigned long flags; | 542 | unsigned long flags; |
532 | int cpu = smp_processor_id(); | 543 | int cpu = smp_processor_id(); |
533 | 544 | ||
534 | /* Mask all interrupts */ | 545 | /* Mask all interrupts */ |
535 | local_irq_save(flags); | 546 | local_irq_save(flags); |
547 | if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, 0, 0, 0) | ||
548 | == NOTIFY_STOP) | ||
549 | ia64_mca_spin(__FUNCTION__); | ||
536 | 550 | ||
537 | ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE; | 551 | ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE; |
538 | /* Register with the SAL monarch that the slave has | 552 | /* Register with the SAL monarch that the slave has |
@@ -540,10 +554,18 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) | |||
540 | */ | 554 | */ |
541 | ia64_sal_mc_rendez(); | 555 | ia64_sal_mc_rendez(); |
542 | 556 | ||
557 | if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, 0, 0, 0) | ||
558 | == NOTIFY_STOP) | ||
559 | ia64_mca_spin(__FUNCTION__); | ||
560 | |||
543 | /* Wait for the monarch cpu to exit. */ | 561 | /* Wait for the monarch cpu to exit. */ |
544 | while (monarch_cpu != -1) | 562 | while (monarch_cpu != -1) |
545 | cpu_relax(); /* spin until monarch leaves */ | 563 | cpu_relax(); /* spin until monarch leaves */ |
546 | 564 | ||
565 | if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, 0, 0, 0) | ||
566 | == NOTIFY_STOP) | ||
567 | ia64_mca_spin(__FUNCTION__); | ||
568 | |||
547 | /* Enable all interrupts */ | 569 | /* Enable all interrupts */ |
548 | local_irq_restore(flags); | 570 | local_irq_restore(flags); |
549 | return IRQ_HANDLED; | 571 | return IRQ_HANDLED; |
@@ -933,6 +955,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
933 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ | 955 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ |
934 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); | 956 | previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); |
935 | monarch_cpu = cpu; | 957 | monarch_cpu = cpu; |
958 | if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) | ||
959 | == NOTIFY_STOP) | ||
960 | ia64_mca_spin(__FUNCTION__); | ||
936 | ia64_wait_for_slaves(cpu); | 961 | ia64_wait_for_slaves(cpu); |
937 | 962 | ||
938 | /* Wakeup all the processors which are spinning in the rendezvous loop. | 963 | /* Wakeup all the processors which are spinning in the rendezvous loop. |
@@ -942,6 +967,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
942 | * spinning in SAL does not work. | 967 | * spinning in SAL does not work. |
943 | */ | 968 | */ |
944 | ia64_mca_wakeup_all(); | 969 | ia64_mca_wakeup_all(); |
970 | if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, 0, 0, 0) | ||
971 | == NOTIFY_STOP) | ||
972 | ia64_mca_spin(__FUNCTION__); | ||
945 | 973 | ||
946 | /* Get the MCA error record and log it */ | 974 | /* Get the MCA error record and log it */ |
947 | ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); | 975 | ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); |
@@ -960,6 +988,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
960 | ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); | 988 | ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); |
961 | sos->os_status = IA64_MCA_CORRECTED; | 989 | sos->os_status = IA64_MCA_CORRECTED; |
962 | } | 990 | } |
991 | if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, 0, 0, recover) | ||
992 | == NOTIFY_STOP) | ||
993 | ia64_mca_spin(__FUNCTION__); | ||
963 | 994 | ||
964 | set_curr_task(cpu, previous_current); | 995 | set_curr_task(cpu, previous_current); |
965 | monarch_cpu = -1; | 996 | monarch_cpu = -1; |
@@ -1188,6 +1219,37 @@ ia64_mca_cpe_poll (unsigned long dummy) | |||
1188 | 1219 | ||
1189 | #endif /* CONFIG_ACPI */ | 1220 | #endif /* CONFIG_ACPI */ |
1190 | 1221 | ||
1222 | static int | ||
1223 | default_monarch_init_process(struct notifier_block *self, unsigned long val, void *data) | ||
1224 | { | ||
1225 | int c; | ||
1226 | struct task_struct *g, *t; | ||
1227 | if (val != DIE_INIT_MONARCH_PROCESS) | ||
1228 | return NOTIFY_DONE; | ||
1229 | printk(KERN_ERR "Processes interrupted by INIT -"); | ||
1230 | for_each_online_cpu(c) { | ||
1231 | struct ia64_sal_os_state *s; | ||
1232 | t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET); | ||
1233 | s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET); | ||
1234 | g = s->prev_task; | ||
1235 | if (g) { | ||
1236 | if (g->pid) | ||
1237 | printk(" %d", g->pid); | ||
1238 | else | ||
1239 | printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g); | ||
1240 | } | ||
1241 | } | ||
1242 | printk("\n\n"); | ||
1243 | if (read_trylock(&tasklist_lock)) { | ||
1244 | do_each_thread (g, t) { | ||
1245 | printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); | ||
1246 | show_stack(t, NULL); | ||
1247 | } while_each_thread (g, t); | ||
1248 | read_unlock(&tasklist_lock); | ||
1249 | } | ||
1250 | return NOTIFY_DONE; | ||
1251 | } | ||
1252 | |||
1191 | /* | 1253 | /* |
1192 | * C portion of the OS INIT handler | 1254 | * C portion of the OS INIT handler |
1193 | * | 1255 | * |
@@ -1212,8 +1274,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
1212 | static atomic_t slaves; | 1274 | static atomic_t slaves; |
1213 | static atomic_t monarchs; | 1275 | static atomic_t monarchs; |
1214 | task_t *previous_current; | 1276 | task_t *previous_current; |
1215 | int cpu = smp_processor_id(), c; | 1277 | int cpu = smp_processor_id(); |
1216 | struct task_struct *g, *t; | ||
1217 | 1278 | ||
1218 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ | 1279 | oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ |
1219 | console_loglevel = 15; /* make sure printks make it to console */ | 1280 | console_loglevel = 15; /* make sure printks make it to console */ |
@@ -1253,8 +1314,17 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
1253 | ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT; | 1314 | ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT; |
1254 | while (monarch_cpu == -1) | 1315 | while (monarch_cpu == -1) |
1255 | cpu_relax(); /* spin until monarch enters */ | 1316 | cpu_relax(); /* spin until monarch enters */ |
1317 | if (notify_die(DIE_INIT_SLAVE_ENTER, "INIT", regs, 0, 0, 0) | ||
1318 | == NOTIFY_STOP) | ||
1319 | ia64_mca_spin(__FUNCTION__); | ||
1320 | if (notify_die(DIE_INIT_SLAVE_PROCESS, "INIT", regs, 0, 0, 0) | ||
1321 | == NOTIFY_STOP) | ||
1322 | ia64_mca_spin(__FUNCTION__); | ||
1256 | while (monarch_cpu != -1) | 1323 | while (monarch_cpu != -1) |
1257 | cpu_relax(); /* spin until monarch leaves */ | 1324 | cpu_relax(); /* spin until monarch leaves */ |
1325 | if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, 0, 0, 0) | ||
1326 | == NOTIFY_STOP) | ||
1327 | ia64_mca_spin(__FUNCTION__); | ||
1258 | printk("Slave on cpu %d returning to normal service.\n", cpu); | 1328 | printk("Slave on cpu %d returning to normal service.\n", cpu); |
1259 | set_curr_task(cpu, previous_current); | 1329 | set_curr_task(cpu, previous_current); |
1260 | ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; | 1330 | ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; |
@@ -1263,6 +1333,9 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
1263 | } | 1333 | } |
1264 | 1334 | ||
1265 | monarch_cpu = cpu; | 1335 | monarch_cpu = cpu; |
1336 | if (notify_die(DIE_INIT_MONARCH_ENTER, "INIT", regs, 0, 0, 0) | ||
1337 | == NOTIFY_STOP) | ||
1338 | ia64_mca_spin(__FUNCTION__); | ||
1266 | 1339 | ||
1267 | /* | 1340 | /* |
1268 | * Wait for a bit. On some machines (e.g., HP's zx2000 and zx6000, INIT can be | 1341 | * Wait for a bit. On some machines (e.g., HP's zx2000 and zx6000, INIT can be |
@@ -1273,27 +1346,16 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, | |||
1273 | printk("Delaying for 5 seconds...\n"); | 1346 | printk("Delaying for 5 seconds...\n"); |
1274 | udelay(5*1000000); | 1347 | udelay(5*1000000); |
1275 | ia64_wait_for_slaves(cpu); | 1348 | ia64_wait_for_slaves(cpu); |
1276 | printk(KERN_ERR "Processes interrupted by INIT -"); | 1349 | /* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through |
1277 | for_each_online_cpu(c) { | 1350 | * to default_monarch_init_process() above and just print all the |
1278 | struct ia64_sal_os_state *s; | 1351 | * tasks. |
1279 | t = __va(__per_cpu_mca[c] + IA64_MCA_CPU_INIT_STACK_OFFSET); | 1352 | */ |
1280 | s = (struct ia64_sal_os_state *)((char *)t + MCA_SOS_OFFSET); | 1353 | if (notify_die(DIE_INIT_MONARCH_PROCESS, "INIT", regs, 0, 0, 0) |
1281 | g = s->prev_task; | 1354 | == NOTIFY_STOP) |
1282 | if (g) { | 1355 | ia64_mca_spin(__FUNCTION__); |
1283 | if (g->pid) | 1356 | if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, 0, 0, 0) |
1284 | printk(" %d", g->pid); | 1357 | == NOTIFY_STOP) |
1285 | else | 1358 | ia64_mca_spin(__FUNCTION__); |
1286 | printk(" %d (cpu %d task 0x%p)", g->pid, task_cpu(g), g); | ||
1287 | } | ||
1288 | } | ||
1289 | printk("\n\n"); | ||
1290 | if (read_trylock(&tasklist_lock)) { | ||
1291 | do_each_thread (g, t) { | ||
1292 | printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); | ||
1293 | show_stack(t, NULL); | ||
1294 | } while_each_thread (g, t); | ||
1295 | read_unlock(&tasklist_lock); | ||
1296 | } | ||
1297 | printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu); | 1359 | printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu); |
1298 | atomic_dec(&monarchs); | 1360 | atomic_dec(&monarchs); |
1299 | set_curr_task(cpu, previous_current); | 1361 | set_curr_task(cpu, previous_current); |
@@ -1462,6 +1524,10 @@ ia64_mca_init(void) | |||
1462 | s64 rc; | 1524 | s64 rc; |
1463 | struct ia64_sal_retval isrv; | 1525 | struct ia64_sal_retval isrv; |
1464 | u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ | 1526 | u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ |
1527 | static struct notifier_block default_init_monarch_nb = { | ||
1528 | .notifier_call = default_monarch_init_process, | ||
1529 | .priority = 0/* we need to notified last */ | ||
1530 | }; | ||
1465 | 1531 | ||
1466 | IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); | 1532 | IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); |
1467 | 1533 | ||
@@ -1555,6 +1621,10 @@ ia64_mca_init(void) | |||
1555 | "(status %ld)\n", rc); | 1621 | "(status %ld)\n", rc); |
1556 | return; | 1622 | return; |
1557 | } | 1623 | } |
1624 | if (register_die_notifier(&default_init_monarch_nb)) { | ||
1625 | printk(KERN_ERR "Failed to register default monarch INIT process\n"); | ||
1626 | return; | ||
1627 | } | ||
1558 | 1628 | ||
1559 | IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__); | 1629 | IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__); |
1560 | 1630 | ||