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 as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 #undef PDC_CHASSIS_DEBUG 23 #ifdef PDC_CHASSIS_DEBUG 24 #define DPRINTK(fmt, args...) printk(fmt, ## args) 25 #else 26 #define DPRINTK(fmt, args...) 27 #endif 28 29 #include <linux/init.h> 30 #include <linux/kernel.h> 31 #include <linux/reboot.h> 32 #include <linux/notifier.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 = 0; 42 static unsigned int pdc_chassis_enabled = 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 (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 (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 notifier_chain_register(&panic_notifier_list, &pdc_chassis_panic_block); 153 154 /* initialize reboot notifier chain */ 155 register_reboot_notifier(&pdc_chassis_reboot_block); 156 } 157 } 158 #endif /* CONFIG_PDC_CHASSIS */ 159 } 160 161 162 /** 163 * pdc_chassis_send_status() - Sends a predefined message to the chassis, 164 * and changes the front panel LEDs according to the new system state 165 * @retval: PDC call return value. 166 * 167 * Only machines with 64 bits PDC PAT and those reported in 168 * pdc_chassis_checkold() are supported atm. 169 * 170 * returns 0 if no error, -1 if no supported PDC is present or invalid message, 171 * else returns the appropriate PDC error code. 172 * 173 * For a list of predefined messages, see asm-parisc/pdc_chassis.h 174 */ 175 176 int pdc_chassis_send_status(int message) 177 { 178 /* Maybe we should do that in an other way ? */ 179 int retval = 0; 180 #ifdef CONFIG_PDC_CHASSIS 181 if (pdc_chassis_enabled) { 182 183 DPRINTK(KERN_DEBUG "%s: pdc_chassis_send_status(%d)\n", __FILE__, message); 184 185 #ifdef CONFIG_64BIT 186 if (is_pdc_pat()) { 187 switch(message) { 188 case PDC_CHASSIS_DIRECT_BSTART: 189 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BSTART, PDC_CHASSIS_LSTATE_RUN_NORMAL); 190 break; 191 192 case PDC_CHASSIS_DIRECT_BCOMPLETE: 193 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BCOMPLETE, PDC_CHASSIS_LSTATE_RUN_NORMAL); 194 break; 195 196 case PDC_CHASSIS_DIRECT_SHUTDOWN: 197 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_SHUTDOWN, PDC_CHASSIS_LSTATE_NONOS); 198 break; 199 200 case PDC_CHASSIS_DIRECT_PANIC: 201 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_PANIC, PDC_CHASSIS_LSTATE_RUN_CRASHREC); 202 break; 203 204 case PDC_CHASSIS_DIRECT_LPMC: 205 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_LPMC, PDC_CHASSIS_LSTATE_RUN_SYSINT); 206 break; 207 208 case PDC_CHASSIS_DIRECT_HPMC: 209 retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_HPMC, PDC_CHASSIS_LSTATE_RUN_NCRIT); 210 break; 211 212 default: 213 retval = -1; 214 } 215 } else retval = -1; 216 #else 217 if (pdc_chassis_old) { 218 switch (message) { 219 case PDC_CHASSIS_DIRECT_BSTART: 220 case PDC_CHASSIS_DIRECT_BCOMPLETE: 221 retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN)); 222 break; 223 224 case PDC_CHASSIS_DIRECT_SHUTDOWN: 225 retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_SHUT)); 226 break; 227 228 case PDC_CHASSIS_DIRECT_HPMC: 229 case PDC_CHASSIS_DIRECT_PANIC: 230 retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_FLT)); 231 break; 232 233 case PDC_CHASSIS_DIRECT_LPMC: 234 retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_WARN)); 235 break; 236 237 default: 238 retval = -1; 239 } 240 } else retval = -1; 241 #endif /* CONFIG_64BIT */ 242 } /* if (pdc_chassis_enabled) */ 243 #endif /* CONFIG_PDC_CHASSIS */ 244 return retval; 245 } 246