From iedowse@maths.tcd.ie  Tue Oct  6 11:01:28 1998
Received: from salmon.maths.tcd.ie (salmon.maths.tcd.ie [134.226.81.11])
          by hub.freebsd.org (8.8.8/8.8.8) with SMTP id LAA05740
          for <FreeBSD-gnats-submit@freebsd.org>; Tue, 6 Oct 1998 11:01:01 -0700 (PDT)
          (envelope-from iedowse@maths.tcd.ie)
Received: from hamilton.maths.tcd.ie by salmon.maths.tcd.ie with SMTP
          id <aa11209@salmon.maths.tcd.ie>; 6 Oct 98 19:00:56 +0100 (BST)
Message-Id: <9810061900.aa25149@hamilton.maths.tcd.ie>
Date: Tue, 6 Oct 98 19:00:52 +0100 (BST)
From: iedowse@maths.tcd.ie
Sender: iedowse@maths.tcd.ie
Reply-To: iedowse@maths.tcd.ie
To: FreeBSD-gnats-submit@freebsd.org
Cc: iedowse@maths.tcd.ie
Subject: Intel EtherExpress Pro 100 support for netboot
X-Send-Pr-Version: 3.2

>Number:         8171
>Category:       i386
>Synopsis:       [patch] Intel EtherExpress Pro 100 support for netboot
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Oct  6 11:10:00 PDT 1998
>Closed-Date:    Thu Mar 23 00:22:04 PST 2000
>Last-Modified:  Thu Mar 23 00:22:21 PST 2000
>Originator:     Ian Dowse
>Release:        FreeBSD 3.0-BETA i386
>Organization:
		School of Mathematics
		Trinity College Dublin
>Environment:

	FreeBSD-current 

>Description:

	The following patches add to netboot support for Intel EtherExpress
	Pro 100 PCI cards. PCs with these cards can be netbooted via the
	msdos nbfxp.com program, or alternatively a flash ROM placed in the
	PLCC socket on the card can be programmed with nbfxp.rom. (I have
	a FreeBSD utility for programming these flash ROMs which I'll submit
	later)

	There are a few changes to start2.S and makerom.c which make it
	easier to generate different rom sizes in the same makefile.
	The makerom program now sets the size fields in the rom header, so
	no rom-size information is required at link time. makerom also
	accepts a PCI device ID, allowing roms with different PCI IDs to
	be generated with one makefile.

	This code is heavily based on FreeBSD-stable PCI code, and it should
	be relatively easy to add support for further PCI network cards.

	I've tested this when compiled under both -stable and -current (a.out),
	and booted from both msdos and flash rom.

>How-To-Repeat:

>Fix:
	
diff -rPc netboot.old/Makefile netboot/Makefile
*** netboot.old/Makefile	Tue Oct  6 16:49:31 1998
--- netboot/Makefile	Tue Oct  6 17:25:00 1998
***************
*** 26,46 ****
  PCI_DEVICE=0x8029
  PCI_CLASS=0x02,0x00,0x00
  
! PROG=	nb8390.com nb3c509.com nb8390.rom nb3c509.rom
  # Order is very important on the SRCS line for this prog
  SRCS=	start2.S main.c misc.c bootmenu.c rpc.c
  
  BINDIR=netboot		/usr/mdec
  BINMODE=	555
! #CFLAGS=		-O2 -DNFS -DROMSIZE=${ROMSIZE} -DRELOC=${RELOCADDR} -DASK_BOOT
! CFLAGS=		-O2 -DNFS -DROMSIZE=${ROMSIZE} -DRELOC=${RELOCADDR} # -DASK_BOOT
! CFLAGS += -DPCI -DPCI_VENDOR=${PCI_VENDOR} -DPCI_DEVICE=${PCI_DEVICE}
! CFLAGS += -DPCI_CLASS=${PCI_CLASS} -DASK_BOOT
  #NS8390=		-DINCLUDE_WD -DWD_DEFAULT_MEM=0xD0000
  NS8390=	-DINCLUDE_NE
  #NS8390+=	-DINCLUDE_3COM -D_3COM_BASE=0x300
  CLEANFILES+=	netboot.com
! CLEANFILES+=	makerom start2.ro 3c509.o ns8390.o
  ROMLDFLAGS=	${LDFLAGS} -N -T ${RELOCADDR} -e _start -nostdlib
  NOSHARED=	YES
  MAN8=	netboot.8
--- 26,50 ----
  PCI_DEVICE=0x8029
  PCI_CLASS=0x02,0x00,0x00
  
! # options for Intel EtherExpress Pro 100 card
! FXP_ROMSIZE=131072
! FXP_PCI_ID=0x12298086
! 
! PROG=	nb8390.com nb3c509.com nbfxp.com nb8390.rom nb3c509.rom nbfxp.rom
  # Order is very important on the SRCS line for this prog
  SRCS=	start2.S main.c misc.c bootmenu.c rpc.c
  
  BINDIR=		/usr/mdec
  BINMODE=	555
! CFLAGS=		-O2 -DNFS -DRELOCSIZE=${RELOCSIZE} -DRELOC=${RELOCADDR}
! CFLAGS +=	-DASK_BOOT
! CFLAGS +=	-DPCI -DPCI_VENDOR=${PCI_VENDOR} -DPCI_DEVICE=${PCI_DEVICE}
! CFLAGS +=	-DPCI_CLASS=${PCI_CLASS}
  #NS8390=		-DINCLUDE_WD -DWD_DEFAULT_MEM=0xD0000
  NS8390=	-DINCLUDE_NE
  #NS8390+=	-DINCLUDE_3COM -D_3COM_BASE=0x300
  CLEANFILES+=	netboot.com
! CLEANFILES+=	makerom start2.ro 3c509.o ns8390.o fxp.o pci.o pcibus.o
  ROMLDFLAGS=	${LDFLAGS} -N -T ${RELOCADDR} -e _start -nostdlib
  NOSHARED=	YES
  MAN8=	netboot.8
***************
*** 48,53 ****
--- 52,60 ----
  
  ROMSIZE=16384
  RELOCADDR=0x90000
+ # Copying 64k should do no harm in the vast majority of cases; this means that
+ # only makerom needs to be told the real rom size.
+ RELOCSIZE=0xFFFF
  
  .SUFFIXES:	.ro
  
***************
*** 60,79 ****
  	${CC} ${CFLAGS} $(NS8390) -o ${.TARGET} -c $<
  
  makerom: makerom.c
! 	${CC} ${CFLAGS} -DROMSIZE=${ROMSIZE} ${LDFLAGS} -o ${.TARGET} \
  	    ${.CURDIR}/makerom.c
  
  nb8390.rom:	makerom start2.ro ${SRCS:N*.h:R:S/$/.o/g} ns8390.o
  	${LD} ${ROMLDFLAGS} -o ${.TARGET} ${OBJS:S/start2.o/start2.ro/} ns8390.o
  	strip ${.TARGET}
  	size ${.TARGET}
! 	${.OBJDIR}/makerom ${.TARGET}
  
  nb3c509.rom:	makerom start2.ro ${SRCS:N*.h:R:S/$/.o/g} 3c509.o
  	${LD} ${ROMLDFLAGS} -o ${.TARGET} ${OBJS:S/start2.o/start2.ro/} 3c509.o
  	strip ${.TARGET}
  	size ${.TARGET}
! 	${.OBJDIR}/makerom ${.TARGET}
  
  nb8390.com:	makerom start2.ro ${SRCS:N*.h:R:S/$/.o/g} ns8390.o
  	${LD} ${ROMLDFLAGS} -o ${.TARGET}.tmp ${OBJS} ns8390.o
--- 67,93 ----
  	${CC} ${CFLAGS} $(NS8390) -o ${.TARGET} -c $<
  
  makerom: makerom.c
! 	${CC} ${CFLAGS} ${LDFLAGS} -o ${.TARGET} \
  	    ${.CURDIR}/makerom.c
  
  nb8390.rom:	makerom start2.ro ${SRCS:N*.h:R:S/$/.o/g} ns8390.o
  	${LD} ${ROMLDFLAGS} -o ${.TARGET} ${OBJS:S/start2.o/start2.ro/} ns8390.o
  	strip ${.TARGET}
  	size ${.TARGET}
! 	${.OBJDIR}/makerom ${ROMSIZE} ${.TARGET}
  
  nb3c509.rom:	makerom start2.ro ${SRCS:N*.h:R:S/$/.o/g} 3c509.o
  	${LD} ${ROMLDFLAGS} -o ${.TARGET} ${OBJS:S/start2.o/start2.ro/} 3c509.o
  	strip ${.TARGET}
  	size ${.TARGET}
! 	${.OBJDIR}/makerom ${ROMSIZE} ${.TARGET}
! 
! nbfxp.rom:	makerom start2.ro ${SRCS:N*.h:R:S/$/.o/g} fxp.o pci.o pcibus.o
! 	${LD} ${ROMLDFLAGS} -o ${.TARGET} ${OBJS:S/start2.o/start2.ro/} \
! 	    fxp.o pci.o pcibus.o
! 	strip ${.TARGET}
! 	size ${.TARGET}
! 	${.OBJDIR}/makerom ${FXP_ROMSIZE} ${.TARGET} ${FXP_PCI_ID}
  
  nb8390.com:	makerom start2.ro ${SRCS:N*.h:R:S/$/.o/g} ns8390.o
  	${LD} ${ROMLDFLAGS} -o ${.TARGET}.tmp ${OBJS} ns8390.o
***************
*** 89,97 ****
  	dd ibs=32 skip=1 if=${.TARGET}.tmp of=${.TARGET}
  	rm -f ${.TARGET}.tmp
  
  # This force the creation of the "machine" symlink.  These objects are
  # specially handled in this file, and thus can't be taken care of in
  # ../Makefile.inc
! 3c509.o makerom ns8390.o start2.ro: machine
  
  .include <bsd.prog.mk>
--- 103,118 ----
  	dd ibs=32 skip=1 if=${.TARGET}.tmp of=${.TARGET}
  	rm -f ${.TARGET}.tmp
  
+ nbfxp.com:	makerom start2.ro ${SRCS:N*.h:R:S/$/.o/g} fxp.o pci.o pcibus.o
+ 	${LD} ${ROMLDFLAGS} -o ${.TARGET}.tmp ${OBJS} fxp.o pci.o pcibus.o
+ 	strip ${.TARGET}.tmp
+ 	size ${.TARGET}.tmp
+ 	dd ibs=32 skip=1 if=${.TARGET}.tmp of=${.TARGET}
+ 	rm -f ${.TARGET}.tmp
+ 
  # This force the creation of the "machine" symlink.  These objects are
  # specially handled in this file, and thus can't be taken care of in
  # ../Makefile.inc
! 3c509.o makerom ns8390.o fxp.o pci.o pcibus.o start2.ro: machine
  
  .include <bsd.prog.mk>
diff -rPc netboot.old/bootmenu.c netboot/bootmenu.c
*** netboot.old/bootmenu.c	Tue Oct  6 16:49:31 1998
--- netboot/bootmenu.c	Tue Oct  6 12:55:17 1998
***************
*** 216,222 ****
--- 216,226 ----
  
  static void mountopts(prefix,args,p)
  	char *prefix;    
+ #if __FreeBSD__ >= 3
  	struct onfs_args *args;
+ #else
+ 	struct nfs_args *args;
+ #endif
  	char *p;
  {
          char *tmp;
diff -rPc netboot.old/netboot/fxp.c netboot/fxp.c
*** netboot.old/netboot/fxp.c	Thu Jan  1 01:00:00 1970
--- netboot/fxp.c	Tue Oct  6 15:13:49 1998
***************
*** 0 ****
--- 1,709 ----
+ /*
+  * Copyright (c) 1995, David Greenman
+  * All rights reserved.
+  *
+  * Modifications to support NetBSD and media selection:
+  * Copyright (c) 1997 Jason R. Thorpe.  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 unmodified, 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.
+  *
+  * 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.
+  *
+  *	$Id$
+  */
+ 
+ /*
+  * Intel EtherExpress Pro/100B PCI Fast Ethernet driver
+  * Highly munged and simplified for netboot environment
+  */
+ 
+ #include <sys/types.h>
+ 
+ #define ETHER_MAX_LEN 1518
+ 
+ #include "pcivar.h"
+ #include "pcireg.h"
+ #include "pcibus.h"
+ 
+ #include "pci.h"
+ #include "fxp.h"
+ 
+ #include "netboot.h"
+ 
+ 
+ #define vtophys(v) ((u_int32_t)(v))
+ #define     FXP_ARGS(sc)            (sc)->unit
+ #define     FXP_FORMAT              "fxp%d"
+ 
+ #define FXP_NTXBUFS 2
+ #define FXP_TXCB_MASK  (FXP_NTXBUFS - 1)
+ 
+ #define FXP_NRFABUFS 4	/* Number of receive packet buffers */
+ 
+ struct fxp_rxbuf {
+ 	struct fxp_rxbuf *next;
+ 	struct fxp_rfa rfa;
+ 	unsigned char data[ETHER_MAX_LEN];
+ };
+ 
+ struct fxp_softc {
+ 	int unit;
+ 	caddr_t csr;
+ 	struct fxp_cb_tx *cbl_base;     /* base of TxCB list */
+ 	struct fxp_cb_tx *cbl_first;    /* first active TxCB in list */
+ 	struct fxp_cb_tx *cbl_last;     /* last active TxCB in list */
+ 
+ 	unsigned char enaddr[6];
+ 
+ 	struct fxp_rxbuf *rxbuf;
+ 
+ 	struct fxp_rxbuf *rxbuf_head;
+ 	struct fxp_rxbuf *rxbuf_tail;
+ 
+ 	int tx_queued;                  /* # of active TxCB's */
+ 	int phy_primary_addr;
+ 	int phy_primary_device;
+ 	int phy_10Mbps_only;
+ 	struct fxp_cb_mcs *mcsp;
+ };
+ 
+ static void fxp_read_eeprom(struct fxp_softc *, u_int16_t *,int, int);
+ 
+ static u_long fxp_count;
+ 
+ 
+ #define FXP_MAXCARDS 1
+ static struct fxp_softc card[FXP_MAXCARDS];
+ static unsigned fxp_nextcard = 0;
+ 
+ static struct fxp_cb_tx card_cb[FXP_MAXCARDS][FXP_NTXBUFS];
+ static struct fxp_cb_mcs card_mcs[FXP_MAXCARDS];
+ 
+ struct fxp_rxbuf rxbuf[FXP_MAXCARDS][FXP_NRFABUFS];
+ 
+ static u_char fxp_cb_config_template[] = {
+         0x0, 0x0,               /* cb_status */
+         0x80, 0x2,              /* cb_command */
+         0xff, 0xff, 0xff, 0xff, /* link_addr */
+         0x16,   /*  0 */
+         0x8,    /*  1 */
+         0x0,    /*  2 */
+         0x0,    /*  3 */
+         0x0,    /*  4 */
+         0x80,   /*  5 */
+         0xb2,   /*  6 */
+         0x3,    /*  7 */
+         0x1,    /*  8 */
+         0x0,    /*  9 */
+         0x26,   /* 10 */
+         0x0,    /* 11 */
+         0x60,   /* 12 */
+         0x0,    /* 13 */
+         0xf2,   /* 14 */
+         0x48,   /* 15 */
+         0x0,    /* 16 */
+         0x40,   /* 17 */
+         0xf3,   /* 18 */
+         0x0,    /* 19 */
+         0x3f,   /* 20 */
+         0x5     /* 21 */
+ };
+ 
+ static char *fxp_probe(config_id, device_id)
+ 	pcici_t config_id;
+ 	pcidi_t device_id;
+ {
+ #define FXP_VENDORID_INTEL	0x8086
+ #define FXP_DEVICEID_i82557	0x1229
+ 	
+ 	if ((device_id & 0xffff) == FXP_VENDORID_INTEL &&
+ 	    ((device_id >> 16) & 0xffff) == FXP_DEVICEID_i82557)
+ 		return ("Intel EtherExpress Pro 10/100B Ethernet");
+ 	
+ 	return NULL;
+ }
+ 	
+ 
+ static void
+ fxp_attach(config_id, unit)
+ 	pcici_t config_id;
+ 	int unit;
+ {
+ 	vm_offset_t pbase;
+ 	struct fxp_softc *sc;
+ 	u_int16_t data;
+ 
+ 	sc = &card[fxp_nextcard++];
+ 
+ 	if (fxp_nextcard > FXP_MAXCARDS) {
+ 		printf("fxp%d: ignoring this interface\n", unit);
+ 		return;
+ 	}
+ 
+ 	bzero(sc, sizeof(struct fxp_softc));
+ 
+ 	sc->unit = unit;
+ 
+ 	if (!pci_map_mem(config_id, FXP_PCI_MMBA,
+ 	    (vm_offset_t *)&sc->csr, &pbase)) {
+ 		printf("fxp%d: couldn't map memory\n", unit);
+ 		goto fail;
+ 	}
+ 
+ 	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
+ 	DELAY(10);
+ 
+ 	sc->cbl_base = &card_cb[fxp_nextcard-1][0];
+ 	sc->mcsp = &card_mcs[fxp_nextcard-1];
+ 
+ 	sc->rxbuf = &rxbuf[fxp_nextcard-1][0];
+ 
+ 	fxp_read_eeprom(sc, (u_int16_t *)&data, 6, 1);
+ 	sc->phy_primary_addr = data & 0xff;
+ 	sc->phy_primary_device = (data >> 8) & 0x3f;
+ 	sc->phy_10Mbps_only = data >> 15;
+ 
+ 	fxp_read_eeprom(sc, (u_int16_t *)sc->enaddr, 0, 3);
+ 
+ 
+ 	printf("fxp%d: Ethernet address %b:%b:%b:%b:%b:%b\n", unit,
+ 	    sc->enaddr[0], sc->enaddr[1], sc->enaddr[2], sc->enaddr[3],
+ 	    sc->enaddr[4], sc->enaddr[5]);
+ 
+ 
+ fail:
+ 
+ }
+ 
+ 
+ 
+ static void
+ fxp_read_eeprom(sc, data, offset, words)
+ 	struct fxp_softc *sc;
+ 	u_short *data;
+ 	int offset;
+ 	int words;
+ {
+ 	u_int16_t reg;
+ 	int i, x;
+ 
+ 	for (i = 0; i < words; i++) {
+ 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, FXP_EEPROM_EECS);
+ 		/*
+ 		 * Shift in read opcode.
+ 		 */
+ 		for (x = 3; x > 0; x--) {
+ 			if (FXP_EEPROM_OPC_READ & (1 << (x - 1))) {
+ 				reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
+ 			} else {
+ 				reg = FXP_EEPROM_EECS;
+ 			}
+ 			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ 			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ 			    reg | FXP_EEPROM_EESK);
+ 			DELAY(1);
+ 			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ 			DELAY(1);
+ 		}
+ 		/*
+ 		 * Shift in address.
+ 		 */
+ 		for (x = 6; x > 0; x--) {
+ 			if ((i + offset) & (1 << (x - 1))) {
+ 				reg = FXP_EEPROM_EECS | FXP_EEPROM_EEDI;
+ 			} else {
+ 				reg = FXP_EEPROM_EECS;
+ 			}
+ 			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ 			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ 			    reg | FXP_EEPROM_EESK);
+ 			DELAY(1);
+ 			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ 			DELAY(1);
+ 		}
+ 		reg = FXP_EEPROM_EECS;
+ 		data[i] = 0;
+ 		/*
+ 		 * Shift out data.
+ 		 */
+ 		for (x = 16; x > 0; x--) {
+ 			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL,
+ 			    reg | FXP_EEPROM_EESK);
+ 			DELAY(1);
+ 			if (CSR_READ_2(sc, FXP_CSR_EEPROMCONTROL) &
+ 			    FXP_EEPROM_EEDO)
+ 				data[i] |= (1 << (x - 1));
+ 			CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, reg);
+ 			DELAY(1);
+ 		}
+ 		CSR_WRITE_2(sc, FXP_CSR_EEPROMCONTROL, 0);
+ 		DELAY(1);
+ 	}
+ 
+ }
+ 			
+ 
+ struct pci_device fxp_device = {
+ 	"fxp",
+ 	fxp_probe,
+ 	fxp_attach,
+ 	&fxp_count,
+ 	0
+ };
+ 
+ static inline void
+ fxp_scb_wait(sc)
+ 	struct fxp_softc *sc;
+ {
+ 	int i = 10000;
+ 	while (CSR_READ_1(sc, FXP_CSR_SCB_COMMAND) && --i);
+ }
+ 
+ static volatile int
+ fxp_mdi_read(sc, phy, reg)
+ 	struct fxp_softc *sc;
+ 	int phy;
+ 	int reg;
+ {
+ 	int count = 10000;
+ 	int value;
+ 
+ 	CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
+ 	    (FXP_MDI_READ << 26) | (reg << 16) | (phy << 21));
+ 	while (((value = CSR_READ_4(sc, FXP_CSR_MDICONTROL)) & 0x10000000) == 0
+ 	    && count--)
+ 		DELAY(10);
+ 
+ 	if (count <= 0)
+ 		printf(FXP_FORMAT ": fxp_mdi_read: timed out\n",
+ 			FXP_ARGS(sc));
+ 	return (value & 0xffff);
+ }
+ 
+ 
+ static void
+ fxp_mdi_write(sc, phy, reg, value)
+         struct fxp_softc *sc;
+         int phy;
+         int reg;
+         int value;
+ {
+         int count = 10000;
+ 
+         CSR_WRITE_4(sc, FXP_CSR_MDICONTROL,
+             (FXP_MDI_WRITE << 26) | (reg << 16) | (phy << 21) |
+             (value & 0xffff));
+ 
+         while((CSR_READ_4(sc, FXP_CSR_MDICONTROL) & 0x10000000) == 0 &&
+             count--)
+                 DELAY(10);
+ 
+         if (count <= 0)
+                 printf("fxp%d: fxp_mdi_write: timed out\n",
+                     FXP_ARGS(sc));
+ }
+ 
+ 
+ /* Add rxbuf to the end of the list of receive buffers */
+ static int
+ fxp_add_rxbuf(struct fxp_softc *sc, struct fxp_rxbuf *rxbuf) {
+ 	struct fxp_rfa *rfa = &rxbuf->rfa;
+ 
+ 	rfa->rfa_status = 0;
+ 	rfa->rfa_control = FXP_RFA_CONTROL_EL;
+ 	rfa->actual_size = 0;
+ 	rfa->link_addr = -1;
+ 	rfa->rbd_addr = -1;
+ 	rfa->size = ETHER_MAX_LEN;
+ 
+ 	if (sc->rxbuf_head) {
+ 		struct fxp_rxbuf *p = sc->rxbuf_tail;
+ 		p->next = rxbuf;
+ 		p->rfa.link_addr = vtophys(rfa);
+ 		p->rfa.rfa_control &= ~FXP_RFA_CONTROL_EL;
+ 	} else {
+ 		rxbuf->next = NULL;
+ 		sc->rxbuf_head = rxbuf;
+ 	}
+ 	sc->rxbuf_tail = rxbuf;
+ }
+ 
+ 
+ static void rxbuf_init(struct fxp_softc *sc) {
+ 	int i;
+ 
+ 	sc->rxbuf_head = NULL;
+ 
+ 	for (i=0; i<FXP_NRFABUFS; i++)
+ 		fxp_add_rxbuf(sc, &sc->rxbuf[i]);
+ }
+ 			
+ 			
+ 
+ /**************************************************************************/
+ 
+ DELAY(int x)
+ { volatile long a, b, l;
+    for (x*=100; x>0; x--) b=a;
+ }  
+ 
+ 
+ /**************************************************************************
+ The following two variables are used externally
+ **************************************************************************/
+ char eth_driver[] = "ed0";
+ char packet[ETHER_MAX_LEN];
+ int  packetlen;
+ short aui = 0;
+ 
+ /**************************************************************************
+ ETH_PROBE - Look for an adapter
+ **************************************************************************/
+ eth_probe()
+ {
+ 	struct fxp_softc *sc = &card[0];
+ 	static pci_configured;
+ 
+ 	if (!pci_configured) {
+ 		printf("\n");
+ 		pci_configure();
+ 	}
+ 
+ 
+ 	if (fxp_nextcard == 0)
+ 		return 0;
+ 	
+ 	eth_reset();
+ 	bcopy(sc->enaddr, arptable[ARP_CLIENT].node, 6);
+ 
+ 	return 1;
+ }
+ 
+ /**************************************************************************
+ ETH_RESET - Reset adapter
+ **************************************************************************/
+ eth_reset()
+ {
+ 
+ 	struct fxp_softc *sc = &card[0];
+ 	struct fxp_cb_config *cbp;
+ 	struct fxp_cb_ias *cb_ias;
+ 	struct fxp_cb_tx *txp;
+ 	int i;
+ 
+ 	/* First reset the card */
+ 	CSR_WRITE_4(sc, FXP_CSR_PORT, FXP_PORT_SELECTIVE_RESET);
+ 	DELAY(10);
+ 
+ 	/*
+ 	 * Initialize base of CBL and RFA memory. Loading with zero
+ 	 * sets it up for regular linear addressing.
+ 	 */
+ 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, 0);
+ 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_BASE);
+ 
+ 	fxp_scb_wait(sc);
+ 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_BASE);
+ 
+ #if 0
+ 	/*
+ 	 * Initialize base of dump-stats buffer.
+ 	 */
+ 	fxp_scb_wait(sc);
+ 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(sc->fxp_stats));
+ 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_DUMP_ADR);
+ #endif
+ 
+ 	/*
+ 	 * We temporarily use memory that contains the TxCB list to
+ 	 * construct the config CB. The TxCB list memory is rebuilt
+ 	 * later.
+ 	 */
+ 	cbp = (struct fxp_cb_config *) sc->cbl_base;
+ 
+ 	/*
+ 	 * This bcopy is kind of disgusting, but there are a bunch of must be
+ 	 * zero and must be one bits in this structure and this is the easiest
+ 	 * way to initialize them all to proper values.
+ 	 */
+ 	bcopy(fxp_cb_config_template, (void *)&cbp->cb_status,
+ 	    sizeof(fxp_cb_config_template));
+ 
+ #define PROMISC 0
+ 
+ 	cbp->cb_status =	0;
+ 	cbp->cb_command =	FXP_CB_COMMAND_CONFIG | FXP_CB_COMMAND_EL;
+ 	cbp->link_addr =	-1;     /* (no) next command */
+         cbp->byte_count =       22;     /* (22) bytes to config */
+         cbp->rx_fifo_limit =    8;      /* rx fifo threshold (32 bytes) */
+         cbp->tx_fifo_limit =    0;      /* tx fifo threshold (0 bytes) */
+         cbp->adaptive_ifs =     0;      /* (no) adaptive interframe spacing */
+         cbp->rx_dma_bytecount = 0;      /* (no) rx DMA max */
+         cbp->tx_dma_bytecount = 0;      /* (no) tx DMA max */
+         cbp->dma_bce =          0;      /* (disable) dma max counters */
+         cbp->late_scb =         0;      /* (don't) defer SCB update */
+         cbp->tno_int =          0;      /* (disable) tx not okay interrupt */
+         cbp->ci_int =           0;      /* interrupt on CU not active */
+         cbp->save_bf =          PROMISC;    /* save bad frames */
+         cbp->disc_short_rx =    !PROMISC;   /* discard short packets */
+         cbp->underrun_retry =   1;      /* retry mode (1) on DMA underrun */
+         cbp->mediatype =        !sc->phy_10Mbps_only; /* interface mode */
+         cbp->nsai =             1;      /* (don't) disable source addr insert */
+         cbp->preamble_length =  2;      /* (7 byte) preamble */
+         cbp->loopback =         0;      /* (don't) loopback */
+         cbp->linear_priority =  0;      /* (normal CSMA/CD operation) */
+         cbp->linear_pri_mode =  0;      /* (wait after xmit only) */
+         cbp->interfrm_spacing = 6;      /* (96 bits of) interframe spacing */
+         cbp->promiscuous =      PROMISC;    /* promiscuous mode */
+         cbp->bcast_disable =    0;      /* (don't) disable broadcasts */
+         cbp->crscdt =           0;      /* (CRS only) */
+         cbp->stripping =        !PROMISC;   /* truncate rx packet to byte count */
+         cbp->padding =          1;      /* (do) pad short tx packets */
+         cbp->rcv_crc_xfer =     0;      /* (don't) xfer CRC to host */
+         cbp->force_fdx =        0;      /* (don't) force full duplex */
+         cbp->fdx_pin_en =       1;      /* (enable) FDX# pin */
+         cbp->multi_ia =         0;      /* (don't) accept multiple IAs */
+         cbp->mc_all =           0; /*sc->all_mcasts*//* accept all multicasts */
+ 
+ 	/*
+ 	 * Start the config command/DMA.
+ 	 */
+ 	fxp_scb_wait(sc);
+ 	CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL, vtophys(&cbp->cb_status));
+ 	CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
+ 	/* ...and wait for it to complete. */
+ 	while (!(cbp->cb_status & FXP_CB_STATUS_C));
+ 	
+ 	/*
+ 	 * Now initialize the station address. Temporarily use the TxCB
+          * memory area like we did above for the config CB.
+          */
+         cb_ias = (struct fxp_cb_ias *) sc->cbl_base;
+         cb_ias->cb_status = 0;
+         cb_ias->cb_command = FXP_CB_COMMAND_IAS | FXP_CB_COMMAND_EL;
+         cb_ias->link_addr = -1;
+         bcopy(sc->enaddr, (void *)cb_ias->macaddr, 6);
+ 
+ 	/*
+          * Start the IAS (Individual Address Setup) command/DMA.
+          */
+         fxp_scb_wait(sc);
+         CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
+         /* ...and wait for it to complete. */
+         while (!(cb_ias->cb_status & FXP_CB_STATUS_C));
+ 
+         /*
+          * Initialize transmit control block (TxCB) list.
+          */
+ 
+         txp = sc->cbl_base;
+         bzero(txp, sizeof(struct fxp_cb_tx) * FXP_NTXBUFS);
+         for (i = 0; i < FXP_NTXBUFS; i++) {
+                 txp[i].cb_status = FXP_CB_STATUS_C | FXP_CB_STATUS_OK;
+                 txp[i].cb_command = FXP_CB_COMMAND_NOP;
+                 txp[i].link_addr = vtophys(&txp[(i + 1) & FXP_TXCB_MASK].cb_status);
+                 txp[i].tbd_array_addr = vtophys(&txp[i].tbd);
+                 txp[i].next = &txp[(i + 1) & FXP_TXCB_MASK];
+         }
+         /*
+          * Set the suspend flag on the first TxCB and start the control
+          * unit. It will execute the NOP and then suspend.
+          */
+         txp->cb_command = FXP_CB_COMMAND_NOP | FXP_CB_COMMAND_S;
+         sc->cbl_first = sc->cbl_last = txp;
+         sc->tx_queued = 1;
+ 
+         fxp_scb_wait(sc);
+         CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_START);
+ 
+ 	rxbuf_init(sc);
+         /*
+          * Initialize receiver buffer area - RFA.
+          */
+         fxp_scb_wait(sc);
+         CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
+             vtophys(&sc->rxbuf_head->rfa));
+         CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
+ 
+         /*
+          * Set current media.
+          */
+ 	fxp_mdi_write(sc, sc->phy_primary_addr,
+ 		FXP_PHY_BMCR,
+ 		(fxp_mdi_read(sc, sc->phy_primary_addr,
+ 		FXP_PHY_BMCR) | FXP_PHY_BMCR_AUTOEN));
+ 
+ 	
+ 	return(1);
+ }
+ 
+ /**************************************************************************
+ ETH_TRANSMIT - Transmit a frame
+ **************************************************************************/
+ eth_transmit(d,t,s,p)
+ 	char *d;			/* Destination */
+ 	unsigned short t;		/* Type */
+ 	unsigned short s;		/* size */
+ 	char *p;			/* Packet */
+ {
+ 
+ 	struct fxp_softc *sc = &card[0];
+ 	struct fxp_cb_tx *txp;
+ 
+ #if FXP_DEBUG > 1
+ 	printf("eth_transmit queued = %d\n", sc->tx_queued);
+ #endif
+ 
+ 	/* Wait for a free transmit buffer */
+ 	while (sc->tx_queued > 0) {
+ 		u_int8_t statack;
+ 
+ 		for (txp = sc->cbl_first; sc->tx_queued &&
+ 		    (txp->cb_status & FXP_CB_STATUS_C) != 0;
+ 		    txp = txp->next) 
+ 			sc->tx_queued--;
+ 				
+ 		sc->cbl_first = txp;
+ 
+ 		if (sc->tx_queued < FXP_NTXBUFS)
+ 			break;
+ 	}
+ 	twiddle();
+ 
+ 	txp = sc->cbl_last->next;
+ 	txp->tbd.tb_addr = vtophys(txp->data);
+ 
+ 	bcopy(d, txp->data, ETHER_ADDR_LEN);
+ 	bcopy(sc->enaddr, txp->data+6, ETHER_ADDR_LEN);
+ 	txp->data[12] = t>>8;
+ 	txp->data[13] = t;
+ 	bcopy(p, &txp->data[14], s);
+ 
+ 	s += 14;
+ 
+ 	txp->tbd.tb_size = s;
+ 	txp->tbd_number = 1;
+ 
+ 	txp->cb_status = 0;
+ 	txp->cb_command =
+ 	    FXP_CB_COMMAND_XMIT | FXP_CB_COMMAND_SF | FXP_CB_COMMAND_S;
+ 	txp->tx_threshold = 64;
+ 
+         /*
+          * Advance the end-of-list forward.
+          */
+         sc->cbl_last->cb_command &= ~FXP_CB_COMMAND_S;
+         sc->cbl_last = txp;
+ 
+         /*
+          * Advance the beginning of the list forward if there are
+          * no other packets queued (when nothing is queued, cbl_first
+          * sits on the last TxCB that was sent out)..
+          */
+         if (sc->tx_queued == 0)
+                 sc->cbl_first = txp;
+ 
+         sc->tx_queued++;
+ 
+         fxp_scb_wait(sc);
+ 
+         /*
+          * Resume transmission if suspended.
+          */
+         CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_CU_RESUME);
+ 
+ 
+ 	return(0);
+ }
+ 
+ /**************************************************************************
+ ETH_POLL - Wait for a frame
+ **************************************************************************/
+ eth_poll()
+ {
+ 	struct fxp_softc *sc = &card[0];
+ 	u_int8_t statack;
+ 
+ 	unsigned short type = 0;
+ 	int ret = 0;
+ 	unsigned short len;
+ 
+ 	struct fxp_rxbuf *p = sc->rxbuf_head;
+ 	struct fxp_rfa *rfa = &p->rfa;
+ 
+ 	if (rfa->rfa_status & FXP_RFA_STATUS_C) {
+ #if FXP_DEBUG > 1
+ 		printf("eth_poll: got a packet\n");
+ #endif
+ 		/*
+ 		 * Remove first packet from the chain.
+ 		 */
+ 		sc->rxbuf_head = p->next;
+ 		p->next = NULL;
+ 
+ 		len =  rfa->actual_size & 0x1fff;
+ 		if (len > 14 && len < 1518) {
+ 			bcopy(p->data, packet, len);
+ 			type = (packet[12]<<8) | packet[13];
+ 			packetlen = len;
+ 			ret = 1;
+ 		}
+ #if FXP_DEBUG > 2
+ 		printf("eth_poll: type %x len %d\n", type, len);
+ 		{	
+ 			int i;
+ 			for (i=0; i< (ret==1 ? len : 100); i++)
+ 				printf("%b ",p->data[i]);
+ 			printf("\n");
+ 		}
+ #endif
+ 
+ 		/* Reattach buffer to chain */
+ 		fxp_add_rxbuf(sc, p);
+ 	}
+ 	/* Just tell the card to continue if overruns occur */
+ 	if (CSR_READ_1(sc, FXP_CSR_SCB_STATACK) & FXP_SCB_STATACK_RNR) {
+ 		fxp_scb_wait(sc);
+ 		CSR_WRITE_1(sc, FXP_CSR_SCB_COMMAND, FXP_SCB_COMMAND_RU_START);
+ 	}
+ 
+ 	if (ret && (type == ARP)) {
+ 		struct arprequest *arpreq;
+ 		unsigned long reqip;
+ 		arpreq = (struct arprequest *)&packet[ETHER_HDR_LEN];
+ 		convert_ipaddr(&reqip, arpreq->tipaddr);
+ 		if ((ntohs(arpreq->opcode) == ARP_REQUEST) &&
+ 		    (reqip == arptable[ARP_CLIENT].ipaddr)) {
+ 			arpreq->opcode = htons(ARP_REPLY);
+ 			bcopy(arpreq->sipaddr, arpreq->tipaddr, 4);
+ 			bcopy(arpreq->shwaddr, arpreq->thwaddr, 6);
+ 			bcopy(arptable[ARP_CLIENT].node, arpreq->shwaddr, 6);
+ 			convert_ipaddr(arpreq->sipaddr, &reqip);
+ 			eth_transmit(arpreq->thwaddr, ARP,
+ 			    sizeof(struct arprequest), arpreq);
+ 			return(0);
+ 		}
+ 	}
+ 	return(ret);
+ 
+ }
+ 
diff -rPc netboot.old/netboot/fxp.h netboot/fxp.h
*** netboot.old/fxp.h	Thu Jan  1 01:00:00 1970
--- netboot/fxp.h	Tue Oct  6 15:15:02 1998
***************
*** 0 ****
--- 1,362 ----
+ /*
+  * Copyright (c) 1995, David Greenman
+  * 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 unmodified, 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.
+  *
+  * 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.
+  *
+  *	$Id$
+  */
+ 
+ #define FXP_VENDORID_INTEL	0x8086
+ #define FXP_DEVICEID_i82557	0x1229
+ 
+ #define FXP_PCI_MMBA	0x10
+ #define FXP_PCI_IOBA	0x14
+ 
+ /*
+  * Control/status registers.
+  */
+ #define	FXP_CSR_SCB_RUSCUS	0	/* scb_rus/scb_cus (1 byte) */
+ #define	FXP_CSR_SCB_STATACK	1	/* scb_statack (1 byte) */
+ #define	FXP_CSR_SCB_COMMAND	2	/* scb_command (1 byte) */
+ #define	FXP_CSR_SCB_INTRCNTL	3	/* scb_intrcntl (1 byte) */
+ #define	FXP_CSR_SCB_GENERAL	4	/* scb_general (4 bytes) */
+ #define	FXP_CSR_PORT		8	/* port (4 bytes) */
+ #define	FXP_CSR_FLASHCONTROL	12	/* flash control (2 bytes) */
+ #define	FXP_CSR_EEPROMCONTROL	14	/* eeprom control (2 bytes) */
+ #define	FXP_CSR_MDICONTROL	16	/* mdi control (4 bytes) */
+ 
+ /*
+  * FOR REFERENCE ONLY, the old definition of FXP_CSR_SCB_RUSCUS:
+  *
+  *	volatile u_int8_t	:2,
+  *				scb_rus:4,
+  *				scb_cus:2;
+  */
+ 
+ #define FXP_PORT_SOFTWARE_RESET		0
+ #define FXP_PORT_SELFTEST		1
+ #define FXP_PORT_SELECTIVE_RESET	2
+ #define FXP_PORT_DUMP			3
+ 
+ #define FXP_SCB_RUS_IDLE		0
+ #define FXP_SCB_RUS_SUSPENDED		1
+ #define FXP_SCB_RUS_NORESOURCES		2
+ #define FXP_SCB_RUS_READY		4
+ #define FXP_SCB_RUS_SUSP_NORBDS		9
+ #define FXP_SCB_RUS_NORES_NORBDS	10
+ #define FXP_SCB_RUS_READY_NORBDS	12
+ 
+ #define FXP_SCB_CUS_IDLE		0
+ #define FXP_SCB_CUS_SUSPENDED		1
+ #define FXP_SCB_CUS_ACTIVE		2
+ 
+ #define FXP_SCB_STATACK_SWI		0x04
+ #define FXP_SCB_STATACK_MDI		0x08
+ #define FXP_SCB_STATACK_RNR		0x10
+ #define FXP_SCB_STATACK_CNA		0x20
+ #define FXP_SCB_STATACK_FR		0x40
+ #define FXP_SCB_STATACK_CXTNO		0x80
+ 
+ #define FXP_SCB_COMMAND_CU_NOP		0x00
+ #define FXP_SCB_COMMAND_CU_START	0x10
+ #define FXP_SCB_COMMAND_CU_RESUME	0x20
+ #define FXP_SCB_COMMAND_CU_DUMP_ADR	0x40
+ #define FXP_SCB_COMMAND_CU_DUMP		0x50
+ #define FXP_SCB_COMMAND_CU_BASE		0x60
+ #define FXP_SCB_COMMAND_CU_DUMPRESET	0x70
+ 
+ #define FXP_SCB_COMMAND_RU_NOP		0
+ #define FXP_SCB_COMMAND_RU_START	1
+ #define FXP_SCB_COMMAND_RU_RESUME	2
+ #define FXP_SCB_COMMAND_RU_ABORT	4
+ #define FXP_SCB_COMMAND_RU_LOADHDS	5
+ #define FXP_SCB_COMMAND_RU_BASE		6
+ #define FXP_SCB_COMMAND_RU_RBDRESUME	7
+ 
+ /*
+  * Command block definitions
+  */
+ struct fxp_cb_nop {
+ 	void *fill[2];
+ 	volatile u_int16_t cb_status;
+ 	volatile u_int16_t cb_command;
+ 	volatile u_int32_t link_addr;
+ };
+ struct fxp_cb_ias {
+ 	void *fill[2];
+ 	volatile u_int16_t cb_status;
+ 	volatile u_int16_t cb_command;
+ 	volatile u_int32_t link_addr;
+ 	volatile u_int8_t macaddr[6];
+ };
+ /* I hate bit-fields :-( */
+ struct fxp_cb_config {
+ 	void *fill[2];
+ 	volatile u_int16_t	cb_status;
+ 	volatile u_int16_t	cb_command;
+ 	volatile u_int32_t	link_addr;
+ 	volatile u_int8_t	byte_count:6,
+ 				:2;
+ 	volatile u_int8_t	rx_fifo_limit:4,
+ 				tx_fifo_limit:3,
+ 				:1;
+ 	volatile u_int8_t	adaptive_ifs;
+ 	volatile u_int8_t	:8;
+ 	volatile u_int8_t	rx_dma_bytecount:7,
+ 				:1;
+ 	volatile u_int8_t	tx_dma_bytecount:7,
+ 				dma_bce:1;
+ 	volatile u_int8_t	late_scb:1,
+ 				:1,
+ 				tno_int:1,
+ 				ci_int:1,
+ 				:3,
+ 				save_bf:1;
+ 	volatile u_int8_t	disc_short_rx:1,
+ 				underrun_retry:2,
+ 				:5;
+ 	volatile u_int8_t	mediatype:1,
+ 				:7;
+ 	volatile u_int8_t	:8;
+ 	volatile u_int8_t	:3,
+ 				nsai:1,
+ 				preamble_length:2,
+ 				loopback:2;
+ 	volatile u_int8_t	linear_priority:3,
+ 				:5;
+ 	volatile u_int8_t	linear_pri_mode:1,
+ 				:3,
+ 				interfrm_spacing:4;
+ 	volatile u_int8_t	:8;
+ 	volatile u_int8_t	:8;
+ 	volatile u_int8_t	promiscuous:1,
+ 				bcast_disable:1,
+ 				:5,
+ 				crscdt:1;
+ 	volatile u_int8_t	:8;
+ 	volatile u_int8_t	:8;
+ 	volatile u_int8_t	stripping:1,
+ 				padding:1,
+ 				rcv_crc_xfer:1,
+ 				:5;
+ 	volatile u_int8_t	:6,
+ 				force_fdx:1,
+ 				fdx_pin_en:1;
+ 	volatile u_int8_t	:6,
+ 				multi_ia:1,
+ 				:1;
+ 	volatile u_int8_t	:3,
+ 				mc_all:1,
+ 				:4;
+ };
+ 
+ #define MAXMCADDR 80
+ struct fxp_cb_mcs {
+ 	struct fxp_cb_tx *next;
+ 	struct mbuf *mb_head;
+ 	volatile u_int16_t cb_status;
+ 	volatile u_int16_t cb_command;
+ 	volatile u_int32_t link_addr;
+ 	volatile u_int16_t mc_cnt;
+ 	volatile u_int8_t mc_addr[MAXMCADDR][6];
+ };
+ 
+ /*
+  * Number of DMA segments in a TxCB. Note that this is carefully
+  * chosen to make the total struct size an even power of two. It's
+  * critical that no TxCB be split across a page boundry since
+  * no attempt is made to allocate physically contiguous memory.
+  * 
+  */
+ #ifdef __alpha__ /* XXX - should be conditional on pointer size */
+ #define FXP_NTXSEG      28
+ #else
+ #define FXP_NTXSEG      29
+ #endif
+ 
+ struct fxp_tbd {
+ 	volatile u_int32_t tb_addr;
+ 	volatile u_int32_t tb_size;
+ };
+ struct fxp_cb_tx {
+ 	struct fxp_cb_tx *next;
+ 	struct mbuf *mb_head;
+ 	volatile u_int16_t cb_status;
+ 	volatile u_int16_t cb_command;
+ 	volatile u_int32_t link_addr;
+ 	volatile u_int32_t tbd_array_addr;
+ 	volatile u_int16_t byte_count;
+ 	volatile u_int8_t tx_threshold;
+ 	volatile u_int8_t tbd_number;
+ 	/*
+ 	 * The following isn't actually part of the TxCB.
+ 	 */
+ 	volatile struct fxp_tbd tbd;
+ 	unsigned char data[ETHER_MAX_LEN];
+ };
+ 
+ /*
+  * Control Block (CB) definitions
+  */
+ 
+ /* status */
+ #define FXP_CB_STATUS_OK	0x2000
+ #define FXP_CB_STATUS_C		0x8000
+ /* commands */
+ #define FXP_CB_COMMAND_NOP	0x0
+ #define FXP_CB_COMMAND_IAS	0x1
+ #define FXP_CB_COMMAND_CONFIG	0x2
+ #define FXP_CB_COMMAND_MCAS	0x3
+ #define FXP_CB_COMMAND_XMIT	0x4
+ #define FXP_CB_COMMAND_RESRV	0x5
+ #define FXP_CB_COMMAND_DUMP	0x6
+ #define FXP_CB_COMMAND_DIAG	0x7
+ /* command flags */
+ #define FXP_CB_COMMAND_SF	0x0008	/* simple/flexible mode */
+ #define FXP_CB_COMMAND_I	0x2000	/* generate interrupt on completion */
+ #define FXP_CB_COMMAND_S	0x4000	/* suspend on completion */
+ #define FXP_CB_COMMAND_EL	0x8000	/* end of list */
+ 
+ /*
+  * RFA definitions
+  */
+ 
+ struct fxp_rfa {
+ 	volatile u_int16_t rfa_status;
+ 	volatile u_int16_t rfa_control;
+ 	volatile u_int32_t link_addr;
+ 	volatile u_int32_t rbd_addr;
+ 	volatile u_int16_t actual_size;
+ 	volatile u_int16_t size;
+ };
+ #define FXP_RFA_STATUS_RCOL	0x0001	/* receive collision */
+ #define FXP_RFA_STATUS_IAMATCH	0x0002	/* 0 = matches station address */
+ #define FXP_RFA_STATUS_S4	0x0010	/* receive error from PHY */
+ #define FXP_RFA_STATUS_TL	0x0020	/* type/length */
+ #define FXP_RFA_STATUS_FTS	0x0080	/* frame too short */
+ #define FXP_RFA_STATUS_OVERRUN	0x0100	/* DMA overrun */
+ #define FXP_RFA_STATUS_RNR	0x0200	/* no resources */
+ #define FXP_RFA_STATUS_ALIGN	0x0400	/* alignment error */
+ #define FXP_RFA_STATUS_CRC	0x0800	/* CRC error */
+ #define FXP_RFA_STATUS_OK	0x2000	/* packet received okay */
+ #define FXP_RFA_STATUS_C	0x8000	/* packet reception complete */
+ #define FXP_RFA_CONTROL_SF	0x08	/* simple/flexible memory mode */
+ #define FXP_RFA_CONTROL_H	0x10	/* header RFD */
+ #define FXP_RFA_CONTROL_S	0x4000	/* suspend after reception */
+ #define FXP_RFA_CONTROL_EL	0x8000	/* end of list */
+ 
+ /*
+  * Statistics dump area definitions
+  */
+ struct fxp_stats {
+ 	volatile u_int32_t tx_good;
+ 	volatile u_int32_t tx_maxcols;
+ 	volatile u_int32_t tx_latecols;
+ 	volatile u_int32_t tx_underruns;
+ 	volatile u_int32_t tx_lostcrs;
+ 	volatile u_int32_t tx_deffered;
+ 	volatile u_int32_t tx_single_collisions;
+ 	volatile u_int32_t tx_multiple_collisions;
+ 	volatile u_int32_t tx_total_collisions;
+ 	volatile u_int32_t rx_good;
+ 	volatile u_int32_t rx_crc_errors;
+ 	volatile u_int32_t rx_alignment_errors;
+ 	volatile u_int32_t rx_rnr_errors;
+ 	volatile u_int32_t rx_overrun_errors;
+ 	volatile u_int32_t rx_cdt_errors;
+ 	volatile u_int32_t rx_shortframes;
+ 	volatile u_int32_t completion_status;
+ };
+ #define FXP_STATS_DUMP_COMPLETE	0xa005
+ #define FXP_STATS_DR_COMPLETE	0xa007
+ 	
+ /*
+  * Serial EEPROM control register bits
+  */
+ /* shift clock */
+ #define FXP_EEPROM_EESK		0x01
+ /* chip select */
+ #define FXP_EEPROM_EECS		0x02
+ /* data in */
+ #define FXP_EEPROM_EEDI		0x04
+ /* data out */
+ #define FXP_EEPROM_EEDO		0x08
+ 
+ /*
+  * Serial EEPROM opcodes, including start bit
+  */
+ #define FXP_EEPROM_OPC_ERASE	0x4
+ #define FXP_EEPROM_OPC_WRITE	0x5
+ #define FXP_EEPROM_OPC_READ	0x6
+ 
+ /*
+  * Management Data Interface opcodes
+  */
+ #define FXP_MDI_WRITE		0x1
+ #define FXP_MDI_READ		0x2
+ 
+ /*
+  * PHY device types
+  */
+ #define FXP_PHY_NONE		0
+ #define FXP_PHY_82553A		1
+ #define FXP_PHY_82553C		2
+ #define FXP_PHY_82503		3
+ #define FXP_PHY_DP83840		4
+ #define FXP_PHY_80C240		5
+ #define FXP_PHY_80C24		6
+ #define FXP_PHY_82555		7
+ #define FXP_PHY_DP83840A	10
+ #define FXP_PHY_82555B		11
+ 
+ /*
+  * PHY BMCR Basic Mode Control Register
+  */
+ #define FXP_PHY_BMCR			0x0
+ #define FXP_PHY_BMCR_FULLDUPLEX		0x0100
+ #define FXP_PHY_BMCR_AUTOEN		0x1000
+ #define FXP_PHY_BMCR_SPEED_100M		0x2000
+ 
+ /*
+  * DP84830 PHY, PCS Configuration Register
+  */
+ #define FXP_DP83840_PCR			0x17
+ #define FXP_DP83840_PCR_LED4_MODE	0x0002	/* 1 = LED4 always indicates full duplex */
+ #define FXP_DP83840_PCR_F_CONNECT	0x0020	/* 1 = force link disconnect function bypass */
+ #define FXP_DP83840_PCR_BIT8		0x0100
+ #define FXP_DP83840_PCR_BIT10		0x0400
+ 
+ 
+ #define	CSR_READ_1(sc, reg)						\
+ 	(*((u_int8_t *)((sc)->csr + (reg))))
+ #define	CSR_READ_2(sc, reg)						\
+ 	(*((u_int16_t *)((sc)->csr + (reg))))
+ #define	CSR_READ_4(sc, reg)						\
+ 	(*((u_int32_t *)((sc)->csr + (reg))))
+ #define	CSR_WRITE_1(sc, reg, val)					\
+ 	(*((u_int8_t *)((sc)->csr + (reg)))) = (val)
+ #define	CSR_WRITE_2(sc, reg, val)					\
+ 	(*((u_int16_t *)((sc)->csr + (reg)))) = (val)
+ #define	CSR_WRITE_4(sc, reg, val)					\
+ 	(*((u_int32_t *)((sc)->csr + (reg)))) = (val)
diff -rPc netboot.old/makerom.c netboot/makerom.c
*** netboot.old/makerom.c	Tue Oct  6 16:49:31 1998
--- netboot/makerom.c	Tue Oct  6 16:11:45 1998
***************
*** 6,42 ****
  
  ************************************************************************/
  #include <stdio.h>
! #include <sys/fcntl.h>
  
- unsigned char rom[ROMSIZE];
  unsigned int sum;
  
  main(argc,argv)
  	int argc; char *argv[];
  {
! 	int i, fd;
! 	if (argc < 1) {
! 		fprintf(stderr,"usage: %s rom-file\n",argv[0]);
  		exit(2);
  	}
! 	if ((fd = open(argv[1], O_RDWR)) < 0) {
  		perror("unable to open file");
  		exit(2);
  	}
! 	bzero(rom, ROMSIZE);
  	if (lseek(fd, (off_t)32, SEEK_SET) < 0) {
  		perror("lseek error");
  		exit(2);
  	}
! 	if (read(fd, rom, ROMSIZE) < 0) {
  		perror("read error");
  		exit(2);
  	}
  	rom[5] = 0;
! 	for (i=0,sum=0; i<ROMSIZE; i++)
  		sum += rom[i];
  	rom[5] = -sum;
! 	for (i=0,sum=0; i<ROMSIZE; i++)
  		sum += rom[i];
  	if (sum & 0x00FF)
  		printf("checksum fails.\n");
--- 6,74 ----
  
  ************************************************************************/
  #include <stdio.h>
! #include <stdlib.h>
! #include <fcntl.h>
  
  unsigned int sum;
  
  main(argc,argv)
  	int argc; char *argv[];
  {
! 	int i, fd, romsize;
! 	unsigned pci_id;
! 	unsigned char *rom;
! 
! 	if (argc < 3) {
! 		fprintf(stderr,"usage: %s rom-size rom-file [pci_id]\n",
! 		    argv[0]);
! 		exit(2);
! 	}
! 	romsize = strtoul(argv[1], NULL, 0);
! 	if (romsize < 512 || (romsize & (romsize-1))) {
! 		printf("invalid rom size\n");
  		exit(2);
  	}
! 	if ((rom = malloc(romsize)) == NULL) {
! 		printf("malloc failed\n");
! 		exit(2);
! 	}
! 
! 	if ((fd = open(argv[2], O_RDWR)) < 0) {
  		perror("unable to open file");
  		exit(2);
  	}
! 	bzero(rom, romsize);
  	if (lseek(fd, (off_t)32, SEEK_SET) < 0) {
  		perror("lseek error");
  		exit(2);
  	}
! 	if (read(fd, rom, romsize) < 0) {
  		perror("read error");
  		exit(2);
  	}
+ 
+ 	/*
+ 	 * Overwrite the rom size field with the specified rom size. If it
+ 	 * doesn't fit in a byte just set the size to 64k (128)
+ 	 */
+ 	rom[2] = romsize > 65536 ? 128 : (romsize >> 9);
+ 	if (!memcmp(&rom[26], "PCIR", 4)) {
+ 		/* Fix the PCI length too */
+ 		*(unsigned short *)&rom[42] = romsize >> 9;
+ 
+ 		/* If a pci device is specified, write that too */
+ 		if (argc > 3) {
+ 			pci_id = strtoul(argv[3], NULL, 0);
+ 			*(unsigned *)&rom[30] = pci_id;
+ 		}
+ 	}
+ 
+ 
  	rom[5] = 0;
! 	for (i=0,sum=0; i<romsize; i++)
  		sum += rom[i];
  	rom[5] = -sum;
! 	for (i=0,sum=0; i<romsize; i++)
  		sum += rom[i];
  	if (sum & 0x00FF)
  		printf("checksum fails.\n");
***************
*** 44,50 ****
  		perror("unable to seek");
  		exit(2);
  	}
! 	if (write(fd, rom, ROMSIZE) < 0) {
  		perror("unable to write");
  		exit(2);
  	}
--- 76,82 ----
  		perror("unable to seek");
  		exit(2);
  	}
! 	if (write(fd, rom, romsize) < 0) {
  		perror("unable to write");
  		exit(2);
  	}
diff -rPc netboot.old/pci.c netboot/pci.c
*** netboot.old/pci.c	Thu Jan  1 01:00:00 1970
--- netboot/pci.c	Tue Oct  6 15:14:25 1998
***************
*** 0 ****
--- 1,1442 ----
+ /**************************************************************************
+ **
+ **  $Id$
+ **
+ **  General subroutines for the PCI bus.
+ **  pci_configure ()
+ **
+ **  FreeBSD
+ **
+ **-------------------------------------------------------------------------
+ **
+ ** Copyright (c) 1994 Wolfgang Stanglmeier.  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. The name of the author may not be used to endorse or promote products
+ **    derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ **
+ ***************************************************************************
+ */
+ 
+ #include "netboot.h"
+ 
+ /*========================================================
+ **
+ **	#includes  and  declarations
+ **
+ **========================================================
+ */
+ 
+ #include <sys/types.h>
+ 
+ #include "pcivar.h"
+ #include "pcireg.h"
+ #include "pcibus.h"
+ 
+ #include "pci.h"
+ #define PCI_MAX_IRQ	(16)
+ 
+ #define bootverbose 0
+ #define PCI_QUIET
+ 
+ void panic(char *s) {
+ 	printf("PANIC: %s\n", s);
+ 	for(;;);
+ }
+ 
+ #define pmap_mapdev(v,s) (v)
+ 	
+ /*========================================================
+ **
+ **	Structs and Functions
+ **
+ **========================================================
+ */
+ 
+ struct pcicb {
+ 	struct pcicb   *pcicb_next;
+ 	struct pcicb   *pcicb_up;
+ 	struct pcicb   *pcicb_down;
+ 	pcici_t 	pcicb_bridge;
+ 
+ 	u_char		pcicb_bus;
+ 	u_char		pcicb_subordinate;
+ 	u_int		pcicb_mfrom;
+ 	u_int		pcicb_mupto;
+ 	u_int		pcicb_mamount;
+ 	u_short		pcicb_pfrom;
+ 	u_short		pcicb_pupto;
+ 	u_short		pcicb_pamount;
+ 	u_char		pcicb_bfrom;
+ 	u_char		pcicb_bupto;
+ 
+ 	u_long		pcicb_iobase;
+ 	u_long		pcicb_iolimit;
+ 	u_long		pcicb_membase;
+ 	u_long		pcicb_memlimit;
+ 	u_long		pcicb_p_membase;
+ 	u_long		pcicb_p_memlimit;
+ };
+ 
+ struct pci_lkm {
+ 	struct pci_device *dvp;
+ 	struct pci_lkm	*next;
+ };
+ 
+ static void
+ not_supported (pcici_t tag, u_long type);
+ 
+ static void
+ pci_bus_config (void);
+ 
+ static void
+ pci_rescan (void);
+ 
+ static void pci_attach (int bus, int dev, int func, 
+ 			struct pci_device *dvp, const char *name);
+ 
+ static int
+ pci_bridge_config (void);
+ 
+ static int
+ pci_mfdev (int bus, int device);
+ 
+ static void pci_remember (int bus, int dev, int func, struct pci_device *dvp);
+ 
+ /*========================================================
+ **
+ **	Variables
+ **
+ **========================================================
+ */
+ 
+ /*
+ **      log2 of safe burst len (in words)
+ */
+ 
+ unsigned pci_max_burst_len = 3; /* 2=16Byte, 3=32Byte, 4=64Byte, ... */
+ unsigned pci_mechanism     = 0;
+ unsigned pci_maxdevice     = 0;
+ unsigned pciroots          = 0; /* XXX pcisupport.c increments this 
+ 				 * for the Orion host to PCI bridge
+ 				 * UGLY hack ... :( Will be changed :)
+ 				 */
+ 
+ 
+ #define MAX_BRIDGES 6
+ struct pcicb pci_bridge[MAX_BRIDGES];
+ 
+ unsigned pci_nextbridge = 0;
+ 
+ 
+ #define MAX_PCI 16
+ struct pci_conf pci_devconf[MAX_PCI];
+ unsigned pci_nextconf = 0;
+ 
+ struct pci_device *pci_devicelist[] = {
+ 	&fxp_device,
+ 	NULL
+ };
+ 
+ /*--------------------------------------------------------
+ **
+ **	Local variables.
+ **
+ **--------------------------------------------------------
+ */
+ 
+ static	struct pcibus	*pcibus;
+ 
+ static	int		pci_conf_count;
+ static	int		pci_info_done;
+ static	int		pcibusmax;
+ static	struct pcicb	*pcicb;
+ 
+ static	struct pci_conf *pci_dev_list;
+ static	unsigned	pci_dev_list_count;
+ static	unsigned	pci_dev_list_size;
+ 
+ static	struct pci_lkm	*pci_lkm_head;
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	The following functions are provided for the device driver
+ **	to read/write the configuration space.
+ **
+ **	pci_conf_read():
+ **		Read a long word from the pci configuration space.
+ **		Requires a tag (from pcitag) and the register
+ **		number (should be a long word alligned one).
+ **
+ **	pci_conf_write():
+ **		Writes a long word to the pci configuration space.
+ **		Requires a tag (from pcitag), the register number
+ **		(should be a long word alligned one), and a value.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ u_long
+ pci_conf_read  (pcici_t tag, u_long reg)
+ {
+     return (pcibus->pb_read (tag, reg));
+ }
+ 
+ void
+ pci_conf_write (pcici_t tag, u_long reg, u_long data)
+ {
+     pcibus->pb_write (tag, reg, data);
+ }
+ 
+ /*========================================================
+ **
+ **	Subroutines for configuration.
+ **
+ **========================================================
+ */
+ 
+ static void
+ pci_register_io (struct pcicb * cb, u_int base, u_int limit)
+ {
+ #ifdef PCI_BRIDGE_DEBUG
+ 	if (bootverbose)
+ 		printf ("register_io:  bus=%d base=%X limit=%X\n",
+ 			cb->pcicb_bus, base, limit);
+ #endif
+ 
+ 	if (!cb->pcicb_pfrom || base < cb->pcicb_pfrom)
+ 		cb->pcicb_pfrom = base;
+ 	if (limit > cb->pcicb_pupto)
+ 		cb->pcicb_pupto = limit;
+ 
+ 	/*
+ 	**	XXX should set bridge io mapping here
+ 	**	but it can be mapped in 4k blocks only,
+ 	**	leading to conflicts with isa/eisa ..
+ 	*/
+ }
+ 
+ static void
+ pci_register_memory (struct pcicb * cb, u_int base, u_int limit)
+ {
+ #ifdef PCI_BRIDGE_DEBUG
+ 	if (bootverbose)
+ 		printf ("register_mem: bus=%d base=%X limit=%X\n",
+ 			cb->pcicb_bus, base, limit);
+ #endif
+ 
+ 	if (!cb->pcicb_mfrom || base < cb->pcicb_mfrom)
+ 		cb->pcicb_mfrom = base;
+ 	if (limit > cb->pcicb_mupto)
+ 		cb->pcicb_mupto = limit;
+ 	/*
+ 	**	set the bridges mapping
+ 	**
+ 	**	XXX should handle the 1Mb granularity.
+ 	*/
+ 	if (cb->pcicb_bridge.tag) {
+ 		pci_conf_write(cb->pcicb_bridge,
+ 			PCI_PCI_BRIDGE_MEM_REG,
+ 			(cb->pcicb_memlimit & 0xffff0000) |
+ 			(cb->pcicb_membase >> 16));
+ #ifdef PCI_DEBUG
+ 		if (bootverbose)
+ 			printf ("\t[pci%d uses memory from %X to %X]\n",
+ 				cb->pcicb_bus,
+ 				(unsigned) cb->pcicb_membase,
+ 				(unsigned) cb->pcicb_memlimit);
+ #endif
+ 	}
+ }
+ 
+ /*
+ **	XXX This function is neither complete nor tested.
+ **	It's only used if the bios hasn't done it's job
+ **	of mapping the pci devices in the physical memory.
+ */
+ 
+ static u_int
+ pci_memalloc (struct pcicb * cb, u_int addr, u_int size)
+ {
+ 	u_int result = 0, limit=0, newbase=0;
+ #ifdef PCI_BRIDGE_DEBUG
+ 	if (bootverbose)
+ 		printf ("memalloc:  bus=%d addr=%X size=%X ..\n",
+ 			cb->pcicb_bus, addr, size);
+ #endif
+ 
+ 	if (!cb) goto done;
+ 
+ 	if (!cb->pcicb_membase) {
+ 		printf ("memalloc: bus%d: membase not set.\n",
+ 			cb->pcicb_bus);
+ 		goto done;
+ 	}
+ 
+ 	/*
+ 	**	get upper allocation limit
+ 	*/
+ 	limit = cb->pcicb_memlimit;
+ 	if (cb->pcicb_mfrom && cb->pcicb_mfrom <= limit)
+ 		limit  = cb->pcicb_mfrom-1;
+ 
+ 	/*
+ 	**	address fixed, and impossible to allocate ?
+ 	*/
+ 	if (addr && addr+size-1 > limit)
+ 		goto done;
+ 
+ 	/*
+ 	**	get possible address
+ 	*/
+ 
+ 	result = addr;
+ 	if (!result) result = ((limit + 1) / size - 1) * size;
+ 
+ 	/*
+ 	**	if not local available, request from parent.
+ 	*/
+ 
+ 	if (result < cb->pcicb_membase) {
+ 		newbase = pci_memalloc (cb->pcicb_up, result, size);
+ 		if (newbase) cb->pcicb_membase = result;
+ 		else result=0;
+ 	}
+ done:
+ 	if (result)
+ 		pci_register_memory (cb, result, result+size-1);
+ 
+ #ifdef PCI_BRIDGE_DEBUG
+ 	printf ("memalloc:  bus=%d addr=%X size=%X --> %X (limit=%X).\n",
+ 		cb->pcicb_bus, addr, size, result, limit);
+ #endif
+ 
+ 	return (result);
+ }
+ 
+ /*========================================================
+ **
+ **	pci_bridge_config()
+ **
+ **	Configuration of a pci bridge.
+ **
+ **========================================================
+ */
+ 
+ static int
+ pci_bridge_config (void)
+ {
+ 	pcici_t tag;
+ 	struct pcicb* parent;
+ 
+ 	tag = pcicb->pcicb_bridge;
+ 	if (tag.tag) {
+ 
+ 	    if (!pcicb->pcicb_bus) {
+ 		u_int data;
+ 		/*
+ 		**	Get the lowest available bus number.
+ 		*/
+ 		pcicb->pcicb_bus = ++pcibusmax;
+ 
+ 		/*
+ 		**	and configure the bridge
+ 		*/
+ 		data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG);
+ 		data = PCI_PRIMARY_BUS_INSERT(data, pcicb->pcicb_up->pcicb_bus);
+ 		data = PCI_SECONDARY_BUS_INSERT(data, pcicb->pcicb_bus);
+ 		data = PCI_SUBORDINATE_BUS_INSERT(data, pcicb->pcicb_bus);
+ 		pci_conf_write (tag, PCI_PCI_BRIDGE_BUS_REG, data);
+ 
+ 		/*
+ 		**	Propagate the new upper bus number limit.
+ 		*/
+ 		for (parent = pcicb->pcicb_up; parent != NULL;
+ 			parent = parent->pcicb_up)
+ 		{
+ 			if (parent->pcicb_subordinate >= pcicb->pcicb_bus)
+ 				continue;
+ 			parent->pcicb_subordinate = pcicb->pcicb_bus;
+ 			if (!parent->pcicb_bridge.tag)
+ 				continue;
+ 			data = pci_conf_read
+ 				(parent->pcicb_bridge, PCI_PCI_BRIDGE_BUS_REG);
+ 			data = PCI_SUBORDINATE_BUS_INSERT
+ 				(data, pcicb->pcicb_bus);
+ 			pci_conf_write (parent->pcicb_bridge,
+ 				PCI_PCI_BRIDGE_BUS_REG, data);
+ 		}
+ 	    }
+ 
+ 	    if (!pcicb->pcicb_membase) {
+ 		u_int size = 0x100000;
+ 		pcicb->pcicb_membase = pci_memalloc (pcicb->pcicb_up, 0, size);
+ 		if (pcicb->pcicb_membase)
+ 			pcicb->pcicb_memlimit = pcicb->pcicb_membase+size-1;
+ 	    }
+ 	}
+ 	return pcicb->pcicb_bus;
+ }
+ 
+ /*========================================================
+ **
+ **	pci_attach()
+ **
+ **	Attach one device
+ **
+ **========================================================
+ */
+ 
+ static void pci_attach (int bus, int dev, int func, 
+ 			struct pci_device *dvp, const char *name)
+ {
+ 	u_long  data;
+ 	int     unit;
+ 	u_char	reg;
+ 	u_char	pciint;
+ 	int	irq;
+ 	pcici_t	tag = pcibus->pb_tag (bus, dev, func);
+ 
+ 	/*
+ 	**	Get and increment the unit.
+ 	*/
+ 
+ 	unit = (*dvp->pd_count)++;
+ 
+ 	/*
+ 	**	Announce this device
+ 	*/
+ 
+ 	printf ("%s%d <%s> rev %d", dvp->pd_name, unit, name,
+ 		(unsigned) pci_conf_read (tag, PCI_CLASS_REG) & 0xff);
+ 
+ 	/*
+ 	**	Get the int pin number (pci interrupt number a-d)
+ 	**	from the pci configuration space.
+ 	*/
+ 
+ 	data = pci_conf_read (tag, PCI_INTERRUPT_REG);
+ 	pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
+ 
+ 	if (pciint) {
+ 
+ 		printf (" int %c irq ", 0x60+pciint);
+ 
+ 		irq = PCI_INTERRUPT_LINE_EXTRACT(data);
+ 
+ 		/*
+ 		**	If it's zero, the isa irq number is unknown,
+ 		**	and we cannot bind the pci interrupt.
+ 		*/
+ 
+ 		if (irq && (irq != 0xff))
+ 			printf ("%d", irq);
+ 		else
+ 			printf ("??");
+ 	};
+ 
+ 	printf (" on pci%d:%d:%d\n", bus, dev, func);
+ 
+ 	/*
+ 	**	Read the current mapping,
+ 	**	and update the pcicb fields.
+ 	*/
+ 
+ 	for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4) {
+ 		u_int map, addr, size;
+ 
+ 		data = pci_conf_read(tag, PCI_CLASS_REG);
+ 		switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
+ 		case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
+ 			continue;
+ 		};
+ 
+ 		map = pci_conf_read (tag, reg);
+ 		if (!(map & PCI_MAP_MEMORY_ADDRESS_MASK))
+ 			continue;
+ 
+ 		pci_conf_write (tag, reg, 0xffffffff);
+ 		data = pci_conf_read (tag, reg);
+ 		pci_conf_write (tag, reg, map);
+ 
+ 		switch (data & 7) {
+ 
+ 		default:
+ 			continue;
+ 		case 1:
+ 		case 5:
+ 			addr = map & PCI_MAP_IO_ADDRESS_MASK;
+ 			size = -(data & PCI_MAP_IO_ADDRESS_MASK);
+ 			size &= ~(addr ^ -addr);
+ 
+ 			pci_register_io (pcicb, addr, addr+size-1);
+ 			pcicb->pcicb_pamount += size;
+ 			break;
+ 
+ 		case 0:
+ 		case 2:
+ 		case 4:
+ 			size = -(data & PCI_MAP_MEMORY_ADDRESS_MASK);
+ 			addr = map & PCI_MAP_MEMORY_ADDRESS_MASK;
+ 			if (addr >= 0x100000) {
+ 				pci_register_memory (pcicb, addr, addr+size-1);
+ 				pcicb->pcicb_mamount += size;
+ 			};
+ 			break;
+ 		};
+ #ifdef PCI_DEBUG
+ 		if (bootverbose)
+ 			printf ("\tmapreg[%02x] type=%d addr=%X size=%X.\n",
+ 				reg, map&7, addr, size);
+ #endif
+ 	};
+ 
+ 	/*
+ 	**	attach device
+ 	**	may produce additional log messages,
+ 	**	i.e. when installing subdevices.
+ 	*/
+ 
+ 	(*dvp->pd_attach) (tag, unit);
+ 
+ 	/*
+ 	**	Special processing of certain classes
+ 	*/
+ 
+ 	data = pci_conf_read(tag, PCI_CLASS_REG);
+ 
+ 	switch (data & (PCI_CLASS_MASK|PCI_SUBCLASS_MASK)) {
+ 		struct pcicb *this, **link;
+ 		unsigned char primary, secondary, subordinate;
+ 		u_int command;
+ 
+ 	case PCI_CLASS_BRIDGE|PCI_SUBCLASS_BRIDGE_PCI:
+ 
+ 		/*
+ 		**	get current configuration of the bridge.
+ 		*/
+ 		data = pci_conf_read (tag, PCI_PCI_BRIDGE_BUS_REG);
+ 		primary     = PCI_PRIMARY_BUS_EXTRACT  (data);
+ 		secondary   = PCI_SECONDARY_BUS_EXTRACT(data);
+ 		subordinate = PCI_SUBORDINATE_BUS_EXTRACT(data);
+ #ifndef PCI_QUIET
+ 		if (bootverbose) {
+ 			printf ("\tbridge from pci%d to pci%d through %d.\n",
+ 				primary, secondary, subordinate);
+ 			printf ("\tmapping regs: io:%X mem:%X pmem:%X\n",
+ 				pci_conf_read (tag, PCI_PCI_BRIDGE_IO_REG),
+ 				pci_conf_read (tag, PCI_PCI_BRIDGE_MEM_REG),
+ 				pci_conf_read (tag, PCI_PCI_BRIDGE_PMEM_REG));
+ 		}
+ #endif
+ 		/*
+ 		**	check for uninitialized bridge.
+ 		*/
+ 		if (!(primary < secondary 
+ 		      && secondary <= subordinate
+ 		      && bus == primary)) {
+ 
+ 			printf ("\tINCORRECTLY or NEVER CONFIGURED.\n");
+ 			/*
+ 			**	disable this bridge
+ 			*/
+ 			pci_conf_write (tag, PCI_COMMAND_STATUS_REG, 0xffff0000);
+ 			secondary   = 0;
+ 			subordinate = 0;
+ 		};
+ 
+ 		/*
+ 		**  allocate bus descriptor for bus behind the bridge
+ 		*/
+ 		link = &pcicb->pcicb_down;
+ 		while (*link && (*link)->pcicb_bus < secondary)
+ 			link = &(*link)->pcicb_next;
+ 
+ 		this = &pci_bridge[pci_nextbridge++];
+ 		if (pci_nextbridge > MAX_BRIDGES)
+ 			panic("Too many pci bridges");
+ 
+ 		/*
+ 		**	Initialize this descriptor so far.
+ 		**	(the initialization is completed just before
+ 		**	scanning the bus behind the bridge.
+ 		*/
+ 		bzero (this, sizeof(*this));
+ 		this->pcicb_next        = *link;
+ 		this->pcicb_up		= pcicb;
+ 		this->pcicb_bridge      = tag;
+ 		this->pcicb_bus 	= secondary;
+ 		this->pcicb_subordinate = subordinate;
+ 
+ 		command = pci_conf_read(tag,PCI_COMMAND_STATUS_REG);
+ 
+ 		if (command & PCI_COMMAND_IO_ENABLE){
+ 			/*
+ 			**	Bridge was configured by the bios.
+ 			**	Read out the mapped io region.
+ 			*/
+ 			unsigned reg;
+ 
+ 			reg = pci_conf_read (tag, PCI_PCI_BRIDGE_IO_REG);
+ 			this->pcicb_iobase  = PCI_PPB_IOBASE_EXTRACT (reg);
+ 			this->pcicb_iolimit = PCI_PPB_IOLIMIT_EXTRACT(reg);
+ 
+ 			/*
+ 			**	Note the used io space.
+ 			*/
+ 			pci_register_io (pcicb, this->pcicb_iobase,
+ 					 this->pcicb_iolimit);
+ 
+ 		};
+ 
+ 		if (command & PCI_COMMAND_MEM_ENABLE) {
+ 			/*
+ 			**	Bridge was configured by the bios.
+ 			**	Read out the mapped memory regions.
+ 			*/
+ 			unsigned reg;
+ 
+ 			/*
+ 			**	non prefetchable memory
+ 			*/
+ 			reg = pci_conf_read (tag, PCI_PCI_BRIDGE_MEM_REG);
+ 			this->pcicb_membase  = PCI_PPB_MEMBASE_EXTRACT (reg);
+ 			this->pcicb_memlimit = PCI_PPB_MEMLIMIT_EXTRACT(reg);
+ 
+ 			/*
+ 			**	Register used memory space.
+ 			*/
+ 			pci_register_memory (pcicb,
+ 					     this->pcicb_membase,
+ 					     this->pcicb_memlimit);
+ 
+ 			/*
+ 			**	prefetchable memory
+ 			*/
+ 			reg = pci_conf_read (tag, PCI_PCI_BRIDGE_PMEM_REG);
+ 			this->pcicb_p_membase  = PCI_PPB_MEMBASE_EXTRACT (reg);
+ 			this->pcicb_p_memlimit = PCI_PPB_MEMLIMIT_EXTRACT(reg);
+ 
+ 			/*
+ 			**	Register used memory space.
+ 			*/
+ 			pci_register_memory (pcicb,
+ 					     this->pcicb_p_membase,
+ 					     this->pcicb_p_memlimit);
+ 		}
+ 
+ 		/*
+ 		**	Link it in chain.
+ 		*/
+ 		*link=this;
+ 
+ 		/*
+ 		**	Update mapping info of parent bus.
+ 		*/
+ 		if (!pcicb->pcicb_bfrom||secondary< pcicb->pcicb_bfrom)
+ 			pcicb->pcicb_bfrom = secondary;
+ 		if (subordinate > pcicb->pcicb_bupto)
+ 			pcicb->pcicb_bupto = subordinate;
+ 	}
+ }
+ 
+ /*========================================================
+ **
+ **	pci_bus_config()
+ **
+ **	Autoconfiguration of one pci bus.
+ **
+ **========================================================
+ */
+ 
+ static int
+ pci_mfdev (int bus, int device)
+ {
+     pcici_t tag;
+ 
+     /*
+     ** Detect a multi-function device that complies to the PCI 2.0 spec
+     */
+     tag = pcibus->pb_tag  (bus, device, 0);
+     if (pci_conf_read (tag, PCI_HEADER_MISC) & PCI_HEADER_MULTIFUNCTION)
+ 	return 1;
+     return 0;
+ }
+ 
+ static void
+ pci_bus_config (void)
+ {
+ 	int	bus_no;
+ 	u_char  device;
+ 	u_char	reg;
+ 	pcici_t tag, mtag;
+ 	pcidi_t type;
+ 
+ 	struct	pci_device *dvp;
+ 
+ 	/*
+ 	**	first initialize the bridge (bus controller chip)
+ 	*/
+ 	bus_no = pci_bridge_config ();
+ 
+ 	printf ("Probing for devices on PCI bus %d:\n", bus_no);
+ #ifndef PCI_QUIET
+ 	if (bootverbose && !pci_info_done) {
+ 		pci_info_done=1;
+ 		printf ("\tconfiguration mode %d allows %d devices.\n",
+ 			pci_mechanism, pci_maxdevice);
+ 	};
+ #endif
+ 
+ 
+ 	for (device=0; device<pci_maxdevice; device ++) {
+ 	    char *name = NULL;
+ 	    struct pci_device **dvpp;
+ 	    int func, maxfunc = 0;
+ 
+ 	    for (func=0; func <= maxfunc; func++) {
+ 		tag  = pcibus->pb_tag  (bus_no, device, func);
+ 		type = pci_conf_read (tag, PCI_ID_REG);
+ 
+ 		if ((!type) || (type==0xfffffffful)) continue;
+ 
+ 		/*
+ 		**	lookup device in ioconfiguration:
+ 		*/
+ 
+ 		dvpp = pci_devicelist;
+ 
+ 		while (dvp = *dvpp++) {
+ 			if (dvp->pd_probe) {
+ 				if (name = (*dvp->pd_probe)(tag, type)) {
+ 					/* Disable interrupt line */
+ 					int irq, picport;
+ 
+ 					irq = pci_conf_read(tag,
+ 					    PCI_INTERRUPT_REG) &
+ 					    PCI_INTERRUPT_LINE_MASK;
+ 
+ 					picport = (irq < 8) ? 0x21 : 0xa1;
+ 					printf("[Disabling IRQ %d]\n", irq);
+ 					outb(picport, inb(picport) |
+ 					    (1<<(irq & 7)));
+ 
+ 					break;
+ 				}
+ 			}
+ 		}
+ 
+ 		/*
+ 		**	check for mirrored devices.
+ 		*/
+ 		if (func != 0) {
+ 			goto real_device;
+ 		}
+ 		if (device & 0x10) {
+ 			mtag=pcibus->pb_tag (bus_no,
+ 				(u_char)(device & ~0x10), 0);
+ 		} else if (device & 0x08) {
+ 			mtag=pcibus->pb_tag (bus_no,
+ 				(u_char)(device & ~0x08), 0);
+ 		} else goto real_device;
+ 
+ 		if (type!=pci_conf_read (mtag, PCI_ID_REG))
+ 			goto real_device;
+ 
+ 		for (reg=PCI_MAP_REG_START;reg<PCI_MAP_REG_END;reg+=4)
+ 			if (pci_conf_read(tag,reg)!=pci_conf_read(mtag,reg))
+ 				goto real_device;
+ 
+ #ifndef PCI_QUIET
+ 		if (dvp==NULL) continue;
+ 		if (bootverbose)
+ 			printf ("%s? <%s> mirrored on pci%d:%d\n",
+ 				dvp->pd_name, name, bus_no, device);
+ #endif
+ 		continue;
+ 
+ 	real_device:
+ 
+ #ifndef PCI_QUIET
+ #ifdef PCI_BRIDGE_DEBUG
+ 		if (bootverbose) {
+ 		    printf ("\tconfig header: 0x%X 0x%X 0x%X 0x%X\n",
+ 			    pci_conf_read (tag, 0),
+ 			    pci_conf_read (tag, 4),
+ 			    pci_conf_read (tag, 8),
+ 			    pci_conf_read (tag, 12));
+ 		}
+ #endif
+ #endif
+ 
+ 		if (func == 0 && pci_mfdev (bus_no, device)) {
+ 			maxfunc = 7;
+ 		}
+ 
+ 		pci_remember(bus_no, device, func, dvp);
+ 
+ 		if (dvp==NULL) {
+ #ifndef PCI_QUIET
+ 			if (pci_conf_count)
+ 				continue;
+ 
+ 			if (maxfunc == 0)
+ 				printf("%s%d:%d:    ", 
+ 				       pcibus->pb_name, bus_no, device);
+ 			else
+ 				printf("%s%d:%d:%d: ", 
+ 				       pcibus->pb_name, bus_no, device, func);
+ 			not_supported (tag, type);
+ #endif
+ 			continue;
+ 		};
+ 
+ 		if (*name) {
+ 			pci_attach (bus_no, device, func, dvp, name);
+ 		}
+ 	    }
+ 	}
+ 
+ #ifndef PCI_QUIET
+ 	if (bootverbose) {
+ 	    if (pcicb->pcicb_mamount)
+ 		printf ("%s%d: uses %u bytes of memory from %X upto %X.\n",
+ 			pcibus->pb_name, bus_no,
+ 			pcicb->pcicb_mamount,
+ 			pcicb->pcicb_mfrom, pcicb->pcicb_mupto);
+ 	    if (pcicb->pcicb_pamount)
+ 		printf ("%s%d: uses %u bytes of I/O space from %X upto %X.\n",
+ 			pcibus->pb_name, bus_no,
+ 			pcicb->pcicb_pamount,
+ 			pcicb->pcicb_pfrom, pcicb->pcicb_pupto);
+ 	    if (pcicb->pcicb_bfrom)
+ 		printf ("%s%d: subordinate busses from %X upto %X.\n",
+ 			pcibus->pb_name, bus_no,
+ 			pcicb->pcicb_bfrom, pcicb->pcicb_bupto);
+ 	}
+ #endif
+ }
+ 
+ /*========================================================
+ **
+ **	pci_configure ()
+ **
+ **      Autoconfiguration of pci devices.
+ **
+ **      Has to take care of mirrored devices, which are
+ **      entailed by incomplete decoding of pci address lines.
+ **
+ **========================================================
+ */
+ 
+ void pci_configure()
+ {
+ 
+ 	/*
+ 	**	check pci bus present
+ 	*/
+ 
+ 	pcibus = &i386pci;
+ 
+ 	(*pcibus->pb_setup)();
+ 
+ 	if (!pci_maxdevice) return;
+ 
+ 	/*
+ 	**	hello world ..
+ 	*/
+ 
+ 	pciroots = 1;
+ 	while (pciroots--) {
+ 
+ 		pcicb = &pci_bridge[pci_nextbridge++];
+ 		if (pci_nextbridge > MAX_BRIDGES) {
+ 			printf("Too many pci bridges");
+ 			return;
+ 		}
+ 		bzero (pcicb, sizeof (struct pcicb));
+ 		pcicb->pcicb_bus	= pcibusmax;
+ 		pcicb->pcicb_iolimit	= 0xffff;
+ 		pcicb->pcicb_membase	= 0x02000000;
+ 		pcicb->pcicb_p_membase	= 0x02000000;
+ 		pcicb->pcicb_memlimit	= 0xffffffff;
+ 		pcicb->pcicb_p_memlimit	= 0xffffffff;
+ 
+ 		while (pcicb != NULL) {
+ 			pci_bus_config ();
+ 
+ 			if (pcibusmax < pcicb->pcicb_bus)
+ 				(pcibusmax = pcicb->pcicb_bus);
+ 
+ 			if (pcicb->pcicb_down) {
+ 				pcicb = pcicb->pcicb_down;
+ 				continue;
+ 			};
+ 
+ 			while (pcicb && !pcicb->pcicb_next)
+ 				pcicb = pcicb->pcicb_up;
+ 
+ 			if (pcicb)
+ 				pcicb = pcicb->pcicb_next;
+ 		}
+ 		pcibusmax++;
+ 	}
+ 	pci_conf_count++;
+ }
+ 
+ /*-----------------------------------------------------------------------
+ **
+ **	Map device into port space.
+ **
+ **	Actually the device should have been mapped by the bios.
+ **	This function only reads and verifies the value.
+ **
+ **	PCI-Specification:  6.2.5.1: address maps
+ **
+ **-----------------------------------------------------------------------
+ */
+ 
+ int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
+ {
+ 	unsigned data, ioaddr, iosize;
+ 	struct pcicb *link = pcicb;
+ 
+ 	/*
+ 	**	sanity check
+ 	*/
+ 
+ 	if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
+ 		printf ("pci_map_port failed: bad register=0x%X\n",
+ 			(unsigned)reg);
+ 		return (0);
+ 	};
+ 
+ 	/*
+ 	**	get size and type of port
+ 	**
+ 	**	type is in the lowest two bits.
+ 	**	If device requires 2^n bytes, the next
+ 	**	n-2 bits are hardwired as 0.
+ 	*/
+ 
+ 	ioaddr = pci_conf_read (tag, reg) & PCI_MAP_IO_ADDRESS_MASK;
+ 	if (!ioaddr) {
+ 		printf ("pci_map_port failed: not configured by bios.\n");
+ 		return (0);
+ 	};
+ 
+ 	pci_conf_write (tag, reg, 0xfffffffful);
+ 	data = pci_conf_read (tag, reg);
+ 	pci_conf_write (tag, reg, ioaddr);
+ 
+ 	if ((data & 0x03) != PCI_MAP_IO) {
+ 		printf ("pci_map_port failed: bad port type=0x%X\n",
+ 			(unsigned) data);
+ 		return (0);
+ 	};
+ 	iosize = -(data &  PCI_MAP_IO_ADDRESS_MASK);
+ 	iosize &= ~(ioaddr ^ -ioaddr);
+ 	if (ioaddr < pcicb->pcicb_iobase
+ 		|| ioaddr + iosize -1 > pcicb->pcicb_iolimit) {
+ 		printf ("pci_map_port failed: device's iorange 0x%X-0x%X "
+ 			"is incompatible with its bridge's range 0x%x-0x%x\n",
+ 			(unsigned) ioaddr, (unsigned) ioaddr + iosize - 1,
+ 			(unsigned) pcicb->pcicb_iobase,
+ 			(unsigned) pcicb->pcicb_iolimit);
+ 		return (0);
+ 	}
+ 
+ #ifndef PCI_QUIET
+ 	if (bootverbose)
+ 		printf ("\treg%d: ioaddr=0x%X size=0x%X\n",
+ 			(unsigned) reg, (unsigned) ioaddr, (unsigned) iosize);
+ #endif
+ 	/*
+ 	**	set the configuration register of and
+ 	**      return the address to the driver.
+ 	**	Make sure to enable each upstream bridge
+ 	**	so I/O and DMA can go all the way.
+ 	*/
+ 
+ 	for (;;) {
+ 		data =	pci_conf_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff;
+ 		data |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ 		(void)	pci_conf_write(tag, PCI_COMMAND_STATUS_REG, data);
+ 		if ((link = link->pcicb_up) == NULL)
+ 			break;
+ 		tag = link->pcicb_bridge;
+ 	}
+ 
+ 	*pa = ioaddr;
+ 
+ 	return (1);
+ }
+ 
+ /*-----------------------------------------------------------------------
+ **
+ **	Map device into virtual and physical space
+ **
+ **	Actually the device should have been mapped by the bios.
+ **	This function only reads and verifies the value.
+ **
+ **      PCI-Specification:  6.2.5.1: address maps
+ **
+ **-----------------------------------------------------------------------
+ */
+ 
+ int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
+ {
+ 	struct pcicb *link = pcicb;
+ 	unsigned    data ,paddr;
+ 	vm_size_t   psize, poffs, pend;
+ 	vm_offset_t vaddr;
+ 
+ 	/*
+ 	**	sanity check
+ 	*/
+ 
+ 	if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
+ 		printf ("pci_map_mem failed: bad register=0x%X\n",
+ 			(unsigned)reg);
+ 		return (0);
+ 	};
+ 
+ 	/*
+ 	**	save old mapping, get size and type of memory
+ 	**
+ 	**	type is in the lowest four bits.
+ 	**	If device requires 2^n bytes, the next
+ 	**	n-4 bits are read as 0.
+ 	*/
+ 
+ 	paddr = pci_conf_read (tag, reg) & PCI_MAP_MEMORY_ADDRESS_MASK;
+ 	pci_conf_write (tag, reg, 0xfffffffful);
+ 	data = pci_conf_read (tag, reg);
+ 	pci_conf_write (tag, reg, paddr);
+ 
+ 	/*
+ 	**	check the type
+ 	*/
+ 
+ 	if (!((data & PCI_MAP_MEMORY_TYPE_MASK) == PCI_MAP_MEMORY_TYPE_32BIT_1M
+ 	      && (paddr & ~0xfffff) == 0)
+ 	    && (data & PCI_MAP_MEMORY_TYPE_MASK) != PCI_MAP_MEMORY_TYPE_32BIT){
+ 		printf ("pci_map_mem failed: bad memory type=0x%X\n",
+ 			(unsigned) data);
+ 		return (0);
+ 	};
+ 
+ 	/*
+ 	**	get the size.
+ 	*/
+ 
+ 	psize = -(data & PCI_MAP_MEMORY_ADDRESS_MASK);
+ 	pend = paddr + psize -1;
+ 
+ 	if (!paddr || paddr == PCI_MAP_MEMORY_ADDRESS_MASK) {
+ 		paddr = pci_memalloc (pcicb, 0, psize);
+ 		if (!paddr) {
+ 			printf ("pci_map_mem: not configured by bios.\n");
+ 			return (0);
+ 		};
+ 		pci_register_memory (pcicb, paddr, pend);
+ 	};
+ 
+ 	if (!((pcicb->pcicb_membase <= paddr &&
+ 	       pend <= pcicb->pcicb_memlimit) || 
+ 	      (pcicb->pcicb_p_membase <= paddr &&
+ 	       pend <= pcicb->pcicb_p_memlimit))) {
+ 		printf ("pci_map_mem: device's memrange 0x%X-0x%X is "
+ 			"incompatible with its bridge's\n"
+ 			"\tmemrange 0x%x-0x%x and prefetchable memrange 0x%x-0x%x\n",
+ 			(unsigned) paddr,
+ 			(unsigned) (paddr + psize - 1),
+ 			(unsigned) pcicb->pcicb_p_membase,
+ 			(unsigned) pcicb->pcicb_p_memlimit,
+ 			(unsigned) pcicb->pcicb_membase,
+ 			(unsigned) pcicb->pcicb_memlimit);
+ 	}
+ 	pci_conf_write (tag, reg, paddr);
+ 
+ 	/*
+ 	**	Truncate paddr to page boundary.
+ 	**	(Or does pmap_mapdev the job?)
+ 	*/
+ 
+ 	poffs = paddr - trunc_page (paddr);
+ 	vaddr = (vm_offset_t) pmap_mapdev (paddr-poffs, psize+poffs);
+ 
+ 	if (!vaddr) return (0);
+ 
+ 	vaddr += poffs;
+ 
+ #ifndef PCI_QUIET
+ 	/*
+ 	**	display values.
+ 	*/
+ 
+ 	if (bootverbose)
+ 		printf ("\treg%d: virtual=0x%X physical=0x%X size=0x%X\n",
+ 		 (unsigned) reg, (u_long)vaddr, (u_long)paddr, (u_long)psize);
+ #endif
+ 	/*
+ 	**      set the configuration register and
+ 	**      return the address to the driver
+ 	**      Make sure to enable each upstream bridge
+ 	**      so memory and DMA can go all the way.
+ 	*/
+ 
+ 	for (;;) {
+ 		data =  pci_conf_read (tag, PCI_COMMAND_STATUS_REG) & 0xffff;
+ 		data |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ 		(void)  pci_conf_write(tag, PCI_COMMAND_STATUS_REG, data);
+ 		if ((link = link->pcicb_up) == NULL)
+ 			break;
+ 		tag = link->pcicb_bridge;
+ 	}
+ 
+ 	*va = vaddr;
+ 	*pa = paddr;
+ 
+ 	return (1);
+ }
+ 
+ /*-----------------------------------------------------------------------
+ **
+ **	Pci meta interrupt handler
+ **
+ **	This handler assumes level triggered interrupts.
+ **	It's possible to build a kernel which handles shared
+ **	edge triggered interrupts by the options "PCI_EDGE_INT".
+ **	But there is a performance penalty.
+ **
+ **	(Of course you can delete the #ifdef PCI_EDGE_INT bracketed
+ **	code at all :-) :-) :-)
+ **
+ **-----------------------------------------------------------------------
+ */
+ 
+ static struct pci_int_desc*
+ 	pci_int_desc [PCI_MAX_IRQ];
+ 
+ #ifndef PCI_QUIET
+ /*-----------------------------------------------------------
+ **
+ **	Display of unknown devices.
+ **
+ **-----------------------------------------------------------
+ */
+ struct vt {
+ 	u_short	    ident;
+ 	const char *name;
+ };
+ 
+ static struct vt VendorTable[] = {
+ 	{0x0e11, "Compaq"},
+ 	{0x1000, "NCR/Symbios"},
+ 	{0x1002, "ATI Technologies Inc."},
+ 	{0x1004, "VLSI"},
+ 	{0x100B, "National Semiconductor"},
+ 	{0x100E, "Weitek"},
+ 	{0x1011, "Digital Equipment Corporation"},
+ 	{0x1013, "Cirrus Logic"},
+ 	{0x101A, "NCR"},
+ 	{0x1022, "AMD"},
+ 	{0x102B, "Matrox"},
+ 	{0x102C, "Chips & Technologies"},
+ 	{0x1039, "Silicon Integrated Systems"},
+ 	{0x1042, "SMC"},
+ 	{0x1044, "DPT"},
+ 	{0x1045, "OPTI"},
+ 	{0x104B, "Bus Logic"},
+ 	{0x104C, "TI"},
+ 	{0x1060, "UMC"},
+ 	{0x1080, "Contaq"},
+ 	{0x1095, "CMD"},
+ 	{0x10b9, "ACER Labs"},
+ 	{0x10c8, "NeoMagic"},
+ 	{0x1106, "VIA Technologies"},
+ 	{0x5333, "S3 Inc."},
+ 	{0x8086, "Intel Corporation"},
+ 	{0x9004, "Adaptec"},
+ 	{0,0}
+ };
+ 
+ typedef struct {
+ 	const int	subclass;
+ 	const char	*name;
+ } subclass_name;
+ 
+ /* 0x00 prehistoric subclasses */
+ static const subclass_name old_subclasses[] =
+ {
+ 	{ 0x00, "misc"	},
+ 	{ 0x01, "vga"	},
+ 	{ 0x00, NULL	}
+ };
+ 
+ /* 0x01 mass storage subclasses */
+ static const subclass_name storage_subclasses[] =
+ {
+ 	{ 0x00, "scsi"	},
+ 	{ 0x01, "ide"	},
+ 	{ 0x02, "floppy"},
+ 	{ 0x03, "ipi"	},
+ 	{ 0x80, "misc"	},
+ 	{ 0x00, NULL	}
+ };
+ 
+ /* 0x02 network subclasses */
+ static const subclass_name network_subclasses[] =
+ {
+ 	{ 0x00, "ethernet"	},
+ 	{ 0x01, "tokenring"	},
+ 	{ 0x02, "fddi"	},
+ 	{ 0x80, "misc"	},
+ 	{ 0x00, NULL	}
+ };
+ 
+ /* 0x03 display subclasses */
+ static const subclass_name display_subclasses[] =
+ {
+ 	{ 0x00, "vga"	},
+ 	{ 0x01, "xga"	},
+ 	{ 0x80, "misc"	},
+ 	{ 0x00, NULL	}
+ };
+ 
+ /* 0x04 multimedia subclasses */
+ static const subclass_name multimedia_subclasses[] =
+ {
+ 	{ 0x00, "video"	},
+ 	{ 0x01, "audio"	},
+ 	{ 0x80, "misc"	},
+ 	{ 0x00, NULL	}
+ };
+ 
+ /* 0x05 memory subclasses */
+ static const subclass_name memory_subclasses[] =
+ {
+ 	{ 0x00, "ram"	},
+ 	{ 0x01, "flash"	},
+ 	{ 0x80, "misc"	},
+ 	{ 0x00, NULL	}
+ };
+ 
+ /* 0x06 bridge subclasses */
+ static const subclass_name bridge_subclasses[] =
+ {
+ 	{ 0x00, "host"	},
+ 	{ 0x01, "isa"	},
+ 	{ 0x02, "eisa"	},
+ 	{ 0x03, "mc"	},
+ 	{ 0x04, "pci"	},
+ 	{ 0x05, "pcmcia"},
+ 	{ 0x07, "cardbus"},
+ 	{ 0x80, "misc"	},
+ 	{ 0x00, NULL	}
+ };
+ 
+ static const subclass_name *const subclasses[] = {
+ 	old_subclasses, 
+ 	storage_subclasses, 
+ 	network_subclasses, 
+ 	display_subclasses,
+ 	multimedia_subclasses,
+ 	memory_subclasses, 
+ 	bridge_subclasses,
+ };
+ 
+ static const char *const majclasses[] = {
+ 	"old", 
+ 	"storage", 
+ 	"network", 
+ 	"display",
+ 	"multimedia", 
+ 	"memory", 
+ 	"bridge",
+ 	"comms",
+ 	"system",
+ 	"input",
+ 	"docking",
+ 	"processor",
+ 	"serial"
+ };
+ 
+ void not_supported (pcici_t tag, u_long type)
+ {
+ 	u_long	reg;
+ 	u_long	data;
+ 	u_char	class;
+ 	u_char	subclass;
+ 	struct vt * vp;
+ 	int	pciint;
+ 	int	irq;
+ 
+ 	/*
+ 	**	lookup the names.
+ 	*/
+ 
+ 	for (vp=VendorTable; vp->ident; vp++)
+ 		if (vp->ident == (type & 0xffff))
+ 			break;
+ 
+ 	/*
+ 	**	and display them.
+ 	*/
+ 
+ 	if (vp->ident) printf (vp->name);
+ 		else   printf ("vendor=0x%X", type & 0xffff);
+ 
+ 	printf (", device=0x%X", type >> 16);
+ 
+ 	data = pci_conf_read(tag, PCI_CLASS_REG);
+ 	class = (data >> 24) & 0xff;
+ 	subclass = (data >> 16) & 0xff;
+ 
+ 	if (class < sizeof(majclasses) / sizeof(majclasses[0])) {
+ 		printf(", class=%s", majclasses[class]);
+ 	} else {
+ 		printf(", class=0x%X", class);
+ 	}
+ 
+ 	if (class < sizeof(subclasses) / sizeof(subclasses[0])) {
+ 		const subclass_name *p = subclasses[class];
+ 		while (p->name && (p->subclass != subclass)) 
+ 			p++;
+ 		if (p->name) {
+ 			printf(" (%s)", p->name);
+ 		} else {
+ 			printf(" (unknown subclass 0x%X)", subclass);
+ 		}
+ 	} else {
+ 		printf(", subclass=0x%X", subclass);
+ 	}
+ 
+ 	data = pci_conf_read (tag, PCI_INTERRUPT_REG);
+ 	pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
+ 
+ 	if (pciint) {
+ 
+ 		printf (" int %c irq ", 0x60+pciint);
+ 
+ 		irq = PCI_INTERRUPT_LINE_EXTRACT(data);
+ 
+ 		/*
+ 		**	If it's zero, the isa irq number is unknown,
+ 		**	and we cannot bind the pci interrupt.
+ 		*/
+ 
+ 		if (irq && (irq != 0xff))
+ 			printf ("%d", irq);
+ 		else
+ 			printf ("??");
+ 	};
+ 
+ 	if (class != (PCI_CLASS_BRIDGE >> 24))
+ 	    printf (" [no driver assigned]");
+ 	printf ("\n");
+ 
+ 	if (bootverbose) {
+ 	    if (class == (PCI_CLASS_BRIDGE >> 24)) {
+ 		printf ("configuration space registers:");
+ 		for (reg = 0; reg < 0x100; reg+=4) {
+ 		    if ((reg & 0x0f) == 0) printf ("\n%X:\t", reg);
+ 		    printf ("%X ", pci_conf_read (tag, reg));
+ 		}
+ 		printf ("\n");
+ 	    } else {
+ 		for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
+ 		    data = pci_conf_read (tag, reg);
+ 		    if ((data&~7)==0) continue;
+ 		    switch (data&7) {
+ 
+ 		case 1:
+ 		case 5:
+ 			printf ("\tmap(%X): io(%X)\n",
+ 				reg, data & ~3);
+ 			break;
+ 		case 0:
+ 			printf ("\tmap(%X): mem32(%X)\n",
+ 				reg, data & ~7);
+ 			break;
+ 		case 2:
+ 			printf ("\tmap(%X): mem20(%X)\n",
+ 				reg, data & ~7);
+ 			break;
+ 		case 4:
+ 			printf ("\tmap(%X): mem64(%X%X)\n",
+ 				reg, pci_conf_read (tag, reg +4), data & ~7);
+ 			reg += 4;
+ 			break;
+ 		    }
+ 		}
+ 	    }
+ 	}
+ }
+ 
+ #endif
+ /*
+  * This is the user interface to the PCI configuration space.
+  */
+ 
+ 
+ static void
+ pci_remember(int bus, int dev, int func, struct pci_device *dvp)
+ {
+ 	struct pci_conf *p;
+ 	pcici_t tag;
+ 
+ 	if (++pci_dev_list_count > pci_dev_list_size) {
+ 		struct pci_conf *new;
+ 
+ 		if (pci_dev_list)
+ 			panic("Too many PCI devices");
+ 		new = pci_devconf;
+ 		pci_dev_list_size = MAX_PCI;
+ 		pci_dev_list = new;
+ 	}
+ 
+ 	p = &pci_dev_list[pci_dev_list_count - 1];
+ 	p->pc_sel.pc_bus  = bus;
+ 	p->pc_sel.pc_dev  = dev;
+ 	p->pc_sel.pc_func = func;
+ 	p->pc_dvp         = dvp;
+ 	p->pc_cb          = pcicb;
+ 
+ 	tag = pcibus->pb_tag  (bus, dev, func);
+ 	p->pc_hdr   = (pci_conf_read (tag, PCI_HEADER_MISC) >> 16) & 0xff;
+ 	p->pc_devid = pci_conf_read(tag, PCI_ID_REG);
+ 	p->pc_class = pci_conf_read(tag, PCI_CLASS_REG);
+ 	switch (p->pc_hdr & 0x7f) {
+ 	case 0:
+ 		p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG0);
+ 		break;
+ 	case 1:
+ 		p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG1);
+ 		break;
+ 	case 2:
+ 		p->pc_subid = pci_conf_read(tag, PCI_SUBID_REG2);
+ 		break;
+ 	default:
+ 		p->pc_subid = 0;
+ 	}
+ }
diff -rPc netboot.old/pci.h netboot/pci.h
*** netboot.old/pci.h	Thu Jan  1 01:00:00 1970
--- netboot/pci.h	Mon Aug 17 20:43:05 1998
***************
*** 0 ****
--- 1,25 ----
+ 
+ extern unsigned pci_maxdevice;
+ extern unsigned pci_mechanism;
+ 
+ extern struct pcibus i386pci;
+ extern struct pci_device fxp_device;
+ 
+ 
+ struct pcisel {
+ 	u_char              pc_bus;         /* bus number */
+ 	u_char              pc_dev;         /* device on this bus */
+ 	u_char              pc_func;        /* function on this device */
+ };
+ 
+ 
+ struct  pci_conf {
+     struct pcisel       pc_sel;         /* bus+slot+function */
+     u_char              pc_hdr;         /* PCI header type */
+     pcidi_t             pc_devid;       /* device ID */
+     pcidi_t             pc_subid;       /* subvendor ID */
+     u_int32_t           pc_class;       /* device class */
+     struct pci_device   *pc_dvp;        /* device driver pointer or NULL */
+     struct pcicb        *pc_cb;         /* pointer to bus parameters */
+ };
+ 
diff -rPc netboot.old/pcibus.c netboot/pcibus.c
*** netboot.old/pcibus.c	Thu Jan  1 01:00:00 1970
--- netboot/pcibus.c	Tue Oct  6 15:14:40 1998
***************
*** 0 ****
--- 1,436 ----
+ /**************************************************************************
+ **
+ **  $Id$
+ **
+ **  pci bus subroutines for i386 architecture.
+ **
+ **  FreeBSD
+ **
+ **-------------------------------------------------------------------------
+ **
+ ** Copyright (c) 1994 Wolfgang Stanglmeier.  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. The name of the author may not be used to endorse or promote products
+ **    derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ **
+ ***************************************************************************
+ */
+ 
+ #include "netboot.h"
+ #include<sys/types.h>
+ 
+ #include "pcivar.h"
+ #include "pcibus.h"
+ #include "pci.h"
+ 
+ 
+ /* #include "vector.h" */
+ 
+ /* #include <sys/param.h> */
+ /* #include <sys/systm.h> */
+ /* #include <sys/kernel.h> */
+ 
+ /* #include <i386/isa/icu.h> */
+ /* #include <i386/isa/isa_device.h> */
+ 
+ /* #include <pci/pcivar.h> */
+ /* #include <pci/pcireg.h> */
+ /* #include <pci/pcibus.h> */
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	The following functions are provided by the pci bios.
+ **	They are used only by the pci configuration.
+ **
+ **	pcibus_setup():
+ **		Probes for a pci system.
+ **		Sets pci_maxdevice and pci_mechanism.
+ **
+ **	pcibus_tag():
+ **		Creates a handle for pci configuration space access.
+ **		This handle is given to the read/write functions.
+ **
+ **	pcibus_ftag():
+ **		Creates a modified handle.
+ **
+ **	pcibus_read():
+ **		Read a long word from the pci configuration space.
+ **		Requires a tag (from pcitag) and the register
+ **		number (should be a long word alligned one).
+ **
+ **	pcibus_write():
+ **		Writes a long word to the pci configuration space.
+ **		Requires a tag (from pcitag), the register number
+ **		(should be a long word alligned one), and a value.
+ **
+ **	pcibus_regirq():
+ **		Register an interupt handler for a pci device.
+ **		Requires a tag (from pcitag), the register number
+ **		(should be a long word alligned one), and a value.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ 
+ static int
+ pcibus_check (void);
+ 
+ static void
+ pcibus_setup (void);
+ 
+ static pcici_t
+ pcibus_tag (u_char bus, u_char device, u_char func);
+ 
+ static pcici_t
+ pcibus_ftag (pcici_t tag, u_char func);
+ 
+ static u_long
+ pcibus_read (pcici_t tag, u_long reg);
+ 
+ static void
+ pcibus_write (pcici_t tag, u_long reg, u_long data);
+ 
+ struct pcibus i386pci = {
+ 	"pci",
+ 	pcibus_setup,
+ 	pcibus_tag,
+ 	pcibus_ftag,
+ 	pcibus_read,
+ 	pcibus_write,
+ };
+ 
+ 
+ 
+ /*
+ **	Announce structure to generic driver
+ */
+ 
+ /* DATA_SET (pcibus_set, i386pci); */
+ 
+ /*--------------------------------------------------------------------
+ **
+ **      Determine configuration mode
+ **
+ **--------------------------------------------------------------------
+ */
+ 
+ 
+ #define CONF1_ADDR_PORT    0x0cf8
+ #define CONF1_DATA_PORT    0x0cfc
+ 
+ #define CONF1_ENABLE       0x80000000ul
+ #define CONF1_ENABLE_CHK   0x80000000ul
+ #define CONF1_ENABLE_MSK   0x7ff00000ul
+ #define CONF1_ENABLE_CHK1  0xff000001ul
+ #define CONF1_ENABLE_MSK1  0x80000001ul
+ #define CONF1_ENABLE_RES1  0x80000000ul
+ 
+ #define CONF2_ENABLE_PORT  0x0cf8
+ #ifdef PC98
+ #define CONF2_FORWARD_PORT 0x0cf9
+ #else
+ #define CONF2_FORWARD_PORT 0x0cfa
+ #endif
+ 
+ #define CONF2_ENABLE_CHK   0x0e
+ #define CONF2_ENABLE_RES   0x0e
+ 
+ #define bootverbose 0
+ 
+ static int
+ pcibus_check (void)
+ {
+ 	u_char device;
+ 
+ #ifdef PCI_DEBUG
+ 	if (bootverbose) printf ("pcibus_check:\tdevice ");
+ #endif
+ 
+ 	for (device = 0; device < pci_maxdevice; device++) {
+ 		unsigned long id;
+ #ifdef PCI_DEBUG
+ 		if (bootverbose) 
+ 			printf ("%d ", device);
+ #endif
+ 		id = pcibus_read (pcibus_tag (0,device,0), 0);
+ 		if (id && id != 0xfffffffful) {
+ #ifdef PCI_DEBUG
+ 			if (bootverbose) printf ("is there (id=%X)\n", id);
+ #endif
+ 			return 1;
+ 		}
+ 	}
+ #ifdef PCI_DEBUG
+ 	if (bootverbose) 
+ 		printf ("-- nothing found\n");
+ #endif
+ 	return 0;
+ }
+ 
+ static void
+ pcibus_setup (void)
+ {
+ 	unsigned long mode1res,oldval1;
+ 	unsigned char mode2res,oldval2;
+ 
+ 	oldval1 = inl (CONF1_ADDR_PORT);
+ 
+ #ifdef PCI_DEBUG
+ 	if (bootverbose) {
+ 		printf ("pcibus_setup(1):\tmode 1 addr port (0x0cf8) is 0x%X\n", oldval1);
+ 	}
+ #endif
+ 
+ 	/*---------------------------------------
+ 	**      Assume configuration mechanism 1 for now ...
+ 	**---------------------------------------
+ 	*/
+ 
+ 	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
+ 
+ 		pci_mechanism = 1;
+ 		pci_maxdevice = 32;
+ 
+ 		outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
+ 		outb (CONF1_ADDR_PORT +3, 0);
+ 		mode1res = inl (CONF1_ADDR_PORT);
+ 		outl (CONF1_ADDR_PORT, oldval1);
+ 
+ #ifdef PCI_DEBUG
+ 		if (bootverbose)
+ 		    printf ("pcibus_setup(1a):\tmode1res=0x%X (0x%X)\n", 
+ 			    mode1res, CONF1_ENABLE_CHK);
+ #endif
+ 
+ 		if (mode1res) {
+ 			if (pcibus_check()) 
+ 				return;
+ 		};
+ 
+ 		outl (CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
+ 		mode1res = inl(CONF1_ADDR_PORT);
+ 		outl (CONF1_ADDR_PORT, oldval1);
+ 
+ #ifdef PCI_DEBUG
+ 		if (bootverbose)
+ 		    printf ("pcibus_setup(1b):\tmode1res=0x%X (0x%X)\n", 
+ 			    mode1res, CONF1_ENABLE_CHK1);
+ #endif
+ 
+ 		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
+ 			if (pcibus_check()) 
+ 				return;
+ 		};
+ 	}
+ 
+ 	/*---------------------------------------
+ 	**      Try configuration mechanism 2 ...
+ 	**---------------------------------------
+ 	*/
+ 
+ 	oldval2 = inb (CONF2_ENABLE_PORT);
+ 
+ #ifdef PCI_DEBUG
+ 	if (bootverbose) {
+ 		printf ("pcibus_setup(2):\tmode 2 enable port (0x0cf8) is 0x%b\n", oldval2);
+ 	}
+ #endif
+ 
+ 	if ((oldval2 & 0xf0) == 0) {
+ 
+ 		pci_mechanism = 2;
+ 		pci_maxdevice = 16;
+ 			
+ 		outb (CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
+ 		mode2res = inb(CONF2_ENABLE_PORT);
+ 		outb (CONF2_ENABLE_PORT, oldval2);
+ 
+ #ifdef PCI_DEBUG
+ 		if (bootverbose)
+ 		    printf ("pcibus_setup(2a):\tmode2res=0x%b (0x%b)\n", 
+ 			    mode2res, CONF2_ENABLE_CHK);
+ #endif
+ 
+ 		if (mode2res == CONF2_ENABLE_RES) {
+ #ifdef PCI_DEBUG
+ 		    if (bootverbose)
+ 			printf ("pcibus_setup(2a):\tnow trying mechanism 2\n");
+ #endif
+ 
+ 			if (pcibus_check()) 
+ 				return;
+ 		}
+ 	}
+ 
+ 	/*---------------------------------------
+ 	**      No PCI bus host bridge found
+ 	**---------------------------------------
+ 	*/
+ 
+ 	pci_mechanism = 0;
+ 	pci_maxdevice = 0;
+ }
+ 
+ /*--------------------------------------------------------------------
+ **
+ **      Build a pcitag from bus, device and function number
+ **
+ **--------------------------------------------------------------------
+ */
+ 
+ static pcici_t
+ pcibus_tag (unsigned char bus, unsigned char device, unsigned char func)
+ {
+ 	pcici_t tag;
+ 
+ 	tag.cfg1 = 0;
+ 	if (func   >=  8) return tag;
+ 
+ 	switch (pci_mechanism) {
+ 
+ 	case 1:
+ 		if (device < 32) {
+ 			tag.cfg1 = CONF1_ENABLE
+ 				| (((u_long) bus   ) << 16ul)
+ 				| (((u_long) device) << 11ul)
+ 				| (((u_long) func  ) <<  8ul);
+ 		}
+ 		break;
+ 	case 2:
+ 		if (device < 16) {
+ 			tag.cfg2.port    = 0xc000 | (device << 8ul);
+ 			tag.cfg2.enable  = 0xf0 | (func << 1ul);
+ 			tag.cfg2.forward = bus;
+ 		}
+ 		break;
+ 	};
+ 	return tag;
+ }
+ 
+ static pcici_t
+ pcibus_ftag (pcici_t tag, u_char func)
+ {
+ 	switch (pci_mechanism) {
+ 
+ 	case 1:
+ 		tag.cfg1 &= ~0x700ul;
+ 		tag.cfg1 |= (((u_long) func) << 8ul);
+ 		break;
+ 	case 2:
+ 		tag.cfg2.enable  = 0xf0 | (func << 1ul);
+ 		break;
+ 	};
+ 	return tag;
+ }
+ 
+ /*--------------------------------------------------------------------
+ **
+ **      Read register from configuration space.
+ **
+ **--------------------------------------------------------------------
+ */
+ 
+ static u_long
+ pcibus_read (pcici_t tag, u_long reg)
+ {
+ 	u_long addr, data = 0;
+ 
+ 	if (!tag.cfg1) return (0xfffffffful);
+ 
+ 	switch (pci_mechanism) {
+ 
+ 	case 1:
+ 		addr = tag.cfg1 | (reg & 0xfc);
+ #ifdef PCI_DEBUG
+ 		printf ("pci_conf_read(1): addr=%X ", addr);
+ #endif
+ 		outl (CONF1_ADDR_PORT, addr);
+ 		data = inl (CONF1_DATA_PORT);
+ 		outl (CONF1_ADDR_PORT, 0   );
+ 		break;
+ 
+ 	case 2:
+ 		addr = tag.cfg2.port | (reg & 0xfc);
+ #ifdef PCI_DEBUG
+ 		printf ("pci_conf_read(2): addr=%X ", addr);
+ #endif
+ 		outb (CONF2_ENABLE_PORT , tag.cfg2.enable );
+ 		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
+ 
+ 		data = inl ((u_short) addr);
+ 
+ 		outb (CONF2_ENABLE_PORT,  0);
+ 		outb (CONF2_FORWARD_PORT, 0);
+ 		break;
+ 	};
+ 
+ #ifdef PCI_DEBUG
+ 	printf ("data=%X\n", data);
+ #endif
+ 
+ 	return (data);
+ }
+ 
+ /*--------------------------------------------------------------------
+ **
+ **      Write register into configuration space.
+ **
+ **--------------------------------------------------------------------
+ */
+ 
+ static void
+ pcibus_write (pcici_t tag, u_long reg, u_long data)
+ {
+ 	u_long addr;
+ 
+ 	if (!tag.cfg1) return;
+ 
+ 	switch (pci_mechanism) {
+ 
+ 	case 1:
+ 		addr = tag.cfg1 | (reg & 0xfc);
+ #ifdef PCI_DEBUG
+ 		printf ("pci_conf_write(1): addr=%X data=%X\n",
+ 			addr, data);
+ #endif
+ 		outl (CONF1_ADDR_PORT, addr);
+ 		outl (CONF1_DATA_PORT, data);
+ 		outl (CONF1_ADDR_PORT,   0 );
+ 		break;
+ 
+ 	case 2:
+ 		addr = tag.cfg2.port | (reg & 0xfc);
+ #ifdef PCI_DEBUG
+ 		printf ("pci_conf_write(2): addr=%X data=%X\n",
+ 			addr, data);
+ #endif
+ 		outb (CONF2_ENABLE_PORT,  tag.cfg2.enable);
+ 		outb (CONF2_FORWARD_PORT, tag.cfg2.forward);
+ 
+ 		outl ((u_short) addr, data);
+ 
+ 		outb (CONF2_ENABLE_PORT,  0);
+ 		outb (CONF2_FORWARD_PORT, 0);
+ 		break;
+ 	};
+ }
+ 
diff -rPc netboot.old/pcibus.h netboot/pcibus.h
*** netboot.old/pcibus.h	Thu Jan  1 01:00:00 1970
--- netboot/pcibus.h	Tue Oct  6 15:15:32 1998
***************
*** 0 ****
--- 1,94 ----
+ /**************************************************************************
+ **
+ **  $Id$
+ **
+ **  Declarations for pci bus driver.
+ **
+ **  FreeBSD
+ **
+ **-------------------------------------------------------------------------
+ **
+ ** Copyright (c) 1995 Wolfgang Stanglmeier.  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. The name of the author may not be used to endorse or promote products
+ **    derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 __PCI_BUS_H__
+ #define __PCI_BUS_H__	"pl1 95/03/13"
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	The following functions are provided by the pci bios.
+ **	They are used only by the pci configuration.
+ **
+ **	pcibus_setup():
+ **		Probes for a pci system.
+ **		Sets pci_maxdevice and pci_mechanism.
+ **
+ **	pcibus_tag():
+ **		Creates a handle for pci configuration space access.
+ **		This handle is given to the read/write functions.
+ **
+ **	pcibus_ftag():
+ **		Creates a modified handle.
+ **
+ **	pcibus_read():
+ **		Read a long word from the pci configuration space.
+ **		Requires a tag (from pcitag) and the register
+ **		number (should be a long word alligned one).
+ **
+ **	pcibus_write():
+ **		Writes a long word to the pci configuration space.
+ **		Requires a tag (from pcitag), the register number
+ **		(should be a long word alligned one), and a value.
+ **
+ **	pcibus_regirq():
+ **		Register an interrupt handler for a pci device.
+ **		Requires a tag (from pcitag), the register number
+ **		(should be a long word alligned one), and a value.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ struct pcibus {
+ 	char     *pb_name;
+ 	void	(*pb_setup )  (void);
+ 	pcici_t (*pb_tag   )  (u_char bus, u_char device, u_char func);
+ 	pcici_t (*pb_ftag  )  (pcici_t tag, u_char func);
+ 	u_long	(*pb_read  )  (pcici_t tag, u_long reg);
+ 	void	(*pb_write )  (pcici_t tag, u_long reg, u_long data);
+ };
+ 
+ #define PCI_MAX_IRQ   (16)
+ 
+ /*
+ **	The following structure should be generated by the driver
+ */
+ 
+ extern struct linker_set pcibus_set;
+ 
+ int pci_register_lkm (struct pci_device *dvp, int if_revision);
+ 
+ #endif
diff -rPc netboot.old/pcireg.h netboot/pcireg.h
*** netboot.old/pcireg.h	Thu Jan  1 01:00:00 1970
--- netboot/pcireg.h	Tue Oct  6 15:15:44 1998
***************
*** 0 ****
--- 1,202 ----
+ /**************************************************************************
+ **
+ **  $Id$
+ **
+ **  Names for PCI configuration space registers.
+ **
+ ** Copyright (c) 1994 Wolfgang Stanglmeier.  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. The name of the author may not be used to endorse or promote products
+ **    derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 __PCI_REG_H__
+ #define __PCI_REG_H__ "pl2 95/03/21"
+ 
+ /*
+ ** Device identification register; contains a vendor ID and a device ID.
+ ** We have little need to distinguish the two parts.
+ */
+ #define	PCI_ID_REG			0x00
+ 
+ /*
+ ** Command and status register.
+ */
+ #define	PCI_COMMAND_STATUS_REG		0x04
+ 
+ #define	PCI_COMMAND_IO_ENABLE		0x00000001
+ #define	PCI_COMMAND_MEM_ENABLE		0x00000002
+ #define	PCI_COMMAND_MASTER_ENABLE	0x00000004
+ #define	PCI_COMMAND_SPECIAL_ENABLE	0x00000008
+ #define	PCI_COMMAND_INVALIDATE_ENABLE	0x00000010
+ #define	PCI_COMMAND_PALETTE_ENABLE	0x00000020
+ #define	PCI_COMMAND_PARITY_ENABLE	0x00000040
+ #define	PCI_COMMAND_STEPPING_ENABLE	0x00000080
+ #define	PCI_COMMAND_SERR_ENABLE		0x00000100
+ #define	PCI_COMMAND_BACKTOBACK_ENABLE	0x00000200
+ 
+ #define	PCI_STATUS_BACKTOBACK_OKAY	0x00800000
+ #define	PCI_STATUS_PARITY_ERROR		0x01000000
+ #define	PCI_STATUS_DEVSEL_FAST		0x00000000
+ #define	PCI_STATUS_DEVSEL_MEDIUM	0x02000000
+ #define	PCI_STATUS_DEVSEL_SLOW		0x04000000
+ #define	PCI_STATUS_DEVSEL_MASK		0x06000000
+ #define	PCI_STATUS_TARGET_TARGET_ABORT	0x08000000
+ #define	PCI_STATUS_MASTER_TARGET_ABORT	0x10000000
+ #define	PCI_STATUS_MASTER_ABORT		0x20000000
+ #define	PCI_STATUS_SPECIAL_ERROR	0x40000000
+ #define	PCI_STATUS_PARITY_DETECT	0x80000000
+ 
+ /*
+ ** Class register; defines basic type of device.
+ */
+ #define	PCI_CLASS_REG			0x08
+ 
+ #define	PCI_CLASS_MASK			0xff000000
+ #define	PCI_SUBCLASS_MASK		0x00ff0000
+ 
+ /* base classes */
+ #define	PCI_CLASS_PREHISTORIC		0x00000000
+ #define	PCI_CLASS_MASS_STORAGE		0x01000000
+ #define	PCI_CLASS_NETWORK		0x02000000
+ #define	PCI_CLASS_DISPLAY		0x03000000
+ #define	PCI_CLASS_MULTIMEDIA		0x04000000
+ #define	PCI_CLASS_MEMORY		0x05000000
+ #define	PCI_CLASS_BRIDGE		0x06000000
+ #define	PCI_CLASS_UNDEFINED		0xff000000
+ 
+ /* 0x00 prehistoric subclasses */
+ #define	PCI_SUBCLASS_PREHISTORIC_MISC	0x00000000
+ #define	PCI_SUBCLASS_PREHISTORIC_VGA	0x00010000
+ 
+ /* 0x01 mass storage subclasses */
+ #define	PCI_SUBCLASS_MASS_STORAGE_SCSI	0x00000000
+ #define	PCI_SUBCLASS_MASS_STORAGE_IDE	0x00010000
+ #define	PCI_SUBCLASS_MASS_STORAGE_FLOPPY	0x00020000
+ #define	PCI_SUBCLASS_MASS_STORAGE_IPI	0x00030000
+ #define	PCI_SUBCLASS_MASS_STORAGE_MISC	0x00800000
+ 
+ /* 0x02 network subclasses */
+ #define	PCI_SUBCLASS_NETWORK_ETHERNET	0x00000000
+ #define	PCI_SUBCLASS_NETWORK_TOKENRING	0x00010000
+ #define	PCI_SUBCLASS_NETWORK_FDDI	0x00020000
+ #define	PCI_SUBCLASS_NETWORK_MISC	0x00800000
+ 
+ /* 0x03 display subclasses */
+ #define	PCI_SUBCLASS_DISPLAY_VGA	0x00000000
+ #define	PCI_SUBCLASS_DISPLAY_XGA	0x00010000
+ #define	PCI_SUBCLASS_DISPLAY_MISC	0x00800000
+ 
+ /* 0x04 multimedia subclasses */
+ #define	PCI_SUBCLASS_MULTIMEDIA_VIDEO	0x00000000
+ #define	PCI_SUBCLASS_MULTIMEDIA_AUDIO	0x00010000
+ #define	PCI_SUBCLASS_MULTIMEDIA_MISC	0x00800000
+ 
+ /* 0x05 memory subclasses */
+ #define	PCI_SUBCLASS_MEMORY_RAM		0x00000000
+ #define	PCI_SUBCLASS_MEMORY_FLASH	0x00010000
+ #define	PCI_SUBCLASS_MEMORY_MISC	0x00800000
+ 
+ /* 0x06 bridge subclasses */
+ #define	PCI_SUBCLASS_BRIDGE_HOST	0x00000000
+ #define	PCI_SUBCLASS_BRIDGE_ISA		0x00010000
+ #define	PCI_SUBCLASS_BRIDGE_EISA	0x00020000
+ #define	PCI_SUBCLASS_BRIDGE_MC		0x00030000
+ #define	PCI_SUBCLASS_BRIDGE_PCI		0x00040000
+ #define	PCI_SUBCLASS_BRIDGE_PCMCIA	0x00050000
+ #define	PCI_SUBCLASS_BRIDGE_MISC	0x00800000
+ 
+ /*
+ ** Header registers
+ */
+ #define PCI_HEADER_MISC			0x0c
+ 
+ #define PCI_HEADER_MULTIFUNCTION	0x00800000
+ 
+ /*
+ ** Mapping registers
+ */
+ #define	PCI_MAP_REG_START		0x10
+ #define	PCI_MAP_REG_END			0x28
+ 
+ #define	PCI_MAP_MEMORY			0x00000000
+ #define	PCI_MAP_IO			0x00000001
+ 
+ #define	PCI_MAP_MEMORY_TYPE_32BIT	0x00000000
+ #define	PCI_MAP_MEMORY_TYPE_32BIT_1M	0x00000002
+ #define	PCI_MAP_MEMORY_TYPE_64BIT	0x00000004
+ #define	PCI_MAP_MEMORY_TYPE_MASK	0x00000006
+ #define	PCI_MAP_MEMORY_CACHABLE		0x00000008
+ #define	PCI_MAP_MEMORY_ADDRESS_MASK	0xfffffff0
+ 
+ #define	PCI_MAP_IO_ADDRESS_MASK         0xfffffffc
+ /*
+ ** PCI-PCI bridge mapping registers
+ */
+ #define PCI_PCI_BRIDGE_BUS_REG		0x18
+ #define PCI_PCI_BRIDGE_IO_REG		0x1c
+ #define PCI_PCI_BRIDGE_MEM_REG		0x20
+ #define PCI_PCI_BRIDGE_PMEM_REG		0x24
+ 
+ #define PCI_SUBID_REG0			0x2c
+ #define PCI_SUBID_REG1			0x34
+ #define PCI_SUBID_REG2			0x40
+ 
+ #define PCI_SUBORDINATE_BUS_MASK	0x00ff0000
+ #define PCI_SECONDARY_BUS_MASK		0x0000ff00
+ #define PCI_PRIMARY_BUS_MASK		0x000000ff
+ 
+ #define PCI_SUBORDINATE_BUS_EXTRACT(x)	(((x) >> 16) & 0xff)
+ #define PCI_SECONDARY_BUS_EXTRACT(x)	(((x) >>  8) & 0xff)
+ #define PCI_PRIMARY_BUS_EXTRACT(x)	(((x)      ) & 0xff)
+ 
+ #define	PCI_PRIMARY_BUS_INSERT(x, y)	(((x) & ~PCI_PRIMARY_BUS_MASK) | ((y) <<  0))
+ #define	PCI_SECONDARY_BUS_INSERT(x, y)	(((x) & ~PCI_SECONDARY_BUS_MASK) | ((y) <<  8))
+ #define	PCI_SUBORDINATE_BUS_INSERT(x, y) (((x) & ~PCI_SUBORDINATE_BUS_MASK) | ((y) << 16))
+ 
+ #define	PCI_PPB_IOBASE_EXTRACT(x)	(((x) << 8) & 0xF000)
+ #define	PCI_PPB_IOLIMIT_EXTRACT(x)	(((x) << 0) & 0xF000 | 0x0FFF)
+ 
+ #define	PCI_PPB_MEMBASE_EXTRACT(x)	(((x) << 16) & 0xFFF00000)
+ #define	PCI_PPB_MEMLIMIT_EXTRACT(x)	(((x) <<  0) & 0xFFF00000 | 0x000FFFFF)
+ 
+ /*
+ ** Interrupt configuration register
+ */
+ #define	PCI_INTERRUPT_REG		0x3c
+ 
+ #define	PCI_INTERRUPT_PIN_MASK		0x0000ff00
+ #define	PCI_INTERRUPT_PIN_EXTRACT(x)	((((x) & PCI_INTERRUPT_PIN_MASK) >> 8) & 0xff)
+ #define	PCI_INTERRUPT_PIN_NONE		0x00
+ #define	PCI_INTERRUPT_PIN_A		0x01
+ #define	PCI_INTERRUPT_PIN_B		0x02
+ #define	PCI_INTERRUPT_PIN_C		0x03
+ #define	PCI_INTERRUPT_PIN_D		0x04
+ 
+ #define	PCI_INTERRUPT_LINE_MASK		0x000000ff
+ #define	PCI_INTERRUPT_LINE_EXTRACT(x)	((((x) & PCI_INTERRUPT_LINE_MASK) >> 0) & 0xff)
+ #define	PCI_INTERRUPT_LINE_INSERT(x,v)	(((x) & ~PCI_INTERRUPT_LINE_MASK) | ((v) << 0))
+ 
+ #endif /* __PCI_REG_H__ */
diff -rPc netboot.old/pcivar.h netboot/pcivar.h
*** netboot.old/pcivar.h	Thu Jan  1 01:00:00 1970
--- netboot/pcivar.h	Tue Oct  6 15:17:45 1998
***************
*** 0 ****
--- 1,229 ----
+ /**************************************************************************
+ **
+ **  $Id$
+ **
+ **  Declarations for pci device drivers.
+ **
+ **  FreeBSD
+ **
+ **-------------------------------------------------------------------------
+ **
+ ** Copyright (c) 1994 Wolfgang Stanglmeier.  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. The name of the author may not be used to endorse or promote products
+ **    derived from this software without specific prior written permission.
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 __PCI_VAR_H__
+ #define __PCI_VAR_H__ "pl2 95/03/21"
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	main pci initialization function.
+ **	called at boot time from autoconf.c
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ void pci_configure (void);
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	The pci configuration id describes a pci device on the bus.
+ **	It is constructed from: bus, device & function numbers.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ typedef union {
+ 	u_long	 cfg1;
+ 	struct {
+ 		 u_char   enable;
+ 		 u_char   forward;
+ 		 u_short  port;
+ 	       } cfg2;
+ 	unsigned tag;
+ 	} pcici_t;
+ 
+ #define sametag(x,y)  ((x).tag == (y).tag)
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	Each pci device has an unique device id.
+ **	It is used to find a matching driver.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ typedef u_long pcidi_t;
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	The following functions are provided for the device driver
+ **	to read/write the configuration space.
+ **
+ **	pci_conf_read():
+ **		Read a long word from the pci configuration space.
+ **		Requires a tag (from pcitag) and the register
+ **		number (should be a long word alligned one).
+ **
+ **	pci_conf_write():
+ **		Writes a long word to the pci configuration space.
+ **		Requires a tag (from pcitag), the register number
+ **		(should be a long word alligned one), and a value.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ u_long pci_conf_read  (pcici_t tag, u_long reg		   );
+ 
+ void   pci_conf_write (pcici_t tag, u_long reg, u_long data);
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	The pci driver structure.
+ **
+ **	name:	The short device name.
+ **
+ **	probe:	Checks if the driver can support a device
+ **		with this type. The tag may be used to get
+ **		more info with pci_read_conf(). See below.
+ **		It returns a string with the devices name,
+ **		or a NULL pointer, if the driver cannot
+ **		support this device.
+ **
+ **	attach:	Allocate a control structure and prepare
+ **		it. This function may use the pci mapping
+ **		functions. See below.
+ **		(configuration id) or type.
+ **
+ **	count:	A pointer to a unit counter.
+ **		It's used by the pci configurator to
+ **		allocate unit numbers.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ struct pci_device {
+     char*    pd_name;
+     char*  (*pd_probe ) (pcici_t tag, pcidi_t type);
+     void   (*pd_attach) (pcici_t tag, int     unit);
+     u_long  *pd_count;
+     int    (*pd_shutdown) (int, int);
+ };
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	This table includes pointers to all pci device drivers.
+ **	It should be generated by the linker.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ extern struct linker_set pcidevice_set;
+ 
+ extern unsigned pci_max_burst_len;  /* log2 of safe burst transfer length */
+ extern unsigned pci_mechanism;
+ extern unsigned pci_maxdevice;
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	Map a pci device to physical and virtual memory.
+ **
+ **      Entry selects the register in the pci configuration
+ **	space, which supplies the size of the region, and
+ **	receives the physical address.
+ **
+ **	In case of success the function sets the addresses
+ **	in *va and *pa, and returns 1.
+ **	In case of errors a message is written,
+ **	and the function returns 0.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ int pci_map_mem (pcici_t tag, u_long entry, vm_offset_t *va, vm_offset_t *pa);
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	Map a pci device to an io port area.
+ **
+ **	Entry selects the register in the pci configuration
+ **	space, which supplies the size of the region, and
+ **	receives the port number.
+ **
+ **	In case of success the function sets the port number in pa,
+ **	and returns 1.
+ **	In case of errors a message is written,
+ **	and the function returns 0.
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ int pci_map_port (pcici_t tag, u_long entry, u_short * pa);
+ 
+ /*-----------------------------------------------------------------
+ **
+ **	Map a pci interrupt to an isa irq line, and enable the interrupt.
+ **
+ **      -----------------
+ **
+ **      func is the interrupt handler, arg is the argument
+ **      to the handler (usually a pointer to a softc).
+ **
+ **      The maskptr argument should be  &bio_imask,
+ **      &net_imask etc. or NULL.
+ **
+ **      If there is any error, a message is written, and
+ **      the function returns with zero.
+ **      Else it returns with a value different to zero.
+ **
+ **      -----------------
+ **
+ **	The irq number is read from the configuration space.
+ **	(Should have been set by the bios).
+ **
+ **	Supports multiple handlers per irq (shared interrupts).
+ **
+ **-----------------------------------------------------------------
+ */
+ 
+ typedef void pci_inthand_t(void *arg);
+ 
+ struct pci_int_desc {
+ 	struct pci_int_desc * pcid_next;
+ 	pcici_t 	      pcid_tag;
+ 	pci_inthand_t	     *pcid_handler;
+ 	void*		      pcid_argument;
+ 	unsigned *	      pcid_maskptr;
+ 	unsigned	      pcid_tally;
+ 	unsigned	      pcid_mask;
+ };
+ 
+ int pci_map_int (pcici_t tag, pci_inthand_t *func, void *arg,
+ 		 unsigned *maskptr);
+ 
+ int pci_unmap_int (pcici_t tag);
+ 
+ #endif
diff -rPc netboot.old/start2.S netboot/start2.S
*** netboot.old/start2.S	Tue Oct  6 16:49:32 1998
--- netboot/start2.S	Tue Oct  6 17:13:14 1998
***************
*** 15,21 ****
   */
  #ifdef BOOTROM
  	.word	0xaa55			/* bios extension signature */
! 	.byte	(ROMSIZE>>9)		/* no. of 512B blocks */
  	jmp	1f			/* enter from bios here */
  	.byte	0			/* checksum */
  #ifdef	PCI
--- 15,21 ----
   */
  #ifdef BOOTROM
  	.word	0xaa55			/* bios extension signature */
! 	.byte	0			/* no of 512B blocks, set by makerom */
  	jmp	1f			/* enter from bios here */
  	.byte	0			/* checksum */
  #ifdef	PCI
***************
*** 29,35 ****
  	.word	0x0018			/* PCI data structure */
  	.byte	0			/* PCI data struct. rev -- 0 */
  	.byte	PCI_CLASS		/* Class code */
! 	.word	(ROMSIZE>>9)            /* no. of 512B blocks */
  	.byte	0,0			/* rev. level */
  	.byte	0			/* code type - 0 =x86 */
  	.byte	0x80			/* indicator of last block */
--- 29,35 ----
  	.word	0x0018			/* PCI data structure */
  	.byte	0			/* PCI data struct. rev -- 0 */
  	.byte	PCI_CLASS		/* Class code */
! 	.word	0			/* no of 512B blocks, set by makerom */
  	.byte	0,0			/* rev. level */
  	.byte	0			/* code type - 0 =x86 */
  	.byte	0x80			/* indicator of last block */
***************
*** 85,92 ****
  	.byte	0xb8			/* MOV $RELOCADDR>>4, %ax */
  	.word	(RELOC>>4)
          mov     %ax, %es
! 	.byte	0xb9			/* MOV $ROMSIZE, %cx */
! 	.word   ROMSIZE
          cs
          rep
          movsb
--- 85,92 ----
  	.byte	0xb8			/* MOV $RELOCADDR>>4, %ax */
  	.word	(RELOC>>4)
          mov     %ax, %es
! 	.byte	0xb9			/* MOV $RELOCSIZE, %cx */
! 	.word   RELOCSIZE
          cs
          rep
          movsb
>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->closed 
State-Changed-By: sheldonh 
State-Changed-When: Thu Mar 23 00:22:04 PST 2000 
State-Changed-Why:  
Closed on originator's request.  Thanks, Ian! 
>Unformatted:
