⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rioboot.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/*** -----------------------------------------------------------------------------****  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**** -----------------------------------------------------------------------------*/#ifdef SCCS_LABELSstatic char *_rioboot_c_sccs_ = "@(#)rioboot.c	1.3";#endif#include <linux/module.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <asm/io.h>#include <asm/system.h>#include <asm/string.h>#include <asm/semaphore.h>#include <linux/termios.h>#include <linux/serial.h>#include <linux/generic_serial.h>#include "linux_compat.h"#include "rio_linux.h"#include "typdef.h"#include "pkt.h"#include "daemon.h"#include "rio.h"#include "riospace.h"#include "top.h"#include "cmdpkt.h"#include "map.h"#include "riotypes.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 "error.h"#include "phb.h"#include "link.h"#include "cmdblk.h"#include "route.h"static int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct PktCmd *PktCmdP );static ucharRIOAtVec2Ctrl[] ={	/* 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};/*** Load in the RTA boot code.*/intRIOBootCodeRTA(p, rbp)struct rio_info *	p;struct DownLoad *	rbp; {	int offset;	func_enter ();	/* Linux doesn't allow you to disable interrupts during a	   "copyin". (Crash when a pagefault occurs). */	/* disable(oldspl); */		rio_dprintk (RIO_DEBUG_BOOT, "Data at user address 0x%x\n",(int)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;		/* restore(oldspl); */		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;		/* restore(oldspl); */		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.	*/	bzero( (caddr_t)p->RIOBootPackets, offset );	/*	** Copy the data from user space.	*/	if ( copyin((int)rbp->DataP,((caddr_t)(p->RIOBootPackets))+offset,				rbp->Count) ==COPYFAIL ) {		rio_dprintk (RIO_DEBUG_BOOT, "Bad data copy from user space\n");		p->RIOError.Error = COPYIN_FAILED;		/* restore(oldspl); */		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;	/* restore(oldspl); */	func_exit();	return 0;}void rio_start_card_running (struct Host * HostP){	func_enter ();	switch ( HostP->Type ) {	case RIO_AT:		rio_dprintk (RIO_DEBUG_BOOT, "Start ISA card running\n");		WBYTE(HostP->Control, 		      BOOT_FROM_RAM | EXTERNAL_BUS_ON		      | HostP->Mode		      | RIOAtVec2Ctrl[HostP->Ivec & 0xF] );		break;		#ifdef FUTURE_RELEASE	case RIO_MCA:				/*				** MCA handles IRQ vectors differently, so we don't write 				** them to this register.				*/		rio_dprintk (RIO_DEBUG_BOOT, "Start MCA card running\n");		WBYTE(HostP->Control, McaTpBootFromRam | McaTpBusEnable | HostP->Mode);		break;	case RIO_EISA:				/*				** EISA is totally different and expects OUTBZs to turn it on.				*/		rio_dprintk (RIO_DEBUG_BOOT, "Start EISA card running\n");		OUTBZ( HostP->Slot, EISA_CONTROL_PORT, HostP->Mode | RIOEisaVec2Ctrl[HostP->Ivec] | EISA_TP_RUN | EISA_TP_BUS_ENABLE | EISA_TP_BOOT_FROM_RAM );		break;#endif	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");		WBYTE(HostP->Control, PCITpBootFromRam | PCITpBusEnable | HostP->Mode);		break;	default:		rio_dprintk (RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type);		break;	}/* 	printk (KERN_INFO "Done with starting the card\n");	func_exit ();*/	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.*/intRIOBootCodeHOST(p, rbp)struct rio_info *	p;register struct DownLoad *rbp;{	register struct Host *HostP;	register caddr_t Cad;	register PARM_MAP *ParmMapP;	register int RupN;	int PortN;	uint host;	caddr_t StartP;	BYTE *DestP;	int wait_count;	ushort OldParmMap;	ushort offset;	/* It is very important that this is a ushort */	/* uint byte; */	caddr_t DownCode = NULL;	unsigned long flags;	HostP = NULL; /* Assure the compiler we've initialized it */	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);		if ( (HostP->Flags & RUN_STATE) != RC_WAITING ) {			rio_dprintk (RIO_DEBUG_BOOT, "%s %d already running\n","Host",host);			continue;		}		/*		** Grab a 32 bit pointer to the card.		*/		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 = (caddr_t)&Cad[p->RIOConf.HostLoadBase-rbp->Count];		rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for host is 0x%x\n", (int)Cad );		rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for download is 0x%x\n", (int)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);		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");		/*		** PCI hostcard can't cope with 32 bit accesses and so need to copy 		** data to a local buffer, and then dripfeed the card.		*/		if ( HostP->Type == RIO_PCI ) {		  /* int offset; */			DownCode = sysbrk(rbp->Count);			if ( !DownCode ) {				rio_dprintk (RIO_DEBUG_BOOT, "No system memory available\n");				p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY;				func_exit ();				return -ENOMEM;			}			bzero(DownCode, rbp->Count);			if ( copyin((int)rbp->DataP,DownCode,rbp->Count)==COPYFAIL ) {				rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n");				sysfree( DownCode, rbp->Count );				p->RIOError.Error = COPYIN_FAILED;				func_exit ();				return -EFAULT;			}			HostP->Copy( DownCode, StartP, rbp->Count );			sysfree( DownCode, rbp->Count );		}		else if ( copyin((int)rbp->DataP,StartP,rbp->Count)==COPYFAIL ) {			rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n");			p->RIOError.Error = COPYIN_FAILED;			func_exit ();			return -EFAULT;		}		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 = (BYTE *)&Cad[0x7FF8];	/* <<<---- READ THE ABOVE COMMENTS */#define	NFIX(N)	(0x60 | (N))	/* .O  = (~(.O + N))<<4 */#define	PFIX(N)	(0x20 | (N))	/* .O  =   (.O + N)<<4  */#define	JUMP(N)	(0x00 | (N))	/* .PC =   .PC + .O	 */		/*		** 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;		WBYTE( DestP[0] , NFIX(((ushort)(~offset) >> (ushort)12) & 0xF) );		WBYTE( DestP[1] , PFIX(( offset >> 8) & 0xF) );		WBYTE( DestP[2] , PFIX(( offset >> 4) & 0xF) );		WBYTE( DestP[3] , JUMP( offset & 0xF) );		WBYTE( DestP[6] , NFIX(0) );		WBYTE( DestP[7] , JUMP(8) );		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);		/*		** Flag what is going on		*/

⌨️ 快捷键说明

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