voyager_cat.c 35.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/* -*- mode: c; c-basic-offset: 8 -*- */

/* Copyright (C) 1999,2001
 *
 * Author: J.E.J.Bottomley@HansenPartnership.com
 *
 * This file contains all the logic for manipulating the CAT bus
 * in a level 5 machine.
 *
 * The CAT bus is a serial configuration and test bus.  Its primary
 * uses are to probe the initial configuration of the system and to
 * diagnose error conditions when a system interrupt occurs.  The low
 * level interface is fairly primitive, so most of this file consists
 * of bit shift manipulations to send and receive packets on the
 * serial bus */

#include <linux/types.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <asm/voyager.h>
#include <asm/vic.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/io.h>

#ifdef VOYAGER_CAT_DEBUG
#define CDEBUG(x)	printk x
#else
#define CDEBUG(x)
#endif

/* the CAT command port */
#define CAT_CMD		(sspb + 0xe)
/* the CAT data port */
#define CAT_DATA	(sspb + 0xd)

/* the internal cat functions */
I
Ingo Molnar 已提交
40 41
static void cat_pack(__u8 * msg, __u16 start_bit, __u8 * data, __u16 num_bits);
static void cat_unpack(__u8 * msg, __u16 start_bit, __u8 * data,
L
Linus Torvalds 已提交
42
		       __u16 num_bits);
I
Ingo Molnar 已提交
43
static void cat_build_header(__u8 * header, const __u16 len,
L
Linus Torvalds 已提交
44 45
			     const __u16 smallest_reg_bits,
			     const __u16 longest_reg_bits);
I
Ingo Molnar 已提交
46
static int cat_sendinst(voyager_module_t * modp, voyager_asic_t * asicp,
L
Linus Torvalds 已提交
47
			__u8 reg, __u8 op);
I
Ingo Molnar 已提交
48 49 50
static int cat_getdata(voyager_module_t * modp, voyager_asic_t * asicp,
		       __u8 reg, __u8 * value);
static int cat_shiftout(__u8 * data, __u16 data_bytes, __u16 header_bytes,
L
Linus Torvalds 已提交
51
			__u8 pad_bits);
I
Ingo Molnar 已提交
52
static int cat_write(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg,
L
Linus Torvalds 已提交
53
		     __u8 value);
I
Ingo Molnar 已提交
54 55 56
static int cat_read(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg,
		    __u8 * value);
static int cat_subread(voyager_module_t * modp, voyager_asic_t * asicp,
L
Linus Torvalds 已提交
57
		       __u16 offset, __u16 len, void *buf);
I
Ingo Molnar 已提交
58
static int cat_senddata(voyager_module_t * modp, voyager_asic_t * asicp,
L
Linus Torvalds 已提交
59
			__u8 reg, __u8 value);
I
Ingo Molnar 已提交
60 61
static int cat_disconnect(voyager_module_t * modp, voyager_asic_t * asicp);
static int cat_connect(voyager_module_t * modp, voyager_asic_t * asicp);
L
Linus Torvalds 已提交
62

I
Ingo Molnar 已提交
63
static inline const char *cat_module_name(int module_id)
L
Linus Torvalds 已提交
64
{
I
Ingo Molnar 已提交
65
	switch (module_id) {
L
Linus Torvalds 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
	case 0x10:
		return "Processor Slot 0";
	case 0x11:
		return "Processor Slot 1";
	case 0x12:
		return "Processor Slot 2";
	case 0x13:
		return "Processor Slot 4";
	case 0x14:
		return "Memory Slot 0";
	case 0x15:
		return "Memory Slot 1";
	case 0x18:
		return "Primary Microchannel";
	case 0x19:
		return "Secondary Microchannel";
	case 0x1a:
		return "Power Supply Interface";
	case 0x1c:
		return "Processor Slot 5";
	case 0x1d:
		return "Processor Slot 6";
	case 0x1e:
		return "Processor Slot 7";
	case 0x1f:
		return "Processor Slot 8";
	default:
		return "Unknown Module";
	}
}

static int sspb = 0;		/* stores the super port location */
int voyager_8slot = 0;		/* set to true if a 51xx monster */

voyager_module_t *voyager_cat_list;

/* the I/O port assignments for the VIC and QIC */
static struct resource vic_res = {
I
Ingo Molnar 已提交
104 105 106
	.name = "Voyager Interrupt Controller",
	.start = 0xFC00,
	.end = 0xFC6F
107
};
L
Linus Torvalds 已提交
108
static struct resource qic_res = {
I
Ingo Molnar 已提交
109 110 111
	.name = "Quad Interrupt Controller",
	.start = 0xFC70,
	.end = 0xFCFF
112
};
L
Linus Torvalds 已提交
113 114 115 116 117 118

/* This function is used to pack a data bit stream inside a message.
 * It writes num_bits of the data buffer in msg starting at start_bit.
 * Note: This function assumes that any unused bit in the data stream
 * is set to zero so that the ors will work correctly */
static void
I
Ingo Molnar 已提交
119
cat_pack(__u8 * msg, const __u16 start_bit, __u8 * data, const __u16 num_bits)
L
Linus Torvalds 已提交
120 121 122 123 124 125 126 127 128
{
	/* compute initial shift needed */
	const __u16 offset = start_bit % BITS_PER_BYTE;
	__u16 len = num_bits / BITS_PER_BYTE;
	__u16 byte = start_bit / BITS_PER_BYTE;
	__u16 residue = (num_bits % BITS_PER_BYTE) + offset;
	int i;

	/* adjust if we have more than a byte of residue */
I
Ingo Molnar 已提交
129
	if (residue >= BITS_PER_BYTE) {
L
Linus Torvalds 已提交
130 131 132 133 134 135 136
		residue -= BITS_PER_BYTE;
		len++;
	}

	/* clear out the bits.  We assume here that if len==0 then
	 * residue >= offset.  This is always true for the catbus
	 * operations */
I
Ingo Molnar 已提交
137
	msg[byte] &= 0xff << (BITS_PER_BYTE - offset);
L
Linus Torvalds 已提交
138
	msg[byte++] |= data[0] >> offset;
I
Ingo Molnar 已提交
139
	if (len == 0)
L
Linus Torvalds 已提交
140
		return;
I
Ingo Molnar 已提交
141 142 143 144
	for (i = 1; i < len; i++)
		msg[byte++] = (data[i - 1] << (BITS_PER_BYTE - offset))
		    | (data[i] >> offset);
	if (residue != 0) {
L
Linus Torvalds 已提交
145
		__u8 mask = 0xff >> residue;
I
Ingo Molnar 已提交
146 147 148
		__u8 last_byte = data[i - 1] << (BITS_PER_BYTE - offset)
		    | (data[i] >> offset);

L
Linus Torvalds 已提交
149 150 151 152 153 154
		last_byte &= ~mask;
		msg[byte] &= mask;
		msg[byte] |= last_byte;
	}
	return;
}
I
Ingo Molnar 已提交
155

L
Linus Torvalds 已提交
156 157 158 159 160 161 162
/* unpack the data again (same arguments as cat_pack()). data buffer
 * must be zero populated.
 *
 * Function: given a message string move to start_bit and copy num_bits into
 * data (starting at bit 0 in data).
 */
static void
I
Ingo Molnar 已提交
163
cat_unpack(__u8 * msg, const __u16 start_bit, __u8 * data, const __u16 num_bits)
L
Linus Torvalds 已提交
164 165 166 167 168 169 170 171
{
	/* compute initial shift needed */
	const __u16 offset = start_bit % BITS_PER_BYTE;
	__u16 len = num_bits / BITS_PER_BYTE;
	const __u8 last_bits = num_bits % BITS_PER_BYTE;
	__u16 byte = start_bit / BITS_PER_BYTE;
	int i;

I
Ingo Molnar 已提交
172
	if (last_bits != 0)
L
Linus Torvalds 已提交
173 174 175 176
		len++;

	/* special case: want < 8 bits from msg and we can get it from
	 * a single byte of the msg */
I
Ingo Molnar 已提交
177
	if (len == 0 && BITS_PER_BYTE - offset >= num_bits) {
L
Linus Torvalds 已提交
178 179 180 181
		data[0] = msg[byte] << offset;
		data[0] &= 0xff >> (BITS_PER_BYTE - num_bits);
		return;
	}
I
Ingo Molnar 已提交
182
	for (i = 0; i < len; i++) {
L
Linus Torvalds 已提交
183 184
		/* this annoying if has to be done just in case a read of
		 * msg one beyond the array causes a panic */
I
Ingo Molnar 已提交
185
		if (offset != 0) {
L
Linus Torvalds 已提交
186 187
			data[i] = msg[byte++] << offset;
			data[i] |= msg[byte] >> (BITS_PER_BYTE - offset);
I
Ingo Molnar 已提交
188
		} else {
L
Linus Torvalds 已提交
189 190 191 192
			data[i] = msg[byte++];
		}
	}
	/* do we need to truncate the final byte */
I
Ingo Molnar 已提交
193 194
	if (last_bits != 0) {
		data[i - 1] &= 0xff << (BITS_PER_BYTE - last_bits);
L
Linus Torvalds 已提交
195 196 197 198 199
	}
	return;
}

static void
I
Ingo Molnar 已提交
200
cat_build_header(__u8 * header, const __u16 len, const __u16 smallest_reg_bits,
L
Linus Torvalds 已提交
201 202 203 204 205 206
		 const __u16 longest_reg_bits)
{
	int i;
	__u16 start_bit = (smallest_reg_bits - 1) % BITS_PER_BYTE;
	__u8 *last_byte = &header[len - 1];

I
Ingo Molnar 已提交
207
	if (start_bit == 0)
L
Linus Torvalds 已提交
208
		start_bit = 1;	/* must have at least one bit in the hdr */
I
Ingo Molnar 已提交
209 210

	for (i = 0; i < len; i++)
L
Linus Torvalds 已提交
211 212
		header[i] = 0;

I
Ingo Molnar 已提交
213
	for (i = start_bit; i > 0; i--)
L
Linus Torvalds 已提交
214 215 216 217 218
		*last_byte = ((*last_byte) << 1) + 1;

}

static int
I
Ingo Molnar 已提交
219
cat_sendinst(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg, __u8 op)
L
Linus Torvalds 已提交
220 221 222 223 224
{
	__u8 parity, inst, inst_buf[4] = { 0 };
	__u8 iseq[VOYAGER_MAX_SCAN_PATH], hseq[VOYAGER_MAX_REG_SIZE];
	__u16 ibytes, hbytes, padbits;
	int i;
I
Ingo Molnar 已提交
225

L
Linus Torvalds 已提交
226 227 228 229
	/* 
	 * Parity is the parity of the register number + 1 (READ_REGISTER
	 * and WRITE_REGISTER always add '1' to the number of bits == 1)
	 */
I
Ingo Molnar 已提交
230 231 232 233
	parity = (__u8) (1 + (reg & 0x01) +
			 ((__u8) (reg & 0x02) >> 1) +
			 ((__u8) (reg & 0x04) >> 2) +
			 ((__u8) (reg & 0x08) >> 3)) % 2;
L
Linus Torvalds 已提交
234 235 236 237

	inst = ((parity << 7) | (reg << 2) | op);

	outb(VOYAGER_CAT_IRCYC, CAT_CMD);
I
Ingo Molnar 已提交
238 239 240 241
	if (!modp->scan_path_connected) {
		if (asicp->asic_id != VOYAGER_CAT_ID) {
			printk
			    ("**WARNING***: cat_sendinst has disconnected scan path not to CAT asic\n");
L
Linus Torvalds 已提交
242 243 244 245
			return 1;
		}
		outb(VOYAGER_CAT_HEADER, CAT_DATA);
		outb(inst, CAT_DATA);
I
Ingo Molnar 已提交
246
		if (inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
L
Linus Torvalds 已提交
247 248 249 250 251 252
			CDEBUG(("VOYAGER CAT: cat_sendinst failed to get CAT_HEADER\n"));
			return 1;
		}
		return 0;
	}
	ibytes = modp->inst_bits / BITS_PER_BYTE;
I
Ingo Molnar 已提交
253
	if ((padbits = modp->inst_bits % BITS_PER_BYTE) != 0) {
L
Linus Torvalds 已提交
254 255 256 257
		padbits = BITS_PER_BYTE - padbits;
		ibytes++;
	}
	hbytes = modp->largest_reg / BITS_PER_BYTE;
I
Ingo Molnar 已提交
258
	if (modp->largest_reg % BITS_PER_BYTE)
L
Linus Torvalds 已提交
259 260 261
		hbytes++;
	CDEBUG(("cat_sendinst: ibytes=%d, hbytes=%d\n", ibytes, hbytes));
	/* initialise the instruction sequence to 0xff */
I
Ingo Molnar 已提交
262
	for (i = 0; i < ibytes + hbytes; i++)
L
Linus Torvalds 已提交
263 264 265 266 267 268 269 270
		iseq[i] = 0xff;
	cat_build_header(hseq, hbytes, modp->smallest_reg, modp->largest_reg);
	cat_pack(iseq, modp->inst_bits, hseq, hbytes * BITS_PER_BYTE);
	inst_buf[0] = inst;
	inst_buf[1] = 0xFF >> (modp->largest_reg % BITS_PER_BYTE);
	cat_pack(iseq, asicp->bit_location, inst_buf, asicp->ireg_length);
#ifdef VOYAGER_CAT_DEBUG
	printk("ins = 0x%x, iseq: ", inst);
I
Ingo Molnar 已提交
271
	for (i = 0; i < ibytes + hbytes; i++)
L
Linus Torvalds 已提交
272 273 274
		printk("0x%x ", iseq[i]);
	printk("\n");
#endif
I
Ingo Molnar 已提交
275
	if (cat_shiftout(iseq, ibytes, hbytes, padbits)) {
L
Linus Torvalds 已提交
276 277 278 279 280 281 282 283
		CDEBUG(("VOYAGER CAT: cat_sendinst: cat_shiftout failed\n"));
		return 1;
	}
	CDEBUG(("CAT SHIFTOUT DONE\n"));
	return 0;
}

static int
I
Ingo Molnar 已提交
284 285
cat_getdata(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg,
	    __u8 * value)
L
Linus Torvalds 已提交
286
{
I
Ingo Molnar 已提交
287 288
	if (!modp->scan_path_connected) {
		if (asicp->asic_id != VOYAGER_CAT_ID) {
L
Linus Torvalds 已提交
289 290 291
			CDEBUG(("VOYAGER CAT: ERROR: cat_getdata to CAT asic with scan path connected\n"));
			return 1;
		}
I
Ingo Molnar 已提交
292
		if (reg > VOYAGER_SUBADDRHI)
L
Linus Torvalds 已提交
293 294 295 296 297
			outb(VOYAGER_CAT_RUN, CAT_CMD);
		outb(VOYAGER_CAT_DRCYC, CAT_CMD);
		outb(VOYAGER_CAT_HEADER, CAT_DATA);
		*value = inb(CAT_DATA);
		outb(0xAA, CAT_DATA);
I
Ingo Molnar 已提交
298
		if (inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
L
Linus Torvalds 已提交
299 300 301 302
			CDEBUG(("cat_getdata: failed to get VOYAGER_CAT_HEADER\n"));
			return 1;
		}
		return 0;
I
Ingo Molnar 已提交
303 304
	} else {
		__u16 sbits = modp->num_asics - 1 + asicp->ireg_length;
L
Linus Torvalds 已提交
305 306
		__u16 sbytes = sbits / BITS_PER_BYTE;
		__u16 tbytes;
I
Ingo Molnar 已提交
307 308
		__u8 string[VOYAGER_MAX_SCAN_PATH],
		    trailer[VOYAGER_MAX_REG_SIZE];
L
Linus Torvalds 已提交
309 310
		__u8 padbits;
		int i;
I
Ingo Molnar 已提交
311

L
Linus Torvalds 已提交
312 313
		outb(VOYAGER_CAT_DRCYC, CAT_CMD);

I
Ingo Molnar 已提交
314
		if ((padbits = sbits % BITS_PER_BYTE) != 0) {
L
Linus Torvalds 已提交
315 316 317 318
			padbits = BITS_PER_BYTE - padbits;
			sbytes++;
		}
		tbytes = asicp->ireg_length / BITS_PER_BYTE;
I
Ingo Molnar 已提交
319
		if (asicp->ireg_length % BITS_PER_BYTE)
L
Linus Torvalds 已提交
320 321
			tbytes++;
		CDEBUG(("cat_getdata: tbytes = %d, sbytes = %d, padbits = %d\n",
I
Ingo Molnar 已提交
322
			tbytes, sbytes, padbits));
L
Linus Torvalds 已提交
323 324
		cat_build_header(trailer, tbytes, 1, asicp->ireg_length);

I
Ingo Molnar 已提交
325
		for (i = tbytes - 1; i >= 0; i--) {
L
Linus Torvalds 已提交
326 327 328 329
			outb(trailer[i], CAT_DATA);
			string[sbytes + i] = inb(CAT_DATA);
		}

I
Ingo Molnar 已提交
330
		for (i = sbytes - 1; i >= 0; i--) {
L
Linus Torvalds 已提交
331 332 333 334
			outb(0xaa, CAT_DATA);
			string[i] = inb(CAT_DATA);
		}
		*value = 0;
I
Ingo Molnar 已提交
335 336 337
		cat_unpack(string,
			   padbits + (tbytes * BITS_PER_BYTE) +
			   asicp->asic_location, value, asicp->ireg_length);
L
Linus Torvalds 已提交
338 339
#ifdef VOYAGER_CAT_DEBUG
		printk("value=0x%x, string: ", *value);
I
Ingo Molnar 已提交
340
		for (i = 0; i < tbytes + sbytes; i++)
L
Linus Torvalds 已提交
341 342 343
			printk("0x%x ", string[i]);
		printk("\n");
#endif
I
Ingo Molnar 已提交
344

L
Linus Torvalds 已提交
345
		/* sanity check the rest of the return */
I
Ingo Molnar 已提交
346
		for (i = 0; i < tbytes; i++) {
L
Linus Torvalds 已提交
347 348
			__u8 input = 0;

I
Ingo Molnar 已提交
349 350 351
			cat_unpack(string, padbits + (i * BITS_PER_BYTE),
				   &input, BITS_PER_BYTE);
			if (trailer[i] != input) {
L
Linus Torvalds 已提交
352 353 354 355 356 357 358 359 360 361
				CDEBUG(("cat_getdata: failed to sanity check rest of ret(%d) 0x%x != 0x%x\n", i, input, trailer[i]));
				return 1;
			}
		}
		CDEBUG(("cat_getdata DONE\n"));
		return 0;
	}
}

static int
I
Ingo Molnar 已提交
362
cat_shiftout(__u8 * data, __u16 data_bytes, __u16 header_bytes, __u8 pad_bits)
L
Linus Torvalds 已提交
363 364
{
	int i;
I
Ingo Molnar 已提交
365 366

	for (i = data_bytes + header_bytes - 1; i >= header_bytes; i--)
L
Linus Torvalds 已提交
367 368
		outb(data[i], CAT_DATA);

I
Ingo Molnar 已提交
369
	for (i = header_bytes - 1; i >= 0; i--) {
L
Linus Torvalds 已提交
370 371 372 373 374 375 376 377
		__u8 header = 0;
		__u8 input;

		outb(data[i], CAT_DATA);
		input = inb(CAT_DATA);
		CDEBUG(("cat_shiftout: returned 0x%x\n", input));
		cat_unpack(data, ((data_bytes + i) * BITS_PER_BYTE) - pad_bits,
			   &header, BITS_PER_BYTE);
I
Ingo Molnar 已提交
378
		if (input != header) {
L
Linus Torvalds 已提交
379 380 381 382 383 384 385 386
			CDEBUG(("VOYAGER CAT: cat_shiftout failed to return header 0x%x != 0x%x\n", input, header));
			return 1;
		}
	}
	return 0;
}

static int
I
Ingo Molnar 已提交
387
cat_senddata(voyager_module_t * modp, voyager_asic_t * asicp,
L
Linus Torvalds 已提交
388 389 390
	     __u8 reg, __u8 value)
{
	outb(VOYAGER_CAT_DRCYC, CAT_CMD);
I
Ingo Molnar 已提交
391 392
	if (!modp->scan_path_connected) {
		if (asicp->asic_id != VOYAGER_CAT_ID) {
L
Linus Torvalds 已提交
393 394 395 396 397
			CDEBUG(("VOYAGER CAT: ERROR: scan path disconnected when asic != CAT\n"));
			return 1;
		}
		outb(VOYAGER_CAT_HEADER, CAT_DATA);
		outb(value, CAT_DATA);
I
Ingo Molnar 已提交
398
		if (inb(CAT_DATA) != VOYAGER_CAT_HEADER) {
L
Linus Torvalds 已提交
399 400 401
			CDEBUG(("cat_senddata: failed to get correct header response to sent data\n"));
			return 1;
		}
I
Ingo Molnar 已提交
402
		if (reg > VOYAGER_SUBADDRHI) {
L
Linus Torvalds 已提交
403 404 405 406
			outb(VOYAGER_CAT_RUN, CAT_CMD);
			outb(VOYAGER_CAT_END, CAT_CMD);
			outb(VOYAGER_CAT_RUN, CAT_CMD);
		}
I
Ingo Molnar 已提交
407

L
Linus Torvalds 已提交
408
		return 0;
I
Ingo Molnar 已提交
409
	} else {
L
Linus Torvalds 已提交
410
		__u16 hbytes = asicp->ireg_length / BITS_PER_BYTE;
I
Ingo Molnar 已提交
411 412 413 414
		__u16 dbytes =
		    (modp->num_asics - 1 + asicp->ireg_length) / BITS_PER_BYTE;
		__u8 padbits, dseq[VOYAGER_MAX_SCAN_PATH],
		    hseq[VOYAGER_MAX_REG_SIZE];
L
Linus Torvalds 已提交
415 416
		int i;

I
Ingo Molnar 已提交
417 418
		if ((padbits = (modp->num_asics - 1
				+ asicp->ireg_length) % BITS_PER_BYTE) != 0) {
L
Linus Torvalds 已提交
419 420 421
			padbits = BITS_PER_BYTE - padbits;
			dbytes++;
		}
I
Ingo Molnar 已提交
422
		if (asicp->ireg_length % BITS_PER_BYTE)
L
Linus Torvalds 已提交
423
			hbytes++;
I
Ingo Molnar 已提交
424

L
Linus Torvalds 已提交
425
		cat_build_header(hseq, hbytes, 1, asicp->ireg_length);
I
Ingo Molnar 已提交
426 427

		for (i = 0; i < dbytes + hbytes; i++)
L
Linus Torvalds 已提交
428 429 430 431 432
			dseq[i] = 0xff;
		CDEBUG(("cat_senddata: dbytes=%d, hbytes=%d, padbits=%d\n",
			dbytes, hbytes, padbits));
		cat_pack(dseq, modp->num_asics - 1 + asicp->ireg_length,
			 hseq, hbytes * BITS_PER_BYTE);
I
Ingo Molnar 已提交
433
		cat_pack(dseq, asicp->asic_location, &value,
L
Linus Torvalds 已提交
434 435 436
			 asicp->ireg_length);
#ifdef VOYAGER_CAT_DEBUG
		printk("dseq ");
I
Ingo Molnar 已提交
437
		for (i = 0; i < hbytes + dbytes; i++) {
L
Linus Torvalds 已提交
438 439 440 441 442 443 444 445 446
			printk("0x%x ", dseq[i]);
		}
		printk("\n");
#endif
		return cat_shiftout(dseq, dbytes, hbytes, padbits);
	}
}

static int
I
Ingo Molnar 已提交
447
cat_write(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg, __u8 value)
L
Linus Torvalds 已提交
448
{
I
Ingo Molnar 已提交
449
	if (cat_sendinst(modp, asicp, reg, VOYAGER_WRITE_CONFIG))
L
Linus Torvalds 已提交
450 451 452 453 454
		return 1;
	return cat_senddata(modp, asicp, reg, value);
}

static int
I
Ingo Molnar 已提交
455 456
cat_read(voyager_module_t * modp, voyager_asic_t * asicp, __u8 reg,
	 __u8 * value)
L
Linus Torvalds 已提交
457
{
I
Ingo Molnar 已提交
458
	if (cat_sendinst(modp, asicp, reg, VOYAGER_READ_CONFIG))
L
Linus Torvalds 已提交
459 460 461 462 463
		return 1;
	return cat_getdata(modp, asicp, reg, value);
}

static int
I
Ingo Molnar 已提交
464
cat_subaddrsetup(voyager_module_t * modp, voyager_asic_t * asicp, __u16 offset,
L
Linus Torvalds 已提交
465 466 467 468
		 __u16 len)
{
	__u8 val;

I
Ingo Molnar 已提交
469
	if (len > 1) {
L
Linus Torvalds 已提交
470 471
		/* set auto increment */
		__u8 newval;
I
Ingo Molnar 已提交
472 473

		if (cat_read(modp, asicp, VOYAGER_AUTO_INC_REG, &val)) {
L
Linus Torvalds 已提交
474 475 476
			CDEBUG(("cat_subaddrsetup: read of VOYAGER_AUTO_INC_REG failed\n"));
			return 1;
		}
I
Ingo Molnar 已提交
477 478
		CDEBUG(("cat_subaddrsetup: VOYAGER_AUTO_INC_REG = 0x%x\n",
			val));
L
Linus Torvalds 已提交
479
		newval = val | VOYAGER_AUTO_INC;
I
Ingo Molnar 已提交
480 481
		if (newval != val) {
			if (cat_write(modp, asicp, VOYAGER_AUTO_INC_REG, val)) {
L
Linus Torvalds 已提交
482 483 484 485 486
				CDEBUG(("cat_subaddrsetup: write to VOYAGER_AUTO_INC_REG failed\n"));
				return 1;
			}
		}
	}
I
Ingo Molnar 已提交
487
	if (cat_write(modp, asicp, VOYAGER_SUBADDRLO, (__u8) (offset & 0xff))) {
L
Linus Torvalds 已提交
488 489 490
		CDEBUG(("cat_subaddrsetup: write to SUBADDRLO failed\n"));
		return 1;
	}
I
Ingo Molnar 已提交
491 492 493
	if (asicp->subaddr > VOYAGER_SUBADDR_LO) {
		if (cat_write
		    (modp, asicp, VOYAGER_SUBADDRHI, (__u8) (offset >> 8))) {
L
Linus Torvalds 已提交
494 495 496 497
			CDEBUG(("cat_subaddrsetup: write to SUBADDRHI failed\n"));
			return 1;
		}
		cat_read(modp, asicp, VOYAGER_SUBADDRHI, &val);
I
Ingo Molnar 已提交
498 499
		CDEBUG(("cat_subaddrsetup: offset = %d, hi = %d\n", offset,
			val));
L
Linus Torvalds 已提交
500 501 502 503 504
	}
	cat_read(modp, asicp, VOYAGER_SUBADDRLO, &val);
	CDEBUG(("cat_subaddrsetup: offset = %d, lo = %d\n", offset, val));
	return 0;
}
I
Ingo Molnar 已提交
505

L
Linus Torvalds 已提交
506
static int
I
Ingo Molnar 已提交
507 508
cat_subwrite(voyager_module_t * modp, voyager_asic_t * asicp, __u16 offset,
	     __u16 len, void *buf)
L
Linus Torvalds 已提交
509 510 511 512
{
	int i, retval;

	/* FIXME: need special actions for VOYAGER_CAT_ID here */
I
Ingo Molnar 已提交
513
	if (asicp->asic_id == VOYAGER_CAT_ID) {
L
Linus Torvalds 已提交
514 515 516 517 518 519
		CDEBUG(("cat_subwrite: ATTEMPT TO WRITE TO CAT ASIC\n"));
		/* FIXME -- This is supposed to be handled better
		 * There is a problem writing to the cat asic in the
		 * PSI.  The 30us delay seems to work, though */
		udelay(30);
	}
I
Ingo Molnar 已提交
520 521

	if ((retval = cat_subaddrsetup(modp, asicp, offset, len)) != 0) {
L
Linus Torvalds 已提交
522 523 524
		printk("cat_subwrite: cat_subaddrsetup FAILED\n");
		return retval;
	}
I
Ingo Molnar 已提交
525 526 527

	if (cat_sendinst
	    (modp, asicp, VOYAGER_SUBADDRDATA, VOYAGER_WRITE_CONFIG)) {
L
Linus Torvalds 已提交
528 529 530
		printk("cat_subwrite: cat_sendinst FAILED\n");
		return 1;
	}
I
Ingo Molnar 已提交
531 532 533 534 535
	for (i = 0; i < len; i++) {
		if (cat_senddata(modp, asicp, 0xFF, ((__u8 *) buf)[i])) {
			printk
			    ("cat_subwrite: cat_sendata element at %d FAILED\n",
			     i);
L
Linus Torvalds 已提交
536 537 538 539 540 541
			return 1;
		}
	}
	return 0;
}
static int
I
Ingo Molnar 已提交
542
cat_subread(voyager_module_t * modp, voyager_asic_t * asicp, __u16 offset,
L
Linus Torvalds 已提交
543 544 545 546
	    __u16 len, void *buf)
{
	int i, retval;

I
Ingo Molnar 已提交
547
	if ((retval = cat_subaddrsetup(modp, asicp, offset, len)) != 0) {
L
Linus Torvalds 已提交
548 549 550 551
		CDEBUG(("cat_subread: cat_subaddrsetup FAILED\n"));
		return retval;
	}

I
Ingo Molnar 已提交
552
	if (cat_sendinst(modp, asicp, VOYAGER_SUBADDRDATA, VOYAGER_READ_CONFIG)) {
L
Linus Torvalds 已提交
553 554 555
		CDEBUG(("cat_subread: cat_sendinst failed\n"));
		return 1;
	}
I
Ingo Molnar 已提交
556 557 558 559
	for (i = 0; i < len; i++) {
		if (cat_getdata(modp, asicp, 0xFF, &((__u8 *) buf)[i])) {
			CDEBUG(("cat_subread: cat_getdata element %d failed\n",
				i));
L
Linus Torvalds 已提交
560 561 562 563 564 565 566 567 568 569 570 571 572 573
			return 1;
		}
	}
	return 0;
}

/* buffer for storing EPROM data read in during initialisation */
static __initdata __u8 eprom_buf[0xFFFF];
static voyager_module_t *voyager_initial_module;

/* Initialise the cat bus components.  We assume this is called by the
 * boot cpu *after* all memory initialisation has been done (so we can
 * use kmalloc) but before smp initialisation, so we can probe the SMP
 * configuration and pick up necessary information.  */
I
Ingo Molnar 已提交
574
void __init voyager_cat_init(void)
L
Linus Torvalds 已提交
575 576 577 578 579 580 581 582
{
	voyager_module_t **modpp = &voyager_initial_module;
	voyager_asic_t **asicpp;
	voyager_asic_t *qabc_asic = NULL;
	int i, j;
	unsigned long qic_addr = 0;
	__u8 qabc_data[0x20];
	__u8 num_submodules, val;
I
Ingo Molnar 已提交
583 584
	voyager_eprom_hdr_t *eprom_hdr = (voyager_eprom_hdr_t *) & eprom_buf[0];

L
Linus Torvalds 已提交
585 586
	__u8 cmos[4];
	unsigned long addr;
I
Ingo Molnar 已提交
587

L
Linus Torvalds 已提交
588
	/* initiallise the SUS mailbox */
I
Ingo Molnar 已提交
589
	for (i = 0; i < sizeof(cmos); i++)
L
Linus Torvalds 已提交
590 591
		cmos[i] = voyager_extended_cmos_read(VOYAGER_DUMP_LOCATION + i);
	addr = *(unsigned long *)cmos;
I
Ingo Molnar 已提交
592 593 594 595
	if ((addr & 0xff000000) != 0xff000000) {
		printk(KERN_ERR
		       "Voyager failed to get SUS mailbox (addr = 0x%lx\n",
		       addr);
L
Linus Torvalds 已提交
596 597
	} else {
		static struct resource res;
I
Ingo Molnar 已提交
598

L
Linus Torvalds 已提交
599 600
		res.name = "voyager SUS";
		res.start = addr;
I
Ingo Molnar 已提交
601 602
		res.end = addr + 0x3ff;

L
Linus Torvalds 已提交
603 604
		request_resource(&iomem_resource, &res);
		voyager_SUS = (struct voyager_SUS *)
I
Ingo Molnar 已提交
605
		    ioremap(addr, 0x400);
L
Linus Torvalds 已提交
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
		printk(KERN_NOTICE "Voyager SUS mailbox version 0x%x\n",
		       voyager_SUS->SUS_version);
		voyager_SUS->kernel_version = VOYAGER_MAILBOX_VERSION;
		voyager_SUS->kernel_flags = VOYAGER_OS_HAS_SYSINT;
	}

	/* clear the processor counts */
	voyager_extended_vic_processors = 0;
	voyager_quad_processors = 0;

	printk("VOYAGER: beginning CAT bus probe\n");
	/* set up the SuperSet Port Block which tells us where the
	 * CAT communication port is */
	sspb = inb(VOYAGER_SSPB_RELOCATION_PORT) * 0x100;
	VDEBUG(("VOYAGER DEBUG: sspb = 0x%x\n", sspb));

	/* now find out if were 8 slot or normal */
I
Ingo Molnar 已提交
623 624
	if ((inb(VIC_PROC_WHO_AM_I) & EIGHT_SLOT_IDENTIFIER)
	    == EIGHT_SLOT_IDENTIFIER) {
L
Linus Torvalds 已提交
625
		voyager_8slot = 1;
I
Ingo Molnar 已提交
626 627
		printk(KERN_NOTICE
		       "Voyager: Eight slot 51xx configuration detected\n");
L
Linus Torvalds 已提交
628 629
	}

I
Ingo Molnar 已提交
630
	for (i = VOYAGER_MIN_MODULE; i <= VOYAGER_MAX_MODULE; i++) {
L
Linus Torvalds 已提交
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
		__u8 input;
		int asic;
		__u16 eprom_size;
		__u16 sp_offset;

		outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
		outb(i, VOYAGER_CAT_CONFIG_PORT);

		/* check the presence of the module */
		outb(VOYAGER_CAT_RUN, CAT_CMD);
		outb(VOYAGER_CAT_IRCYC, CAT_CMD);
		outb(VOYAGER_CAT_HEADER, CAT_DATA);
		/* stream series of alternating 1's and 0's to stimulate
		 * response */
		outb(0xAA, CAT_DATA);
		input = inb(CAT_DATA);
		outb(VOYAGER_CAT_END, CAT_CMD);
I
Ingo Molnar 已提交
648
		if (input != VOYAGER_CAT_HEADER) {
L
Linus Torvalds 已提交
649 650 651 652
			continue;
		}
		CDEBUG(("VOYAGER DEBUG: found module id 0x%x, %s\n", i,
			cat_module_name(i)));
I
Ingo Molnar 已提交
653 654
		*modpp = kmalloc(sizeof(voyager_module_t), GFP_KERNEL);	/*&voyager_module_storage[cat_count++]; */
		if (*modpp == NULL) {
L
Linus Torvalds 已提交
655 656 657 658 659 660
			printk("**WARNING** kmalloc failure in cat_init\n");
			continue;
		}
		memset(*modpp, 0, sizeof(voyager_module_t));
		/* need temporary asic for cat_subread.  It will be
		 * filled in correctly later */
I
Ingo Molnar 已提交
661 662
		(*modpp)->asic = kmalloc(sizeof(voyager_asic_t), GFP_KERNEL);	/*&voyager_asic_storage[asic_count]; */
		if ((*modpp)->asic == NULL) {
L
Linus Torvalds 已提交
663 664 665 666 667 668 669 670
			printk("**WARNING** kmalloc failure in cat_init\n");
			continue;
		}
		memset((*modpp)->asic, 0, sizeof(voyager_asic_t));
		(*modpp)->asic->asic_id = VOYAGER_CAT_ID;
		(*modpp)->asic->subaddr = VOYAGER_SUBADDR_HI;
		(*modpp)->module_addr = i;
		(*modpp)->scan_path_connected = 0;
I
Ingo Molnar 已提交
671
		if (i == VOYAGER_PSI) {
L
Linus Torvalds 已提交
672 673 674 675
			/* Exception leg for modules with no EEPROM */
			printk("Module \"%s\"\n", cat_module_name(i));
			continue;
		}
I
Ingo Molnar 已提交
676

L
Linus Torvalds 已提交
677 678 679
		CDEBUG(("cat_init: Reading eeprom for module 0x%x at offset %d\n", i, VOYAGER_XSUM_END_OFFSET));
		outb(VOYAGER_CAT_RUN, CAT_CMD);
		cat_disconnect(*modpp, (*modpp)->asic);
I
Ingo Molnar 已提交
680 681 682 683 684 685
		if (cat_subread(*modpp, (*modpp)->asic,
				VOYAGER_XSUM_END_OFFSET, sizeof(eprom_size),
				&eprom_size)) {
			printk
			    ("**WARNING**: Voyager couldn't read EPROM size for module 0x%x\n",
			     i);
L
Linus Torvalds 已提交
686 687 688
			outb(VOYAGER_CAT_END, CAT_CMD);
			continue;
		}
I
Ingo Molnar 已提交
689 690 691 692
		if (eprom_size > sizeof(eprom_buf)) {
			printk
			    ("**WARNING**: Voyager insufficient size to read EPROM data, module 0x%x.  Need %d\n",
			     i, eprom_size);
L
Linus Torvalds 已提交
693 694 695 696 697
			outb(VOYAGER_CAT_END, CAT_CMD);
			continue;
		}
		outb(VOYAGER_CAT_END, CAT_CMD);
		outb(VOYAGER_CAT_RUN, CAT_CMD);
I
Ingo Molnar 已提交
698 699 700 701
		CDEBUG(("cat_init: module 0x%x, eeprom_size %d\n", i,
			eprom_size));
		if (cat_subread
		    (*modpp, (*modpp)->asic, 0, eprom_size, eprom_buf)) {
L
Linus Torvalds 已提交
702 703 704 705 706 707
			outb(VOYAGER_CAT_END, CAT_CMD);
			continue;
		}
		outb(VOYAGER_CAT_END, CAT_CMD);
		printk("Module \"%s\", version 0x%x, tracer 0x%x, asics %d\n",
		       cat_module_name(i), eprom_hdr->version_id,
I
Ingo Molnar 已提交
708
		       *((__u32 *) eprom_hdr->tracer), eprom_hdr->num_asics);
L
Linus Torvalds 已提交
709 710 711 712 713
		(*modpp)->ee_size = eprom_hdr->ee_size;
		(*modpp)->num_asics = eprom_hdr->num_asics;
		asicpp = &((*modpp)->asic);
		sp_offset = eprom_hdr->scan_path_offset;
		/* All we really care about are the Quad cards.  We
I
Ingo Molnar 已提交
714 715 716
		 * identify them because they are in a processor slot
		 * and have only four asics */
		if ((i < 0x10 || (i >= 0x14 && i < 0x1c) || i > 0x1f)) {
L
Linus Torvalds 已提交
717 718 719 720 721 722 723 724 725 726
			modpp = &((*modpp)->next);
			continue;
		}
		/* Now we know it's in a processor slot, does it have
		 * a quad baseboard submodule */
		outb(VOYAGER_CAT_RUN, CAT_CMD);
		cat_read(*modpp, (*modpp)->asic, VOYAGER_SUBMODPRESENT,
			 &num_submodules);
		/* lowest two bits, active low */
		num_submodules = ~(0xfc | num_submodules);
I
Ingo Molnar 已提交
727 728 729
		CDEBUG(("VOYAGER CAT: %d submodules present\n",
			num_submodules));
		if (num_submodules == 0) {
L
Linus Torvalds 已提交
730 731 732 733 734
			/* fill in the dyadic extended processors */
			__u8 cpu = i & 0x07;

			printk("Module \"%s\": Dyadic Processor Card\n",
			       cat_module_name(i));
I
Ingo Molnar 已提交
735
			voyager_extended_vic_processors |= (1 << cpu);
L
Linus Torvalds 已提交
736
			cpu += 4;
I
Ingo Molnar 已提交
737
			voyager_extended_vic_processors |= (1 << cpu);
L
Linus Torvalds 已提交
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
			outb(VOYAGER_CAT_END, CAT_CMD);
			continue;
		}

		/* now we want to read the asics on the first submodule,
		 * which should be the quad base board */

		cat_read(*modpp, (*modpp)->asic, VOYAGER_SUBMODSELECT, &val);
		CDEBUG(("cat_init: SUBMODSELECT value = 0x%x\n", val));
		val = (val & 0x7c) | VOYAGER_QUAD_BASEBOARD;
		cat_write(*modpp, (*modpp)->asic, VOYAGER_SUBMODSELECT, val);

		outb(VOYAGER_CAT_END, CAT_CMD);

		CDEBUG(("cat_init: Reading eeprom for module 0x%x at offset %d\n", i, VOYAGER_XSUM_END_OFFSET));
		outb(VOYAGER_CAT_RUN, CAT_CMD);
		cat_disconnect(*modpp, (*modpp)->asic);
I
Ingo Molnar 已提交
755 756 757 758 759 760
		if (cat_subread(*modpp, (*modpp)->asic,
				VOYAGER_XSUM_END_OFFSET, sizeof(eprom_size),
				&eprom_size)) {
			printk
			    ("**WARNING**: Voyager couldn't read EPROM size for module 0x%x\n",
			     i);
L
Linus Torvalds 已提交
761 762 763
			outb(VOYAGER_CAT_END, CAT_CMD);
			continue;
		}
I
Ingo Molnar 已提交
764 765 766 767
		if (eprom_size > sizeof(eprom_buf)) {
			printk
			    ("**WARNING**: Voyager insufficient size to read EPROM data, module 0x%x.  Need %d\n",
			     i, eprom_size);
L
Linus Torvalds 已提交
768 769 770 771 772
			outb(VOYAGER_CAT_END, CAT_CMD);
			continue;
		}
		outb(VOYAGER_CAT_END, CAT_CMD);
		outb(VOYAGER_CAT_RUN, CAT_CMD);
I
Ingo Molnar 已提交
773 774 775 776
		CDEBUG(("cat_init: module 0x%x, eeprom_size %d\n", i,
			eprom_size));
		if (cat_subread
		    (*modpp, (*modpp)->asic, 0, eprom_size, eprom_buf)) {
L
Linus Torvalds 已提交
777 778 779 780 781 782 783 784 785 786 787
			outb(VOYAGER_CAT_END, CAT_CMD);
			continue;
		}
		outb(VOYAGER_CAT_END, CAT_CMD);
		/* Now do everything for the QBB submodule 1 */
		(*modpp)->ee_size = eprom_hdr->ee_size;
		(*modpp)->num_asics = eprom_hdr->num_asics;
		asicpp = &((*modpp)->asic);
		sp_offset = eprom_hdr->scan_path_offset;
		/* get rid of the dummy CAT asic and read the real one */
		kfree((*modpp)->asic);
I
Ingo Molnar 已提交
788
		for (asic = 0; asic < (*modpp)->num_asics; asic++) {
L
Linus Torvalds 已提交
789
			int j;
I
Ingo Molnar 已提交
790
			voyager_asic_t *asicp = *asicpp = kzalloc(sizeof(voyager_asic_t), GFP_KERNEL);	/*&voyager_asic_storage[asic_count++]; */
L
Linus Torvalds 已提交
791 792 793 794
			voyager_sp_table_t *sp_table;
			voyager_at_t *asic_table;
			voyager_jtt_t *jtag_table;

I
Ingo Molnar 已提交
795 796 797
			if (asicp == NULL) {
				printk
				    ("**WARNING** kmalloc failure in cat_init\n");
L
Linus Torvalds 已提交
798 799 800 801
				continue;
			}
			asicpp = &(asicp->next);
			asicp->asic_location = asic;
I
Ingo Molnar 已提交
802 803
			sp_table =
			    (voyager_sp_table_t *) (eprom_buf + sp_offset);
L
Linus Torvalds 已提交
804
			asicp->asic_id = sp_table->asic_id;
I
Ingo Molnar 已提交
805 806 807 808
			asic_table =
			    (voyager_at_t *) (eprom_buf +
					      sp_table->asic_data_offset);
			for (j = 0; j < 4; j++)
L
Linus Torvalds 已提交
809
				asicp->jtag_id[j] = asic_table->jtag_id[j];
I
Ingo Molnar 已提交
810 811 812
			jtag_table =
			    (voyager_jtt_t *) (eprom_buf +
					       asic_table->jtag_offset);
L
Linus Torvalds 已提交
813 814 815
			asicp->ireg_length = jtag_table->ireg_len;
			asicp->bit_location = (*modpp)->inst_bits;
			(*modpp)->inst_bits += asicp->ireg_length;
I
Ingo Molnar 已提交
816
			if (asicp->ireg_length > (*modpp)->largest_reg)
L
Linus Torvalds 已提交
817 818 819 820 821 822 823
				(*modpp)->largest_reg = asicp->ireg_length;
			if (asicp->ireg_length < (*modpp)->smallest_reg ||
			    (*modpp)->smallest_reg == 0)
				(*modpp)->smallest_reg = asicp->ireg_length;
			CDEBUG(("asic 0x%x, ireg_length=%d, bit_location=%d\n",
				asicp->asic_id, asicp->ireg_length,
				asicp->bit_location));
I
Ingo Molnar 已提交
824
			if (asicp->asic_id == VOYAGER_QUAD_QABC) {
L
Linus Torvalds 已提交
825 826 827 828 829
				CDEBUG(("VOYAGER CAT: QABC ASIC found\n"));
				qabc_asic = asicp;
			}
			sp_offset += sizeof(voyager_sp_table_t);
		}
I
Ingo Molnar 已提交
830
		CDEBUG(("Module inst_bits = %d, largest_reg = %d, smallest_reg=%d\n", (*modpp)->inst_bits, (*modpp)->largest_reg, (*modpp)->smallest_reg));
L
Linus Torvalds 已提交
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
		/* OK, now we have the QUAD ASICs set up, use them.
		 * we need to:
		 *
		 * 1. Find the Memory area for the Quad CPIs.
		 * 2. Find the Extended VIC processor
		 * 3. Configure a second extended VIC processor (This
		 *    cannot be done for the 51xx.
		 * */
		outb(VOYAGER_CAT_RUN, CAT_CMD);
		cat_connect(*modpp, (*modpp)->asic);
		CDEBUG(("CAT CONNECTED!!\n"));
		cat_subread(*modpp, qabc_asic, 0, sizeof(qabc_data), qabc_data);
		qic_addr = qabc_data[5] << 8;
		qic_addr = (qic_addr | qabc_data[6]) << 8;
		qic_addr = (qic_addr | qabc_data[7]) << 8;
I
Ingo Molnar 已提交
846 847 848
		printk
		    ("Module \"%s\": Quad Processor Card; CPI 0x%lx, SET=0x%x\n",
		     cat_module_name(i), qic_addr, qabc_data[8]);
L
Linus Torvalds 已提交
849
#if 0				/* plumbing fails---FIXME */
I
Ingo Molnar 已提交
850
		if ((qabc_data[8] & 0xf0) == 0) {
L
Linus Torvalds 已提交
851 852 853 854 855 856 857 858 859 860
			/* FIXME: 32 way 8 CPU slot monster cannot be
			 * plumbed this way---need to check for it */

			printk("Plumbing second Extended Quad Processor\n");
			/* second VIC line hardwired to Quad CPU 1 */
			qabc_data[8] |= 0x20;
			cat_subwrite(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
#ifdef VOYAGER_CAT_DEBUG
			/* verify plumbing */
			cat_subread(*modpp, qabc_asic, 8, 1, &qabc_data[8]);
I
Ingo Molnar 已提交
861 862 863
			if ((qabc_data[8] & 0xf0) == 0) {
				CDEBUG(("PLUMBING FAILED: 0x%x\n",
					qabc_data[8]));
L
Linus Torvalds 已提交
864 865 866 867 868 869
			}
#endif
		}
#endif

		{
I
Ingo Molnar 已提交
870 871
			struct resource *res =
			    kzalloc(sizeof(struct resource), GFP_KERNEL);
L
Linus Torvalds 已提交
872
			res->name = kmalloc(128, GFP_KERNEL);
I
Ingo Molnar 已提交
873 874
			sprintf((char *)res->name, "Voyager %s Quad CPI",
				cat_module_name(i));
L
Linus Torvalds 已提交
875 876 877 878 879
			res->start = qic_addr;
			res->end = qic_addr + 0x3ff;
			request_resource(&iomem_resource, res);
		}

880
		qic_addr = (unsigned long)ioremap_cache(qic_addr, 0x400);
I
Ingo Molnar 已提交
881 882

		for (j = 0; j < 4; j++) {
L
Linus Torvalds 已提交
883 884
			__u8 cpu;

I
Ingo Molnar 已提交
885
			if (voyager_8slot) {
L
Linus Torvalds 已提交
886 887 888
				/* 8 slot has a different mapping,
				 * each slot has only one vic line, so
				 * 1 cpu in each slot must be < 8 */
I
Ingo Molnar 已提交
889
				cpu = (i & 0x07) + j * 8;
L
Linus Torvalds 已提交
890
			} else {
I
Ingo Molnar 已提交
891
				cpu = (i & 0x03) + j * 4;
L
Linus Torvalds 已提交
892
			}
I
Ingo Molnar 已提交
893 894
			if ((qabc_data[8] & (1 << j))) {
				voyager_extended_vic_processors |= (1 << cpu);
L
Linus Torvalds 已提交
895
			}
I
Ingo Molnar 已提交
896
			if (qabc_data[8] & (1 << (j + 4))) {
L
Linus Torvalds 已提交
897 898 899 900
				/* Second SET register plumbed: Quad
				 * card has two VIC connected CPUs.
				 * Secondary cannot be booted as a VIC
				 * CPU */
I
Ingo Molnar 已提交
901 902 903
				voyager_extended_vic_processors |= (1 << cpu);
				voyager_allowed_boot_processors &=
				    (~(1 << cpu));
L
Linus Torvalds 已提交
904 905
			}

I
Ingo Molnar 已提交
906
			voyager_quad_processors |= (1 << cpu);
L
Linus Torvalds 已提交
907
			voyager_quad_cpi_addr[cpu] = (struct voyager_qic_cpi *)
I
Ingo Molnar 已提交
908
			    (qic_addr + (j << 8));
L
Linus Torvalds 已提交
909 910 911 912 913 914 915 916 917
			CDEBUG(("CPU%d: CPI address 0x%lx\n", cpu,
				(unsigned long)voyager_quad_cpi_addr[cpu]));
		}
		outb(VOYAGER_CAT_END, CAT_CMD);

		*asicpp = NULL;
		modpp = &((*modpp)->next);
	}
	*modpp = NULL;
I
Ingo Molnar 已提交
918 919 920 921
	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);
L
Linus Torvalds 已提交
922
	request_resource(&ioport_resource, &vic_res);
I
Ingo Molnar 已提交
923
	if (voyager_quad_processors)
L
Linus Torvalds 已提交
924 925 926 927
		request_resource(&ioport_resource, &qic_res);
	/* set up the front power switch */
}

I
Ingo Molnar 已提交
928
int voyager_cat_readb(__u8 module, __u8 asic, int reg)
L
Linus Torvalds 已提交
929 930 931 932
{
	return 0;
}

I
Ingo Molnar 已提交
933
static int cat_disconnect(voyager_module_t * modp, voyager_asic_t * asicp)
L
Linus Torvalds 已提交
934 935 936 937
{
	__u8 val;
	int err = 0;

I
Ingo Molnar 已提交
938
	if (!modp->scan_path_connected)
L
Linus Torvalds 已提交
939
		return 0;
I
Ingo Molnar 已提交
940
	if (asicp->asic_id != VOYAGER_CAT_ID) {
L
Linus Torvalds 已提交
941 942 943 944
		CDEBUG(("cat_disconnect: ASIC is not CAT\n"));
		return 1;
	}
	err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
I
Ingo Molnar 已提交
945
	if (err) {
L
Linus Torvalds 已提交
946 947 948 949 950
		CDEBUG(("cat_disconnect: failed to read SCANPATH\n"));
		return err;
	}
	val &= VOYAGER_DISCONNECT_ASIC;
	err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
I
Ingo Molnar 已提交
951
	if (err) {
L
Linus Torvalds 已提交
952 953 954 955 956 957 958 959 960 961
		CDEBUG(("cat_disconnect: failed to write SCANPATH\n"));
		return err;
	}
	outb(VOYAGER_CAT_END, CAT_CMD);
	outb(VOYAGER_CAT_RUN, CAT_CMD);
	modp->scan_path_connected = 0;

	return 0;
}

I
Ingo Molnar 已提交
962
static int cat_connect(voyager_module_t * modp, voyager_asic_t * asicp)
L
Linus Torvalds 已提交
963 964 965 966
{
	__u8 val;
	int err = 0;

I
Ingo Molnar 已提交
967
	if (modp->scan_path_connected)
L
Linus Torvalds 已提交
968
		return 0;
I
Ingo Molnar 已提交
969
	if (asicp->asic_id != VOYAGER_CAT_ID) {
L
Linus Torvalds 已提交
970 971 972 973 974
		CDEBUG(("cat_connect: ASIC is not CAT\n"));
		return 1;
	}

	err = cat_read(modp, asicp, VOYAGER_SCANPATH, &val);
I
Ingo Molnar 已提交
975
	if (err) {
L
Linus Torvalds 已提交
976 977 978 979 980
		CDEBUG(("cat_connect: failed to read SCANPATH\n"));
		return err;
	}
	val |= VOYAGER_CONNECT_ASIC;
	err = cat_write(modp, asicp, VOYAGER_SCANPATH, val);
I
Ingo Molnar 已提交
981
	if (err) {
L
Linus Torvalds 已提交
982 983 984 985 986 987 988 989 990 991
		CDEBUG(("cat_connect: failed to write SCANPATH\n"));
		return err;
	}
	outb(VOYAGER_CAT_END, CAT_CMD);
	outb(VOYAGER_CAT_RUN, CAT_CMD);
	modp->scan_path_connected = 1;

	return 0;
}

I
Ingo Molnar 已提交
992
void voyager_cat_power_off(void)
L
Linus Torvalds 已提交
993 994
{
	/* Power the machine off by writing to the PSI over the CAT
I
Ingo Molnar 已提交
995
	 * bus */
L
Linus Torvalds 已提交
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
	__u8 data;
	voyager_module_t psi = { 0 };
	voyager_asic_t psi_asic = { 0 };

	psi.asic = &psi_asic;
	psi.asic->asic_id = VOYAGER_CAT_ID;
	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
	psi.module_addr = VOYAGER_PSI;
	psi.scan_path_connected = 0;

	outb(VOYAGER_CAT_END, CAT_CMD);
	/* Connect the PSI to the CAT Bus */
	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
	outb(VOYAGER_CAT_RUN, CAT_CMD);
	cat_disconnect(&psi, &psi_asic);
	/* Read the status */
	cat_subread(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
	outb(VOYAGER_CAT_END, CAT_CMD);
	CDEBUG(("PSI STATUS 0x%x\n", data));
	/* These two writes are power off prep and perform */
	data = PSI_CLEAR;
	outb(VOYAGER_CAT_RUN, CAT_CMD);
	cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
	outb(VOYAGER_CAT_END, CAT_CMD);
	data = PSI_POWER_DOWN;
	outb(VOYAGER_CAT_RUN, CAT_CMD);
	cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG, 1, &data);
	outb(VOYAGER_CAT_END, CAT_CMD);
}

struct voyager_status voyager_status = { 0 };

I
Ingo Molnar 已提交
1029
void voyager_cat_psi(__u8 cmd, __u16 reg, __u8 * data)
L
Linus Torvalds 已提交
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
{
	voyager_module_t psi = { 0 };
	voyager_asic_t psi_asic = { 0 };

	psi.asic = &psi_asic;
	psi.asic->asic_id = VOYAGER_CAT_ID;
	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
	psi.module_addr = VOYAGER_PSI;
	psi.scan_path_connected = 0;

	outb(VOYAGER_CAT_END, CAT_CMD);
	/* Connect the PSI to the CAT Bus */
	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
	outb(VOYAGER_CAT_RUN, CAT_CMD);
	cat_disconnect(&psi, &psi_asic);
I
Ingo Molnar 已提交
1046
	switch (cmd) {
L
Linus Torvalds 已提交
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
	case VOYAGER_PSI_READ:
		cat_read(&psi, &psi_asic, reg, data);
		break;
	case VOYAGER_PSI_WRITE:
		cat_write(&psi, &psi_asic, reg, *data);
		break;
	case VOYAGER_PSI_SUBREAD:
		cat_subread(&psi, &psi_asic, reg, 1, data);
		break;
	case VOYAGER_PSI_SUBWRITE:
		cat_subwrite(&psi, &psi_asic, reg, 1, data);
		break;
	default:
		printk(KERN_ERR "Voyager PSI, unrecognised command %d\n", cmd);
		break;
	}
	outb(VOYAGER_CAT_END, CAT_CMD);
}

I
Ingo Molnar 已提交
1066
void voyager_cat_do_common_interrupt(void)
L
Linus Torvalds 已提交
1067 1068 1069 1070 1071 1072 1073 1074
{
	/* This is caused either by a memory parity error or something
	 * in the PSI */
	__u8 data;
	voyager_module_t psi = { 0 };
	voyager_asic_t psi_asic = { 0 };
	struct voyager_psi psi_reg;
	int i;
I
Ingo Molnar 已提交
1075
      re_read:
L
Linus Torvalds 已提交
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
	psi.asic = &psi_asic;
	psi.asic->asic_id = VOYAGER_CAT_ID;
	psi.asic->subaddr = VOYAGER_SUBADDR_HI;
	psi.module_addr = VOYAGER_PSI;
	psi.scan_path_connected = 0;

	outb(VOYAGER_CAT_END, CAT_CMD);
	/* Connect the PSI to the CAT Bus */
	outb(VOYAGER_CAT_DESELECT, VOYAGER_CAT_CONFIG_PORT);
	outb(VOYAGER_PSI, VOYAGER_CAT_CONFIG_PORT);
	outb(VOYAGER_CAT_RUN, CAT_CMD);
	cat_disconnect(&psi, &psi_asic);
	/* Read the status.  NOTE: Need to read *all* the PSI regs here
	 * otherwise the cmn int will be reasserted */
I
Ingo Molnar 已提交
1090 1091
	for (i = 0; i < sizeof(psi_reg.regs); i++) {
		cat_read(&psi, &psi_asic, i, &((__u8 *) & psi_reg.regs)[i]);
L
Linus Torvalds 已提交
1092 1093
	}
	outb(VOYAGER_CAT_END, CAT_CMD);
I
Ingo Molnar 已提交
1094
	if ((psi_reg.regs.checkbit & 0x02) == 0) {
L
Linus Torvalds 已提交
1095 1096 1097 1098 1099 1100
		psi_reg.regs.checkbit |= 0x02;
		cat_write(&psi, &psi_asic, 5, psi_reg.regs.checkbit);
		printk("VOYAGER RE-READ PSI\n");
		goto re_read;
	}
	outb(VOYAGER_CAT_RUN, CAT_CMD);
I
Ingo Molnar 已提交
1101
	for (i = 0; i < sizeof(psi_reg.subregs); i++) {
L
Linus Torvalds 已提交
1102 1103
		/* This looks strange, but the PSI doesn't do auto increment
		 * correctly */
I
Ingo Molnar 已提交
1104 1105
		cat_subread(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG + i,
			    1, &((__u8 *) & psi_reg.subregs)[i]);
L
Linus Torvalds 已提交
1106 1107 1108 1109
	}
	outb(VOYAGER_CAT_END, CAT_CMD);
#ifdef VOYAGER_CAT_DEBUG
	printk("VOYAGER PSI: ");
I
Ingo Molnar 已提交
1110 1111
	for (i = 0; i < sizeof(psi_reg.regs); i++)
		printk("%02x ", ((__u8 *) & psi_reg.regs)[i]);
L
Linus Torvalds 已提交
1112
	printk("\n           ");
I
Ingo Molnar 已提交
1113 1114
	for (i = 0; i < sizeof(psi_reg.subregs); i++)
		printk("%02x ", ((__u8 *) & psi_reg.subregs)[i]);
L
Linus Torvalds 已提交
1115 1116
	printk("\n");
#endif
I
Ingo Molnar 已提交
1117
	if (psi_reg.regs.intstatus & PSI_MON) {
L
Linus Torvalds 已提交
1118 1119
		/* switch off or power fail */

I
Ingo Molnar 已提交
1120 1121 1122 1123
		if (psi_reg.subregs.supply & PSI_SWITCH_OFF) {
			if (voyager_status.switch_off) {
				printk(KERN_ERR
				       "Voyager front panel switch turned off again---Immediate power off!\n");
L
Linus Torvalds 已提交
1124 1125 1126
				voyager_cat_power_off();
				/* not reached */
			} else {
I
Ingo Molnar 已提交
1127 1128
				printk(KERN_ERR
				       "Voyager front panel switch turned off\n");
L
Linus Torvalds 已提交
1129 1130
				voyager_status.switch_off = 1;
				voyager_status.request_from_kernel = 1;
1131
				wake_up_process(voyager_thread);
L
Linus Torvalds 已提交
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
			}
			/* Tell the hardware we're taking care of the
			 * shutdown, otherwise it will power the box off
			 * within 3 seconds of the switch being pressed and,
			 * which is much more important to us, continue to 
			 * assert the common interrupt */
			data = PSI_CLR_SWITCH_OFF;
			outb(VOYAGER_CAT_RUN, CAT_CMD);
			cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_SUPPLY_REG,
				     1, &data);
			outb(VOYAGER_CAT_END, CAT_CMD);
		} else {

			VDEBUG(("Voyager ac fail reg 0x%x\n",
				psi_reg.subregs.ACfail));
I
Ingo Molnar 已提交
1147
			if ((psi_reg.subregs.ACfail & AC_FAIL_STAT_CHANGE) == 0) {
L
Linus Torvalds 已提交
1148 1149 1150 1151 1152 1153 1154
				/* No further update */
				return;
			}
#if 0
			/* Don't bother trying to find out who failed.
			 * FIXME: This probably makes the code incorrect on
			 * anything other than a 345x */
I
Ingo Molnar 已提交
1155 1156
			for (i = 0; i < 5; i++) {
				if (psi_reg.subregs.ACfail & (1 << i)) {
L
Linus Torvalds 已提交
1157 1158 1159 1160 1161 1162
					break;
				}
			}
			printk(KERN_NOTICE "AC FAIL IN SUPPLY %d\n", i);
#endif
			/* DON'T do this: it shuts down the AC PSI 
I
Ingo Molnar 已提交
1163 1164 1165 1166 1167 1168
			   outb(VOYAGER_CAT_RUN, CAT_CMD);
			   data = PSI_MASK_MASK | i;
			   cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_MASK,
			   1, &data);
			   outb(VOYAGER_CAT_END, CAT_CMD);
			 */
L
Linus Torvalds 已提交
1169 1170 1171 1172 1173 1174 1175 1176
			printk(KERN_ERR "Voyager AC power failure\n");
			outb(VOYAGER_CAT_RUN, CAT_CMD);
			data = PSI_COLD_START;
			cat_subwrite(&psi, &psi_asic, VOYAGER_PSI_GENERAL_REG,
				     1, &data);
			outb(VOYAGER_CAT_END, CAT_CMD);
			voyager_status.power_fail = 1;
			voyager_status.request_from_kernel = 1;
1177
			wake_up_process(voyager_thread);
L
Linus Torvalds 已提交
1178
		}
I
Ingo Molnar 已提交
1179 1180

	} else if (psi_reg.regs.intstatus & PSI_FAULT) {
L
Linus Torvalds 已提交
1181
		/* Major fault! */
I
Ingo Molnar 已提交
1182 1183
		printk(KERN_ERR
		       "Voyager PSI Detected major fault, immediate power off!\n");
L
Linus Torvalds 已提交
1184 1185
		voyager_cat_power_off();
		/* not reached */
I
Ingo Molnar 已提交
1186 1187 1188
	} else if (psi_reg.regs.intstatus & (PSI_DC_FAIL | PSI_ALARM
					     | PSI_CURRENT | PSI_DVM
					     | PSI_PSCFAULT | PSI_STAT_CHG)) {
L
Linus Torvalds 已提交
1189 1190 1191 1192 1193 1194 1195 1196 1197
		/* other psi fault */

		printk(KERN_WARNING "Voyager PSI status 0x%x\n", data);
		/* clear the PSI fault */
		outb(VOYAGER_CAT_RUN, CAT_CMD);
		cat_write(&psi, &psi_asic, VOYAGER_PSI_STATUS_REG, 0);
		outb(VOYAGER_CAT_END, CAT_CMD);
	}
}