1 /* 2 * interfaces to log Chassis Codes via PDC (firmware) 3 * 4 * Copyright (C) 2002 Laurent Canet <canetl@esiee.fr> 5 * Copyright (C) 2002-2004 Thibaut VARENE <varenet@parisc-linux.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License, version 2, as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 #undef PDC_CHASSIS_DEBUG 22 #ifdef PDC_CHASSIS_DEBUG 23 #define DPRINTK(fmt, args...) printk(fmt, ## args) 24 #else 25 #define DPRINTK(fmt, args...) 26 #endif 27 28 #include <linux/init.h> 29 #include <linux/kernel.h> 30 #include <linux/reboot.h> 31 #include <linux/notifier.h> 32 #include <linux/cache.h> 33 34 #include <asm/pdc_chassis.h> 35 #include <asm/processor.h> 36 #include <asm/pdc.h> 37 #include <asm/pdcpat.h> 38 39 40 #ifdef CONFIG_PDC_CHASSIS 41 static int pdc_chassis_old __read_mostly = 0; 42 static unsigned int pdc_chassis_enabled __read_mostly = 1; 43 44 45 /** 46 * pdc_chassis_setup() - Enable/disable pdc_chassis code at boot time. 47 * @str configuration param: 0 to disable chassis log 48 * @return 1 49 */ 50 51 static int __init pdc_chassis_setup(char *str) 52 { 53 /*panic_timeout = simple_strtoul(str, NULL, 0);*/ 54 get_option(&str, &pdc_chassis_enabled); 55 return 1; 56 } 57 __setup("pdcchassis=", pdc_chassis_setup); 58 59 60 /** 61 * pdc_chassis_checkold() - Checks for old PDC_CHASSIS compatibility 62 * @pdc_chassis_old: 1 if old pdc chassis style 63 * 64 * Currently, only E class and A180 are known to work with this. 65 * Inspired by Christoph Plattner 66 */ 67 68 static void __init pdc_chassis_checkold(void) 69 { 70 switch(CPU_HVERSION) { 71 case 0x480: /* E25 */ 72 case 0x481: /* E35 */ 73 case 0x482: /* E45 */ 74 case 0x483: /* E55 */ 75 case 0x516: /* A180 */ 76 pdc_chassis_old = 1; 77 break; 78 79 default: 80 break; 81 } 82 DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old); 83 } 84 85 86 /** 87 * pdc_chassis_panic_event() - Called by the panic handler. 88 * 89 * As soon as a panic occurs, we should inform the PDC. 90 */ 91 92 static int pdc_chassis_panic_event(struct notifier_block *this, 93 unsigned long event, void *ptr) 94 { 95 pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC); 96 return NOTIFY_DONE; 97 } 98 99 100 static struct notifier_block pdc_chassis_panic_block = { 101 .notifier_call = pdc_chassis_panic_event, 102 .priority = INT_MAX, 103 }; 104 105 106 /** 107 * parisc_reboot_event() - Called by the reboot handler. 108 * 109 * As soon as a reboot occurs, we should inform the PDC. 110 */ 111 112 static int pdc_chassis_reboot_event(struct notifier_block *this, 113 unsigned long event, void *ptr) 114 { 115 pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN); 116 return NOTIFY_DONE; 117 } 118 119 120 static struct notifier_block pdc_chassis_reboot_block = { 121 .notifier_call = pdc_chassis_reboot_event, 122 .priority = INT_MAX, 123 }; 124 #endif /* CONFIG_PDC_CHASSIS */ 125 126 127 /** 128 * parisc_pdc_chassis_init() - Called at boot time. 129 */ 130 131 void __init parisc_pdc_chassis_init(void) 132 { 133 #ifdef CONFIG_PDC_CHASSIS 134 int handle = 0; 135 if (likely(pdc_chassis_enabled)) { 136 DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__); 137 138 /* Let see if we have something to handle... */ 139 /* Check for PDC_PAT or old LED Panel */ 140 pdc_chassis_checkold(); 141 if (is_pdc_pat()) { 142 printk(KERN_INFO "Enabling PDC_PAT chassis codes support.\n"); 143 handle = 1; 144 } 145 else if (unlikely(pdc_chassis_old)) { 146 printk(KERN_INFO "Enabling old style chassis LED panel support.\n"); 147 handle = 1; 148 } 149 150 if (handle) { 151 /* initialize panic notifier chain */ 152 atomic_notifier_chain_register(&panic_notifier_list, 153 &pdc_chassis_panic_block); 154 155 /* initialize reboot notifier chain */ 156 register_reboot_notifier(&pdc_chassis_reboot_block); 157 } 158 } 159 #endif /* CONFIG_PDC_CHASSIS */ 160 } 161 162 163 /** 164 * pdc_chassis_send_status() - Sends a predefined message to the chassis, 165 * and changes the front panel LEDs according to the new system state 166 * @retval: PDC call return value. 167 * 168 * Only machines with 64 bits PDC PAT and those reported in 169 * pdc_chassis_checkold() are supported atm. 170 * 171 * returns 0 if no error, -1 if no supported PDC is present or invalid message, 172 * else returns the appropriate PDC error code. 173 * 174 * For a list of predefined messages, see asm-parisc/pdc_chassis.h 175 */ 176 177 int pdc_chassis_send_status(int message) 178 { 179 /* Maybe we should do that in an other way ? */ 180 int retval = 0; 181 #ifdef CONFIG_PDC_CHASSIS 182 if (likely(pdc_chassis_enabled)) { 183 184 DPRINTK(KERN_DEBUG "%s: pdc_chassis_send_status(%d)\n", __FILE__, message); 185 186 #ifdef CONFIG_64BIT 187 if (is_pdc_pat()) { 188 switch(message) { 189 case PDC_CHASSIS_DIRECT_BSTART: 190 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BSTART, PDC_CHASSIS_LSTATE_RUN_NORMAL); 191 break; 192 193 case PDC_CHASSIS_DIRECT_BCOMPLETE: 194 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BCOMPLETE, PDC_CHASSIS_LSTATE_RUN_NORMAL); 195 break; 196 197 case PDC_CHASSIS_DIRECT_SHUTDOWN: 198 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_SHUTDOWN, PDC_CHASSIS_LSTATE_NONOS); 199 break; 200 201 case PDC_CHASSIS_DIRECT_PANIC: 202 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_PANIC, PDC_CHASSIS_LSTATE_RUN_CRASHREC); 203 break; 204 205 case PDC_CHASSIS_DIRECT_LPMC: 206 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_LPMC, PDC_CHASSIS_LSTATE_RUN_SYSINT); 207 break; 208 209 case PDC_CHASSIS_DIRECT_HPMC: 210 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_HPMC, PDC_CHASSIS_LSTATE_RUN_NCRIT); 211 break; 212 213 default: 214 retval = -1; 215 } 216 } else retval = -1; 217 #else 218 if (unlikely(pdc_chassis_old)) { 219 switch (message) { 220 case PDC_CHASSIS_DIRECT_BSTART: 221 case PDC_CHASSIS_DIRECT_BCOMPLETE: 222 retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN)); 223 break; 224 225 case PDC_CHASSIS_DIRECT_SHUTDOWN: 226 retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_SHUT)); 227 break; 228 229 case PDC_CHASSIS_DIRECT_HPMC: 230 case PDC_CHASSIS_DIRECT_PANIC: 231 retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_FLT)); 232 break; 233 234 case PDC_CHASSIS_DIRECT_LPMC: 235 retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_WARN)); 236 break; 237 238 default: 239 retval = -1; 240 } 241 } else retval = -1; 242 #endif /* CONFIG_64BIT */ 243 } /* if (pdc_chassis_enabled) */ 244 #endif /* CONFIG_PDC_CHASSIS */ 245 return retval; 246 } 247