Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | /* * ras.c * Copyright (C) 2001 Dave Engebretsen IBM Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Change Activity: * 2001/09/21 : engebret : Created with minimal EPOW and HW exception support. * End Change Activity */ #include <linux/ptrace.h> #include <linux/errno.h> #include <linux/threads.h> #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/timex.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/irq.h> #include <linux/proc_fs.h> #include <linux/random.h> #include <linux/sysrq.h> #include <asm/uaccess.h> #include <asm/bitops.h> #include <asm/system.h> #include <asm/io.h> #include <asm/pgtable.h> #include <asm/irq.h> #include <asm/cache.h> #include <asm/prom.h> #include <asm/ptrace.h> #include <asm/iSeries/LparData.h> #include <asm/machdep.h> #include <asm/rtas.h> #include <asm/ppcdebug.h> static void ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs); static void ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs); void init_ras_IRQ(void); /* #define DEBUG */ /* * Initialize handlers for the set of interrupts caused by hardware errors * and power system events. */ void init_ras_IRQ(void) { struct device_node *np; unsigned int *ireg, len, i; if((np = find_path_device("/event-sources/internal-errors")) && (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", &len))) { for(i=0; i<(len / sizeof(*ireg)); i++) { request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, &ras_error_interrupt, 0, "RAS_ERROR", NULL); ireg++; } } if((np = find_path_device("/event-sources/epow-events")) && (ireg = (unsigned int *)get_property(np, "open-pic-interrupt", &len))) { for(i=0; i<(len / sizeof(*ireg)); i++) { request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, &ras_epow_interrupt, 0, "RAS_EPOW", NULL); ireg++; } } } /* * Handle power subsystem events (EPOW). * * Presently we just log the event has occured. This should be fixed * to examine the type of power failure and take appropriate action where * the time horizon permits something useful to be done. */ static void ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct rtas_error_log log_entry; unsigned int size = sizeof(log_entry); long status = 0xdeadbeef; status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 0x500, irq, EPOW_WARNING | POWERMGM_EVENTS, 1, /* Time Critical */ __pa(&log_entry), size); udbg_printf("EPOW <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_WARNING "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status); } /* * Handle hardware error interrupts. * * RTAS check-exception is called to collect data on the exception. If * the error is deemed recoverable, we log a warning and return. * For nonrecoverable errors, an error is logged and we stop all processing * as quickly as possible in order to prevent propagation of the failure. */ static void ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct rtas_error_log log_entry; unsigned int size = sizeof(log_entry); long status = 0xdeadbeef; status = rtas_call(rtas_token("check-exception"), 6, 1, NULL, 0x500, irq, INTERNAL_ERROR, 1, /* Time Critical */ __pa(&log_entry), size); if((status != 1) && (log_entry.severity >= SEVERITY_ERROR_SYNC)) { udbg_printf("HW Error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_EMERG "Error: Fatal hardware error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); #ifndef DEBUG /* Don't actually power off when debugging so we can test * without actually failing while injecting errors. */ ppc_md.power_off(); #endif } else { udbg_printf("Recoverable HW Error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); printk(KERN_WARNING "Warning: Recoverable hardware error <0x%lx 0x%lx>\n", *((unsigned long *)&log_entry), status); return; } } |