Sven Schnelle | bc29483 | 2021-10-14 21:49:16 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 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> |
Helge Deller | d6ab9fc | 2022-01-07 14:05:11 +0100 | [diff] [blame] | 12 | #include <asm/ldcw.h> |
Helge Deller | 30f3089 | 2022-01-17 10:10:10 +0100 | [diff] [blame] | 13 | #include <asm/processor.h> |
Sven Schnelle | bc29483 | 2021-10-14 21:49:16 +0200 | [diff] [blame] | 14 | |
Helge Deller | d6ab9fc | 2022-01-07 14:05:11 +0100 | [diff] [blame] | 15 | static unsigned int __aligned(16) toc_lock = 1; |
Helge Deller | 180d0eb | 2022-01-13 11:58:05 +0100 | [diff] [blame] | 16 | DEFINE_PER_CPU_PAGE_ALIGNED(char [16384], toc_stack) __visible; |
Sven Schnelle | bc29483 | 2021-10-14 21:49:16 +0200 | [diff] [blame] | 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 | |
Helge Deller | d6ab9fc | 2022-01-07 14:05:11 +0100 | [diff] [blame] | 69 | /* verify we wrote regs to the correct stack */ |
| 70 | BUG_ON(regs != (struct pt_regs *)&per_cpu(toc_stack, raw_smp_processor_id())); |
Sven Schnelle | bc29483 | 2021-10-14 21:49:16 +0200 | [diff] [blame] | 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 |
Helge Deller | d6ab9fc | 2022-01-07 14:05:11 +0100 | [diff] [blame] | 83 | nmi_enter(); |
| 84 | |
Sven Schnelle | bc29483 | 2021-10-14 21:49:16 +0200 | [diff] [blame] | 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 |
Helge Deller | d6ab9fc | 2022-01-07 14:05:11 +0100 | [diff] [blame] | 89 | |
| 90 | /* serialize output, otherwise all CPUs write backtrace at once */ |
| 91 | while (__ldcw(&toc_lock) == 0) |
| 92 | ; /* wait */ |
Sven Schnelle | bc29483 | 2021-10-14 21:49:16 +0200 | [diff] [blame] | 93 | show_regs(regs); |
Helge Deller | d6ab9fc | 2022-01-07 14:05:11 +0100 | [diff] [blame] | 94 | toc_lock = 1; /* release lock for next CPU */ |
| 95 | |
| 96 | if (raw_smp_processor_id() != 0) |
| 97 | while (1) ; /* all but monarch CPU will wait endless. */ |
Sven Schnelle | bc29483 | 2021-10-14 21:49:16 +0200 | [diff] [blame] | 98 | |
| 99 | /* give other CPUs time to show their backtrace */ |
| 100 | mdelay(2000); |
Helge Deller | d6ab9fc | 2022-01-07 14:05:11 +0100 | [diff] [blame] | 101 | |
Sven Schnelle | bc29483 | 2021-10-14 21:49:16 +0200 | [diff] [blame] | 102 | machine_restart("TOC"); |
| 103 | |
| 104 | /* should never reach this */ |
| 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); |