rioboot.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,115 行 · 第 1/3 页

C
1,115
字号
/*** -----------------------------------------------------------------------------****  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>#include <linux/termios.h>#include <linux/serial.h>#include <linux/vmalloc.h>#include <asm/semaphore.h>#include <linux/generic_serial.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/system.h>#include <asm/string.h>#include <asm/uaccess.h>#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"static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd *PktCmdP);static const unsigned char RIOAtVec2Ctrl[] = {	/* 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,	/* 10 */ INTERRUPT_DISABLE,	/* 11 */ IRQ_11 | INTERRUPT_ENABLE,	/* 12 */ IRQ_12 | INTERRUPT_ENABLE,	/* 13 */ INTERRUPT_DISABLE,	/* 14 */ INTERRUPT_DISABLE,	/* 15 */ IRQ_15 | INTERRUPT_ENABLE};/** *	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){	int offset;	func_enter();	rio_dprintk(RIO_DEBUG_BOOT, "Data at user address %p\n", rbp->DataP);	/*	 ** 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");		p->RIOError.Error = HOST_FILE_TOO_LARGE;		func_exit();		return -ENOMEM;	}	if (p->RIOBooting) {		rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code : BUSY BUSY BUSY!\n");		p->RIOError.Error = BOOT_IN_PROGRESS;		func_exit();		return -EBUSY;	}	/*	 ** 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;	/*	 ** 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.	 */	memset(p->RIOBootPackets, 0, offset);	/*	 ** Copy the data from user space into the array	 */	if (copy_from_user(((u8 *)p->RIOBootPackets) + offset, rbp->DataP, rbp->Count)) {		rio_dprintk(RIO_DEBUG_BOOT, "Bad data copy from user space\n");		p->RIOError.Error = COPYIN_FAILED;		func_exit();		return -EFAULT;	}	/*	 ** 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;	func_exit();	return 0;}/** *	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. */void rio_start_card_running(struct Host *HostP){	switch (HostP->Type) {	case RIO_AT:		rio_dprintk(RIO_DEBUG_BOOT, "Start ISA card running\n");		writeb(BOOT_FROM_RAM | EXTERNAL_BUS_ON | HostP->Mode | RIOAtVec2Ctrl[HostP->Ivec & 0xF], &HostP->Control);		break;	case RIO_PCI:		/*		 ** 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");		writeb(PCITpBootFromRam | PCITpBusEnable | HostP->Mode, &HostP->Control);		break;	default:		rio_dprintk(RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type);		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.*/int RIOBootCodeHOST(struct rio_info *p, struct DownLoad *rbp){	struct Host *HostP;	u8 *Cad;	PARM_MAP *ParmMapP;	int RupN;	int PortN;	unsigned int host;	u8 *StartP;	u8 *DestP;	int wait_count;	u16 OldParmMap;	u16 offset;		/* It is very important that this is a u16 */	u8 *DownCode = NULL;	unsigned long flags;	HostP = NULL;		/* Assure the compiler we've initialized it */	/* Walk the hosts */	for (host = 0; host < p->RIONumHosts; host++) {		rio_dprintk(RIO_DEBUG_BOOT, "Attempt to boot host %d\n", host);		HostP = &p->RIOHosts[host];		rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec);		/* Don't boot hosts already running */		if ((HostP->Flags & RUN_STATE) != RC_WAITING) {			rio_dprintk(RIO_DEBUG_BOOT, "%s %d already running\n", "Host", host);			continue;		}		/*		 ** Grab a pointer to the card (ioremapped)		 */		Cad = HostP->Caddr;		/*		 ** 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)		 */		StartP = &Cad[p->RIOConf.HostLoadBase - rbp->Count];		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);		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);		/* Make sure it fits */		if (p->RIOConf.HostLoadBase < rbp->Count) {			rio_dprintk(RIO_DEBUG_BOOT, "Bin too large\n");			p->RIOError.Error = HOST_FILE_TOO_LARGE;			func_exit();			return -EFBIG;		}		/*		 ** Ensure that the host really is stopped.		 ** Disable it's external bus & twang its reset line.		 */		RIOHostReset(HostP->Type, (struct DpRam *) HostP->CardP, HostP->Slot);		/*		 ** 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");		/* Buffer to local memory as we want to use I/O space and		   some cards only do 8 or 16 bit I/O */		DownCode = vmalloc(rbp->Count);		if (!DownCode) {			p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY;			func_exit();			return -ENOMEM;		}		if (copy_from_user(rbp->DataP, DownCode, rbp->Count)) {			kfree(DownCode);			p->RIOError.Error = COPYIN_FAILED;			func_exit();			return -EFAULT;		}		HostP->Copy(DownCode, StartP, rbp->Count);		vfree(DownCode);		rio_dprintk(RIO_DEBUG_BOOT, "Copy completed\n");		/*		 **                     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.		 */		/*		 ** 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'.		 */		/*		 ** 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.		 */		DestP = (u8 *) &Cad[0x7FF8];	/* <<<---- READ THE ABOVE COMMENTS */#define	NFIX(N)	(0x60 | (N))	/* .O  = (~(.O + N))<<4 */#define	PFIX(N)	(0x20 | (N))	/* .O  =   (.O + N)<<4  */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?