| 1 | |
| 2 |
|
| 3 | #include <linux/kernel.h>
|
| 4 | #include <linux/kgdb.h>
|
| 5 | #include <linux/printk.h>
|
| 6 | #include <linux/sched/debug.h>
|
| 7 | #include <linux/delay.h>
|
| 8 | #include <linux/reboot.h>
|
| 9 |
|
| 10 | #include <asm/pdc.h>
|
| 11 | #include <asm/pdc_chassis.h>
|
| 12 | #include <asm/ldcw.h>
|
| 13 | #include <asm/processor.h>
|
| 14 |
|
| 15 | static unsigned int __aligned(16) toc_lock = 1;
|
| 16 | DEFINE_PER_CPU_PAGE_ALIGNED(char [16384], toc_stack) __visible;
|
| 17 |
|
| 18 | static void toc20_to_pt_regs(struct pt_regs *regs, struct pdc_toc_pim_20 *toc)
|
| 19 | {
|
| 20 | int i;
|
| 21 |
|
| 22 | regs->gr[0] = (unsigned long)toc->cr[22];
|
| 23 |
|
| 24 | for (i = 1; i < 32; i++)
|
| 25 | regs->gr[i] = (unsigned long)toc->gr[i];
|
| 26 |
|
| 27 | for (i = 0; i < 8; i++)
|
| 28 | regs->sr[i] = (unsigned long)toc->sr[i];
|
| 29 |
|
| 30 | regs->iasq[0] = (unsigned long)toc->cr[17];
|
| 31 | regs->iasq[1] = (unsigned long)toc->iasq_back;
|
| 32 | regs->iaoq[0] = (unsigned long)toc->cr[18];
|
| 33 | regs->iaoq[1] = (unsigned long)toc->iaoq_back;
|
| 34 |
|
| 35 | regs->sar = (unsigned long)toc->cr[11];
|
| 36 | regs->iir = (unsigned long)toc->cr[19];
|
| 37 | regs->isr = (unsigned long)toc->cr[20];
|
| 38 | regs->ior = (unsigned long)toc->cr[21];
|
| 39 | }
|
| 40 |
|
| 41 | static void toc11_to_pt_regs(struct pt_regs *regs, struct pdc_toc_pim_11 *toc)
|
| 42 | {
|
| 43 | int i;
|
| 44 |
|
| 45 | regs->gr[0] = toc->cr[22];
|
| 46 |
|
| 47 | for (i = 1; i < 32; i++)
|
| 48 | regs->gr[i] = toc->gr[i];
|
| 49 |
|
| 50 | for (i = 0; i < 8; i++)
|
| 51 | regs->sr[i] = toc->sr[i];
|
| 52 |
|
| 53 | regs->iasq[0] = toc->cr[17];
|
| 54 | regs->iasq[1] = toc->iasq_back;
|
| 55 | regs->iaoq[0] = toc->cr[18];
|
| 56 | regs->iaoq[1] = toc->iaoq_back;
|
| 57 |
|
| 58 | regs->sar = toc->cr[11];
|
| 59 | regs->iir = toc->cr[19];
|
| 60 | regs->isr = toc->cr[20];
|
| 61 | regs->ior = toc->cr[21];
|
| 62 | }
|
| 63 |
|
| 64 | void notrace __noreturn __cold toc_intr(struct pt_regs *regs)
|
| 65 | {
|
| 66 | struct pdc_toc_pim_20 pim_data20;
|
| 67 | struct pdc_toc_pim_11 pim_data11;
|
| 68 |
|
| 69 |
|
| 70 | BUG_ON(regs != (struct pt_regs *)&per_cpu(toc_stack, raw_smp_processor_id()));
|
| 71 |
|
| 72 | if (boot_cpu_data.cpu_type >= pcxu) {
|
| 73 | if (pdc_pim_toc20(&pim_data20))
|
| 74 | panic("Failed to get PIM data");
|
| 75 | toc20_to_pt_regs(regs, &pim_data20);
|
| 76 | } else {
|
| 77 | if (pdc_pim_toc11(&pim_data11))
|
| 78 | panic("Failed to get PIM data");
|
| 79 | toc11_to_pt_regs(regs, &pim_data11);
|
| 80 | }
|
| 81 |
|
| 82 | #ifdef CONFIG_KGDB
|
| 83 | nmi_enter();
|
| 84 |
|
| 85 | if (atomic_read(&kgdb_active) != -1)
|
| 86 | kgdb_nmicallback(raw_smp_processor_id(), regs);
|
| 87 | kgdb_handle_exception(9, SIGTRAP, 0, regs);
|
| 88 | #endif
|
| 89 |
|
| 90 |
|
| 91 | while (__ldcw(&toc_lock) == 0)
|
| 92 | ;
|
| 93 | show_regs(regs);
|
| 94 | toc_lock = 1;
|
| 95 |
|
| 96 | if (raw_smp_processor_id() != 0)
|
| 97 | while (1) ;
|
| 98 |
|
| 99 |
|
| 100 | mdelay(2000);
|
| 101 |
|
| 102 | machine_restart("TOC");
|
| 103 |
|
| 104 |
|
| 105 | panic("TOC");
|
| 106 | }
|
| 107 |
|
| 108 | static __init int setup_toc(void)
|
| 109 | {
|
| 110 | unsigned int csum = 0;
|
| 111 | unsigned long toc_code = (unsigned long)dereference_function_descriptor(toc_handler);
|
| 112 | int i;
|
| 113 |
|
| 114 | PAGE0->vec_toc = __pa(toc_code) & 0xffffffff;
|
| 115 | #ifdef CONFIG_64BIT
|
| 116 | PAGE0->vec_toc_hi = __pa(toc_code) >> 32;
|
| 117 | #endif
|
| 118 | PAGE0->vec_toclen = toc_handler_size;
|
| 119 |
|
| 120 | for (i = 0; i < toc_handler_size/4; i++)
|
| 121 | csum += ((u32 *)toc_code)[i];
|
| 122 | toc_handler_csum = -csum;
|
| 123 | pr_info("TOC handler registered\n");
|
| 124 | return 0;
|
| 125 | }
|
| 126 | early_initcall(setup_toc);
|