rioboot.c

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

C
1,115
字号
#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;		writeb(NFIX(((unsigned short) (~offset) >> (unsigned short) 12) & 0xF), DestP);		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);		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		 */		HostP->Flags &= ~RUN_STATE;		HostP->Flags |= RC_STARTUP;		/*		 ** Grab a copy of the current ParmMap pointer, so we		 ** can tell when it has changed.		 */		OldParmMap = readw(&HostP->__ParmMapR);		rio_dprintk(RIO_DEBUG_BOOT, "Original parmmap is 0x%x\n", OldParmMap);		/*		 ** 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);		rio_start_card_running(HostP);		rio_dprintk(RIO_DEBUG_BOOT, "Set control port\n");		/*		 ** Now, wait for upto five seconds for the Tp to setup the parmmap		 ** pointer:		 */		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);		}		/*		 ** If the parmmap pointer is unchanged, then the host code		 ** has crashed & burned in a really spectacular way		 */		if (readw(&HostP->__ParmMapR) == OldParmMap) {			rio_dprintk(RIO_DEBUG_BOOT, "parmmap 0x%x\n", readw(&HostP->__ParmMapR));			rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n");			HostP->Flags &= ~RUN_STATE;			HostP->Flags |= RC_STUFFED;			RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );			continue;		}		rio_dprintk(RIO_DEBUG_BOOT, "Running 0x%x\n", readw(&HostP->__ParmMapR));		/*		 ** 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.		 */		/*		 ** Grab a 32 bit pointer to the parmmap structure		 */		ParmMapP = (PARM_MAP *) RIO_PTR(Cad, readw(&HostP->__ParmMapR));		rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP);		ParmMapP = (PARM_MAP *) ((unsigned long) Cad + readw(&HostP->__ParmMapR));		rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP);		/*		 ** 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.		 */		if (readw(&ParmMapP->links) != 0xFFFF) {			rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name);			rio_dprintk(RIO_DEBUG_BOOT, "Links = 0x%x\n", readw(&ParmMapP->links));			HostP->Flags &= ~RUN_STATE;			HostP->Flags |= RC_STUFFED;			RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );			continue;		}		writew(RIO_LINK_ENABLE, &ParmMapP->links);		/*		 ** 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);		HostP->timeout_id = 0;		for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && !readw(&ParmMapP->init_done); wait_count++) {			rio_dprintk(RIO_DEBUG_BOOT, "Waiting for init_done\n");			mdelay(100);		}		rio_dprintk(RIO_DEBUG_BOOT, "OK! init_done!\n");		if (readw(&ParmMapP->error) != E_NO_ERROR || !readw(&ParmMapP->init_done)) {			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;			RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );			continue;		}		rio_dprintk(RIO_DEBUG_BOOT, "Got init_done\n");		/*		 ** It runs! It runs!		 */		rio_dprintk(RIO_DEBUG_BOOT, "Host ID %x Running\n", HostP->UniqueNum);		/*		 ** set the time period between interrupts.		 */		writew(p->RIOConf.Timer, &ParmMapP->timer);		/*		 ** Translate all the 16 bit pointers in the __ParmMapR into		 ** 32 bit pointers for the driver in ioremap space.		 */		HostP->ParmMapP = ParmMapP;		HostP->PhbP = (struct PHB *) RIO_PTR(Cad, readw(&ParmMapP->phb_ptr));		HostP->RupP = (struct RUP *) RIO_PTR(Cad, readw(&ParmMapP->rups));		HostP->PhbNumP = (unsigned short *) RIO_PTR(Cad, readw(&ParmMapP->phb_num_ptr));		HostP->LinkStrP = (struct LPB *) RIO_PTR(Cad, readw(&ParmMapP->link_str_ptr));		/*		 ** 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;			HostP->UnixRups[RupN].BaseSysPort = NO_PORT;			spin_lock_init(&HostP->UnixRups[RupN].RupLock);		}		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);		}		/*		 ** 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) {				struct Port *PortP = p->RIOPortp[PortN];				struct PHB *PhbP;				/* int oldspl; */				if (!PortP->Mapped)					continue;				PhbP = &HostP->PhbP[PortP->HostPort];				rio_spin_lock_irqsave(&PortP->portSem, flags);				PortP->PhbP = PhbP;				PortP->TxAdd = (u16 *) RIO_PTR(Cad, readw(&PhbP->tx_add));				PortP->TxStart = (u16 *) RIO_PTR(Cad, readw(&PhbP->tx_start));				PortP->TxEnd = (u16 *) RIO_PTR(Cad, readw(&PhbP->tx_end));				PortP->RxRemove = (u16 *) RIO_PTR(Cad, readw(&PhbP->rx_remove));				PortP->RxStart = (u16 *) RIO_PTR(Cad, readw(&PhbP->rx_start));				PortP->RxEnd = (u16 *) RIO_PTR(Cad, readw(&PhbP->rx_end));				rio_spin_unlock_irqrestore(&PortP->portSem, flags);				/*				 ** point the UnixRup at the base SysPort				 */				if (!(PortN % PORTS_PER_RTA))					HostP->UnixRups[PortP->RupNum].BaseSysPort = PortN;			}		}		rio_dprintk(RIO_DEBUG_BOOT, "Set the card running... \n");		/*		 ** last thing - show the world that everything is in place		 */		HostP->Flags &= ~RUN_STATE;		HostP->Flags |= RC_RUNNING;	}	/*	 ** MPX always uses a poller. This is actually patched into the system	 ** configuration and called directly from each clock tick.	 **	 */	p->RIOPolling = 1;	p->RIOSystemUp++;	rio_dprintk(RIO_DEBUG_BOOT, "Done everything %x\n", HostP->Ivec);	func_exit();	return 0;}/** *	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. */int RIOBootRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT *PacketP){	struct PktCmd *PktCmdP = (struct PktCmd *) PacketP->data;	struct PktCmd_M *PktReplyP;	struct CmdBlk *CmdBlkP;	unsigned int sequence;	/*	 ** 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");		return 0;	}	/*	 ** 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!	 */	if ((readb(&PacketP->len) & PKT_CMD_BIT) && (readb(&PktCmdP->Command) == BOOT_COMPLETED))		return RIOBootComplete(p, HostP, Rup, PktCmdP);	/*	 ** Try to allocate a command block. This is in kernel space	 */	if (!(CmdBlkP = RIOGetCmdBlk())) {		rio_dprintk(RIO_DEBUG_BOOT, "No command blocks to boot RTA! come back later.\n");		return 0;	}	/*	 ** Fill in the default info on the command block	 */	CmdBlkP->Packet.dest_unit = Rup < (unsigned short) MAX_RUP ? Rup : 0;	CmdBlkP->Packet.dest_port = BOOT_RUP;	CmdBlkP->Packet.src_unit = 0;	CmdBlkP->Packet.src_port = BOOT_RUP;	CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;	PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data;	/*	 ** process COMMANDS on the boot rup!	 */	if (readb(&PacketP->len) & PKT_CMD_BIT) {		/*		 ** We only expect one type of command - a BOOT_REQUEST!		 */		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);			RIOFreeCmdBlk(CmdBlkP);			return 1;		}		/*		 ** 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 :		 */		PktReplyP->Command = BOOT_SEQUENCE;		PktReplyP->BootSequence.NumPackets = p->RIONumBootPkts;		PktReplyP->BootSequence.LoadBase = p->RIOConf.RtaLoadBase;		PktReplyP->BootSequence.CodeSize = p->RIOBootCount;		CmdBlkP->Packet.len = BOOT_SEQUENCE_LEN | PKT_CMD_BIT;		memcpy((void *) &CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN], "BOOT", 4);		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);		/*		 ** 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.		 */		p->RIOBooting++;		RIOQueueCmdBlk(HostP, Rup, CmdBlkP);		return 1;	}	/*	 ** It is a request for boot data.	 */	sequence = readw(&PktCmdP->Sequence);	rio_dprintk(RIO_DEBUG_BOOT, "Boot block %d on Host %Zd Rup%d\n", sequence, HostP - p->RIOHosts, Rup);	if (sequence >= p->RIONumBootPkts) {		rio_dprintk(RIO_DEBUG_BOOT, "Got a request for packet %d, max is %d\n", sequence, p->RIONumBootPkts);	}	PktReplyP->Sequence = sequence;	memcpy(PktReplyP->BootData, p->RIOBootPackets[p->RIONumBootPkts - sequence - 1], RTA_BOOT_DATA_SIZE);	CmdBlkP->Packet.len = PKT_MAX_DATA_LEN;	RIOQueueCmdBlk(HostP, Rup, CmdBlkP);	return 1;}/** *	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. */static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd *PktCmdP){	struct Map *MapP = NULL;	struct Map *MapP2 = NULL;	int Flag;	int found;	int host, rta;	int EmptySlot = -1;	int entry, entry2;	char *MyType, *MyName;	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);	p->RIOBooting = 0;	rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot completed - BootInProgress now %d\n", p->RIOBooting);	/*	 ** Determine type of unit (16/8 port RTA).

⌨️ 快捷键说明

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