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