• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: c; c-basic-offset: 8 -*- */
2 
3 /* Copyright (C) 1999,2001
4  *
5  * Author: J.E.J.Bottomley@HansenPartnership.com
6  *
7  * This file contains all the logic for manipulating the CAT bus
8  * in a level 5 machine.
9  *
10  * The CAT bus is a serial configuration and test bus.  Its primary
11  * uses are to probe the initial configuration of the system and to
12  * diagnose error conditions when a system interrupt occurs.  The low
13  * level interface is fairly primitive, so most of this file consists
14  * of bit shift manipulations to send and receive packets on the
15  * serial bus */
16 
17 #include <linux/types.h>
18 #include <linux/completion.h>
19 #include <linux/sched.h>
20 #include <asm/voyager.h>
21 #include <asm/vic.h>
22 #include <linux/ioport.h>
23 #include <linux/init.h>
24 #include <linux/slab.h>
25 #include <linux/delay.h>
26 #include <asm/io.h>
27 
28 #ifdef VOYAGER_CAT_DEBUG
29 #define CDEBUG(x)	printk x
30 #else
31 #define CDEBUG(x)
32 #endif
33 
34 /* the CAT command port */
35 #define CAT_CMD		(sspb + 0xe)
36 /* the CAT data port */
37 #define CAT_DATA	(sspb + 0xd)
38 
39 /* the internal cat functions */
40 static void cat_pack(__u8 * msg, __u16 start_bit, __u8 * data, __u16 num_bits);
41 static void cat_unpack(__u8 * msg, __u16 start_bit, __u8 * data,
42 		       __u16 num_bits);
43 static void cat_build_header(__u8 * header, const __u16 len,
44 			     const __u16 smallest_reg_bits,
45 			     const __u16 longest_reg_bits);
46 static int cat_sendinst(voyager_module_t * modp, voyager_asic_t * asicp,
47 			__u8 reg, __u8 op);
48 static int cat_getdata(voyager_module_t * modp, voyager_asic_t * asicp,
49 		       __u8 reg, __u8 * value);
50 static int cat_shiftout(__u8 * data, __u16 data_bytes, __u16 header_bytes,
51 			__u8 pad_bits);
52 static int cat_write(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg,
53 		     __u8 value);
54 static int cat_read(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg,
55 		    __u8 * value);
56 static int cat_subread(voyager_module_t * modp, voyager_asic_t * asicp,
57 		       __u16 offset, __u16 len, void *buf);
58 static int cat_senddata(voyager_module_t * modp, voyager_asic_t * asicp,
59 			__u8 reg, __u8 value);
60 static int cat_disconnect(voyager_module_t * modp, voyager_asic_t * asicp);
61 static int cat_connect(voyager_module_t * modp, voyager_asic_t * asicp);
62 
cat_module_name(int module_id)63 static inline const char *cat_module_name(int module_id)
64 {
65 	switch (module_id) {
66 	case 0x10:
67 		return "Processor Slot 0";
68 	case 0x11:
69 		return "Processor Slot 1";
70 	case 0x12:
71 		return "Processor Slot 2";
72 	case 0x13:
73 		return "Processor Slot 4";
74 	case 0x14:
75 		return "Memory Slot 0";
76 	case 0x15:
77 		return "Memory Slot 1";
78 	case 0x18:
79 		return "Primary Microchannel";
80 	case 0x19:
81 		return "Secondary Microchannel";
82 	case 0x1a:
83 		return "Power Supply Interface";
84 	case 0x1c:
85 		return "Processor Slot 5";
86 	case 0x1d:
87 		return "Processor Slot 6";
88 	case 0x1e:
89 		return "Processor Slot 7";
90 	case 0x1f:
91 		return "Processor Slot 8";
92 	default:
93 		return "Unknown Module";
94 	}
95 }
96 
97 static int sspb = 0;		/* stores the super port location */
98 int voyager_8slot = 0;		/* set to true if a 51xx monster */
99 
100 voyager_module_t *voyager_cat_list;
101 
102 /* the I/O port assignments for the VIC and QIC */
103 static struct resource vic_res = {
104 	.name = "Voyager Interrupt Controller",
105 	.start = 0xFC00,
106 	.end = 0xFC6F
107 };
108 static struct resource qic_res = {
109 	.name = "Quad Interrupt Controller",
110 	.start = 0xFC70,
111 	.end = 0xFCFF
112 };
113 
114 /* This function is used to pack a data bit stream inside a message.
115  * It writes num_bits of the data buffer in msg starting at start_bit.
116  * Note: This function assumes that any unused bit in the data stream
117  * is set to zero so that the ors will work correctly */
118 static void
cat_pack(__u8 * msg,const __u16 start_bit,__u8 * data,const __u16 num_bits)119 cat_pack(__u8 * msg, const __u16 start_bit, __u8 * data, const __u16 num_bits)
120 {
121 	/* compute initial shift needed */
122 	const __u16 offset = start_bit % BITS_PER_BYTE;
123 	__u16 len = num_bits / BITS_PER_BYTE;
124 	__u16 byte = start_bit / BITS_PER_BYTE;
125 	__u16 residue = (num_bits % BITS_PER_BYTE) + offset;
126 	int i;
127 
128 	/* adjust if we have more than a byte of residue */
129 	if (residue >= BITS_PER_BYTE) {
130 		residue -= BITS_PER_BYTE;
131 		len++;
132 	}
133 
134 	/* clear out the bits.  We assume here that if len==0 then
135 	 * residue >= offset.  This is always true for the catbus
136 	 * operations */
137 	msg[byte] &= 0xff << (BITS_PER_BYTE - offset);
138 	msg[byte++] |= data[0] >> offset;
139 	if (len == 0)
140 		return;
141 	for (i = 1; i < len; i++)
142 		msg[byte++] = (data[i - 1] << (BITS_PER_BYTE - offset))
143 		    | (data[i] >> offset);
144 	if (residue != 0) {
145 		__u8 mask = 0xff >> residue;
146 		__u8 last_byte = data[i - 1] << (BITS_PER_BYTE - offset)
147 		    | (data[i] >> offset);
148 
149 		last_byte &= ~mask;
150 		msg[byte] &= mask;
151 		msg[byte] |= last_byte;
152 	}
153 	return;
154 }
155 
156 /* unpack the data again (same arguments as cat_pack()). data buffer
157  * must be zero populated.
158  *
159  * Function: given a message string move to start_bit and copy num_bits into
160  * data (starting at bit 0 in data).
161  */
162 static void
cat_unpack(__u8 * msg,const __u16 start_bit,__u8 * data,const __u16 num_bits)163 cat_unpack(__u8 * msg, const __u16 start_bit, __u8 * data, const __u16 num_bits)
164 {
165 	/* compute initial shift needed */
166 	const __u16 offset = start_bit % BITS_PER_BYTE;
167 	__u16 len = num_bits / BITS_PER_BYTE;
168 	const __u8 last_bits = num_bits % BITS_PER_BYTE;
169 	__u16 byte = start_bit / BITS_PER_BYTE;
170 	int i;
171 
172 	if (last_bits != 0)
173 		len++;
174 
175 	/* special case: want < 8 bits from msg and we can get it from
176 	 * a single byte of the msg */
177 	if (len == 0 && BITS_PER_BYTE - offset >= num_bits) {
178 		data[0] = msg[byte] << offset;
179 		data[0] &= 0xff >> (BITS_PER_BYTE - num_bits);
180 		return;
181 	}
182 	for (i = 0; i < len; i++) {
183 		/* this annoying if has to be done just in case a read of
184 		 * msg one beyond the array causes a panic */
185 		if (offset != 0) {
186 			data[i] = msg[byte++] << offset;
187 			data[i] |= msg[byte] >> (BITS_PER_BYTE - offset);
188 		} else {
189 			data[i] = msg[byte++];
190 		}
191 	}
192 	/* do we need to truncate the final byte */
193 	if (last_bits != 0) {
194 		data[i - 1] &= 0xff << (BITS_PER_BYTE - last_bits);
195 	}
196 	return;
197 }
198 
199 static void
cat_build_header(__u8 * header,const __u16 len,const __u16 smallest_reg_bits,const __u16 longest_reg_bits)200 cat_build_header(__u8 * header, const __u16 len, const __u16 smallest_reg_bits,
201 		 const __u16 longest_reg_bits)
202 {
203 	int i;
204 	__u16 start_bit = (smallest_reg_bits - 1) % BITS_PER_BYTE;
205 	__u8 *last_byte = &header[len - 1];
206 
207 	if (start_bit == 0)
208 		start_bit = 1;	/* must have at least one bit in the hdr */
209 
210 	for (i = 0; i < len; i++)
211 		header[i] = 0;
212 
213 	for (i = start_bit; i > 0; i--)
214 		*last_byte = ((*last_byte) << 1) + 1;
215 
216 }
217 
218 static int
cat_sendinst(voyager_module_t * modp,voyager_asic_t * asicp,__u8 reg,__u8 op)219 cat_sendinst(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg, __u8 op)
220 {
221 	__u8 parity, inst, inst_buf[4] = { 0 };
222 	__u8 iseq[VOYAGER_MAX_SCAN_PATH], hseq[VOYAGER_MAX_REG_SIZE];
223 	__u16 ibytes, hbytes, padbits;
224 	int i;
225 
226 	/*
227 	 * Parity is the parity of the register number + 1 (READ_REGISTER
228 	 * and WRITE_REGISTER always add '1' to the number of bits == 1)
229 	 */
230 	parity = (__u8) (1 + (reg & 0x01) +
231 			 ((__u8) (reg & 0x02) >> 1) +
232 			 ((__u8) (reg & 0x04) >> 2) +
233 			 ((__u8) (reg & 0x08) >> 3)) % 2;
234 
235 	inst = ((parity << 7) | (reg << 2) | op);
236 
237 	outb(VOYAGER_CAT_IRCYC, CAT_CMD);
238 	if (!modp->scan_path_connected) {
239 		if (asicp->asic_id != VOYAGER_CAT_ID) {
240 			printk
241 			    ("**WARNING***: cat_sendinst has disconnected scan path not to CAT asic\n");
242 			return 1;
243 		}
244 		outb(VOYAGER_CAT_HEADER, CAT_DATA);
245 		outb(inst, CAT_DATA);
246 		if (inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
247 			CDEBUG(("VOYAGER CAT: cat_sendinst failed to get CAT_HEADER\n"));
248 			return 1;
249 		}
250 		return 0;
251 	}
252 	ibytes = modp->inst_bits / BITS_PER_BYTE;
253 	if ((padbits = modp->inst_bits % BITS_PER_BYTE) != 0) {
254 		padbits = BITS_PER_BYTE - padbits;
255 		ibytes++;
256 	}
257 	hbytes = modp->largest_reg / BITS_PER_BYTE;
258 	if (modp->largest_reg % BITS_PER_BYTE)
259 		hbytes++;
260 	CDEBUG(("cat_sendinst: ibytes=%d, hbytes=%d\n", ibytes, hbytes));
261 	/* initialise the instruction sequence to 0xff */
262 	for (i = 0; i < ibytes + hbytes; i++)
263 		iseq[i] = 0xff;
264 	cat_build_header(hseq, hbytes, modp->smallest_reg, modp->largest_reg);
265 	cat_pack(iseq, modp->inst_bits, hseq, hbytes * BITS_PER_BYTE);
266 	inst_buf[0] = inst;
267 	inst_buf[1] = 0xFF >> (modp->largest_reg % BITS_PER_BYTE);
268 	cat_pack(iseq, asicp->bit_location, inst_buf, asicp->ireg_length);
269 #ifdef VOYAGER_CAT_DEBUG
270 	printk("ins = 0x%x, iseq: ", inst);
271 	for (i = 0; i < ibytes + hbytes; i++)
272 		printk("0x%x ", iseq[i]);
273 	printk("\n");
274 #endif
275 	if (cat_shiftout(iseq, ibytes, hbytes, padbits)) {
276 		CDEBUG(("VOYAGER CAT: cat_sendinst: cat_shiftout failed\n"));
277 		return 1;
278 	}
279 	CDEBUG(("CAT SHIFTOUT DONE\n"));
280 	return 0;
281 }
282 
283 static int
cat_getdata(voyager_module_t * modp,voyager_asic_t * asicp,__u8 reg,__u8 * value)284 cat_getdata(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg,
285 	    __u8 * value)
286 {
287 	if (!modp->scan_path_connected) {
288 		if (asicp->asic_id != VOYAGER_CAT_ID) {
289 			CDEBUG(("VOYAGER CAT: ERROR: cat_getdata to CAT asic with scan path connected\n"));
290 			return 1;
291 		}
292 		if (reg > VOYAGER_SUBADDRHI)
293 			outb(VOYAGER_CAT_RUN, CAT_CMD);
294 		outb(VOYAGER_CAT_DRCYC, CAT_CMD);
295 		outb(VOYAGER_CAT_HEADER, CAT_DATA);
296 		*value = inb(CAT_DATA);
297 		outb(0xAA, CAT_DATA);
298 		if (inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
299 			CDEBUG(("cat_getdata: failed to get VOYAGER_CAT_HEADER\n"));
300 			return 1;
301 		}
302 		return 0;
303 	} else {
304 		__u16 sbits = modp->num_asics - 1 + asicp->ireg_length;
305 		__u16 sbytes = sbits / BITS_PER_BYTE;
306 		__u16 tbytes;
307 		__u8 string[VOYAGER_MAX_SCAN_PATH],
308 		    trailer[VOYAGER_MAX_REG_SIZE];
309 		__u8 padbits;
310 		int i;
311 
312 		outb(VOYAGER_CAT_DRCYC, CAT_CMD);
313 
314 		if ((padbits = sbits % BITS_PER_BYTE) != 0) {
315 			padbits = BITS_PER_BYTE - padbits;
316 			sbytes++;
317 		}
318 		tbytes = asicp->ireg_length / BITS_PER_BYTE;
319 		if (asicp->ireg_length % BITS_PER_BYTE)
320 			tbytes++;
321 		CDEBUG(("cat_getdata: tbytes = %d, sbytes = %d, padbits = %d\n",
322 			tbytes, sbytes, padbits));
323 		cat_build_header(trailer, tbytes, 1, asicp->ireg_length);
324 
325 		for (i = tbytes - 1; i >= 0; i--) {
326 			outb(trailer[i], CAT_DATA);
327 			string[sbytes + i] = inb(CAT_DATA);
328 		}
329 
330 		for (i = sbytes - 1; i >= 0; i--) {
331 			outb(0xaa, CAT_DATA);
332 			string[i] = inb(CAT_DATA);
333 		}
334 		*value = 0;
335 		cat_unpack(string,
336 			   padbits + (tbytes * BITS_PER_BYTE) +
337 			   asicp->asic_location, value, asicp->ireg_length);
338 #ifdef VOYAGER_CAT_DEBUG
339 		printk("value=0x%x, string: ", *value);
340 		for (i = 0; i < tbytes + sbytes; i++)
341 			printk("0x%x ", string[i]);
342 		printk("\n");
343 #endif
344 
345 		/* sanity check the rest of the return */
346 		for (i = 0; i < tbytes; i++) {
347 			__u8 input = 0;
348 
349 			cat_unpack(string, padbits + (i * BITS_PER_BYTE),
350 				   &input, BITS_PER_BYTE);
351 			if (trailer[i] != input) {
352 				CDEBUG(("cat_getdata: failed to sanity check rest of ret(%d) 0x%x != 0x%x\n", i, input, trailer[i]));
353 				return 1;
354 			}
355 		}
356 		CDEBUG(("cat_getdata DONE\n"));
357 		return 0;
358 	}
359 }
360 
361 static int
cat_shiftout(__u8 * data,__u16 data_bytes,__u16 header_bytes,__u8 pad_bits)362 cat_shiftout(__u8 * data, __u16 data_bytes, __u16 header_bytes, __u8 pad_bits)
363 {
364 	int i;
365 
366 	for (i = data_bytes + header_bytes - 1; i >= header_bytes; i--)
367 		outb(data[i], CAT_DATA);
368 
369 	for (i = header_bytes - 1; i >= 0; i--) {
370 		__u8 header = 0;
371 		__u8 input;
372 
373 		outb(data[i], CAT_DATA);
374 		input = inb(CAT_DATA);
375 		CDEBUG(("cat_shiftout: returned 0x%x\n", input));
376 		cat_unpack(data, ((data_bytes + i) * BITS_PER_BYTE) - pad_bits,
377 			   &header, BITS_PER_BYTE);
378 		if (input != header) {
379 			CDEBUG(("VOYAGER CAT: cat_shiftout failed to return header 0x%x != 0x%x\n", input, header));
380 			return 1;
381 		}
382 	}
383 	return 0;
384 }
385 
386 static int
cat_senddata(voyager_module_t * modp,voyager_asic_t * asicp,__u8 reg,__u8 value)387 cat_senddata(voyager_module_t * modp, voyager_asic_t * asicp,
388 	     __u8 reg, __u8 value)
389 {
390 	outb(VOYAGER_CAT_DRCYC, CAT_CMD);
391 	if (!modp->scan_path_connected) {
392 		if (asicp->asic_id != VOYAGER_CAT_ID) {
393 			CDEBUG(("VOYAGER CAT: ERROR: scan path disconnected when asic != CAT\n"));
394 			return 1;
395 		}
396 		outb(VOYAGER_CAT_HEADER, CAT_DATA);
397 		outb(value, CAT_DATA);
398 		if (inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
399 			CDEBUG(("cat_senddata: failed to get correct header response to sent data\n"));
400 			return 1;
401 		}
402 		if (reg > VOYAGER_SUBADDRHI) {
403 			outb(VOYAGER_CAT_RUN, CAT_CMD);
404 			outb(VOYAGER_CAT_END, CAT_CMD);
405 			outb(VOYAGER_CAT_RUN, CAT_CMD);
406 		}
407 
408 		return 0;
409 	} else {
410 		__u16 hbytes = asicp->ireg_length / BITS_PER_BYTE;
411 		__u16 dbytes =
412 		    (modp->num_asics - 1 + asicp->ireg_length) / BITS_PER_BYTE;
413 		__u8 padbits, dseq[VOYAGER_MAX_SCAN_PATH],
414 		    hseq[VOYAGER_MAX_REG_SIZE];
415 		int i;
416 
417 		if ((padbits = (modp->num_asics - 1
418 				+ asicp->ireg_length) % BITS_PER_BYTE) != 0) {
419 			padbits = BITS_PER_BYTE - padbits;
420 			dbytes++;
421 		}
422 		if (asicp->ireg_length % BITS_PER_BYTE)
423 			hbytes++;
424 
425 		cat_build_header(hseq, hbytes, 1, asicp->ireg_length);
426 
427 		for (i = 0; i < dbytes + hbytes; i++)
428 			dseq[i] = 0xff;
429 		CDEBUG(("cat_senddata: dbytes=%d, hbytes=%d, padbits=%d\n",
430 			dbytes, hbytes, padbits));
431 		cat_pack(dseq, modp->num_asics - 1 + asicp->ireg_length,
432 			 hseq, hbytes * BITS_PER_BYTE);
433 		cat_pack(dseq, asicp->asic_location, &value,
434 			 asicp->ireg_length);
435 #ifdef VOYAGER_CAT_DEBUG
436 		printk("dseq ");
437 		for (i = 0; i < hbytes + dbytes; i++) {
438 			printk("0x%x ", dseq[i]);
439 		}
440 		printk("\n");
441 #endif
442 		return cat_shiftout(dseq, dbytes, hbytes, padbits);
443 	}
444 }
445 
446 static int
cat_write(voyager_module_t * modp,voyager_asic_t * asicp,__u8 reg,__u8 value)447 cat_write(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg, __u8 value)
448 {
449 	if (cat_sendinst(modp, asicp, reg, VOYAGER_WRITE_CONFIG))
450 		return 1;
451 	return cat_senddata(modp, asicp, reg, value);
452 }
453 
454 static int
cat_read(voyager_module_t * modp,voyager_asic_t * asicp,__u8 reg,__u8 * value)455 cat_read(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg,
456 	 __u8 * value)
457 {
458 	if (cat_sendinst(modp, asicp, reg, VOYAGER_READ_CONFIG))
459 		return 1;
460 	return cat_getdata(modp, asicp, reg, value);
461 }
462 
463 static int
cat_subaddrsetup(voyager_module_t * modp,voyager_asic_t * asicp,__u16 offset,__u16 len)464 cat_subaddrsetup(voyager_module_t * modp, voyager_asic_t * asicp, __u16 offset,
465 		 __u16 len)
466 {
467 	__u8 val;
468 
469 	if (len > 1) {
470 		/* set auto increment */
471 		__u8 newval;
472 
473 		if (cat_read(modp, asicp, VOYAGER_AUTO_INC_REG, &val)) {
474 			CDEBUG(("cat_subaddrsetup: read of VOYAGER_AUTO_INC_REG failed\n"));
475 			return 1;
476 		}
477 		CDEBUG(("cat_subaddrsetup: VOYAGER_AUTO_INC_REG = 0x%x\n",
478 			val));
479 		newval = val | VOYAGER_AUTO_INC;
480 		if (newval != val) {
481 			if (cat_write(modp, asicp, VOYAGER_AUTO_INC_REG, val)) {
482 				CDEBUG(("cat_subaddrsetup: write to VOYAGER_AUTO_INC_REG failed\n"));
483 				return 1;
484 			}
485 		}
486 	}
487 	if (cat_write(modp, asicp, VOYAGER_SUBADDRLO, (__u8) (offset & 0xff))) {
488 		CDEBUG(("cat_subaddrsetup: write to SUBADDRLO failed\n"));
489 		return 1;
490 	}
491 	if (asicp->subaddr > VOYAGER_SUBADDR_LO) {
492 		if (cat_write
493 		    (modp, asicp, VOYAGER_SUBADDRHI, (__u8) (offset >> 8))) {
494 			CDEBUG(("cat_subaddrsetup: write to SUBADDRHI failed\n"));
495 			return 1;
496 		}
497 		cat_read(modp, asicp, VOYAGER_SUBADDRHI, &val);
498 		CDEBUG(("cat_subaddrsetup: offset = %d, hi = %d\n", offset,
499 			val));
500 	}
501 	cat_read(modp, asicp, VOYAGER_SUBADDRLO, &val);
502 	CDEBUG(("cat_subaddrsetup: offset = %d, lo = %d\n", offset, val));
503 	return 0;
504 }
505 
506 static int
cat_subwrite(voyager_module_t * modp,voyager_asic_t * asicp,__u16 offset,__u16 len,void * buf)507 cat_subwrite(voyager_module_t * modp, voyager_asic_t * asicp, __u16 offset,
508 	     __u16 len, void *buf)
509 {
510 	int i, retval;
511 
512 	/* FIXME: need special actions for VOYAGER_CAT_ID here */
513 	if (asicp->asic_id == VOYAGER_CAT_ID) {
514 		CDEBUG(("cat_subwrite: ATTEMPT TO WRITE TO CAT ASIC\n"));
515 		/* FIXME -- This is supposed to be handled better
516 		 * There is a problem writing to the cat asic in the
517 		 * PSI.  The 30us delay seems to work, though */
518 		udelay(30);
519 	}
520 
521 	if ((retval = cat_subaddrsetup(modp, asicp, offset, len)) != 0) {
522 		printk("cat_subwrite: cat_subaddrsetup FAILED\n");
523 		return retval;
524 	}
525 
526 	if (cat_sendinst
527 	    (modp, asicp, VOYAGER_SUBADDRDATA, VOYAGER_WRITE_CONFIG)) {
528 		printk("cat_subwrite: cat_sendinst FAILED\n");
529 		return 1;
530 	}
531 	for (i = 0; i < len; i++) {
532 		if (cat_senddata(modp, asicp, 0xFF, ((__u8 *) buf)[i])) {
533 			printk
534 			    ("cat_subwrite: cat_sendata element at %d FAILED\n",
535 			     i);
536 			return 1;
537 		}
538 	}
539 	return 0;
540 }
541 static int
cat_subread(voyager_module_t * modp,voyager_asic_t * asicp,__u16 offset,__u16 len,void * buf)542 cat_subread(voyager_module_t * modp, voyager_asic_t * asicp, __u16 offset,
543 	    __u16 len, void *buf)
544 {
545 	int i, retval;
546 
547 	if ((retval = cat_subaddrsetup(modp, asicp, offset, len)) != 0) {
548 		CDEBUG(("cat_subread: cat_subaddrsetup FAILED\n"));
549 		return retval;
550 	}
551 
552 	if (cat_sendinst(modp, asicp, VOYAGER_SUBADDRDATA, VOYAGER_READ_CONFIG)) {
553 		CDEBUG(("cat_subread: cat_sendinst failed\n"));
554 		return 1;
555 	}
556 	for (i = 0; i < len; i++) {
557 		if (cat_getdata(modp, asicp, 0xFF, &((__u8 *) buf)[i])) {
558 			CDEBUG(("cat_subread: cat_getdata element %d failed\n",
559 				i));
560 			return 1;
561 		}
562 	}
563 	return 0;
564 }
565 
566 /* buffer for storing EPROM data read in during initialisation */
567 static __initdata __u8 eprom_buf[0xFFFF];
568 static voyager_module_t *voyager_initial_module;
569 
570 /* Initialise the cat bus components.  We assume this is called by the
571  * boot cpu *after* all memory initialisation has been done (so we can
572  * use kmalloc) but before smp initialisation, so we can probe the SMP
573  * configuration and pick up necessary information.  */
voyager_cat_init(void)574 void __init voyager_cat_init(void)
575 {
576 	voyager_module_t **modpp = &voyager_initial_module;
577 	voyager_asic_t **asicpp;
578 	voyager_asic_t *qabc_asic = NULL;
579 	int i, j;
580 	unsigned long qic_addr = 0;
581 	__u8 qabc_data[0x20];
582 	__u8 num_submodules, val;
583 	voyager_eprom_hdr_t *eprom_hdr = (voyager_eprom_hdr_t *) & eprom_buf[0];
584 
585 	__u8 cmos[4];
586 	unsigned long addr;
587 
588 	/* initiallise the SUS mailbox */
589 	for (i = 0; i < sizeof(cmos); i++)
590 		cmos[i] = voyager_extended_cmos_read(VOYAGER_DUMP_LOCATION + i);
591 	addr = *(unsigned long *)cmos;
592 	if ((addr & 0xff000000) != 0xff000000) {
593 		printk(KERN_ERR
594 		       "Voyager failed to get SUS mailbox (addr = 0x%lx\n",
595 		       addr);
596 	} else {
597 		static struct resource res;
598 
599 		res.name = "voyager SUS";
600 		res.start = addr;
601 		res.end = addr + 0x3ff;
602 
603 		request_resource(&iomem_resource, &res);
604 		voyager_SUS = (struct voyager_SUS *)
605 		    ioremap(addr, 0x400);
606 		printk(KERN_NOTICE "Voyager SUS mailbox version 0x%x\n",
607 		       voyager_SUS->SUS_version);
608 		voyager_SUS->kernel_version = VOYAGER_MAILBOX_VERSION;
609 		voyager_SUS->kernel_flags = VOYAGER_OS_HAS_SYSINT;
610 	}
611 
612 	/* clear the processor counts */
613 	voyager_extended_vic_processors = 0;
614 	voyager_quad_processors = 0;
615 
616 	printk("VOYAGER: beginning CAT bus probe\n");
617 	/* set up the SuperSet Port Block which tells us where the
618 	 * CAT communication port is */
619 	sspb = inb(VOYAGER_SSPB_RELOCATION_PORT) * 0x100;
620 	VDEBUG(("VOYAGER DEBUG: sspb = 0x%x\n", sspb));
621 
622 	/* now find out if were 8 slot or normal */
623 	if ((inb(VIC_PROC_WHO_AM_I) & EIGHT_SLOT_IDENTIFIER)
624 	    == EIGHT_SLOT_IDENTIFIER) {
625 		voyager_8slot = 1;
626 		printk(KERN_NOTICE
627 		       "Voyager: Eight slot 51xx configuration detected\n");
628 	}
629 
630 	for (i = VOYAGER_MIN_MODULE; i <= VOYAGER_MAX_MODULE; i++) {
631 		__u8 input;
632 		int asic;
633 		__u16 eprom_size;
634 		__u16 sp_offset;
635 
636 		outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
637 		outb(i, VOYAGER_CAT_CONFIG_PORT);
638 
639 		/* check the presence of the module */
640 		outb(VOYAGER_CAT_RUN, CAT_CMD);
641 		outb(VOYAGER_CAT_IRCYC, CAT_CMD);
642 		outb(VOYAGER_CAT_HEADER, CAT_DATA);
643 		/* stream series of alternating 1's and 0's to stimulate
644 		 * response */
645 		outb(0xAA, CAT_DATA);
646 		input = inb(CAT_DATA);
647 		outb(VOYAGER_CAT_END, CAT_CMD);
648 		if (input != VOYAGER_CAT_HEADER) {
649 			continue;
650 		}
651 		CDEBUG(("VOYAGER DEBUG: found module id 0x%x, %s\n", i,
652 			cat_module_name(i)));
653 		*modpp = kmalloc(sizeof(voyager_module_t), GFP_KERNEL);	/*&voyager_module_storage[cat_count++]; */
654 		if (*modpp == NULL) {
655 			printk("**WARNING** kmalloc failure in cat_init\n");
656 			continue;
657 		}
658 		memset(*modpp, 0, sizeof(voyager_module_t));
659 		/* need temporary asic for cat_subread.  It will be
660 		 * filled in correctly later */
661 		(*modpp)->asic = kmalloc(sizeof(voyager_asic_t), GFP_KERNEL);	/*&voyager_asic_storage[asic_count]; */
662 		if ((*modpp)->asic == NULL) {
663 			printk("**WARNING** kmalloc failure in cat_init\n");
664 			continue;
665 		}
666 		memset((*modpp)->asic, 0, sizeof(voyager_asic_t));
667 		(*modpp)->asic->asic_id = VOYAGER_CAT_ID;
668 		(*modpp)->asic->subaddr = VOYAGER_SUBADDR_HI;
669 		(*modpp)->module_addr = i;
670 		(*modpp)->scan_path_connected = 0;
671 		if (i == VOYAGER_PSI) {
672 			/* Exception leg for modules with no EEPROM */
673 			printk("Module \"%s\"\n", cat_module_name(i));
674 			continue;
675 		}
676 
677 		CDEBUG(("cat_init: Reading eeprom for module 0x%x at offset %d\n", i, VOYAGER_XSUM_END_OFFSET));
678 		outb(VOYAGER_CAT_RUN, CAT_CMD);
679 		cat_disconnect(*modpp, (*modpp)->asic);
680 		if (cat_subread(*modpp, (*modpp)->asic,
681 				VOYAGER_XSUM_END_OFFSET, sizeof(eprom_size),
682 				&eprom_size)) {
683 			printk
684 			    ("**WARNING**: Voyager couldn't read EPROM size for module 0x%x\n",
685 			     i);
686 			outb(VOYAGER_CAT_END, CAT_CMD);
687 			continue;
688 		}
689 		if (eprom_size > sizeof(eprom_buf)) {
690 			printk
691 			    ("**WARNING**: Voyager insufficient size to read EPROM data, module 0x%x.  Need %d\n",
692 			     i, eprom_size);
693 			outb(VOYAGER_CAT_END, CAT_CMD);
694 			continue;
695 		}
696 		outb(VOYAGER_CAT_END, CAT_CMD);
697 		outb(VOYAGER_CAT_RUN, CAT_CMD);
698 		CDEBUG(("cat_init: module 0x%x, eeprom_size %d\n", i,
699 			eprom_size));
700 		if (cat_subread
701 		    (*modpp, (*modpp)->asic, 0, eprom_size, eprom_buf)) {
702 			outb(VOYAGER_CAT_END, CAT_CMD);
703 			continue;
704 		}
705 		outb(VOYAGER_CAT_END, CAT_CMD);
706 		printk("Module \"%s\", version 0x%x, tracer 0x%x, asics %d\n",
707 		       cat_module_name(i), eprom_hdr->version_id,
708 		       *((__u32 *) eprom_hdr->tracer), eprom_hdr->num_asics);
709 		(*modpp)->ee_size = eprom_hdr->ee_size;
710 		(*modpp)->num_asics = eprom_hdr->num_asics;
711 		asicpp = &((*modpp)->asic);
712 		sp_offset = eprom_hdr->scan_path_offset;
713 		/* All we really care about are the Quad cards.  We
714 		 * identify them because they are in a processor slot
715 		 * and have only four asics */
716 		if ((i < 0x10 || (i >= 0x14 && i < 0x1c) || i > 0x1f)) {
717 			modpp = &((*modpp)->next);
718 			continue;
719 		}
720 		/* Now we know it's in a processor slot, does it have
721 		 * a quad baseboard submodule */
722 		outb(VOYAGER_CAT_RUN, CAT_CMD);
723 		cat_read(*modpp, (*modpp)->asic, VOYAGER_SUBMODPRESENT,
724 			 &num_submodules);
725 		/* lowest two bits, active low */
726 		num_submodules = ~(0xfc | num_submodules);
727 		CDEBUG(("VOYAGER CAT: %d submodules present\n",
728 			num_submodules));
729 		if (num_submodules == 0) {
730 			/* fill in the dyadic extended processors */
731 			__u8 cpu = i & 0x07;
732 
733 			printk("Module \"%s\": Dyadic Processor Card\n",
734 			       cat_module_name(i));
735 			voyager_extended_vic_processors |= (1 << cpu);
736 			cpu += 4;
737 			voyager_extended_vic_processors |= (1 << cpu);
738 			outb(VOYAGER_CAT_END, CAT_CMD);
739 			continue;
740 		}
741 
742 		/* now we want to read the asics on the first submodule,
743 		 * which should be the quad base board */
744 
745 		cat_read(*modpp, (*modpp)->asic, VOYAGER_SUBMODSELECT, &val);
746 		CDEBUG(("cat_init: SUBMODSELECT value = 0x%x\n", val));
747 		val = (val & 0x7c) | VOYAGER_QUAD_BASEBOARD;
748 		cat_write(*modpp, (*modpp)->asic, VOYAGER_SUBMODSELECT, val);
749 
750 		outb(VOYAGER_CAT_END, CAT_CMD);
751 
752 		CDEBUG(("cat_init: Reading eeprom for module 0x%x at offset %d\n", i, VOYAGER_XSUM_END_OFFSET));
753 		outb(VOYAGER_CAT_RUN, CAT_CMD);
754 		cat_disconnect(*modpp, (*modpp)->asic);
755 		if (cat_subread(*modpp, (*modpp)->asic,
756 				VOYAGER_XSUM_END_OFFSET, sizeof(eprom_size),
757 				&eprom_size)) {
758 			printk
759 			    ("**WARNING**: Voyager couldn't read EPROM size for module 0x%x\n",
760 			     i);
761 			outb(VOYAGER_CAT_END, CAT_CMD);
762 			continue;
763 		}
764 		if (eprom_size > sizeof(eprom_buf)) {
765 			printk
766 			    ("**WARNING**: Voyager insufficient size to read EPROM data, module 0x%x.  Need %d\n",
767 			     i, eprom_size);
768 			outb(VOYAGER_CAT_END, CAT_CMD);
769 			continue;
770 		}
771 		outb(VOYAGER_CAT_END, CAT_CMD);
772 		outb(VOYAGER_CAT_RUN, CAT_CMD);
773 		CDEBUG(("cat_init: module 0x%x, eeprom_size %d\n", i,
774 			eprom_size));
775 		if (cat_subread
776 		    (*modpp, (*modpp)->asic, 0, eprom_size, eprom_buf)) {
777 			outb(VOYAGER_CAT_END, CAT_CMD);
778 			continue;
779 		}
780 		outb(VOYAGER_CAT_END, CAT_CMD);
781 		/* Now do everything for the QBB submodule 1 */
782 		(*modpp)->ee_size = eprom_hdr->ee_size;
783 		(*modpp)->num_asics = eprom_hdr->num_asics;
784 		asicpp = &((*modpp)->asic);
785 		sp_offset = eprom_hdr->scan_path_offset;
786 		/* get rid of the dummy CAT asic and read the real one */
787 		kfree((*modpp)->asic);
788 		for (asic = 0; asic < (*modpp)->num_asics; asic++) {
789 			int j;
790 			voyager_asic_t *asicp = *asicpp = kzalloc(sizeof(voyager_asic_t), GFP_KERNEL);	/*&voyager_asic_storage[asic_count++]; */
791 			voyager_sp_table_t *sp_table;
792 			voyager_at_t *asic_table;
793 			voyager_jtt_t *jtag_table;
794 
795 			if (asicp == NULL) {
796 				printk
797 				    ("**WARNING** kmalloc failure in cat_init\n");
798 				continue;
799 			}
800 			asicpp = &(asicp->next);
801 			asicp->asic_location = asic;
802 			sp_table =
803 			    (voyager_sp_table_t *) (eprom_buf + sp_offset);
804 			asicp->asic_id = sp_table->asic_id;
805 			asic_table =
806 			    (voyager_at_t *) (eprom_buf +
807 					      sp_table->asic_data_offset);
808 			for (j = 0; j < 4; j++)
809 				asicp->jtag_id[j] = asic_table->jtag_id[j];
810 			jtag_table =
811 			    (voyager_jtt_t *) (eprom_buf +
812 					       asic_table->jtag_offset);
813 			asicp->ireg_length = jtag_table->ireg_len;
814 			asicp->bit_location = (*modpp)->inst_bits;
815 			(*modpp)->inst_bits += asicp->ireg_length;
816 			if (asicp->ireg_length > (*modpp)->largest_reg)
817 				(*modpp)->largest_reg = asicp->ireg_length;
818 			if (asicp->ireg_length < (*modpp)->smallest_reg ||
819 			    (*modpp)->smallest_reg == 0)
820 				(*modpp)->smallest_reg = asicp->ireg_length;
821 			CDEBUG(("asic 0x%x, ireg_length=%d, bit_location=%d\n",
822 				asicp->asic_id, asicp->ireg_length,
823 				asicp->bit_location));
824 			if (asicp->asic_id == VOYAGER_QUAD_QABC) {
825 				CDEBUG(("VOYAGER CAT: QABC ASIC found\n"));
826 				qabc_asic = asicp;
827 			}
828 			sp_offset += sizeof(voyager_sp_table_t);
829 		}
830 		CDEBUG(("Module inst_bits = %d, largest_reg = %d, smallest_reg=%d\n", (*modpp)->inst_bits, (*modpp)->largest_reg, (*modpp)->smallest_reg));
831 		/* OK, now we have the QUAD ASICs set up, use them.
832 		 * we need to:
833 		 *
834 		 * 1. Find the Memory area for the Quad CPIs.
835 		 * 2. Find the Extended VIC processor
836 		 * 3. Configure a second extended VIC processor (This
837 		 *    cannot be done for the 51xx.
838 		 * */
839 		outb(VOYAGER_CAT_RUN, CAT_CMD);
840 		cat_connect(*modpp, (*modpp)->asic);
841 		CDEBUG(("CAT CONNECTED!!\n"));
842 		cat_subread(*modpp, qabc_asic, 0, sizeof(qabc_data), qabc_data);
843 		qic_addr = qabc_data[5] << 8;
844 		qic_addr = (qic_addr | qabc_data[6]) << 8;
845 		qic_addr = (qic_addr | qabc_data[7]) << 8;
846 		printk
847 		    ("Module \"%s\": Quad Processor Card; CPI 0x%lx, SET=0x%x\n",
848 		     cat_module_name(i), qic_addr, qabc_data[8]);
849 #if 0				/* plumbing fails---FIXME */
850 		if ((qabc_data[8] & 0xf0) == 0) {
851 			/* FIXME: 32 way 8 CPU slot monster cannot be
852 			 * plumbed this way---need to check for it */
853 
854 			printk("Plumbing second Extended Quad Processor\n");
855 			/* second VIC line hardwired to Quad CPU 1 */
856 			qabc_data[8] |= 0x20;
857 			cat_subwrite(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
858 #ifdef VOYAGER_CAT_DEBUG
859 			/* verify plumbing */
860 			cat_subread(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
861 			if ((qabc_data[8] & 0xf0) == 0) {
862 				CDEBUG(("PLUMBING FAILED: 0x%x\n",
863 					qabc_data[8]));
864 			}
865 #endif
866 		}
867 #endif
868 
869 		{
870 			struct resource *res =
871 			    kzalloc(sizeof(struct resource), GFP_KERNEL);
872 			res->name = kmalloc(128, GFP_KERNEL);
873 			sprintf((char *)res->name, "Voyager %s Quad CPI",
874 				cat_module_name(i));
875 			res->start = qic_addr;
876 			res->end = qic_addr + 0x3ff;
877 			request_resource(&iomem_resource, res);
878 		}
879 
880 		qic_addr = (unsigned long)ioremap_cache(qic_addr, 0x400);
881 
882 		for (j = 0; j < 4; j++) {
883 			__u8 cpu;
884 
885 			if (voyager_8slot) {
886 				/* 8 slot has a different mapping,
887 				 * each slot has only one vic line, so
888 				 * 1 cpu in each slot must be < 8 */
889 				cpu = (i & 0x07) + j * 8;
890 			} else {
891 				cpu = (i & 0x03) + j * 4;
892 			}
893 			if ((qabc_data[8] & (1 << j))) {
894 				voyager_extended_vic_processors |= (1 << cpu);
895 			}
896 			if (qabc_data[8] & (1 << (j + 4))) {
897 				/* Second SET register plumbed: Quad
898 				 * card has two VIC connected CPUs.
899 				 * Secondary cannot be booted as a VIC
900 				 * CPU */
901 				voyager_extended_vic_processors |= (1 << cpu);
902 				voyager_allowed_boot_processors &=
903 				    (~(1 << cpu));
904 			}
905 
906 			voyager_quad_processors |= (1 << cpu);
907 			voyager_quad_cpi_addr[cpu] = (struct voyager_qic_cpi *)
908 			    (qic_addr + (j << 8));
909 			CDEBUG(("CPU%d: CPI address 0x%lx\n", cpu,
910 				(unsigned long)voyager_quad_cpi_addr[cpu]));
911 		}
912 		outb(VOYAGER_CAT_END, CAT_CMD);
913 
914 		*asicpp = NULL;
915 		modpp = &((*modpp)->next);
916 	}
917 	*modpp = NULL;
918 	printk
919 	    ("CAT Bus Initialisation finished: extended procs 0x%x, quad procs 0x%x, allowed vic boot = 0x%x\n",
920 	     voyager_extended_vic_processors, voyager_quad_processors,
921 	     voyager_allowed_boot_processors);
922 	request_resource(&ioport_resource, &vic_res);
923 	if (voyager_quad_processors)
924 		request_resource(&ioport_resource, &qic_res);
925 	/* set up the front power switch */
926 }
927 
voyager_cat_readb(__u8 module,__u8 asic,int reg)928 int voyager_cat_readb(__u8 module, __u8 asic, int reg)
929 {
930 	return 0;
931 }
932 
cat_disconnect(voyager_module_t * modp,voyager_asic_t * asicp)933 static int cat_disconnect(voyager_module_t * modp, voyager_asic_t * asicp)
934 {
935 	__u8 val;
936 	int err = 0;
937 
938 	if (!modp->scan_path_connected)
939 		return 0;
940 	if (asicp->asic_id != VOYAGER_CAT_ID) {
941 		CDEBUG(("cat_disconnect: ASIC is not CAT\n"));
942 		return 1;
943 	}
944 	err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
945 	if (err) {
946 		CDEBUG(("cat_disconnect: failed to read SCANPATH\n"));
947 		return err;
948 	}
949 	val &= VOYAGER_DISCONNECT_ASIC;
950 	err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
951 	if (err) {
952 		CDEBUG(("cat_disconnect: failed to write SCANPATH\n"));
953 		return err;
954 	}
955 	outb(VOYAGER_CAT_END, CAT_CMD);
956 	outb(VOYAGER_CAT_RUN, CAT_CMD);
957 	modp->scan_path_connected = 0;
958 
959 	return 0;
960 }
961 
cat_connect(voyager_module_t * modp,voyager_asic_t * asicp)962 static int cat_connect(voyager_module_t * modp, voyager_asic_t * asicp)
963 {
964 	__u8 val;
965 	int err = 0;
966 
967 	if (modp->scan_path_connected)
968 		return 0;
969 	if (asicp->asic_id != VOYAGER_CAT_ID) {
970 		CDEBUG(("cat_connect: ASIC is not CAT\n"));
971 		return 1;
972 	}
973 
974 	err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
975 	if (err) {
976 		CDEBUG(("cat_connect: failed to read SCANPATH\n"));
977 		return err;
978 	}
979 	val |= VOYAGER_CONNECT_ASIC;
980 	err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
981 	if (err) {
982 		CDEBUG(("cat_connect: failed to write SCANPATH\n"));
983 		return err;
984 	}
985 	outb(VOYAGER_CAT_END, CAT_CMD);
986 	outb(VOYAGER_CAT_RUN, CAT_CMD);
987 	modp->scan_path_connected = 1;
988 
989 	return 0;
990 }
991 
voyager_cat_power_off(void)992 void voyager_cat_power_off(void)
993 {
994 	/* Power the machine off by writing to the PSI over the CAT
995 	 * bus */
996 	__u8 data;
997 	voyager_module_t psi = { 0 };
998 	voyager_asic_t psi_asic = { 0 };
999 
1000 	psi.asic = &psi_asic;
1001 	psi.asic->asic_id = VOYAGER_CAT_ID;
1002 	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
1003 	psi.module_addr = VOYAGER_PSI;
1004 	psi.scan_path_connected = 0;
1005 
1006 	outb(VOYAGER_CAT_END, CAT_CMD);
1007 	/* Connect the PSI to the CAT Bus */
1008 	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
1009 	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
1010 	outb(VOYAGER_CAT_RUN, CAT_CMD);
1011 	cat_disconnect(&psi, &psi_asic);
1012 	/* Read the status */
1013 	cat_subread(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
1014 	outb(VOYAGER_CAT_END, CAT_CMD);
1015 	CDEBUG(("PSI STATUS 0x%x\n", data));
1016 	/* These two writes are power off prep and perform */
1017 	data = PSI_CLEAR;
1018 	outb(VOYAGER_CAT_RUN, CAT_CMD);
1019 	cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
1020 	outb(VOYAGER_CAT_END, CAT_CMD);
1021 	data = PSI_POWER_DOWN;
1022 	outb(VOYAGER_CAT_RUN, CAT_CMD);
1023 	cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
1024 	outb(VOYAGER_CAT_END, CAT_CMD);
1025 }
1026 
1027 struct voyager_status voyager_status = { 0 };
1028 
voyager_cat_psi(__u8 cmd,__u16 reg,__u8 * data)1029 void voyager_cat_psi(__u8 cmd, __u16 reg, __u8 * data)
1030 {
1031 	voyager_module_t psi = { 0 };
1032 	voyager_asic_t psi_asic = { 0 };
1033 
1034 	psi.asic = &psi_asic;
1035 	psi.asic->asic_id = VOYAGER_CAT_ID;
1036 	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
1037 	psi.module_addr = VOYAGER_PSI;
1038 	psi.scan_path_connected = 0;
1039 
1040 	outb(VOYAGER_CAT_END, CAT_CMD);
1041 	/* Connect the PSI to the CAT Bus */
1042 	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
1043 	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
1044 	outb(VOYAGER_CAT_RUN, CAT_CMD);
1045 	cat_disconnect(&psi, &psi_asic);
1046 	switch (cmd) {
1047 	case VOYAGER_PSI_READ:
1048 		cat_read(&psi, &psi_asic, reg, data);
1049 		break;
1050 	case VOYAGER_PSI_WRITE:
1051 		cat_write(&psi, &psi_asic, reg, *data);
1052 		break;
1053 	case VOYAGER_PSI_SUBREAD:
1054 		cat_subread(&psi, &psi_asic, reg, 1, data);
1055 		break;
1056 	case VOYAGER_PSI_SUBWRITE:
1057 		cat_subwrite(&psi, &psi_asic, reg, 1, data);
1058 		break;
1059 	default:
1060 		printk(KERN_ERR "Voyager PSI, unrecognised command %d\n", cmd);
1061 		break;
1062 	}
1063 	outb(VOYAGER_CAT_END, CAT_CMD);
1064 }
1065 
voyager_cat_do_common_interrupt(void)1066 void voyager_cat_do_common_interrupt(void)
1067 {
1068 	/* This is caused either by a memory parity error or something
1069 	 * in the PSI */
1070 	__u8 data;
1071 	voyager_module_t psi = { 0 };
1072 	voyager_asic_t psi_asic = { 0 };
1073 	struct voyager_psi psi_reg;
1074 	int i;
1075       re_read:
1076 	psi.asic = &psi_asic;
1077 	psi.asic->asic_id = VOYAGER_CAT_ID;
1078 	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
1079 	psi.module_addr = VOYAGER_PSI;
1080 	psi.scan_path_connected = 0;
1081 
1082 	outb(VOYAGER_CAT_END, CAT_CMD);
1083 	/* Connect the PSI to the CAT Bus */
1084 	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
1085 	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
1086 	outb(VOYAGER_CAT_RUN, CAT_CMD);
1087 	cat_disconnect(&psi, &psi_asic);
1088 	/* Read the status.  NOTE: Need to read *all* the PSI regs here
1089 	 * otherwise the cmn int will be reasserted */
1090 	for (i = 0; i < sizeof(psi_reg.regs); i++) {
1091 		cat_read(&psi, &psi_asic, i, &((__u8 *) & psi_reg.regs)[i]);
1092 	}
1093 	outb(VOYAGER_CAT_END, CAT_CMD);
1094 	if ((psi_reg.regs.checkbit & 0x02) == 0) {
1095 		psi_reg.regs.checkbit |= 0x02;
1096 		cat_write(&psi, &psi_asic, 5, psi_reg.regs.checkbit);
1097 		printk("VOYAGER RE-READ PSI\n");
1098 		goto re_read;
1099 	}
1100 	outb(VOYAGER_CAT_RUN, CAT_CMD);
1101 	for (i = 0; i < sizeof(psi_reg.subregs); i++) {
1102 		/* This looks strange, but the PSI doesn't do auto increment
1103 		 * correctly */
1104 		cat_subread(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG + i,
1105 			    1, &((__u8 *) & psi_reg.subregs)[i]);
1106 	}
1107 	outb(VOYAGER_CAT_END, CAT_CMD);
1108 #ifdef VOYAGER_CAT_DEBUG
1109 	printk("VOYAGER PSI: ");
1110 	for (i = 0; i < sizeof(psi_reg.regs); i++)
1111 		printk("%02x ", ((__u8 *) & psi_reg.regs)[i]);
1112 	printk("\n           ");
1113 	for (i = 0; i < sizeof(psi_reg.subregs); i++)
1114 		printk("%02x ", ((__u8 *) & psi_reg.subregs)[i]);
1115 	printk("\n");
1116 #endif
1117 	if (psi_reg.regs.intstatus & PSI_MON) {
1118 		/* switch off or power fail */
1119 
1120 		if (psi_reg.subregs.supply & PSI_SWITCH_OFF) {
1121 			if (voyager_status.switch_off) {
1122 				printk(KERN_ERR
1123 				       "Voyager front panel switch turned off again---Immediate power off!\n");
1124 				voyager_cat_power_off();
1125 				/* not reached */
1126 			} else {
1127 				printk(KERN_ERR
1128 				       "Voyager front panel switch turned off\n");
1129 				voyager_status.switch_off = 1;
1130 				voyager_status.request_from_kernel = 1;
1131 				wake_up_process(voyager_thread);
1132 			}
1133 			/* Tell the hardware we're taking care of the
1134 			 * shutdown, otherwise it will power the box off
1135 			 * within 3 seconds of the switch being pressed and,
1136 			 * which is much more important to us, continue to
1137 			 * assert the common interrupt */
1138 			data = PSI_CLR_SWITCH_OFF;
1139 			outb(VOYAGER_CAT_RUN, CAT_CMD);
1140 			cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG,
1141 				     1, &data);
1142 			outb(VOYAGER_CAT_END, CAT_CMD);
1143 		} else {
1144 
1145 			VDEBUG(("Voyager ac fail reg 0x%x\n",
1146 				psi_reg.subregs.ACfail));
1147 			if ((psi_reg.subregs.ACfail & AC_FAIL_STAT_CHANGE) == 0) {
1148 				/* No further update */
1149 				return;
1150 			}
1151 #if 0
1152 			/* Don't bother trying to find out who failed.
1153 			 * FIXME: This probably makes the code incorrect on
1154 			 * anything other than a 345x */
1155 			for (i = 0; i < 5; i++) {
1156 				if (psi_reg.subregs.ACfail & (1 << i)) {
1157 					break;
1158 				}
1159 			}
1160 			printk(KERN_NOTICE "AC FAIL IN SUPPLY %d\n", i);
1161 #endif
1162 			/* DON'T do this: it shuts down the AC PSI
1163 			   outb(VOYAGER_CAT_RUN, CAT_CMD);
1164 			   data = PSI_MASK_MASK | i;
1165 			   cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_MASK,
1166 			   1, &data);
1167 			   outb(VOYAGER_CAT_END, CAT_CMD);
1168 			 */
1169 			printk(KERN_ERR "Voyager AC power failure\n");
1170 			outb(VOYAGER_CAT_RUN, CAT_CMD);
1171 			data = PSI_COLD_START;
1172 			cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG,
1173 				     1, &data);
1174 			outb(VOYAGER_CAT_END, CAT_CMD);
1175 			voyager_status.power_fail = 1;
1176 			voyager_status.request_from_kernel = 1;
1177 			wake_up_process(voyager_thread);
1178 		}
1179 
1180 	} else if (psi_reg.regs.intstatus & PSI_FAULT) {
1181 		/* Major fault! */
1182 		printk(KERN_ERR
1183 		       "Voyager PSI Detected major fault, immediate power off!\n");
1184 		voyager_cat_power_off();
1185 		/* not reached */
1186 	} else if (psi_reg.regs.intstatus & (PSI_DC_FAIL | PSI_ALARM
1187 					     | PSI_CURRENT | PSI_DVM
1188 					     | PSI_PSCFAULT | PSI_STAT_CHG)) {
1189 		/* other psi fault */
1190 
1191 		printk(KERN_WARNING "Voyager PSI status 0x%x\n", data);
1192 		/* clear the PSI fault */
1193 		outb(VOYAGER_CAT_RUN, CAT_CMD);
1194 		cat_write(&psi, &psi_asic, VOYAGER_PSI_STATUS_REG, 0);
1195 		outb(VOYAGER_CAT_END, CAT_CMD);
1196 	}
1197 }
1198