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