d1a3b410ec
it clear that the recent PCI cards do not require firmware to be loaded, unlike the completely different ISA cards that are branded with the same name.
504 lines
13 KiB
C
504 lines
13 KiB
C
/*****************************************************************************/
|
|
|
|
/*
|
|
* stlload.c -- stallion intelligent multiport down loader.
|
|
*
|
|
* Copyright (c) 1994-1996 Greg Ungerer (gerg@stallion.oz.au).
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Greg Ungerer.
|
|
* 4. Neither the name of the author nor the names of any co-contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
/*****************************************************************************/
|
|
|
|
#ifndef lint
|
|
static const char rcsid[] =
|
|
"$FreeBSD$";
|
|
#endif /* not lint */
|
|
|
|
#include <err.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <machine/cdk.h>
|
|
|
|
/*****************************************************************************/
|
|
|
|
char *version = "1.0.0";
|
|
const char defdevice[] = "/dev/staliomem%d";
|
|
char *image = BOOTDIR "/cdk.sys";
|
|
char *oldimage = BOOTDIR "/2681.sys";
|
|
|
|
char *memdevice;
|
|
char devstr[128];
|
|
int brdnr = 0;
|
|
int verbose = 0;
|
|
int reset = 0;
|
|
|
|
/*
|
|
* Define a local buffer for copying the image into the shared memory.
|
|
*/
|
|
#define BUFSIZE 4096
|
|
|
|
char buf[BUFSIZE];
|
|
|
|
/*
|
|
* Define the timeout length when waiting for slave to start up.
|
|
* The quantity is measured in seconds.
|
|
*/
|
|
#define TIMEOUT 5
|
|
|
|
/*
|
|
* Set up a default feature area structure.
|
|
*/
|
|
cdkfeature_t feature = { 0, 0, ETYP_CDK, 0, 0, 0, 0, 0 };
|
|
|
|
/*
|
|
* Have local copies of the board signatures ready.
|
|
*/
|
|
cdkecpsig_t ecpsig;
|
|
cdkonbsig_t onbsig;
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* Declare internal function prototypes here.
|
|
*/
|
|
static void usage(void);
|
|
int ecpfindports(cdkecpsig_t *sigp);
|
|
int onbfindports(cdkonbsig_t *sigp);
|
|
int download(void);
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void usage()
|
|
{
|
|
fprintf(stderr, "%s\n%s\n",
|
|
"usage: stlload [-vhVR] [-i image-file] [-c control-device] [-r rx-buf-size]",
|
|
" [-t tx-buf-size] [-B boot-banner] [-b unit-number]");
|
|
exit(0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* Given a boards signature determine how many ports it has. We need to
|
|
* know this to setup the slave feature arguments. This function is for
|
|
* ECP boards only.
|
|
*/
|
|
|
|
int ecpfindports(cdkecpsig_t *sigp)
|
|
{
|
|
unsigned int id;
|
|
int bank, nrports;
|
|
|
|
nrports = 0;
|
|
for (bank = 0; (bank < 8); bank++) {
|
|
id = (unsigned int) sigp->panelid[bank];
|
|
if (id == 0xff)
|
|
break;
|
|
if ((id & 0x07) != bank)
|
|
break;
|
|
if (id & 0x20) {
|
|
nrports += 16;
|
|
bank++;
|
|
} else {
|
|
nrports += 8;
|
|
}
|
|
}
|
|
|
|
return(nrports);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* Given a boards signature determine how many ports it has. We need to
|
|
* know this to setup the slave feature arguments. This function is for
|
|
* ONboards and Brumbys.
|
|
*/
|
|
|
|
int onbfindports(cdkonbsig_t *sigp)
|
|
{
|
|
int i, nrports;
|
|
|
|
if (sigp->amask1) {
|
|
nrports = 32;
|
|
} else {
|
|
for (i = 0; (i < 16); i++) {
|
|
if (((sigp->amask0 << i) & 0x8000) == 0)
|
|
break;
|
|
}
|
|
nrports = i;
|
|
}
|
|
|
|
return(nrports);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* Download an image to the slave board. There is a long sequence of
|
|
* things to do to get the slave running, but it is basically a simple
|
|
* process. Main things to do are: copy slave image into shared memory,
|
|
* start slave running and then read shared memory map.
|
|
*/
|
|
|
|
int download()
|
|
{
|
|
unsigned char alivemarker;
|
|
time_t strttime;
|
|
int memfd, ifd;
|
|
int nrdevs, sigok, n;
|
|
|
|
if (verbose)
|
|
printf("Opening shared memory device %s\n", memdevice);
|
|
if ((memfd = open(memdevice, O_RDWR)) < 0) {
|
|
warn("failed to open memory device %s", memdevice);
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* Before starting the download must tell driver that we are about to
|
|
* stop its slave. This is only important if it is already running.
|
|
* Once we have told the driver its stopped then do a hardware reset
|
|
* on it, to get it into a known state.
|
|
*/
|
|
if (verbose)
|
|
printf("Stoping any current slave\n");
|
|
if (ioctl(memfd, STL_BSTOP, 0) < 0) {
|
|
warn("ioctl(STL_BSTOP)");
|
|
printf(" (Perhaps you're trying to download firmare to a PCI card that\n doesn't require this?)\n");
|
|
return(-1);
|
|
}
|
|
|
|
if (verbose)
|
|
printf("Reseting the board\n");
|
|
if (ioctl(memfd, STL_BRESET, 0) < 0) {
|
|
warn("ioctl(STL_BRESET)");
|
|
return(-1);
|
|
}
|
|
if (reset)
|
|
return(0);
|
|
|
|
/*
|
|
* After reseting the board we need to send an interrupt to the older
|
|
* board types to get them to become active. Do that now.
|
|
*/
|
|
if (verbose)
|
|
printf("Interrupting board to activate shared memory\n");
|
|
if (ioctl(memfd, STL_BINTR, 0) < 0) {
|
|
warn("ioctl(STL_BINTR)");
|
|
return(-1);
|
|
}
|
|
/*sleep(1);*/
|
|
|
|
if (verbose)
|
|
printf("Opening slave image file %s\n", image);
|
|
if ((ifd = open(image, O_RDONLY)) < 0) {
|
|
warn("failed to open image file %s", image);
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* At this point get the signature of the board from the shared memory.
|
|
* Do a double check that it is a board we know about. We will also need
|
|
* to calculate the number of ports on this board (to use later).
|
|
*/
|
|
sigok = 0;
|
|
if (verbose)
|
|
printf("Reading ROM signature from board\n");
|
|
|
|
if (lseek(memfd, CDK_SIGADDR, SEEK_SET) != CDK_SIGADDR) {
|
|
warn("lseek(%x) failed on memory file", CDK_FEATADDR);
|
|
return(-1);
|
|
}
|
|
if (read(memfd, &ecpsig, sizeof(cdkecpsig_t)) < 0) {
|
|
warn("read of ROM signature failed");
|
|
return(-1);
|
|
}
|
|
if (ecpsig.magic == ECP_MAGIC) {
|
|
nrdevs = ecpfindports(&ecpsig);
|
|
if (nrdevs < 0)
|
|
return(-1);
|
|
sigok++;
|
|
}
|
|
|
|
if (lseek(memfd, CDK_SIGADDR, SEEK_SET) != CDK_SIGADDR) {
|
|
warn("lseek(%x) failed on memory file", CDK_FEATADDR);
|
|
return(-1);
|
|
}
|
|
if (read(memfd, &onbsig, sizeof(cdkonbsig_t)) < 0) {
|
|
warn("read of ROM signature failed");
|
|
return(-1);
|
|
}
|
|
if ((onbsig.magic0 == ONB_MAGIC0) && (onbsig.magic1 == ONB_MAGIC1) &&
|
|
(onbsig.magic2 == ONB_MAGIC2) &&
|
|
(onbsig.magic3 == ONB_MAGIC3)) {
|
|
nrdevs = onbfindports(&onbsig);
|
|
if (nrdevs < 0)
|
|
return(-1);
|
|
sigok++;
|
|
}
|
|
|
|
if (! sigok) {
|
|
warnx("unknown signature from board");
|
|
return(-1);
|
|
}
|
|
|
|
if (verbose)
|
|
printf("Board signature reports %d ports\n", nrdevs);
|
|
|
|
/*
|
|
* Start to copy the image file into shared memory. The first thing to
|
|
* do is copy the vector region in from shared memory address 0. We will
|
|
* then skip over the signature and feature area and start copying the
|
|
* actual image data and code from 4k upwards.
|
|
*/
|
|
if (verbose)
|
|
printf("Copying vector table into shared memory\n");
|
|
if ((n = read(ifd, buf, CDK_SIGADDR)) < 0) {
|
|
warn("read of image file failed");
|
|
return(-1);
|
|
}
|
|
if (lseek(memfd, 0, SEEK_SET) != 0) {
|
|
warn("lseek(%x) failed on memory file", CDK_FEATADDR);
|
|
return(-1);
|
|
}
|
|
if (write(memfd, buf, n) < 0) {
|
|
warn("write to memory device failed");
|
|
return(-1);
|
|
}
|
|
|
|
if (lseek(ifd, 0x1000, SEEK_SET) != 0x1000) {
|
|
warn("lseek(%x) failed on image file", CDK_FEATADDR);
|
|
return(-1);
|
|
}
|
|
if (lseek(memfd, 0x1000, SEEK_SET) != 0x1000) {
|
|
warn("lseek(%x) failed on memory device", CDK_FEATADDR);
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* Copy buffer size chunks of data from the image file into shared memory.
|
|
*/
|
|
do {
|
|
if ((n = read(ifd, buf, BUFSIZE)) < 0) {
|
|
warn("read of image file failed");
|
|
return(-1);
|
|
}
|
|
if (write(memfd, buf, n) < 0) {
|
|
warn("write to memory device failed");
|
|
return(-1);
|
|
}
|
|
} while (n == BUFSIZE);
|
|
|
|
close(ifd);
|
|
|
|
/*
|
|
* We need to down load the start up parameters for the slave. This is
|
|
* done via the feature area of shared memory. Think of the feature area
|
|
* as a way of passing "command line" arguments to the slave.
|
|
* FIX: should do something here to load "brdspec" as well...
|
|
*/
|
|
feature.nrdevs = nrdevs;
|
|
if (verbose)
|
|
printf("Loading features into shared memory\n");
|
|
if (lseek(memfd, CDK_FEATADDR, SEEK_SET) != CDK_FEATADDR) {
|
|
warn("lseek(%x) failed on memory device", CDK_FEATADDR);
|
|
return(-1);
|
|
}
|
|
if (write(memfd, &feature, sizeof(cdkfeature_t)) < 0) {
|
|
warn("write to memory device failed");
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* Wait for board alive marker to be set. The slave image will set the
|
|
* byte at address CDK_RDYADDR to 0x13 after it has successfully started.
|
|
* If this doesn't happen we timeout and fail.
|
|
*/
|
|
if (verbose)
|
|
printf("Setting alive marker to 0\n");
|
|
if (lseek(memfd, CDK_RDYADDR, SEEK_SET) != CDK_RDYADDR) {
|
|
warn("lseek(%x) failed on memory device", CDK_RDYADDR);
|
|
return(-1);
|
|
}
|
|
alivemarker = 0;
|
|
if (write(memfd, &alivemarker, 1) < 0) {
|
|
warn("write to memory device failed");
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* At this point the entire image is loaded into shared memory. To start
|
|
* it executiong we poke the board with an interrupt.
|
|
*/
|
|
if (verbose)
|
|
printf("Interrupting board to start slave image\n");
|
|
if (ioctl(memfd, STL_BINTR, 0) < 0) {
|
|
warn("ioctl(STL_BINTR) failed");
|
|
return(-1);
|
|
}
|
|
|
|
strttime = time((time_t *) NULL);
|
|
if (verbose)
|
|
printf("Waiting for slave alive marker, time=%x timeout=%d\n",
|
|
strttime, TIMEOUT);
|
|
while (time((time_t *) NULL) < (strttime + TIMEOUT)) {
|
|
if (lseek(memfd, CDK_RDYADDR, SEEK_SET) != CDK_RDYADDR) {
|
|
warn("lseek(%x) failed on memory device", CDK_RDYADDR);
|
|
return(-1);
|
|
}
|
|
if (read(memfd, &alivemarker, 1) < 0){
|
|
warn("read of image file failed");
|
|
return(-1);
|
|
}
|
|
if (alivemarker == CDK_ALIVEMARKER)
|
|
break;
|
|
}
|
|
|
|
if (alivemarker != CDK_ALIVEMARKER) {
|
|
warnx("slave image failed to start");
|
|
return(-1);
|
|
}
|
|
|
|
if (lseek(memfd, CDK_RDYADDR, SEEK_SET) != CDK_RDYADDR) {
|
|
warn("lseek(%x) failed on memory device", CDK_RDYADDR);
|
|
return(-1);
|
|
}
|
|
alivemarker = 0;
|
|
if (write(memfd, &alivemarker, 1) < 0) {
|
|
warn("write to memory device failed");
|
|
return(-1);
|
|
}
|
|
|
|
if (verbose)
|
|
printf("Slave image started successfully\n");
|
|
|
|
/*
|
|
* The last thing to do now is to get the driver started. Now that the
|
|
* slave is operational it must read in the memory map and gets its
|
|
* internal tables initialized.
|
|
*/
|
|
if (verbose)
|
|
printf("Driver initializing host shared memory interface\n");
|
|
if (ioctl(memfd, STL_BSTART, 0) < 0) {
|
|
warn("ioctl(STL_BSTART) failed");
|
|
return(-1);
|
|
}
|
|
|
|
close(memfd);
|
|
return(0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct stat statinfo;
|
|
int c;
|
|
|
|
while ((c = getopt(argc, argv, "hvVRB:i:b:c:t:r:")) != -1) {
|
|
switch (c) {
|
|
case 'V':
|
|
printf("stlload version %s\n", version);
|
|
exit(0);
|
|
break;
|
|
case 'B':
|
|
feature.banner = atol(optarg);
|
|
break;
|
|
case 'h':
|
|
usage();
|
|
break;
|
|
case 'v':
|
|
verbose++;
|
|
break;
|
|
case 'i':
|
|
image = optarg;
|
|
break;
|
|
case 'R':
|
|
reset++;
|
|
break;
|
|
case 'b':
|
|
brdnr = atoi(optarg);
|
|
break;
|
|
case 'c':
|
|
memdevice = optarg;
|
|
break;
|
|
case 't':
|
|
feature.txrqsize = atol(optarg);
|
|
break;
|
|
case 'r':
|
|
feature.rxrqsize = atol(optarg);
|
|
break;
|
|
case '?':
|
|
default:
|
|
usage();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (memdevice == (char *) NULL) {
|
|
if ((brdnr < 0) || (brdnr >= 8))
|
|
errx(1, "invalid board number %d specified", brdnr);
|
|
sprintf(devstr, defdevice, brdnr);
|
|
memdevice = &devstr[0];
|
|
if (verbose)
|
|
printf("Using shared memory device %s\n", memdevice);
|
|
}
|
|
|
|
if (verbose)
|
|
printf("Downloading image %s to board %d\n", image, brdnr);
|
|
|
|
/*
|
|
* Check that the shared memory device exits and is a character device.
|
|
*/
|
|
if (stat(memdevice, &statinfo) < 0)
|
|
errx(1, "memory device %s does not exist", memdevice);
|
|
if ((statinfo.st_mode & S_IFMT) != S_IFCHR)
|
|
errx(1, "memory device %s is not a char device", memdevice);
|
|
|
|
if (stat(image, &statinfo) < 0)
|
|
errx(1, "image file %s does not exist", image);
|
|
|
|
/*
|
|
* All argument checking is now done. So lets get this show on the road.
|
|
*/
|
|
if (download() < 0)
|
|
exit(1);
|
|
exit(0);
|
|
}
|
|
|
|
/*****************************************************************************/
|