PageRenderTime 79ms CodeModel.GetById 12ms app.highlight 57ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/i386/mach-voyager/voyager_cat.c

https://bitbucket.org/evzijst/gittest
C | 1178 lines | 938 code | 106 blank | 134 comment | 161 complexity | ba09f5d7e95cea95472568923a0b51d6 MD5 | raw file
   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/config.h>
  20#include <linux/types.h>
  21#include <linux/completion.h>
  22#include <linux/sched.h>
  23#include <asm/voyager.h>
  24#include <asm/vic.h>
  25#include <linux/ioport.h>
  26#include <linux/init.h>
  27#include <linux/slab.h>
  28#include <linux/delay.h>
  29#include <asm/io.h>
  30
  31#ifdef VOYAGER_CAT_DEBUG
  32#define CDEBUG(x)	printk x
  33#else
  34#define CDEBUG(x)
  35#endif
  36
  37/* the CAT command port */
  38#define CAT_CMD		(sspb + 0xe)
  39/* the CAT data port */
  40#define CAT_DATA	(sspb + 0xd)
  41
  42/* the internal cat functions */
  43static void cat_pack(__u8 *msg, __u16 start_bit, __u8 *data, 
  44		     __u16 num_bits);
  45static void cat_unpack(__u8 *msg, __u16 start_bit, __u8 *data,
  46		       __u16 num_bits);
  47static void cat_build_header(__u8 *header, const __u16 len, 
  48			     const __u16 smallest_reg_bits,
  49			     const __u16 longest_reg_bits);
  50static int cat_sendinst(voyager_module_t *modp, voyager_asic_t *asicp,
  51			__u8 reg, __u8 op);
  52static int cat_getdata(voyager_module_t *modp, voyager_asic_t *asicp,
  53		       __u8 reg, __u8 *value);
  54static int cat_shiftout(__u8 *data, __u16 data_bytes, __u16 header_bytes,
  55			__u8 pad_bits);
  56static int cat_write(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
  57		     __u8 value);
  58static int cat_read(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
  59		    __u8 *value);
  60static int cat_subread(voyager_module_t *modp, voyager_asic_t *asicp,
  61		       __u16 offset, __u16 len, void *buf);
  62static int cat_senddata(voyager_module_t *modp, voyager_asic_t *asicp,
  63			__u8 reg, __u8 value);
  64static int cat_disconnect(voyager_module_t *modp, voyager_asic_t *asicp);
  65static int cat_connect(voyager_module_t *modp, voyager_asic_t *asicp);
  66
  67static inline const char *
  68cat_module_name(int module_id)
  69{
  70	switch(module_id) {
  71	case 0x10:
  72		return "Processor Slot 0";
  73	case 0x11:
  74		return "Processor Slot 1";
  75	case 0x12:
  76		return "Processor Slot 2";
  77	case 0x13:
  78		return "Processor Slot 4";
  79	case 0x14:
  80		return "Memory Slot 0";
  81	case 0x15:
  82		return "Memory Slot 1";
  83	case 0x18:
  84		return "Primary Microchannel";
  85	case 0x19:
  86		return "Secondary Microchannel";
  87	case 0x1a:
  88		return "Power Supply Interface";
  89	case 0x1c:
  90		return "Processor Slot 5";
  91	case 0x1d:
  92		return "Processor Slot 6";
  93	case 0x1e:
  94		return "Processor Slot 7";
  95	case 0x1f:
  96		return "Processor Slot 8";
  97	default:
  98		return "Unknown Module";
  99	}
 100}
 101
 102static int sspb = 0;		/* stores the super port location */
 103int voyager_8slot = 0;		/* set to true if a 51xx monster */
 104
 105voyager_module_t *voyager_cat_list;
 106
 107/* the I/O port assignments for the VIC and QIC */
 108static struct resource vic_res = {
 109	"Voyager Interrupt Controller", 0xFC00, 0xFC6F };
 110static struct resource qic_res = {
 111	"Quad Interrupt Controller", 0xFC70, 0xFCFF };
 112
 113/* This function is used to pack a data bit stream inside a message.
 114 * It writes num_bits of the data buffer in msg starting at start_bit.
 115 * Note: This function assumes that any unused bit in the data stream
 116 * is set to zero so that the ors will work correctly */
 117#define BITS_PER_BYTE 8
 118static void
 119cat_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/* unpack the data again (same arguments as cat_pack()). data buffer
 156 * must be zero populated.
 157 *
 158 * Function: given a message string move to start_bit and copy num_bits into
 159 * data (starting at bit 0 in data).
 160 */
 161static void
 162cat_unpack(__u8 *msg, const __u16 start_bit, __u8 *data, const __u16 num_bits)
 163{
 164	/* compute initial shift needed */
 165	const __u16 offset = start_bit % BITS_PER_BYTE;
 166	__u16 len = num_bits / BITS_PER_BYTE;
 167	const __u8 last_bits = num_bits % BITS_PER_BYTE;
 168	__u16 byte = start_bit / BITS_PER_BYTE;
 169	int i;
 170
 171	if(last_bits != 0)
 172		len++;
 173
 174	/* special case: want < 8 bits from msg and we can get it from
 175	 * a single byte of the msg */
 176	if(len == 0 && BITS_PER_BYTE - offset >= num_bits) {
 177		data[0] = msg[byte] << offset;
 178		data[0] &= 0xff >> (BITS_PER_BYTE - num_bits);
 179		return;
 180	}
 181	for(i = 0; i < len; i++) {
 182		/* this annoying if has to be done just in case a read of
 183		 * msg one beyond the array causes a panic */
 184		if(offset != 0) {
 185			data[i] = msg[byte++] << offset;
 186			data[i] |= msg[byte] >> (BITS_PER_BYTE - offset);
 187		}
 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
 199static void
 200cat_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
 218static int
 219cat_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("**WARNING***: cat_sendinst has disconnected scan path not to CAT asic\n");
 241			return 1;
 242		}
 243		outb(VOYAGER_CAT_HEADER, CAT_DATA);
 244		outb(inst, CAT_DATA);
 245		if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
 246			CDEBUG(("VOYAGER CAT: cat_sendinst failed to get CAT_HEADER\n"));
 247			return 1;
 248		}
 249		return 0;
 250	}
 251	ibytes = modp->inst_bits / BITS_PER_BYTE;
 252	if((padbits = modp->inst_bits % BITS_PER_BYTE) != 0) {
 253		padbits = BITS_PER_BYTE - padbits;
 254		ibytes++;
 255	}
 256	hbytes = modp->largest_reg / BITS_PER_BYTE;
 257	if(modp->largest_reg % BITS_PER_BYTE)
 258		hbytes++;
 259	CDEBUG(("cat_sendinst: ibytes=%d, hbytes=%d\n", ibytes, hbytes));
 260	/* initialise the instruction sequence to 0xff */
 261	for(i=0; i < ibytes + hbytes; i++)
 262		iseq[i] = 0xff;
 263	cat_build_header(hseq, hbytes, modp->smallest_reg, modp->largest_reg);
 264	cat_pack(iseq, modp->inst_bits, hseq, hbytes * BITS_PER_BYTE);
 265	inst_buf[0] = inst;
 266	inst_buf[1] = 0xFF >> (modp->largest_reg % BITS_PER_BYTE);
 267	cat_pack(iseq, asicp->bit_location, inst_buf, asicp->ireg_length);
 268#ifdef VOYAGER_CAT_DEBUG
 269	printk("ins = 0x%x, iseq: ", inst);
 270	for(i=0; i< ibytes + hbytes; i++)
 271		printk("0x%x ", iseq[i]);
 272	printk("\n");
 273#endif
 274	if(cat_shiftout(iseq, ibytes, hbytes, padbits)) {
 275		CDEBUG(("VOYAGER CAT: cat_sendinst: cat_shiftout failed\n"));
 276		return 1;
 277	}
 278	CDEBUG(("CAT SHIFTOUT DONE\n"));
 279	return 0;
 280}
 281
 282static int
 283cat_getdata(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg, 
 284	    __u8 *value)
 285{
 286	if(!modp->scan_path_connected) {
 287		if(asicp->asic_id != VOYAGER_CAT_ID) {
 288			CDEBUG(("VOYAGER CAT: ERROR: cat_getdata to CAT asic with scan path connected\n"));
 289			return 1;
 290		}
 291		if(reg > VOYAGER_SUBADDRHI) 
 292			outb(VOYAGER_CAT_RUN, CAT_CMD);
 293		outb(VOYAGER_CAT_DRCYC, CAT_CMD);
 294		outb(VOYAGER_CAT_HEADER, CAT_DATA);
 295		*value = inb(CAT_DATA);
 296		outb(0xAA, CAT_DATA);
 297		if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
 298			CDEBUG(("cat_getdata: failed to get VOYAGER_CAT_HEADER\n"));
 299			return 1;
 300		}
 301		return 0;
 302	}
 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], trailer[VOYAGER_MAX_REG_SIZE];
 308		__u8 padbits;
 309		int i;
 310		
 311		outb(VOYAGER_CAT_DRCYC, CAT_CMD);
 312
 313		if((padbits = sbits % BITS_PER_BYTE) != 0) {
 314			padbits = BITS_PER_BYTE - padbits;
 315			sbytes++;
 316		}
 317		tbytes = asicp->ireg_length / BITS_PER_BYTE;
 318		if(asicp->ireg_length % BITS_PER_BYTE)
 319			tbytes++;
 320		CDEBUG(("cat_getdata: tbytes = %d, sbytes = %d, padbits = %d\n",
 321			tbytes,	sbytes, padbits));
 322		cat_build_header(trailer, tbytes, 1, asicp->ireg_length);
 323
 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, padbits + (tbytes * BITS_PER_BYTE) + asicp->asic_location, value, asicp->ireg_length);
 336#ifdef VOYAGER_CAT_DEBUG
 337		printk("value=0x%x, string: ", *value);
 338		for(i=0; i< tbytes+sbytes; i++)
 339			printk("0x%x ", string[i]);
 340		printk("\n");
 341#endif
 342		
 343		/* sanity check the rest of the return */
 344		for(i=0; i < tbytes; i++) {
 345			__u8 input = 0;
 346
 347			cat_unpack(string, padbits + (i * BITS_PER_BYTE), &input, BITS_PER_BYTE);
 348			if(trailer[i] != input) {
 349				CDEBUG(("cat_getdata: failed to sanity check rest of ret(%d) 0x%x != 0x%x\n", i, input, trailer[i]));
 350				return 1;
 351			}
 352		}
 353		CDEBUG(("cat_getdata DONE\n"));
 354		return 0;
 355	}
 356}
 357
 358static int
 359cat_shiftout(__u8 *data, __u16 data_bytes, __u16 header_bytes, __u8 pad_bits)
 360{
 361	int i;
 362	
 363	for(i = data_bytes + header_bytes - 1; i >= header_bytes; i--)
 364		outb(data[i], CAT_DATA);
 365
 366	for(i = header_bytes - 1; i >= 0; i--) {
 367		__u8 header = 0;
 368		__u8 input;
 369
 370		outb(data[i], CAT_DATA);
 371		input = inb(CAT_DATA);
 372		CDEBUG(("cat_shiftout: returned 0x%x\n", input));
 373		cat_unpack(data, ((data_bytes + i) * BITS_PER_BYTE) - pad_bits,
 374			   &header, BITS_PER_BYTE);
 375		if(input != header) {
 376			CDEBUG(("VOYAGER CAT: cat_shiftout failed to return header 0x%x != 0x%x\n", input, header));
 377			return 1;
 378		}
 379	}
 380	return 0;
 381}
 382
 383static int
 384cat_senddata(voyager_module_t *modp, voyager_asic_t *asicp, 
 385	     __u8 reg, __u8 value)
 386{
 387	outb(VOYAGER_CAT_DRCYC, CAT_CMD);
 388	if(!modp->scan_path_connected) {
 389		if(asicp->asic_id != VOYAGER_CAT_ID) {
 390			CDEBUG(("VOYAGER CAT: ERROR: scan path disconnected when asic != CAT\n"));
 391			return 1;
 392		}
 393		outb(VOYAGER_CAT_HEADER, CAT_DATA);
 394		outb(value, CAT_DATA);
 395		if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
 396			CDEBUG(("cat_senddata: failed to get correct header response to sent data\n"));
 397			return 1;
 398		}
 399		if(reg > VOYAGER_SUBADDRHI) {
 400			outb(VOYAGER_CAT_RUN, CAT_CMD);
 401			outb(VOYAGER_CAT_END, CAT_CMD);
 402			outb(VOYAGER_CAT_RUN, CAT_CMD);
 403		}
 404		
 405		return 0;
 406	}
 407	else {
 408		__u16 hbytes = asicp->ireg_length / BITS_PER_BYTE;
 409		__u16 dbytes = (modp->num_asics - 1 + asicp->ireg_length)/BITS_PER_BYTE;
 410		__u8 padbits, dseq[VOYAGER_MAX_SCAN_PATH], 
 411			hseq[VOYAGER_MAX_REG_SIZE];
 412		int i;
 413
 414		if((padbits = (modp->num_asics - 1 
 415			       + asicp->ireg_length) % BITS_PER_BYTE) != 0) {
 416			padbits = BITS_PER_BYTE - padbits;
 417			dbytes++;
 418		}
 419		if(asicp->ireg_length % BITS_PER_BYTE)
 420			hbytes++;
 421		
 422		cat_build_header(hseq, hbytes, 1, asicp->ireg_length);
 423		
 424		for(i = 0; i < dbytes + hbytes; i++)
 425			dseq[i] = 0xff;
 426		CDEBUG(("cat_senddata: dbytes=%d, hbytes=%d, padbits=%d\n",
 427			dbytes, hbytes, padbits));
 428		cat_pack(dseq, modp->num_asics - 1 + asicp->ireg_length,
 429			 hseq, hbytes * BITS_PER_BYTE);
 430		cat_pack(dseq, asicp->asic_location, &value, 
 431			 asicp->ireg_length);
 432#ifdef VOYAGER_CAT_DEBUG
 433		printk("dseq ");
 434		for(i=0; i<hbytes+dbytes; i++) {
 435			printk("0x%x ", dseq[i]);
 436		}
 437		printk("\n");
 438#endif
 439		return cat_shiftout(dseq, dbytes, hbytes, padbits);
 440	}
 441}
 442
 443static int
 444cat_write(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
 445	 __u8 value)
 446{
 447	if(cat_sendinst(modp, asicp, reg, VOYAGER_WRITE_CONFIG))
 448		return 1;
 449	return cat_senddata(modp, asicp, reg, value);
 450}
 451
 452static int
 453cat_read(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,
 454	 __u8 *value)
 455{
 456	if(cat_sendinst(modp, asicp, reg, VOYAGER_READ_CONFIG))
 457		return 1;
 458	return cat_getdata(modp, asicp, reg, value);
 459}
 460
 461static int
 462cat_subaddrsetup(voyager_module_t *modp, voyager_asic_t *asicp, __u16 offset,
 463		 __u16 len)
 464{
 465	__u8 val;
 466
 467	if(len > 1) {
 468		/* set auto increment */
 469		__u8 newval;
 470		
 471		if(cat_read(modp, asicp, VOYAGER_AUTO_INC_REG, &val)) {
 472			CDEBUG(("cat_subaddrsetup: read of VOYAGER_AUTO_INC_REG failed\n"));
 473			return 1;
 474		}
 475		CDEBUG(("cat_subaddrsetup: VOYAGER_AUTO_INC_REG = 0x%x\n", val));
 476		newval = val | VOYAGER_AUTO_INC;
 477		if(newval != val) {
 478			if(cat_write(modp, asicp, VOYAGER_AUTO_INC_REG, val)) {
 479				CDEBUG(("cat_subaddrsetup: write to VOYAGER_AUTO_INC_REG failed\n"));
 480				return 1;
 481			}
 482		}
 483	}
 484	if(cat_write(modp, asicp, VOYAGER_SUBADDRLO, (__u8)(offset &0xff))) {
 485		CDEBUG(("cat_subaddrsetup: write to SUBADDRLO failed\n"));
 486		return 1;
 487	}
 488	if(asicp->subaddr > VOYAGER_SUBADDR_LO) {
 489		if(cat_write(modp, asicp, VOYAGER_SUBADDRHI, (__u8)(offset >> 8))) {
 490			CDEBUG(("cat_subaddrsetup: write to SUBADDRHI failed\n"));
 491			return 1;
 492		}
 493		cat_read(modp, asicp, VOYAGER_SUBADDRHI, &val);
 494		CDEBUG(("cat_subaddrsetup: offset = %d, hi = %d\n", offset, val));
 495	}
 496	cat_read(modp, asicp, VOYAGER_SUBADDRLO, &val);
 497	CDEBUG(("cat_subaddrsetup: offset = %d, lo = %d\n", offset, val));
 498	return 0;
 499}
 500		
 501static int
 502cat_subwrite(voyager_module_t *modp, voyager_asic_t *asicp, __u16 offset,
 503	    __u16 len, void *buf)
 504{
 505	int i, retval;
 506
 507	/* FIXME: need special actions for VOYAGER_CAT_ID here */
 508	if(asicp->asic_id == VOYAGER_CAT_ID) {
 509		CDEBUG(("cat_subwrite: ATTEMPT TO WRITE TO CAT ASIC\n"));
 510		/* FIXME -- This is supposed to be handled better
 511		 * There is a problem writing to the cat asic in the
 512		 * PSI.  The 30us delay seems to work, though */
 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				= kmalloc(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			memset(asicp, 0, sizeof(voyager_asic_t));
 785			asicpp = &(asicp->next);
 786			asicp->asic_location = asic;
 787			sp_table = (voyager_sp_table_t *)(eprom_buf + sp_offset);
 788			asicp->asic_id = sp_table->asic_id;
 789			asic_table = (voyager_at_t *)(eprom_buf + sp_table->asic_data_offset);
 790			for(j=0; j<4; j++)
 791				asicp->jtag_id[j] = asic_table->jtag_id[j];
 792			jtag_table = (voyager_jtt_t *)(eprom_buf + asic_table->jtag_offset);
 793			asicp->ireg_length = jtag_table->ireg_len;
 794			asicp->bit_location = (*modpp)->inst_bits;
 795			(*modpp)->inst_bits += asicp->ireg_length;
 796			if(asicp->ireg_length > (*modpp)->largest_reg)
 797				(*modpp)->largest_reg = asicp->ireg_length;
 798			if (asicp->ireg_length < (*modpp)->smallest_reg ||
 799			    (*modpp)->smallest_reg == 0)
 800				(*modpp)->smallest_reg = asicp->ireg_length;
 801			CDEBUG(("asic 0x%x, ireg_length=%d, bit_location=%d\n",
 802				asicp->asic_id, asicp->ireg_length,
 803				asicp->bit_location));
 804			if(asicp->asic_id == VOYAGER_QUAD_QABC) {
 805				CDEBUG(("VOYAGER CAT: QABC ASIC found\n"));
 806				qabc_asic = asicp;
 807			}
 808			sp_offset += sizeof(voyager_sp_table_t);
 809		}
 810		CDEBUG(("Module inst_bits = %d, largest_reg = %d, smallest_reg=%d\n",
 811			(*modpp)->inst_bits, (*modpp)->largest_reg,
 812			(*modpp)->smallest_reg));
 813		/* OK, now we have the QUAD ASICs set up, use them.
 814		 * we need to:
 815		 *
 816		 * 1. Find the Memory area for the Quad CPIs.
 817		 * 2. Find the Extended VIC processor
 818		 * 3. Configure a second extended VIC processor (This
 819		 *    cannot be done for the 51xx.
 820		 * */
 821		outb(VOYAGER_CAT_RUN, CAT_CMD);
 822		cat_connect(*modpp, (*modpp)->asic);
 823		CDEBUG(("CAT CONNECTED!!\n"));
 824		cat_subread(*modpp, qabc_asic, 0, sizeof(qabc_data), qabc_data);
 825		qic_addr = qabc_data[5] << 8;
 826		qic_addr = (qic_addr | qabc_data[6]) << 8;
 827		qic_addr = (qic_addr | qabc_data[7]) << 8;
 828		printk("Module \"%s\": Quad Processor Card; CPI 0x%lx, SET=0x%x\n",
 829		       cat_module_name(i), qic_addr, qabc_data[8]);
 830#if 0				/* plumbing fails---FIXME */
 831		if((qabc_data[8] & 0xf0) == 0) {
 832			/* FIXME: 32 way 8 CPU slot monster cannot be
 833			 * plumbed this way---need to check for it */
 834
 835			printk("Plumbing second Extended Quad Processor\n");
 836			/* second VIC line hardwired to Quad CPU 1 */
 837			qabc_data[8] |= 0x20;
 838			cat_subwrite(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
 839#ifdef VOYAGER_CAT_DEBUG
 840			/* verify plumbing */
 841			cat_subread(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
 842			if((qabc_data[8] & 0xf0) == 0) {
 843				CDEBUG(("PLUMBING FAILED: 0x%x\n", qabc_data[8]));
 844			}
 845#endif
 846		}
 847#endif
 848
 849		{
 850			struct resource *res = kmalloc(sizeof(struct resource),GFP_KERNEL);
 851			memset(res, 0, sizeof(struct resource));
 852			res->name = kmalloc(128, GFP_KERNEL);
 853			sprintf((char *)res->name, "Voyager %s Quad CPI", cat_module_name(i));
 854			res->start = qic_addr;
 855			res->end = qic_addr + 0x3ff;
 856			request_resource(&iomem_resource, res);
 857		}
 858
 859		qic_addr = (unsigned long)ioremap(qic_addr, 0x400);
 860				
 861		for(j = 0; j < 4; j++) {
 862			__u8 cpu;
 863
 864			if(voyager_8slot) {
 865				/* 8 slot has a different mapping,
 866				 * each slot has only one vic line, so
 867				 * 1 cpu in each slot must be < 8 */
 868				cpu = (i & 0x07) + j*8;
 869			} else {
 870				cpu = (i & 0x03) + j*4;
 871			}
 872			if( (qabc_data[8] & (1<<j))) {
 873				voyager_extended_vic_processors |= (1<<cpu);
 874			}
 875			if(qabc_data[8] & (1<<(j+4)) ) {
 876				/* Second SET register plumbed: Quad
 877				 * card has two VIC connected CPUs.
 878				 * Secondary cannot be booted as a VIC
 879				 * CPU */
 880				voyager_extended_vic_processors |= (1<<cpu);
 881				voyager_allowed_boot_processors &= (~(1<<cpu));
 882			}
 883
 884			voyager_quad_processors |= (1<<cpu);
 885			voyager_quad_cpi_addr[cpu] = (struct voyager_qic_cpi *)
 886				(qic_addr+(j<<8));
 887			CDEBUG(("CPU%d: CPI address 0x%lx\n", cpu,
 888				(unsigned long)voyager_quad_cpi_addr[cpu]));
 889		}
 890		outb(VOYAGER_CAT_END, CAT_CMD);
 891
 892		
 893		
 894		*asicpp = NULL;
 895		modpp = &((*modpp)->next);
 896	}
 897	*modpp = NULL;
 898	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);
 899	request_resource(&ioport_resource, &vic_res);
 900	if(voyager_quad_processors)
 901		request_resource(&ioport_resource, &qic_res);
 902	/* set up the front power switch */
 903}
 904
 905int
 906voyager_cat_readb(__u8 module, __u8 asic, int reg)
 907{
 908	return 0;
 909}
 910
 911static int
 912cat_disconnect(voyager_module_t *modp, voyager_asic_t *asicp) 
 913{
 914	__u8 val;
 915	int err = 0;
 916
 917	if(!modp->scan_path_connected)
 918		return 0;
 919	if(asicp->asic_id != VOYAGER_CAT_ID) {
 920		CDEBUG(("cat_disconnect: ASIC is not CAT\n"));
 921		return 1;
 922	}
 923	err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
 924	if(err) {
 925		CDEBUG(("cat_disconnect: failed to read SCANPATH\n"));
 926		return err;
 927	}
 928	val &= VOYAGER_DISCONNECT_ASIC;
 929	err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
 930	if(err) {
 931		CDEBUG(("cat_disconnect: failed to write SCANPATH\n"));
 932		return err;
 933	}
 934	outb(VOYAGER_CAT_END, CAT_CMD);
 935	outb(VOYAGER_CAT_RUN, CAT_CMD);
 936	modp->scan_path_connected = 0;
 937
 938	return 0;
 939}
 940
 941static int
 942cat_connect(voyager_module_t *modp, voyager_asic_t *asicp) 
 943{
 944	__u8 val;
 945	int err = 0;
 946
 947	if(modp->scan_path_connected)
 948		return 0;
 949	if(asicp->asic_id != VOYAGER_CAT_ID) {
 950		CDEBUG(("cat_connect: ASIC is not CAT\n"));
 951		return 1;
 952	}
 953
 954	err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
 955	if(err) {
 956		CDEBUG(("cat_connect: failed to read SCANPATH\n"));
 957		return err;
 958	}
 959	val |= VOYAGER_CONNECT_ASIC;
 960	err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
 961	if(err) {
 962		CDEBUG(("cat_connect: failed to write SCANPATH\n"));
 963		return err;
 964	}
 965	outb(VOYAGER_CAT_END, CAT_CMD);
 966	outb(VOYAGER_CAT_RUN, CAT_CMD);
 967	modp->scan_path_connected = 1;
 968
 969	return 0;
 970}
 971
 972void
 973voyager_cat_power_off(void)
 974{
 975	/* Power the machine off by writing to the PSI over the CAT
 976         * bus */
 977	__u8 data;
 978	voyager_module_t psi = { 0 };
 979	voyager_asic_t psi_asic = { 0 };
 980
 981	psi.asic = &psi_asic;
 982	psi.asic->asic_id = VOYAGER_CAT_ID;
 983	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
 984	psi.module_addr = VOYAGER_PSI;
 985	psi.scan_path_connected = 0;
 986
 987	outb(VOYAGER_CAT_END, CAT_CMD);
 988	/* Connect the PSI to the CAT Bus */
 989	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
 990	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
 991	outb(VOYAGER_CAT_RUN, CAT_CMD);
 992	cat_disconnect(&psi, &psi_asic);
 993	/* Read the status */
 994	cat_subread(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
 995	outb(VOYAGER_CAT_END, CAT_CMD);
 996	CDEBUG(("PSI STATUS 0x%x\n", data));
 997	/* These two writes are power off prep and perform */
 998	data = PSI_CLEAR;
 999	outb(VOYAGER_CAT_RUN, CAT_CMD);
1000	cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
1001	outb(VOYAGER_CAT_END, CAT_CMD);
1002	data = PSI_POWER_DOWN;
1003	outb(VOYAGER_CAT_RUN, CAT_CMD);
1004	cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
1005	outb(VOYAGER_CAT_END, CAT_CMD);
1006}
1007
1008struct voyager_status voyager_status = { 0 };
1009
1010void
1011voyager_cat_psi(__u8 cmd, __u16 reg, __u8 *data)
1012{
1013	voyager_module_t psi = { 0 };
1014	voyager_asic_t psi_asic = { 0 };
1015
1016	psi.asic = &psi_asic;
1017	psi.asic->asic_id = VOYAGER_CAT_ID;
1018	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
1019	psi.module_addr = VOYAGER_PSI;
1020	psi.scan_path_connected = 0;
1021
1022	outb(VOYAGER_CAT_END, CAT_CMD);
1023	/* Connect the PSI to the CAT Bus */
1024	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
1025	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
1026	outb(VOYAGER_CAT_RUN, CAT_CMD);
1027	cat_disconnect(&psi, &psi_asic);
1028	switch(cmd) {
1029	case VOYAGER_PSI_READ:
1030		cat_read(&psi, &psi_asic, reg, data);
1031		break;
1032	case VOYAGER_PSI_WRITE:
1033		cat_write(&psi, &psi_asic, reg, *data);
1034		break;
1035	case VOYAGER_PSI_SUBREAD:
1036		cat_subread(&psi, &psi_asic, reg, 1, data);
1037		break;
1038	case VOYAGER_PSI_SUBWRITE:
1039		cat_subwrite(&psi, &psi_asic, reg, 1, data);
1040		break;
1041	default:
1042		printk(KERN_ERR "Voyager PSI, unrecognised command %d\n", cmd);
1043		break;
1044	}
1045	outb(VOYAGER_CAT_END, CAT_CMD);
1046}
1047
1048void
1049voyager_cat_do_common_interrupt(void)
1050{
1051	/* This is caused either by a memory parity error or something
1052	 * in the PSI */
1053	__u8 data;
1054	voyager_module_t psi = { 0 };
1055	voyager_asic_t psi_asic = { 0 };
1056	struct voyager_psi psi_reg;
1057	int i;
1058 re_read:
1059	psi.asic = &psi_asic;
1060	psi.asic->asic_id = VOYAGER_CAT_ID;
1061	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
1062	psi.module_addr = VOYAGER_PSI;
1063	psi.scan_path_connected = 0;
1064
1065	outb(VOYAGER_CAT_END, CAT_CMD);
1066	/* Connect the PSI to the CAT Bus */
1067	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
1068	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
1069	outb(VOYAGER_CAT_RUN, CAT_CMD);
1070	cat_disconnect(&psi, &psi_asic);
1071	/* Read the status.  NOTE: Need to read *all* the PSI regs here
1072	 * otherwise the cmn int will be reasserted */
1073	for(i = 0; i < sizeof(psi_reg.regs); i++) {
1074		cat_read(&psi, &psi_asic, i, &((__u8 *)&psi_reg.regs)[i]);
1075	}
1076	outb(VOYAGER_CAT_END, CAT_CMD);
1077	if((psi_reg.regs.checkbit & 0x02) == 0) {
1078		psi_reg.regs.checkbit |= 0x02;
1079		cat_write(&psi, &psi_asic, 5, psi_reg.regs.checkbit);
1080		printk("VOYAGER RE-READ PSI\n");
1081		goto re_read;
1082	}
1083	outb(VOYAGER_CAT_RUN, CAT_CMD);
1084	for(i = 0; i < sizeof(psi_reg.subregs); i++) {
1085		/* This looks strange, but the PSI doesn't do auto increment
1086		 * correctly */
1087		cat_subread(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG + i, 
1088			    1, &((__u8 *)&psi_reg.subregs)[i]); 
1089	}
1090	outb(VOYAGER_CAT_END, CAT_CMD);
1091#ifdef VOYAGER_CAT_DEBUG
1092	printk("VOYAGER PSI: ");
1093	for(i=0; i<sizeof(psi_reg.regs); i++)
1094		printk("%02x ", ((__u8 *)&psi_reg.regs)[i]);
1095	printk("\n           ");
1096	for(i=0; i<sizeof(psi_reg.subregs); i++)
1097		printk("%02x ", ((__u8 *)&psi_reg.subregs)[i]);
1098	printk("\n");
1099#endif
1100	if(psi_reg.regs.intstatus & PSI_MON) {
1101		/* switch off or power fail */
1102
1103		if(psi_reg.subregs.supply & PSI_SWITCH_OFF) {
1104			if(voyager_status.switch_off) {
1105				printk(KERN_ERR "Voyager front panel switch turned off again---Immediate power off!\n");
1106				voyager_cat_power_off();
1107				/* not reached */
1108			} else {
1109				printk(KERN_ERR "Voyager front panel switch turned off\n");
1110				voyager_status.switch_off = 1;
1111				voyager_status.request_from_kernel = 1;
1112				up(&kvoyagerd_sem);
1113			}
1114			/* Tell the hardware we're taking care of the
1115			 * shutdown, otherwise it will power the box off
1116			 * within 3 seconds of the switch being pressed and,
1117			 * which is much more important to us, continue to 
1118			 * assert the common interrupt */
1119			data = PSI_CLR_SWITCH_OFF;
1120			outb(VOYAGER_CAT_RUN, CAT_CMD);
1121			cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG,
1122				     1, &data);
1123			outb(VOYAGER_CAT_END, CAT_CMD);
1124		} else {
1125
1126			VDEBUG(("Voyager ac fail reg 0x%x\n",
1127				psi_reg.subregs.ACfail));
1128			if((psi_reg.subregs.ACfail & AC_FAIL_STAT_CHANGE) == 0) {
1129				/* No further update */
1130				return;
1131			}
1132#if 0
1133			/* Don't bother trying to find out who failed.
1134			 * FIXME: This probably makes the code incorrect on
1135			 * anything other than a 345x */
1136			for(i=0; i< 5; i++) {
1137				if( psi_reg.subregs.ACfail &(1<<i)) {
1138					break;
1139				}
1140			}
1141			printk(KERN_NOTICE "AC FAIL IN SUPPLY %d\n", i);
1142#endif
1143			/* DON'T do this: it shuts down the AC PSI 
1144			outb(VOYAGER_CAT_RUN, CAT_CMD);
1145			data = PSI_MASK_MASK | i;
1146			cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_MASK,
1147				     1, &data);
1148			outb(VOYAGER_CAT_END, CAT_CMD);
1149			*/
1150			printk(KERN_ERR "Voyager AC power failure\n");
1151			outb(VOYAGER_CAT_RUN, CAT_CMD);
1152			data = PSI_COLD_START;
1153			cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG,
1154				     1, &data);
1155			outb(VOYAGER_CAT_END, CAT_CMD);
1156			voyager_status.power_fail = 1;
1157			voyager_status.request_from_kernel = 1;
1158			up(&kvoyagerd_sem);
1159		}
1160		
1161		
1162	} else if(psi_reg.regs.intstatus & PSI_FAULT) {
1163		/* Major fault! */
1164		printk(KERN_ERR "Voyager PSI Detected major fault, immediate power off!\n");
1165		voyager_cat_power_off();
1166		/* not reached */
1167	} else if(psi_reg.regs.intstatus & (PSI_DC_FAIL | PSI_ALARM
1168					    | PSI_CURRENT | PSI_DVM
1169					    | PSI_PSCFAULT | PSI_STAT_CHG)) {
1170		/* other psi fault */
1171
1172		printk(KERN_WARNING "Voyager PSI status 0x%x\n", data);
1173		/* clear the PSI fault */
1174		outb(VOYAGER_CAT_RUN, CAT_CMD);
1175		cat_write(&psi, &psi_asic, VOYAGER_PSI_STATUS_REG, 0);
1176		outb(VOYAGER_CAT_END, CAT_CMD);
1177	}
1178}