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 + -
显示快捷键?