rioboot.c 37.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
/*
** -----------------------------------------------------------------------------
**
**  Perle Specialix driver for Linux
**  Ported from existing RIO Driver for SCO sources.
 *
 *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**	Module		: rioboot.c
**	SID		: 1.3
**	Last Modified	: 11/6/98 10:33:36
**	Retrieved	: 11/6/98 10:33:48
**
**  ident @(#)rioboot.c	1.3
**
** -----------------------------------------------------------------------------
*/

#include <linux/module.h>
#include <linux/slab.h>
A
Alan Cox 已提交
35 36
#include <linux/termios.h>
#include <linux/serial.h>
A
Alan Cox 已提交
37
#include <linux/vmalloc.h>
A
Alan Cox 已提交
38 39
#include <asm/semaphore.h>
#include <linux/generic_serial.h>
L
Linus Torvalds 已提交
40 41
#include <linux/errno.h>
#include <linux/interrupt.h>
A
Alan Cox 已提交
42
#include <linux/delay.h>
L
Linus Torvalds 已提交
43 44 45
#include <asm/io.h>
#include <asm/system.h>
#include <asm/string.h>
A
Alan Cox 已提交
46
#include <asm/uaccess.h>
L
Linus Torvalds 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73


#include "linux_compat.h"
#include "rio_linux.h"
#include "pkt.h"
#include "daemon.h"
#include "rio.h"
#include "riospace.h"
#include "cmdpkt.h"
#include "map.h"
#include "rup.h"
#include "port.h"
#include "riodrvr.h"
#include "rioinfo.h"
#include "func.h"
#include "errors.h"
#include "pci.h"

#include "parmmap.h"
#include "unixrup.h"
#include "board.h"
#include "host.h"
#include "phb.h"
#include "link.h"
#include "cmdblk.h"
#include "route.h"

A
Al Viro 已提交
74
static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd __iomem *PktCmdP);
A
Alan Cox 已提交
75

A
Alan Cox 已提交
76
static const unsigned char RIOAtVec2Ctrl[] = {
A
Alan Cox 已提交
77 78 79 80 81 82 83 84 85 86
	/* 0 */ INTERRUPT_DISABLE,
	/* 1 */ INTERRUPT_DISABLE,
	/* 2 */ INTERRUPT_DISABLE,
	/* 3 */ INTERRUPT_DISABLE,
	/* 4 */ INTERRUPT_DISABLE,
	/* 5 */ INTERRUPT_DISABLE,
	/* 6 */ INTERRUPT_DISABLE,
	/* 7 */ INTERRUPT_DISABLE,
	/* 8 */ INTERRUPT_DISABLE,
	/* 9 */ IRQ_9 | INTERRUPT_ENABLE,
L
Linus Torvalds 已提交
87
	/* 10 */ INTERRUPT_DISABLE,
A
Alan Cox 已提交
88 89
	/* 11 */ IRQ_11 | INTERRUPT_ENABLE,
	/* 12 */ IRQ_12 | INTERRUPT_ENABLE,
L
Linus Torvalds 已提交
90 91
	/* 13 */ INTERRUPT_DISABLE,
	/* 14 */ INTERRUPT_DISABLE,
A
Alan Cox 已提交
92
	/* 15 */ IRQ_15 | INTERRUPT_ENABLE
L
Linus Torvalds 已提交
93 94
};

A
Alan Cox 已提交
95 96 97 98 99 100 101 102 103 104
/**
 *	RIOBootCodeRTA		-	Load RTA boot code
 *	@p: RIO to load
 *	@rbp: Download descriptor
 *
 *	Called when the user process initiates booting of the card firmware.
 *	Lads the firmware
 */

int RIOBootCodeRTA(struct rio_info *p, struct DownLoad * rbp)
L
Linus Torvalds 已提交
105 106 107
{
	int offset;

A
Alan Cox 已提交
108
	func_enter();
L
Linus Torvalds 已提交
109

A
Alan Cox 已提交
110
	rio_dprintk(RIO_DEBUG_BOOT, "Data at user address %p\n", rbp->DataP);
L
Linus Torvalds 已提交
111 112

	/*
A
Alan Cox 已提交
113 114 115 116
	 ** Check that we have set asside enough memory for this
	 */
	if (rbp->Count > SIXTY_FOUR_K) {
		rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code Too Large!\n");
L
Linus Torvalds 已提交
117
		p->RIOError.Error = HOST_FILE_TOO_LARGE;
A
Alan Cox 已提交
118
		func_exit();
L
Linus Torvalds 已提交
119 120 121
		return -ENOMEM;
	}

A
Alan Cox 已提交
122 123
	if (p->RIOBooting) {
		rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code : BUSY BUSY BUSY!\n");
L
Linus Torvalds 已提交
124
		p->RIOError.Error = BOOT_IN_PROGRESS;
A
Alan Cox 已提交
125
		func_exit();
L
Linus Torvalds 已提交
126 127 128 129
		return -EBUSY;
	}

	/*
A
Alan Cox 已提交
130 131 132 133 134
	 ** The data we load in must end on a (RTA_BOOT_DATA_SIZE) byte boundary,
	 ** so calculate how far we have to move the data up the buffer
	 ** to achieve this.
	 */
	offset = (RTA_BOOT_DATA_SIZE - (rbp->Count % RTA_BOOT_DATA_SIZE)) % RTA_BOOT_DATA_SIZE;
L
Linus Torvalds 已提交
135 136

	/*
A
Alan Cox 已提交
137 138 139 140
	 ** Be clean, and clear the 'unused' portion of the boot buffer,
	 ** because it will (eventually) be part of the Rta run time environment
	 ** and so should be zeroed.
	 */
A
Alan Cox 已提交
141
	memset(p->RIOBootPackets, 0, offset);
L
Linus Torvalds 已提交
142 143

	/*
A
Alan Cox 已提交
144
	 ** Copy the data from user space into the array
A
Alan Cox 已提交
145
	 */
L
Linus Torvalds 已提交
146

A
Alan Cox 已提交
147
	if (copy_from_user(((u8 *)p->RIOBootPackets) + offset, rbp->DataP, rbp->Count)) {
A
Alan Cox 已提交
148
		rio_dprintk(RIO_DEBUG_BOOT, "Bad data copy from user space\n");
L
Linus Torvalds 已提交
149
		p->RIOError.Error = COPYIN_FAILED;
A
Alan Cox 已提交
150
		func_exit();
L
Linus Torvalds 已提交
151 152 153 154
		return -EFAULT;
	}

	/*
A
Alan Cox 已提交
155 156 157 158 159
	 ** Make sure that our copy of the size includes that offset we discussed
	 ** earlier.
	 */
	p->RIONumBootPkts = (rbp->Count + offset) / RTA_BOOT_DATA_SIZE;
	p->RIOBootCount = rbp->Count;
L
Linus Torvalds 已提交
160 161 162 163 164

	func_exit();
	return 0;
}

A
Alan Cox 已提交
165 166 167 168 169 170 171 172
/**
 *	rio_start_card_running		-	host card start
 *	@HostP: The RIO to kick off
 *
 *	Start a RIO processor unit running. Encapsulates the knowledge
 *	of the card type.
 */

A
Alan Cox 已提交
173
void rio_start_card_running(struct Host *HostP)
L
Linus Torvalds 已提交
174
{
A
Alan Cox 已提交
175
	switch (HostP->Type) {
L
Linus Torvalds 已提交
176
	case RIO_AT:
A
Alan Cox 已提交
177
		rio_dprintk(RIO_DEBUG_BOOT, "Start ISA card running\n");
A
Alan Cox 已提交
178
		writeb(BOOT_FROM_RAM | EXTERNAL_BUS_ON | HostP->Mode | RIOAtVec2Ctrl[HostP->Ivec & 0xF], &HostP->Control);
L
Linus Torvalds 已提交
179 180
		break;
	case RIO_PCI:
A
Alan Cox 已提交
181 182 183 184 185 186
		/*
		 ** PCI is much the same as MCA. Everything is once again memory
		 ** mapped, so we are writing to memory registers instead of io
		 ** ports.
		 */
		rio_dprintk(RIO_DEBUG_BOOT, "Start PCI card running\n");
A
Alan Cox 已提交
187
		writeb(PCITpBootFromRam | PCITpBusEnable | HostP->Mode, &HostP->Control);
L
Linus Torvalds 已提交
188 189
		break;
	default:
A
Alan Cox 已提交
190
		rio_dprintk(RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type);
L
Linus Torvalds 已提交
191 192 193 194 195 196 197 198 199 200 201 202
		break;
	}
	return;
}

/*
** Load in the host boot code - load it directly onto all halted hosts
** of the correct type.
**
** Put your rubber pants on before messing with this code - even the magic
** numbers have trouble understanding what they are doing here.
*/
A
Alan Cox 已提交
203 204

int RIOBootCodeHOST(struct rio_info *p, struct DownLoad *rbp)
L
Linus Torvalds 已提交
205
{
A
Alan Cox 已提交
206
	struct Host *HostP;
A
Al Viro 已提交
207 208
	u8 __iomem *Cad;
	PARM_MAP __iomem *ParmMapP;
A
Alan Cox 已提交
209
	int RupN;
L
Linus Torvalds 已提交
210
	int PortN;
A
Alan Cox 已提交
211
	unsigned int host;
A
Al Viro 已提交
212 213
	u8 __iomem *StartP;
	u8 __iomem *DestP;
L
Linus Torvalds 已提交
214
	int wait_count;
A
Alan Cox 已提交
215 216 217
	u16 OldParmMap;
	u16 offset;		/* It is very important that this is a u16 */
	u8 *DownCode = NULL;
L
Linus Torvalds 已提交
218 219
	unsigned long flags;

A
Alan Cox 已提交
220
	HostP = NULL;		/* Assure the compiler we've initialized it */
A
Alan Cox 已提交
221 222 223


	/* Walk the hosts */
A
Alan Cox 已提交
224 225
	for (host = 0; host < p->RIONumHosts; host++) {
		rio_dprintk(RIO_DEBUG_BOOT, "Attempt to boot host %d\n", host);
L
Linus Torvalds 已提交
226 227
		HostP = &p->RIOHosts[host];

A
Alan Cox 已提交
228
		rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec);
L
Linus Torvalds 已提交
229

A
Alan Cox 已提交
230
		/* Don't boot hosts already running */
A
Alan Cox 已提交
231 232
		if ((HostP->Flags & RUN_STATE) != RC_WAITING) {
			rio_dprintk(RIO_DEBUG_BOOT, "%s %d already running\n", "Host", host);
L
Linus Torvalds 已提交
233 234 235 236
			continue;
		}

		/*
A
Alan Cox 已提交
237
		 ** Grab a pointer to the card (ioremapped)
A
Alan Cox 已提交
238
		 */
L
Linus Torvalds 已提交
239 240 241
		Cad = HostP->Caddr;

		/*
A
Alan Cox 已提交
242 243 244 245 246
		 ** We are going to (try) and load in rbp->Count bytes.
		 ** The last byte will reside at p->RIOConf.HostLoadBase-1;
		 ** Therefore, we need to start copying at address
		 ** (caddr+p->RIOConf.HostLoadBase-rbp->Count)
		 */
A
Alan Cox 已提交
247
		StartP = &Cad[p->RIOConf.HostLoadBase - rbp->Count];
A
Alan Cox 已提交
248

A
Alan Cox 已提交
249 250
		rio_dprintk(RIO_DEBUG_BOOT, "kernel virtual address for host is %p\n", Cad);
		rio_dprintk(RIO_DEBUG_BOOT, "kernel virtual address for download is %p\n", StartP);
A
Alan Cox 已提交
251 252 253
		rio_dprintk(RIO_DEBUG_BOOT, "host loadbase is 0x%x\n", p->RIOConf.HostLoadBase);
		rio_dprintk(RIO_DEBUG_BOOT, "size of download is 0x%x\n", rbp->Count);

A
Alan Cox 已提交
254
		/* Make sure it fits */
A
Alan Cox 已提交
255 256
		if (p->RIOConf.HostLoadBase < rbp->Count) {
			rio_dprintk(RIO_DEBUG_BOOT, "Bin too large\n");
L
Linus Torvalds 已提交
257
			p->RIOError.Error = HOST_FILE_TOO_LARGE;
A
Alan Cox 已提交
258
			func_exit();
L
Linus Torvalds 已提交
259 260 261
			return -EFBIG;
		}
		/*
A
Alan Cox 已提交
262 263 264
		 ** Ensure that the host really is stopped.
		 ** Disable it's external bus & twang its reset line.
		 */
A
Al Viro 已提交
265
		RIOHostReset(HostP->Type, HostP->CardP, HostP->Slot);
L
Linus Torvalds 已提交
266 267

		/*
A
Alan Cox 已提交
268 269 270 271 272
		 ** Copy the data directly from user space to the SRAM.
		 ** This ain't going to be none too clever if the download
		 ** code is bigger than this segment.
		 */
		rio_dprintk(RIO_DEBUG_BOOT, "Copy in code\n");
L
Linus Torvalds 已提交
273

A
Alan Cox 已提交
274 275
		/* Buffer to local memory as we want to use I/O space and
		   some cards only do 8 or 16 bit I/O */
L
Linus Torvalds 已提交
276

A
Alan Cox 已提交
277 278 279 280 281 282
		DownCode = vmalloc(rbp->Count);
		if (!DownCode) {
			p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY;
			func_exit();
			return -ENOMEM;
		}
283
		if (copy_from_user(DownCode, rbp->DataP, rbp->Count)) {
A
Alan Cox 已提交
284
			kfree(DownCode);
L
Linus Torvalds 已提交
285
			p->RIOError.Error = COPYIN_FAILED;
A
Alan Cox 已提交
286
			func_exit();
L
Linus Torvalds 已提交
287 288
			return -EFAULT;
		}
A
Alan Cox 已提交
289 290
		HostP->Copy(DownCode, StartP, rbp->Count);
		vfree(DownCode);
L
Linus Torvalds 已提交
291

A
Alan Cox 已提交
292
		rio_dprintk(RIO_DEBUG_BOOT, "Copy completed\n");
L
Linus Torvalds 已提交
293 294

		/*
A
Alan Cox 已提交
295 296 297 298 299 300 301 302 303 304 305 306 307
		 **                     S T O P !
		 **
		 ** Upto this point the code has been fairly rational, and possibly
		 ** even straight forward. What follows is a pile of crud that will
		 ** magically turn into six bytes of transputer assembler. Normally
		 ** you would expect an array or something, but, being me, I have
		 ** chosen [been told] to use a technique whereby the startup code
		 ** will be correct if we change the loadbase for the code. Which
		 ** brings us onto another issue - the loadbase is the *end* of the
		 ** code, not the start.
		 **
		 ** If I were you I wouldn't start from here.
		 */
L
Linus Torvalds 已提交
308 309

		/*
A
Alan Cox 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
		 ** We now need to insert a short boot section into
		 ** the memory at the end of Sram2. This is normally (de)composed
		 ** of the last eight bytes of the download code. The
		 ** download has been assembled/compiled to expect to be
		 ** loaded from 0x7FFF downwards. We have loaded it
		 ** at some other address. The startup code goes into the small
		 ** ram window at Sram2, in the last 8 bytes, which are really
		 ** at addresses 0x7FF8-0x7FFF.
		 **
		 ** If the loadbase is, say, 0x7C00, then we need to branch to
		 ** address 0x7BFE to run the host.bin startup code. We assemble
		 ** this jump manually.
		 **
		 ** The two byte sequence 60 08 is loaded into memory at address
		 ** 0x7FFE,F. This is a local branch to location 0x7FF8 (60 is nfix 0,
		 ** which adds '0' to the .O register, complements .O, and then shifts
		 ** it left by 4 bit positions, 08 is a jump .O+8 instruction. This will
		 ** add 8 to .O (which was 0xFFF0), and will branch RELATIVE to the new
		 ** location. Now, the branch starts from the value of .PC (or .IP or
		 ** whatever the bloody register is called on this chip), and the .PC
		 ** will be pointing to the location AFTER the branch, in this case
		 ** .PC == 0x8000, so the branch will be to 0x8000+0xFFF8 = 0x7FF8.
		 **
		 ** A long branch is coded at 0x7FF8. This consists of loading a four
		 ** byte offset into .O using nfix (as above) and pfix operators. The
		 ** pfix operates in exactly the same way as the nfix operator, but
		 ** without the complement operation. The offset, of course, must be
		 ** relative to the address of the byte AFTER the branch instruction,
		 ** which will be (urm) 0x7FFC, so, our final destination of the branch
		 ** (loadbase-2), has to be reached from here. Imagine that the loadbase
		 ** is 0x7C00 (which it is), then we will need to branch to 0x7BFE (which
		 ** is the first byte of the initial two byte short local branch of the
		 ** download code).
		 **
		 ** To code a jump from 0x7FFC (which is where the branch will start
		 ** from) to 0x7BFE, we will need to branch 0xFC02 bytes (0x7FFC+0xFC02)=
		 ** 0x7BFE.
		 ** This will be coded as four bytes:
		 ** 60 2C 20 02
		 ** being nfix .O+0
		 **        pfix .O+C
		 **        pfix .O+0
		 **        jump .O+2
		 **
		 ** The nfix operator is used, so that the startup code will be
		 ** compatible with the whole Tp family. (lies, damn lies, it'll never
		 ** work in a month of Sundays).
		 **
		 ** The nfix nyble is the 1s complement of the nyble value you
		 ** want to load - in this case we wanted 'F' so we nfix loaded '0'.
		 */
L
Linus Torvalds 已提交
361 362 363


		/*
A
Alan Cox 已提交
364 365 366 367
		 ** Dest points to the top 8 bytes of Sram2. The Tp jumps
		 ** to 0x7FFE at reset time, and starts executing. This is
		 ** a short branch to 0x7FF8, where a long branch is coded.
		 */
L
Linus Torvalds 已提交
368

A
Al Viro 已提交
369
		DestP = &Cad[0x7FF8];	/* <<<---- READ THE ABOVE COMMENTS */
L
Linus Torvalds 已提交
370 371 372

#define	NFIX(N)	(0x60 | (N))	/* .O  = (~(.O + N))<<4 */
#define	PFIX(N)	(0x20 | (N))	/* .O  =   (.O + N)<<4  */
A
Alan Cox 已提交
373
#define	JUMP(N)	(0x00 | (N))	/* .PC =   .PC + .O      */
L
Linus Torvalds 已提交
374 375

		/*
A
Alan Cox 已提交
376 377 378 379 380 381 382 383 384 385
		 ** 0x7FFC is the address of the location following the last byte of
		 ** the four byte jump instruction.
		 ** READ THE ABOVE COMMENTS
		 **
		 ** offset is (TO-FROM) % MEMSIZE, but with compound buggering about.
		 ** Memsize is 64K for this range of Tp, so offset is a short (unsigned,
		 ** cos I don't understand 2's complement).
		 */
		offset = (p->RIOConf.HostLoadBase - 2) - 0x7FFC;

386
		writeb(NFIX(((unsigned short) (~offset) >> (unsigned short) 12) & 0xF), DestP);
A
Alan Cox 已提交
387 388 389 390 391 392
		writeb(PFIX((offset >> 8) & 0xF), DestP + 1);
		writeb(PFIX((offset >> 4) & 0xF), DestP + 2);
		writeb(JUMP(offset & 0xF), DestP + 3);

		writeb(NFIX(0), DestP + 6);
		writeb(JUMP(8), DestP + 7);
A
Alan Cox 已提交
393 394 395

		rio_dprintk(RIO_DEBUG_BOOT, "host loadbase is 0x%x\n", p->RIOConf.HostLoadBase);
		rio_dprintk(RIO_DEBUG_BOOT, "startup offset is 0x%x\n", offset);
L
Linus Torvalds 已提交
396 397

		/*
A
Alan Cox 已提交
398 399
		 ** Flag what is going on
		 */
L
Linus Torvalds 已提交
400 401 402 403
		HostP->Flags &= ~RUN_STATE;
		HostP->Flags |= RC_STARTUP;

		/*
A
Alan Cox 已提交
404 405 406
		 ** Grab a copy of the current ParmMap pointer, so we
		 ** can tell when it has changed.
		 */
A
Alan Cox 已提交
407
		OldParmMap = readw(&HostP->__ParmMapR);
L
Linus Torvalds 已提交
408

A
Alan Cox 已提交
409
		rio_dprintk(RIO_DEBUG_BOOT, "Original parmmap is 0x%x\n", OldParmMap);
L
Linus Torvalds 已提交
410 411

		/*
A
Alan Cox 已提交
412 413 414 415 416
		 ** And start it running (I hope).
		 ** As there is nothing dodgy or obscure about the
		 ** above code, this is guaranteed to work every time.
		 */
		rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec);
L
Linus Torvalds 已提交
417 418 419

		rio_start_card_running(HostP);

A
Alan Cox 已提交
420
		rio_dprintk(RIO_DEBUG_BOOT, "Set control port\n");
L
Linus Torvalds 已提交
421 422

		/*
A
Alan Cox 已提交
423 424 425
		 ** Now, wait for upto five seconds for the Tp to setup the parmmap
		 ** pointer:
		 */
A
Alan Cox 已提交
426 427 428
		for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && (readw(&HostP->__ParmMapR) == OldParmMap); wait_count++) {
			rio_dprintk(RIO_DEBUG_BOOT, "Checkout %d, 0x%x\n", wait_count, readw(&HostP->__ParmMapR));
			mdelay(100);
L
Linus Torvalds 已提交
429 430 431 432

		}

		/*
A
Alan Cox 已提交
433 434 435
		 ** If the parmmap pointer is unchanged, then the host code
		 ** has crashed & burned in a really spectacular way
		 */
A
Alan Cox 已提交
436 437
		if (readw(&HostP->__ParmMapR) == OldParmMap) {
			rio_dprintk(RIO_DEBUG_BOOT, "parmmap 0x%x\n", readw(&HostP->__ParmMapR));
A
Alan Cox 已提交
438 439 440
			rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n");
			HostP->Flags &= ~RUN_STATE;
			HostP->Flags |= RC_STUFFED;
A
Al Viro 已提交
441
			RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
A
Alan Cox 已提交
442 443
			continue;
		}
A
Alan Cox 已提交
444

A
Alan Cox 已提交
445
		rio_dprintk(RIO_DEBUG_BOOT, "Running 0x%x\n", readw(&HostP->__ParmMapR));
L
Linus Torvalds 已提交
446 447

		/*
A
Alan Cox 已提交
448 449 450 451
		 ** Well, the board thought it was OK, and setup its parmmap
		 ** pointer. For the time being, we will pretend that this
		 ** board is running, and check out what the error flag says.
		 */
L
Linus Torvalds 已提交
452 453

		/*
A
Alan Cox 已提交
454 455
		 ** Grab a 32 bit pointer to the parmmap structure
		 */
A
Al Viro 已提交
456
		ParmMapP = (PARM_MAP __iomem *) RIO_PTR(Cad, readw(&HostP->__ParmMapR));
A
Alan Cox 已提交
457
		rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP);
A
Al Viro 已提交
458
		ParmMapP = (PARM_MAP __iomem *)(Cad + readw(&HostP->__ParmMapR));
A
Alan Cox 已提交
459
		rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP);
L
Linus Torvalds 已提交
460 461

		/*
A
Alan Cox 已提交
462 463 464 465
		 ** The links entry should be 0xFFFF; we set it up
		 ** with a mask to say how many PHBs to use, and
		 ** which links to use.
		 */
A
Alan Cox 已提交
466
		if (readw(&ParmMapP->links) != 0xFFFF) {
A
Alan Cox 已提交
467
			rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name);
A
Alan Cox 已提交
468
			rio_dprintk(RIO_DEBUG_BOOT, "Links = 0x%x\n", readw(&ParmMapP->links));
A
Alan Cox 已提交
469 470
			HostP->Flags &= ~RUN_STATE;
			HostP->Flags |= RC_STUFFED;
A
Al Viro 已提交
471
			RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
A
Alan Cox 已提交
472 473
			continue;
		}
A
Alan Cox 已提交
474

A
Alan Cox 已提交
475
		writew(RIO_LINK_ENABLE, &ParmMapP->links);
L
Linus Torvalds 已提交
476 477

		/*
A
Alan Cox 已提交
478 479 480 481
		 ** now wait for the card to set all the parmmap->XXX stuff
		 ** this is a wait of upto two seconds....
		 */
		rio_dprintk(RIO_DEBUG_BOOT, "Looking for init_done - %d ticks\n", p->RIOConf.StartupTime);
L
Linus Torvalds 已提交
482
		HostP->timeout_id = 0;
A
Alan Cox 已提交
483
		for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && !readw(&ParmMapP->init_done); wait_count++) {
A
Alan Cox 已提交
484
			rio_dprintk(RIO_DEBUG_BOOT, "Waiting for init_done\n");
A
Alan Cox 已提交
485
			mdelay(100);
L
Linus Torvalds 已提交
486
		}
A
Alan Cox 已提交
487
		rio_dprintk(RIO_DEBUG_BOOT, "OK! init_done!\n");
L
Linus Torvalds 已提交
488

A
Alan Cox 已提交
489
		if (readw(&ParmMapP->error) != E_NO_ERROR || !readw(&ParmMapP->init_done)) {
A
Alan Cox 已提交
490 491 492 493
			rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name);
			rio_dprintk(RIO_DEBUG_BOOT, "Timedout waiting for init_done\n");
			HostP->Flags &= ~RUN_STATE;
			HostP->Flags |= RC_STUFFED;
A
Al Viro 已提交
494
			RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
A
Alan Cox 已提交
495 496
			continue;
		}
L
Linus Torvalds 已提交
497

A
Alan Cox 已提交
498
		rio_dprintk(RIO_DEBUG_BOOT, "Got init_done\n");
L
Linus Torvalds 已提交
499 500

		/*
A
Alan Cox 已提交
501 502 503
		 ** It runs! It runs!
		 */
		rio_dprintk(RIO_DEBUG_BOOT, "Host ID %x Running\n", HostP->UniqueNum);
L
Linus Torvalds 已提交
504 505

		/*
A
Alan Cox 已提交
506 507
		 ** set the time period between interrupts.
		 */
A
Alan Cox 已提交
508
		writew(p->RIOConf.Timer, &ParmMapP->timer);
L
Linus Torvalds 已提交
509 510

		/*
A
Alan Cox 已提交
511
		 ** Translate all the 16 bit pointers in the __ParmMapR into
A
Alan Cox 已提交
512
		 ** 32 bit pointers for the driver in ioremap space.
A
Alan Cox 已提交
513 514
		 */
		HostP->ParmMapP = ParmMapP;
A
Al Viro 已提交
515 516 517 518
		HostP->PhbP = (struct PHB __iomem *) RIO_PTR(Cad, readw(&ParmMapP->phb_ptr));
		HostP->RupP = (struct RUP __iomem *) RIO_PTR(Cad, readw(&ParmMapP->rups));
		HostP->PhbNumP = (unsigned short __iomem *) RIO_PTR(Cad, readw(&ParmMapP->phb_num_ptr));
		HostP->LinkStrP = (struct LPB __iomem *) RIO_PTR(Cad, readw(&ParmMapP->link_str_ptr));
L
Linus Torvalds 已提交
519 520

		/*
A
Alan Cox 已提交
521 522 523 524 525
		 ** point the UnixRups at the real Rups
		 */
		for (RupN = 0; RupN < MAX_RUP; RupN++) {
			HostP->UnixRups[RupN].RupP = &HostP->RupP[RupN];
			HostP->UnixRups[RupN].Id = RupN + 1;
L
Linus Torvalds 已提交
526 527 528 529
			HostP->UnixRups[RupN].BaseSysPort = NO_PORT;
			spin_lock_init(&HostP->UnixRups[RupN].RupLock);
		}

A
Alan Cox 已提交
530 531 532 533 534
		for (RupN = 0; RupN < LINKS_PER_UNIT; RupN++) {
			HostP->UnixRups[RupN + MAX_RUP].RupP = &HostP->LinkStrP[RupN].rup;
			HostP->UnixRups[RupN + MAX_RUP].Id = 0;
			HostP->UnixRups[RupN + MAX_RUP].BaseSysPort = NO_PORT;
			spin_lock_init(&HostP->UnixRups[RupN + MAX_RUP].RupLock);
L
Linus Torvalds 已提交
535 536 537
		}

		/*
A
Alan Cox 已提交
538 539 540 541
		 ** point the PortP->Phbs at the real Phbs
		 */
		for (PortN = p->RIOFirstPortsMapped; PortN < p->RIOLastPortsMapped + PORTS_PER_RTA; PortN++) {
			if (p->RIOPortp[PortN]->HostP == HostP) {
L
Linus Torvalds 已提交
542
				struct Port *PortP = p->RIOPortp[PortN];
A
Al Viro 已提交
543
				struct PHB __iomem *PhbP;
L
Linus Torvalds 已提交
544 545
				/* int oldspl; */

A
Alan Cox 已提交
546
				if (!PortP->Mapped)
L
Linus Torvalds 已提交
547 548 549 550 551 552 553
					continue;

				PhbP = &HostP->PhbP[PortP->HostPort];
				rio_spin_lock_irqsave(&PortP->portSem, flags);

				PortP->PhbP = PhbP;

A
Al Viro 已提交
554 555 556 557 558 559
				PortP->TxAdd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_add));
				PortP->TxStart = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_start));
				PortP->TxEnd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_end));
				PortP->RxRemove = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_remove));
				PortP->RxStart = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_start));
				PortP->RxEnd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_end));
L
Linus Torvalds 已提交
560 561 562

				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
				/*
A
Alan Cox 已提交
563 564 565
				 ** point the UnixRup at the base SysPort
				 */
				if (!(PortN % PORTS_PER_RTA))
L
Linus Torvalds 已提交
566 567 568 569
					HostP->UnixRups[PortP->RupNum].BaseSysPort = PortN;
			}
		}

A
Alan Cox 已提交
570
		rio_dprintk(RIO_DEBUG_BOOT, "Set the card running... \n");
L
Linus Torvalds 已提交
571
		/*
A
Alan Cox 已提交
572 573
		 ** last thing - show the world that everything is in place
		 */
L
Linus Torvalds 已提交
574 575 576 577
		HostP->Flags &= ~RUN_STATE;
		HostP->Flags |= RC_RUNNING;
	}
	/*
A
Alan Cox 已提交
578 579 580 581
	 ** MPX always uses a poller. This is actually patched into the system
	 ** configuration and called directly from each clock tick.
	 **
	 */
L
Linus Torvalds 已提交
582 583 584
	p->RIOPolling = 1;

	p->RIOSystemUp++;
A
Alan Cox 已提交
585 586 587

	rio_dprintk(RIO_DEBUG_BOOT, "Done everything %x\n", HostP->Ivec);
	func_exit();
L
Linus Torvalds 已提交
588 589 590 591 592
	return 0;
}



A
Alan Cox 已提交
593 594 595 596 597 598 599 600 601 602 603
/**
 *	RIOBootRup		-	Boot an RTA
 *	@p: rio we are working with
 *	@Rup: Rup number
 *	@HostP: host object
 *	@PacketP: packet to use
 *
 *	If we have successfully processed this boot, then
 *	return 1. If we havent, then return 0.
 */

A
Al Viro 已提交
604
int RIOBootRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem *PacketP)
L
Linus Torvalds 已提交
605
{
A
Al Viro 已提交
606
	struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) PacketP->data;
L
Linus Torvalds 已提交
607 608
	struct PktCmd_M *PktReplyP;
	struct CmdBlk *CmdBlkP;
A
Alan Cox 已提交
609
	unsigned int sequence;
L
Linus Torvalds 已提交
610 611

	/*
A
Alan Cox 已提交
612 613 614 615
	 ** If we haven't been told what to boot, we can't boot it.
	 */
	if (p->RIONumBootPkts == 0) {
		rio_dprintk(RIO_DEBUG_BOOT, "No RTA code to download yet\n");
L
Linus Torvalds 已提交
616 617 618 619
		return 0;
	}

	/*
A
Alan Cox 已提交
620 621 622 623 624
	 ** Special case of boot completed - if we get one of these then we
	 ** don't need a command block. For all other cases we do, so handle
	 ** this first and then get a command block, then handle every other
	 ** case, relinquishing the command block if disaster strikes!
	 */
A
Alan Cox 已提交
625
	if ((readb(&PacketP->len) & PKT_CMD_BIT) && (readb(&PktCmdP->Command) == BOOT_COMPLETED))
A
Alan Cox 已提交
626
		return RIOBootComplete(p, HostP, Rup, PktCmdP);
L
Linus Torvalds 已提交
627 628

	/*
A
Alan Cox 已提交
629
	 ** Try to allocate a command block. This is in kernel space
A
Alan Cox 已提交
630 631 632
	 */
	if (!(CmdBlkP = RIOGetCmdBlk())) {
		rio_dprintk(RIO_DEBUG_BOOT, "No command blocks to boot RTA! come back later.\n");
L
Linus Torvalds 已提交
633 634 635 636
		return 0;
	}

	/*
A
Alan Cox 已提交
637 638
	 ** Fill in the default info on the command block
	 */
639
	CmdBlkP->Packet.dest_unit = Rup < (unsigned short) MAX_RUP ? Rup : 0;
L
Linus Torvalds 已提交
640
	CmdBlkP->Packet.dest_port = BOOT_RUP;
A
Alan Cox 已提交
641 642
	CmdBlkP->Packet.src_unit = 0;
	CmdBlkP->Packet.src_port = BOOT_RUP;
L
Linus Torvalds 已提交
643 644

	CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
A
Alan Cox 已提交
645
	PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data;
L
Linus Torvalds 已提交
646 647

	/*
A
Alan Cox 已提交
648 649
	 ** process COMMANDS on the boot rup!
	 */
A
Alan Cox 已提交
650
	if (readb(&PacketP->len) & PKT_CMD_BIT) {
L
Linus Torvalds 已提交
651
		/*
A
Alan Cox 已提交
652 653
		 ** We only expect one type of command - a BOOT_REQUEST!
		 */
A
Alan Cox 已提交
654 655
		if (readb(&PktCmdP->Command) != BOOT_REQUEST) {
			rio_dprintk(RIO_DEBUG_BOOT, "Unexpected command %d on BOOT RUP %d of host %Zd\n", readb(&PktCmdP->Command), Rup, HostP - p->RIOHosts);
A
Alan Cox 已提交
656
			RIOFreeCmdBlk(CmdBlkP);
L
Linus Torvalds 已提交
657 658 659 660
			return 1;
		}

		/*
A
Alan Cox 已提交
661 662 663 664 665 666 667 668 669
		 ** Build a Boot Sequence command block
		 **
		 ** We no longer need to use "Boot Mode", we'll always allow
		 ** boot requests - the boot will not complete if the device
		 ** appears in the bindings table.
		 **
		 ** We'll just (always) set the command field in packet reply
		 ** to allow an attempted boot sequence :
		 */
L
Linus Torvalds 已提交
670 671 672
		PktReplyP->Command = BOOT_SEQUENCE;

		PktReplyP->BootSequence.NumPackets = p->RIONumBootPkts;
A
Alan Cox 已提交
673 674
		PktReplyP->BootSequence.LoadBase = p->RIOConf.RtaLoadBase;
		PktReplyP->BootSequence.CodeSize = p->RIOBootCount;
L
Linus Torvalds 已提交
675

A
Alan Cox 已提交
676
		CmdBlkP->Packet.len = BOOT_SEQUENCE_LEN | PKT_CMD_BIT;
L
Linus Torvalds 已提交
677

A
Alan Cox 已提交
678
		memcpy((void *) &CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN], "BOOT", 4);
L
Linus Torvalds 已提交
679

A
Alan Cox 已提交
680
		rio_dprintk(RIO_DEBUG_BOOT, "Boot RTA on Host %Zd Rup %d - %d (0x%x) packets to 0x%x\n", HostP - p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, p->RIOConf.RtaLoadBase);
L
Linus Torvalds 已提交
681 682

		/*
A
Alan Cox 已提交
683 684 685 686 687 688
		 ** If this host is in slave mode, send the RTA an invalid boot
		 ** sequence command block to force it to kill the boot. We wait
		 ** for half a second before sending this packet to prevent the RTA
		 ** attempting to boot too often. The master host should then grab
		 ** the RTA and make it its own.
		 */
L
Linus Torvalds 已提交
689
		p->RIOBooting++;
A
Alan Cox 已提交
690
		RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
L
Linus Torvalds 已提交
691 692 693 694
		return 1;
	}

	/*
A
Alan Cox 已提交
695 696
	 ** It is a request for boot data.
	 */
A
Alan Cox 已提交
697
	sequence = readw(&PktCmdP->Sequence);
L
Linus Torvalds 已提交
698

A
Alan Cox 已提交
699
	rio_dprintk(RIO_DEBUG_BOOT, "Boot block %d on Host %Zd Rup%d\n", sequence, HostP - p->RIOHosts, Rup);
L
Linus Torvalds 已提交
700

A
Alan Cox 已提交
701 702
	if (sequence >= p->RIONumBootPkts) {
		rio_dprintk(RIO_DEBUG_BOOT, "Got a request for packet %d, max is %d\n", sequence, p->RIONumBootPkts);
L
Linus Torvalds 已提交
703 704 705
	}

	PktReplyP->Sequence = sequence;
A
Alan Cox 已提交
706
	memcpy(PktReplyP->BootData, p->RIOBootPackets[p->RIONumBootPkts - sequence - 1], RTA_BOOT_DATA_SIZE);
L
Linus Torvalds 已提交
707
	CmdBlkP->Packet.len = PKT_MAX_DATA_LEN;
A
Alan Cox 已提交
708
	RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
L
Linus Torvalds 已提交
709 710 711
	return 1;
}

A
Alan Cox 已提交
712 713 714 715 716 717 718 719 720 721 722 723 724
/**
 *	RIOBootComplete		-	RTA boot is done
 *	@p: RIO we are working with
 *	@HostP: Host structure
 *	@Rup: RUP being used
 *	@PktCmdP: Packet command that was used
 *
 *	This function is called when an RTA been booted.
 *	If booted by a host, HostP->HostUniqueNum is the booting host.
 *	If booted by an RTA, HostP->Mapping[Rup].RtaUniqueNum is the booting RTA.
 *	RtaUniq is the booted RTA.
 */

A
Al Viro 已提交
725
static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd __iomem *PktCmdP)
L
Linus Torvalds 已提交
726
{
A
Alan Cox 已提交
727 728 729 730 731 732 733 734
	struct Map *MapP = NULL;
	struct Map *MapP2 = NULL;
	int Flag;
	int found;
	int host, rta;
	int EmptySlot = -1;
	int entry, entry2;
	char *MyType, *MyName;
A
Alan Cox 已提交
735 736 737
	unsigned int MyLink;
	unsigned short RtaType;
	u32 RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&PktCmdP->UniqNum[3]) << 24);
L
Linus Torvalds 已提交
738 739 740

	p->RIOBooting = 0;

A
Alan Cox 已提交
741
	rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot completed - BootInProgress now %d\n", p->RIOBooting);
L
Linus Torvalds 已提交
742 743

	/*
A
Alan Cox 已提交
744 745
	 ** Determine type of unit (16/8 port RTA).
	 */
A
Alan Cox 已提交
746

L
Linus Torvalds 已提交
747
	RtaType = GetUnitType(RtaUniq);
748
	if (Rup >= (unsigned short) MAX_RUP)
A
Alan Cox 已提交
749 750 751
		rio_dprintk(RIO_DEBUG_BOOT, "RIO: Host %s has booted an RTA(%d) on link %c\n", HostP->Name, 8 * RtaType, readb(&PktCmdP->LinkNum) + 'A');
	else
		rio_dprintk(RIO_DEBUG_BOOT, "RIO: RTA %s has booted an RTA(%d) on link %c\n", HostP->Mapping[Rup].Name, 8 * RtaType, readb(&PktCmdP->LinkNum) + 'A');
L
Linus Torvalds 已提交
752

A
Alan Cox 已提交
753
	rio_dprintk(RIO_DEBUG_BOOT, "UniqNum is 0x%x\n", RtaUniq);
L
Linus Torvalds 已提交
754

A
Alan Cox 已提交
755
	if (RtaUniq == 0x00000000 || RtaUniq == 0xffffffff) {
A
Alan Cox 已提交
756
		rio_dprintk(RIO_DEBUG_BOOT, "Illegal RTA Uniq Number\n");
757
		return 1;
L
Linus Torvalds 已提交
758 759 760
	}

	/*
A
Alan Cox 已提交
761 762 763 764
	 ** If this RTA has just booted an RTA which doesn't belong to this
	 ** system, or the system is in slave mode, do not attempt to create
	 ** a new table entry for it.
	 */
A
Alan Cox 已提交
765

A
Alan Cox 已提交
766
	if (!RIOBootOk(p, HostP, RtaUniq)) {
A
Alan Cox 已提交
767 768
		MyLink = readb(&PktCmdP->LinkNum);
		if (Rup < (unsigned short) MAX_RUP) {
A
Alan Cox 已提交
769 770 771 772 773 774 775 776
			/*
			 ** RtaUniq was clone booted (by this RTA). Instruct this RTA
			 ** to hold off further attempts to boot on this link for 30
			 ** seconds.
			 */
			if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink)) {
				rio_dprintk(RIO_DEBUG_BOOT, "RTA failed to suspend booting on link %c\n", 'A' + MyLink);
			}
A
Alan Cox 已提交
777
		} else
A
Alan Cox 已提交
778 779 780 781 782
			/*
			 ** RtaUniq was booted by this host. Set the booting link
			 ** to hold off for 30 seconds to give another unit a
			 ** chance to boot it.
			 */
A
Alan Cox 已提交
783
			writew(30, &HostP->LinkStrP[MyLink].WaitNoBoot);
A
Alan Cox 已提交
784
		rio_dprintk(RIO_DEBUG_BOOT, "RTA %x not owned - suspend booting down link %c on unit %x\n", RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum);
785
		return 1;
L
Linus Torvalds 已提交
786 787 788
	}

	/*
A
Alan Cox 已提交
789 790 791 792 793 794 795 796 797 798 799
	 ** Check for a SLOT_IN_USE entry for this RTA attached to the
	 ** current host card in the driver table.
	 **
	 ** If it exists, make a note that we have booted it. Other parts of
	 ** the driver are interested in this information at a later date,
	 ** in particular when the booting RTA asks for an ID for this unit,
	 ** we must have set the BOOTED flag, and the NEWBOOT flag is used
	 ** to force an open on any ports that where previously open on this
	 ** unit.
	 */
	for (entry = 0; entry < MAX_RUP; entry++) {
A
Alan Cox 已提交
800
		unsigned int sysport;
A
Alan Cox 已提交
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821

		if ((HostP->Mapping[entry].Flags & SLOT_IN_USE) && (HostP->Mapping[entry].RtaUniqueNum == RtaUniq)) {
			HostP->Mapping[entry].Flags |= RTA_BOOTED | RTA_NEWBOOT;
			if ((sysport = HostP->Mapping[entry].SysPort) != NO_PORT) {
				if (sysport < p->RIOFirstPortsBooted)
					p->RIOFirstPortsBooted = sysport;
				if (sysport > p->RIOLastPortsBooted)
					p->RIOLastPortsBooted = sysport;
				/*
				 ** For a 16 port RTA, check the second bank of 8 ports
				 */
				if (RtaType == TYPE_RTA16) {
					entry2 = HostP->Mapping[entry].ID2 - 1;
					HostP->Mapping[entry2].Flags |= RTA_BOOTED | RTA_NEWBOOT;
					sysport = HostP->Mapping[entry2].SysPort;
					if (sysport < p->RIOFirstPortsBooted)
						p->RIOFirstPortsBooted = sysport;
					if (sysport > p->RIOLastPortsBooted)
						p->RIOLastPortsBooted = sysport;
				}
			}
A
Alan Cox 已提交
822
			if (RtaType == TYPE_RTA16)
A
Alan Cox 已提交
823
				rio_dprintk(RIO_DEBUG_BOOT, "RTA will be given IDs %d+%d\n", entry + 1, entry2 + 1);
A
Alan Cox 已提交
824
			else
A
Alan Cox 已提交
825
				rio_dprintk(RIO_DEBUG_BOOT, "RTA will be given ID %d\n", entry + 1);
826
			return 1;
L
Linus Torvalds 已提交
827 828 829
		}
	}

A
Alan Cox 已提交
830
	rio_dprintk(RIO_DEBUG_BOOT, "RTA not configured for this host\n");
L
Linus Torvalds 已提交
831

A
Alan Cox 已提交
832
	if (Rup >= (unsigned short) MAX_RUP) {
A
Alan Cox 已提交
833 834 835 836 837 838 839 840 841 842 843
		/*
		 ** It was a host that did the booting
		 */
		MyType = "Host";
		MyName = HostP->Name;
	} else {
		/*
		 ** It was an RTA that did the booting
		 */
		MyType = "RTA";
		MyName = HostP->Mapping[Rup].Name;
L
Linus Torvalds 已提交
844
	}
A
Alan Cox 已提交
845
	MyLink = readb(&PktCmdP->LinkNum);
L
Linus Torvalds 已提交
846 847

	/*
A
Alan Cox 已提交
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
	 ** There is no SLOT_IN_USE entry for this RTA attached to the current
	 ** host card in the driver table.
	 **
	 ** Check for a SLOT_TENTATIVE entry for this RTA attached to the
	 ** current host card in the driver table.
	 **
	 ** If we find one, then we re-use that slot.
	 */
	for (entry = 0; entry < MAX_RUP; entry++) {
		if ((HostP->Mapping[entry].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry].RtaUniqueNum == RtaUniq)) {
			if (RtaType == TYPE_RTA16) {
				entry2 = HostP->Mapping[entry].ID2 - 1;
				if ((HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq))
					rio_dprintk(RIO_DEBUG_BOOT, "Found previous tentative slots (%d+%d)\n", entry, entry2);
				else
					continue;
			} else
				rio_dprintk(RIO_DEBUG_BOOT, "Found previous tentative slot (%d)\n", entry);
			if (!p->RIONoMessage)
A
Alan Cox 已提交
867
				printk("RTA connected to %s '%s' (%c) not configured.\n", MyType, MyName, MyLink + 'A');
868
			return 1;
L
Linus Torvalds 已提交
869 870 871 872
		}
	}

	/*
A
Alan Cox 已提交
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
	 ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
	 ** attached to the current host card in the driver table.
	 **
	 ** Check if there is a SLOT_IN_USE or SLOT_TENTATIVE entry on another
	 ** host for this RTA in the driver table.
	 **
	 ** For a SLOT_IN_USE entry on another host, we need to delete the RTA
	 ** entry from the other host and add it to this host (using some of
	 ** the functions from table.c which do this).
	 ** For a SLOT_TENTATIVE entry on another host, we must cope with the
	 ** following scenario:
	 **
	 ** + Plug 8 port RTA into host A. (This creates SLOT_TENTATIVE entry
	 **   in table)
	 ** + Unplug RTA and plug into host B. (We now have 2 SLOT_TENTATIVE
	 **   entries)
	 ** + Configure RTA on host B. (This slot now becomes SLOT_IN_USE)
	 ** + Unplug RTA and plug back into host A.
	 ** + Configure RTA on host A. We now have the same RTA configured
	 **   with different ports on two different hosts.
	 */
	rio_dprintk(RIO_DEBUG_BOOT, "Have we seen RTA %x before?\n", RtaUniq);
L
Linus Torvalds 已提交
895
	found = 0;
A
Alan Cox 已提交
896 897 898 899 900 901 902 903 904 905 906 907 908 909
	Flag = 0;		/* Convince the compiler this variable is initialized */
	for (host = 0; !found && (host < p->RIONumHosts); host++) {
		for (rta = 0; rta < MAX_RUP; rta++) {
			if ((p->RIOHosts[host].Mapping[rta].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (p->RIOHosts[host].Mapping[rta].RtaUniqueNum == RtaUniq)) {
				Flag = p->RIOHosts[host].Mapping[rta].Flags;
				MapP = &p->RIOHosts[host].Mapping[rta];
				if (RtaType == TYPE_RTA16) {
					MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1];
					rio_dprintk(RIO_DEBUG_BOOT, "This RTA is units %d+%d from host %s\n", rta + 1, MapP->ID2, p->RIOHosts[host].Name);
				} else
					rio_dprintk(RIO_DEBUG_BOOT, "This RTA is unit %d from host %s\n", rta + 1, p->RIOHosts[host].Name);
				found = 1;
				break;
			}
L
Linus Torvalds 已提交
910 911 912 913
		}
	}

	/*
A
Alan Cox 已提交
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
	 ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
	 ** attached to the current host card in the driver table.
	 **
	 ** If we have not found a SLOT_IN_USE or SLOT_TENTATIVE entry on
	 ** another host for this RTA in the driver table...
	 **
	 ** Check for a SLOT_IN_USE entry for this RTA in the config table.
	 */
	if (!MapP) {
		rio_dprintk(RIO_DEBUG_BOOT, "Look for RTA %x in RIOSavedTable\n", RtaUniq);
		for (rta = 0; rta < TOTAL_MAP_ENTRIES; rta++) {
			rio_dprintk(RIO_DEBUG_BOOT, "Check table entry %d (%x)", rta, p->RIOSavedTable[rta].RtaUniqueNum);

			if ((p->RIOSavedTable[rta].Flags & SLOT_IN_USE) && (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq)) {
				MapP = &p->RIOSavedTable[rta];
				Flag = p->RIOSavedTable[rta].Flags;
				if (RtaType == TYPE_RTA16) {
					for (entry2 = rta + 1; entry2 < TOTAL_MAP_ENTRIES; entry2++) {
						if (p->RIOSavedTable[entry2].RtaUniqueNum == RtaUniq)
							break;
					}
					MapP2 = &p->RIOSavedTable[entry2];
					rio_dprintk(RIO_DEBUG_BOOT, "This RTA is from table entries %d+%d\n", rta, entry2);
				} else
					rio_dprintk(RIO_DEBUG_BOOT, "This RTA is from table entry %d\n", rta);
				break;
			}
L
Linus Torvalds 已提交
941 942 943 944
		}
	}

	/*
A
Alan Cox 已提交
945 946 947 948 949 950 951 952 953 954 955 956
	 ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
	 ** attached to the current host card in the driver table.
	 **
	 ** We may have found a SLOT_IN_USE entry on another host for this
	 ** RTA in the config table, or a SLOT_IN_USE or SLOT_TENTATIVE entry
	 ** on another host for this RTA in the driver table.
	 **
	 ** Check the driver table for room to fit this newly discovered RTA.
	 ** RIOFindFreeID() first looks for free slots and if it does not
	 ** find any free slots it will then attempt to oust any
	 ** tentative entry in the table.
	 */
L
Linus Torvalds 已提交
957
	EmptySlot = 1;
A
Alan Cox 已提交
958 959 960
	if (RtaType == TYPE_RTA16) {
		if (RIOFindFreeID(p, HostP, &entry, &entry2) == 0) {
			RIODefaultName(p, HostP, entry);
961
			rio_fill_host_slot(entry, entry2, RtaUniq, HostP);
A
Alan Cox 已提交
962 963 964 965 966
			EmptySlot = 0;
		}
	} else {
		if (RIOFindFreeID(p, HostP, &entry, NULL) == 0) {
			RIODefaultName(p, HostP, entry);
967
			rio_fill_host_slot(entry, 0, RtaUniq, HostP);
A
Alan Cox 已提交
968 969
			EmptySlot = 0;
		}
L
Linus Torvalds 已提交
970 971 972
	}

	/*
A
Alan Cox 已提交
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
	 ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
	 ** attached to the current host card in the driver table.
	 **
	 ** If we found a SLOT_IN_USE entry on another host for this
	 ** RTA in the config or driver table, and there are enough free
	 ** slots in the driver table, then we need to move it over and
	 ** delete it from the other host.
	 ** If we found a SLOT_TENTATIVE entry on another host for this
	 ** RTA in the driver table, just delete the other host entry.
	 */
	if (EmptySlot == 0) {
		if (MapP) {
			if (Flag & SLOT_IN_USE) {
				rio_dprintk(RIO_DEBUG_BOOT, "This RTA configured on another host - move entry to current host (1)\n");
				HostP->Mapping[entry].SysPort = MapP->SysPort;
A
Alan Cox 已提交
988
				memcpy(HostP->Mapping[entry].Name, MapP->Name, MAX_NAME_LEN);
A
Alan Cox 已提交
989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
				HostP->Mapping[entry].Flags = SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT;
				RIOReMapPorts(p, HostP, &HostP->Mapping[entry]);
				if (HostP->Mapping[entry].SysPort < p->RIOFirstPortsBooted)
					p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort;
				if (HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted)
					p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort;
				rio_dprintk(RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int) MapP->SysPort, MapP->Name);
			} else {
				rio_dprintk(RIO_DEBUG_BOOT, "This RTA has a tentative entry on another host - delete that entry (1)\n");
				HostP->Mapping[entry].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT;
			}
			if (RtaType == TYPE_RTA16) {
				if (Flag & SLOT_IN_USE) {
					HostP->Mapping[entry2].Flags = SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
					HostP->Mapping[entry2].SysPort = MapP2->SysPort;
					/*
					 ** Map second block of ttys for 16 port RTA
					 */
					RIOReMapPorts(p, HostP, &HostP->Mapping[entry2]);
					if (HostP->Mapping[entry2].SysPort < p->RIOFirstPortsBooted)
						p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort;
					if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted)
						p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort;
					rio_dprintk(RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int) HostP->Mapping[entry2].SysPort, HostP->Mapping[entry].Name);
				} else
					HostP->Mapping[entry2].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
A
Alan Cox 已提交
1015
				memset(MapP2, 0, sizeof(struct Map));
A
Alan Cox 已提交
1016
			}
A
Alan Cox 已提交
1017
			memset(MapP, 0, sizeof(struct Map));
A
Alan Cox 已提交
1018
			if (!p->RIONoMessage)
A
Alan Cox 已提交
1019
				printk("An orphaned RTA has been adopted by %s '%s' (%c).\n", MyType, MyName, MyLink + 'A');
A
Alan Cox 已提交
1020
		} else if (!p->RIONoMessage)
A
Alan Cox 已提交
1021
			printk("RTA connected to %s '%s' (%c) not configured.\n", MyType, MyName, MyLink + 'A');
A
Alan Cox 已提交
1022
		RIOSetChange(p);
1023
		return 1;
L
Linus Torvalds 已提交
1024 1025 1026
	}

	/*
A
Alan Cox 已提交
1027 1028 1029 1030 1031
	 ** There is no room in the driver table to make an entry for the
	 ** booted RTA. Keep a note of its Uniq Num in the overflow table,
	 ** so we can ignore it's ID requests.
	 */
	if (!p->RIONoMessage)
A
Alan Cox 已提交
1032
		printk("The RTA connected to %s '%s' (%c) cannot be configured.  You cannot configure more than 128 ports to one host card.\n", MyType, MyName, MyLink + 'A');
A
Alan Cox 已提交
1033 1034 1035 1036 1037
	for (entry = 0; entry < HostP->NumExtraBooted; entry++) {
		if (HostP->ExtraUnits[entry] == RtaUniq) {
			/*
			 ** already got it!
			 */
1038
			return 1;
A
Alan Cox 已提交
1039
		}
L
Linus Torvalds 已提交
1040 1041
	}
	/*
A
Alan Cox 已提交
1042 1043 1044 1045
	 ** If there is room, add the unit to the list of extras
	 */
	if (HostP->NumExtraBooted < MAX_EXTRA_UNITS)
		HostP->ExtraUnits[HostP->NumExtraBooted++] = RtaUniq;
1046
	return 1;
L
Linus Torvalds 已提交
1047 1048 1049 1050 1051
}


/*
** If the RTA or its host appears in the RIOBindTab[] structure then
1052
** we mustn't boot the RTA and should return 0.
L
Linus Torvalds 已提交
1053 1054 1055 1056 1057 1058
** This operation is slightly different from the other drivers for RIO
** in that this is designed to work with the new utilities
** not config.rio and is FAR SIMPLER.
** We no longer support the RIOBootMode variable. It is all done from the
** "boot/noboot" field in the rio.cf file.
*/
A
Alan Cox 已提交
1059
int RIOBootOk(struct rio_info *p, struct Host *HostP, unsigned long RtaUniq)
L
Linus Torvalds 已提交
1060
{
A
Alan Cox 已提交
1061
	int Entry;
A
Alan Cox 已提交
1062
	unsigned int HostUniq = HostP->UniqueNum;
L
Linus Torvalds 已提交
1063 1064

	/*
A
Alan Cox 已提交
1065 1066 1067 1068 1069
	 ** Search bindings table for RTA or its parent.
	 ** If it exists, return 0, else 1.
	 */
	for (Entry = 0; (Entry < MAX_RTA_BINDINGS) && (p->RIOBindTab[Entry] != 0); Entry++) {
		if ((p->RIOBindTab[Entry] == HostUniq) || (p->RIOBindTab[Entry] == RtaUniq))
L
Linus Torvalds 已提交
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
			return 0;
	}
	return 1;
}

/*
** Make an empty slot tentative. If this is a 16 port RTA, make both
** slots tentative, and the second one RTA_SECOND_SLOT as well.
*/

1080
void rio_fill_host_slot(int entry, int entry2, unsigned int rta_uniq, struct Host *host)
L
Linus Torvalds 已提交
1081
{
A
Alan Cox 已提交
1082
	int link;
L
Linus Torvalds 已提交
1083

1084
	rio_dprintk(RIO_DEBUG_BOOT, "rio_fill_host_slot(%d, %d, 0x%x...)\n", entry, entry2, rta_uniq);
L
Linus Torvalds 已提交
1085

1086 1087 1088 1089 1090 1091
	host->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE);
	host->Mapping[entry].SysPort = NO_PORT;
	host->Mapping[entry].RtaUniqueNum = rta_uniq;
	host->Mapping[entry].HostUniqueNum = host->UniqueNum;
	host->Mapping[entry].ID = entry + 1;
	host->Mapping[entry].ID2 = 0;
L
Linus Torvalds 已提交
1092
	if (entry2) {
1093 1094 1095 1096 1097 1098 1099 1100
		host->Mapping[entry2].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE | RTA16_SECOND_SLOT);
		host->Mapping[entry2].SysPort = NO_PORT;
		host->Mapping[entry2].RtaUniqueNum = rta_uniq;
		host->Mapping[entry2].HostUniqueNum = host->UniqueNum;
		host->Mapping[entry2].Name[0] = '\0';
		host->Mapping[entry2].ID = entry2 + 1;
		host->Mapping[entry2].ID2 = entry + 1;
		host->Mapping[entry].ID2 = entry2 + 1;
L
Linus Torvalds 已提交
1101 1102
	}
	/*
A
Alan Cox 已提交
1103 1104 1105 1106
	 ** Must set these up, so that utilities show
	 ** topology of 16 port RTAs correctly
	 */
	for (link = 0; link < LINKS_PER_UNIT; link++) {
1107 1108
		host->Mapping[entry].Topology[link].Unit = ROUTE_DISCONNECT;
		host->Mapping[entry].Topology[link].Link = NO_LINK;
L
Linus Torvalds 已提交
1109
		if (entry2) {
1110 1111
			host->Mapping[entry2].Topology[link].Unit = ROUTE_DISCONNECT;
			host->Mapping[entry2].Topology[link].Link = NO_LINK;
L
Linus Torvalds 已提交
1112 1113 1114
		}
	}
}