Merge from Etherboot 5.4
authorMichael Brown <mcb30@etherboot.org>
Thu, 16 Mar 2006 17:05:38 +0000 (17:05 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 16 Mar 2006 17:05:38 +0000 (17:05 +0000)
112 files changed:
LOG
VERSION
contrib/bin2intelhex/bin2intelhex.c
contrib/initrd/ChangeLog
src/Config
src/Makefile
src/Makefile.housekeeping
src/arch/armnommu/Config
src/arch/armnommu/core/serial.c
src/arch/armnommu/drivers/net/p2001_eth.c
src/arch/armnommu/include/hardware.h
src/arch/armnommu/include/lxt971a.h [deleted file]
src/arch/armnommu/include/stdint.h
src/arch/e1/include/stdint.h
src/arch/i386/Config
src/arch/i386/Makefile
src/arch/i386/core/freebsd_loader.c
src/arch/i386/core/hooks.c
src/arch/i386/firmware/pcbios/basemem.c
src/arch/i386/image/nbi.c
src/arch/i386/image/pxe_image.c [moved from src/arch/i386/core/pxe_loader.c with 99% similarity]
src/arch/i386/include/basemem.h
src/arch/i386/include/bochs.h
src/arch/i386/include/hooks.h
src/arch/i386/include/librm.h
src/arch/i386/include/pxe_addr.h [new file with mode: 0644]
src/arch/i386/include/pxe_callbacks.h
src/arch/i386/include/pxe_types.h [deleted file]
src/arch/i386/include/realmode.h
src/arch/i386/include/registers.h
src/arch/i386/include/stdint.h
src/arch/i386/include/virtaddr.h
src/arch/i386/prefix/int19exit.c
src/arch/i386/prefix/romprefix.S
src/arch/i386/prefix/select_isapnp.c
src/arch/i386/prefix/select_pci.c
src/arch/i386/transitions/libkir.S
src/arch/i386/transitions/librm.S
src/arch/i386/transitions/librm_mgmt.c
src/arch/ia64/include/stdint.h
src/config.h
src/core/background.c [new file with mode: 0644]
src/core/buffer.c
src/core/config.c
src/core/console.c
src/core/errno.c [new file with mode: 0644]
src/core/main.c
src/core/nic.c
src/core/pxe_export.c [deleted file]
src/core/vsprintf.c
src/doc/build_sys.dox [new file with mode: 0644]
src/doxygen.cfg [new file with mode: 0644]
src/drivers/bus/isapnp.c
src/drivers/net/3c515.c
src/drivers/net/amd8111e.c [new file with mode: 0644]
src/drivers/net/amd8111e.h [new file with mode: 0644]
src/drivers/net/davicom.c
src/drivers/net/depca.c
src/drivers/net/dmfe.c
src/drivers/net/e1000.c
src/drivers/net/eepro.c
src/drivers/net/eepro100.c
src/drivers/net/forcedeth.c
src/drivers/net/mtd80x.c
src/drivers/net/natsemi.c
src/drivers/net/ns83820.c
src/drivers/net/pcnet32.c
src/drivers/net/r8169.c
src/drivers/net/sis900.c
src/drivers/net/sis900.h
src/drivers/net/smc9000.c
src/drivers/net/smc9000.h
src/drivers/net/sundance.c
src/drivers/net/tg3.c
src/drivers/net/tg3.h
src/drivers/net/tlan.h
src/drivers/net/tulip.c
src/drivers/net/w89c840.c
src/include/background.h [new file with mode: 0644]
src/include/buffer.h
src/include/compiler.h
src/include/console.h
src/include/dns.h
src/include/errno.h [new file with mode: 0644]
src/include/etherboot.h
src/include/igmp.h
src/include/nmb.h
src/include/pci_ids.h
src/include/pxe.h
src/include/pxe_api.h [new file with mode: 0644]
src/include/pxe_export.h [deleted file]
src/include/pxe_types.h [new file with mode: 0644]
src/include/tables.h
src/include/tftp.h
src/include/tftpcore.h [new file with mode: 0644]
src/include/vsprintf.h
src/interface/pxe/pxe.c [new file with mode: 0644]
src/interface/pxe/pxe_errors.c [new file with mode: 0644]
src/interface/pxe/pxe_loader.c [new file with mode: 0644]
src/interface/pxe/pxe_preboot.c [new file with mode: 0644]
src/interface/pxe/pxe_tftp.c [new file with mode: 0644]
src/interface/pxe/pxe_udp.c [new file with mode: 0644]
src/interface/pxe/pxe_undi.c [new file with mode: 0644]
src/proto/fsp.c [new file with mode: 0644]
src/proto/http.c
src/proto/igmp.c [new file with mode: 0644]
src/proto/nmb.c
src/proto/tcp.c
src/proto/tftm.c
src/proto/tftp.c
src/proto/tftpcore.c [new file with mode: 0644]
src/util/makerom.pl

diff --git a/LOG b/LOG
index 79ad4c0..39179ac 100644 (file)
--- a/LOG
+++ b/LOG
@@ -2861,3 +2861,12 @@ driver
 
 + Hermann Gausterer sent a patch to support additional Broadcom PHYs
 
++ Timothy Legge updated the forcedeth driver to the latest Linux version
+2.6.10 (untested and broken)
+
++ YhLu fixed the updated forcedeth driver so that it worked and confirmed 
+that it supports the Gigabit nVidia NICs
+
++ Timothy Legge fixed relocation issues with the eepro driver
+
++ Jan Kiszka provided a patch for the smc9000 for missing phy-setup
diff --git a/VERSION b/VERSION
index 85570a8..3328f15 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-5.4.0 2005-04-01
+5.5.0 2005-05-17
index 92c2728..75b88c1 100644 (file)
@@ -24,8 +24,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2005/05/17 16:45:06  mcb30
- * Import from Etherboot 5.4
+ * Revision 1.1  2005/05/17 16:45:06  mcb30
+ * Initial revision
  *
  * Revision 1.9  1997/12/14 05:14:54  install
  * - some documentation....
index 74d3ce1..94f8f6a 100644 (file)
@@ -3,8 +3,8 @@ mkinitrd-net ChangeLog
 Last Modified: Fri Jul 26 23:08:28 2002
 
 $Log$
-Revision 1.1.1.1  2005/05/17 16:45:02  mcb30
-Import from Etherboot 5.4
+Revision 1.1  2005/05/17 16:45:02  mcb30
+Initial revision
 
 Revision 1.1  2002/11/06 06:31:06  ken_yap
 Contributed by Michael Brown.
index ca069c7..2f3dea8 100644 (file)
 #
 #      Obscure options you probably don't need to touch:
 #
+#      -DZPXE_SUFFIX_STRIP
+#                      If the last 5 characters of the filename passed to Etherboot is
+#                      ".zpxe" then strip it off. This is useful in cases where a DHCP server
+#                      is not able to be configured to support conditionals. The way it works
+#                      is that the DHCP server is configured with a filename like
+#                      "foo.nbi.zpxe" so that when PXE asks for a filename it gets that, and
+#                      loads Etherboot from that file. Etherboot then starts up and once
+#                      again asks the DHCP server for a filename and once again gets
+#                      foo.nbi.zpxe, but with this option turned on loads "foo.nbi" instead.
+#                      This allows people to use Etherboot who might not otherwise be able to
+#                      because their DHCP servers won't let them.
+#
 #      -DPOWERSAVE
 #                      Halt the processor when waiting for keyboard input
 #                      which saves power while waiting for user interaction.
@@ -295,7 +307,7 @@ CFLAGS+=    -DALLOW_ONLY_ENCAPSULATED
 
 # Limit the delay on packet loss/congestion to a more bearable value. See
 # description above.  If unset, do not limit the delay between resend.
-CFLAGS+=       -DBACKOFF_LIMIT=7 -DCONGESTED
+CFLAGS+=       -DBACKOFF_LIMIT=5 -DCONGESTED
 
 # More optional features
 # CFLAGS+=     -DTRY_FLOPPY_FIRST=4
index fa7b3f3..cb6b944 100644 (file)
@@ -29,7 +29,7 @@ include arch/$(ARCH)/Config
 # If invoked with no build target, print out a helpfully suggestive
 # message.
 #
-noargs : blib
+noargs :
        @echo '===================================================='
        @echo 'No target specified. To specify a target, do: '
        @echo
@@ -79,6 +79,7 @@ MKCONFIG      ?= $(PERL) ./util/mkconfig.pl
 SYMCHECK       ?= $(PERL) ./util/symcheck.pl
 SORTOBJDUMP    ?= $(PERL) ./util/sortobjdump.pl
 NRV2B          ?= ./util/nrv2b
+DOXYGEN                ?= doxygen
 
 # Location to place generated files
 #
@@ -130,10 +131,11 @@ DEBUG_TARGETS     += dbg2.o dbg.o c s
 #
 SRCDIRS                += core
 SRCDIRS                += proto
-SRCDIRS                += image
+#SRCDIRS               += image
 SRCDIRS                += drivers/bus
 SRCDIRS                += drivers/net
 #SRCDIRS               += drivers/disk 
+SRCDIRS                += interface/pxe
 
 # NON_AUTO_SRCS lists files that are excluded from the normal
 # automatic build system.
index 1f06d69..2a95032 100644 (file)
@@ -10,8 +10,8 @@ CLEANUP       := $(BIN)/*.* # *.* to avoid catching the "CVS" directory
 # Version number calculations 
 #
 VERSION_MAJOR  = 5
-VERSION_MINOR  = 3
-VERSION_PATCH  = 14
+VERSION_MINOR  = 5
+VERSION_PATCH  = 0
 EXTRAVERSION   =       
 MM_VERSION     = $(VERSION_MAJOR).$(VERSION_MINOR)
 VERSION                = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
@@ -422,6 +422,31 @@ $(BIN)/%.rebuild :
        rm -f $(BIN)/$*
        $(MAKE) $(MAKEFLAGS) $(BIN)/$*
 
+# Documentation
+#
+$(BIN)/doxygen.cfg : doxygen.cfg $(MAKEDEPS)
+       $(PERL) -pe 's{\@SRCDIRS\@}{$(SRCDIRS)}; ' \
+               -e  's{\@BIN\@}{$(BIN)}; ' \
+               -e  's{\@ARCH\@}{$(ARCH)}; ' \
+               $< > $@
+
+$(BIN)/doc : $(BIN)/doxygen.cfg
+       $(DOXYGEN) $<
+
+.PHONY : $(BIN)/doc
+
+VERYCLEANUP    += $(BIN)/doc
+
+doc : $(BIN)/doc
+
+docview :
+       @[ -f $(BIN)/doc/html/index.html ] || $(MAKE) $(BIN)/doc
+       @if [ -n "$$BROWSER" ] ; then \
+               ( $$BROWSER $(BIN)/doc/html/index.html & ) ; \
+       else \
+               echo "Documentation index in $(BIN)/doc/html/index.html" ; \
+       fi
+
 # Clean-up
 #
 clean :
index 4c220cd..5794203 100644 (file)
@@ -17,6 +17,12 @@ CFLAGS+= -DRAWADDR=0x40100000
 # NIC Debug Outputs
 #CFLAGS+= -DDEBUG_NIC
 
+# Reduced Media Independent Interface
+# MAZBR LPEC2001: MII  (Intel LXT971ALE at 0..1)
+# Elmeg D@VOS   : RMII (Altima AC104-QF at 4..7)
+# Telekom XI521 : RMII (Altima AC104-QF at 4..7)
+#CFLAGS+= -DRMII
+
 # Fixed MAC address
 # p2001_eth has no flash and fixed mac address
 #CFLAGS+=      -DMAC_HW_ADDR_DRV="'H','Y','L','N','X','1'"
index 3ae98d4..0fb6e79 100644 (file)
@@ -17,7 +17,7 @@ void serial_putc(int ch)
 {
        /* wait for room in the 32 byte tx FIFO */
        while ((P2001_UART->r.STATUS & 0x3f) > /* 30 */ 0) ;
-       P2001_UART->w.TX1 = ch & 0xff;
+       P2001_UART->w.TX[0] = ch & 0xff;
 }
 
 /*
@@ -27,7 +27,7 @@ void serial_putc(int ch)
 int serial_getc(void)
 {
        while (((P2001_UART->r.STATUS >> 6) & 0x3f) == 0) ;
-       return P2001_UART->r.RX1 & 0xff;
+       return P2001_UART->r.RX[0] & 0xff;
 }
 
 /*
index 81bc84c..bdf2f0e 100644 (file)
@@ -1,10 +1,10 @@
 /**************************************************************************
-Etherboot -  BOOTP/TFTP Bootstrap Program
-P2001 NIC driver for Etherboot
-***************************************************************************/
+ * Etherboot -  BOOTP/TFTP Bootstrap Program
+ * P2001 NIC driver for Etherboot
+ **************************************************************************/
 
 /*
- *  Copyright (C) 2004 Tobias Lorenz
+ *  Copyright (C) 2005 Tobias Lorenz
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,7 +19,7 @@ P2001 NIC driver for Etherboot
 #include "isa.h"
 
 #include "hardware.h"
-#include "lxt971a.h"
+#include "mii.h"
 #include "timer.h"
 
 
@@ -31,25 +31,20 @@ static unsigned char MAC_HW_ADDR[6]={MAC_HW_ADDR_DRV};
 #define DMA_BUF_SIZE   2048    /* Buffer size */
 static DMA_DSC txd              __attribute__ ((__section__(".dma.desc")));
 static DMA_DSC rxd[NUM_RX_DESC] __attribute__ ((__section__(".dma.desc")));
-static unsigned char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
-static unsigned char txb[              DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
+static char rxb[NUM_RX_DESC * DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
+static char txb[              DMA_BUF_SIZE] __attribute__ ((__section__(".dma.buffer")));
 static unsigned int cur_rx;
 
 /* Device selectors */
 static unsigned int cur_channel;       // DMA channel    : 0..3
 static unsigned int cur_phy;           // PHY Address    : 0..31
 static P2001_ETH_regs_ptr EU;          // Ethernet Unit  : 0x0018_000 with _=0..3
-static P2001_ETH_regs_ptr MU;          // Management Unit: 0x00180000
 
-#define MDIO_MAXCOUNT 1000                     /* mdio abort */
-static unsigned int mdio_error;                        /* mdio error */
-
-/* Function prototypes */
-static void         p2001_eth_mdio_init ();
-static void         p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data);
-static unsigned int p2001_eth_mdio_read (unsigned int phyadr, unsigned int regadr);
-extern unsigned int p2001_eth_mdio_error;
+/* mdio handling */
+static int          p2001_eth_mdio_read (int phy_id, int location);
+static void         p2001_eth_mdio_write(int phy_id, int location, int val);
 
+/* net_device functions */
 static int          p2001_eth_poll      (struct nic *nic, int retrieve);
 static void         p2001_eth_transmit  (struct nic *nic, const char *d,
                                        unsigned int t, unsigned int s, const char *p);
@@ -60,103 +55,107 @@ static void         p2001_eth_init      ();
 static void         p2001_eth_disable   (struct dev *dev);
 
 static int          p2001_eth_check_link(unsigned int phy);
+static int          link;
+static void         p2001_eth_phyreset  ();
 static int          p2001_eth_probe     (struct dev *dev, unsigned short *probe_addrs __unused);
 
+/* Supported MII list */
+static struct mii_chip_info {
+       const char * name;
+       unsigned int physid;    // (MII_PHYSID2 << 16) | MII_PHYSID1
+} mii_chip_table[] = {
+       { "Intel LXT971A",      0x78e20013 },
+       { "Altima AC104-QF",    0x55410022 },
+       {NULL,0},
+};
+
+
 
 /**************************************************************************
-PHY MANAGEMENT UNIT - Read/write
-***************************************************************************/
-static void p2001_eth_mdio_init()
+ * PHY MANAGEMENT UNIT - Read/write
+ **************************************************************************/
+
+/**
+ *     mdio_read - read MII PHY register
+ *     @dev: the net device to read
+ *     @regadr: the phy register id to read
+ *
+ *     Read MII registers through MDIO and MDC
+ *     using MDIO management frame structure and protocol(defined by ISO/IEC).
+ */
+static int p2001_eth_mdio_read(int phy_id, int location)
 {
-       /* reset ethernet PHYs */
-       printf("Resetting PHYs...\n");
+       int result, boguscnt = 1000;
 
-       /* GPIO24/25: TX_ER2/TX_ER0 */
-       /* GPIO26/27: PHY_RESET/TX_ER1 */
-       P2001_GPIO->PIN_MUX |= 0x0018;
-       // 31-16: 0000 1111 0000 0000
-       P2001_GPIO->GPIO2_En |= 0x0400;
+       do {
+               /* Warten bis Hardware inaktiv (MIU = "0") */
+               while (P2001_MU->MU_CNTL & 0x8000)
+                       barrier();
 
-       P2001_GPIO->GPIO2_Out |= 0x04000000;
-       P2001_GPIO->GPIO2_Out &= ~0x0400;
-       mdelay(500);
-       P2001_GPIO->GPIO2_Out |= 0x0400;
+               /* Schreiben MU_CNTL */
+               P2001_MU->MU_CNTL = location + (phy_id<<5) + (2<<10);
 
-       /* set management unit clock divisor */
-       // max. MDIO CLK = 2.048 MHz (EU.doc)
-       // max. MDIO CLK = 8.000 MHz (LXT971A)
-       // sysclk/(2*(n+1)) = MDIO CLK <= 2.048 MHz
-       // n >= sysclk/4.096 MHz - 1
-#if SYSCLK == 73728000
-       P2001_MU->MU_DIV = 17;  // 73.728 MHZ =17=> 2.020 MHz
-#else
-       //MU->MU_DIV = (SYSCLK/4.096)-1;
-#error "Please define a proper MDIO CLK divisor for that sysclk."
-#endif
-       asm("nop \n nop");
+               /* Warten bis Hardware aktiv (MIU = "1") */
+               while ((P2001_MU->MU_CNTL & 0x8000) == 0)
+                       barrier();
+               //asm("nop \r\n nop");
+
+               /* Warten bis Hardware inaktiv (MIU = "0") */
+               while (P2001_MU->MU_CNTL & 0x8000)
+                       barrier();
+
+               /* Fehler, wenn MDIO Read Error (MRE = "1") */
+       } while ((P2001_MU->MU_CNTL & 0x4000) && (--boguscnt > 0));
+
+       /* Lesen MU_DATA */
+       result = P2001_MU->MU_DATA;
+
+       if (boguscnt == 0)
+               return 0;
+       if ((result & 0xffff) == 0xffff)
+               return 0;
+
+       return result & 0xffff;
 }
 
-static void p2001_eth_mdio_write(unsigned int phyadr, unsigned int regadr, unsigned int data)
-{
-       static unsigned int count;
-       count = 0;
 
+/**
+ *     mdio_write - write MII PHY register
+ *     @dev: the net device to write
+ *     @regadr: the phy register id to write
+ *     @value: the register value to write with
+ *
+ *     Write MII registers with @value through MDIO and MDC
+ *     using MDIO management frame structure and protocol(defined by ISO/IEC)
+ */
+static void p2001_eth_mdio_write(int phy_id, int location, int val)
+{
        /* Warten bis Hardware inaktiv (MIU = "0") */
-       while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
-               count++;
+       while (P2001_MU->MU_CNTL & 0x8000)
+               barrier();
 
        /* Schreiben MU_DATA */
-       MU->MU_DATA = data;
+       P2001_MU->MU_DATA = val;
 
        /* Schreiben MU_CNTL */
-       MU->MU_CNTL = regadr + (phyadr<<5) + (1<<10);
+       P2001_MU->MU_CNTL = location + (phy_id<<5) + (1<<10);
 
        /* Warten bis Hardware aktiv (MIU = "1") */
-       while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
-               count++;
+       while ((P2001_MU->MU_CNTL & 0x8000) == 0)
+               barrier();
        //asm("nop \r\n nop");
 
        /* Warten bis Hardware inaktiv (MIU = "0") */
-       while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
-               count++;
-
-       mdio_error = (count >= MDIO_MAXCOUNT);
+       while (P2001_MU->MU_CNTL & 0x8000)
+               barrier();
 }
 
-static unsigned int p2001_eth_mdio_read(unsigned int phyadr, unsigned int regadr)
-{
-       static unsigned int count;
-       count = 0;
-
-       do {
-               /* Warten bis Hardware inaktiv (MIU = "0") */
-               while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
-                       count++;
-
-               /* Schreiben MU_CNTL */
-               MU->MU_CNTL = regadr + (phyadr<<5) + (2<<10);
-
-               /* Warten bis Hardware aktiv (MIU = "1") */
-               while (((MU->MU_CNTL & 0x8000) == 0) && (count < MDIO_MAXCOUNT))
-                       count++;
-               //asm("nop \r\n nop");
-
-               /* Warten bis Hardware inaktiv (MIU = "0") */
-               while ((MU->MU_CNTL & 0x8000) && (count < MDIO_MAXCOUNT))
-                       count++;
-
-               /* Fehler, wenn MDIO Read Error (MRE = "1") */
-       } while ((MU->MU_CNTL & 0x4000) && (count < MDIO_MAXCOUNT));
-
-       /* Lesen MU_DATA */
-       mdio_error = (count >= MDIO_MAXCOUNT);
-       return MU->MU_DATA;
-}
 
 
 /**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
+ * POLL - Wait for a frame
+ **************************************************************************/
+
 /* Function: p2001_eth_poll
  *
  * Description: checks for a received packet and returns it if found.
@@ -231,9 +230,11 @@ static int p2001_eth_poll(struct nic *nic, int retrieve)
 }
 
 
+
 /**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
+ * TRANSMIT - Transmit a frame
+ **************************************************************************/
+
 /* Function: p2001_eth_transmit
  *
  * Description: transmits a packet and waits for completion or timeout.
@@ -271,7 +272,7 @@ static void p2001_eth_transmit(
        // TMAC_CNTL.ATP does the same
 
 #ifdef DEBUG_NIC
-       printf("p2001_eth_transmit: packet from %! to %! sent\n", txb+ETH_ALEN, txb);
+       printf("p2001_eth_transmit: packet from %! to %! sent (size: %d)\n", txb+ETH_ALEN, txb, s);
 #endif
 
        /* configure descriptor */
@@ -281,12 +282,12 @@ static void p2001_eth_transmit(
 
        /* restart the transmitter */
        EU->TMAC_DMA_EN = 0x01;         /* set run bit */
-       while(EU->TMAC_DMA_EN & 0x01) ; /* wait */
+       while(EU->TMAC_DMA_EN & 0x01) /* wait */
 
 #ifdef DEBUG_NIC
        /* check status */
        status = EU->TMAC_DMA_STAT;
-       if (status & ~(0x40))
+       if (status & ~(0x40))   // not END
                printf("p2001_eth_transmit: dma status=0x%hx\n", status);
 
        printf("TMAC_MIB6..7: %d:%d\n", EU->TMAC_MIB6, EU->TMAC_MIB7);
@@ -294,9 +295,11 @@ static void p2001_eth_transmit(
 }
 
 
+
 /**************************************************************************
-IRQ - Enable, Disable or Force Interrupts
-***************************************************************************/
+ * IRQ - Enable, Disable or Force Interrupts
+ **************************************************************************/
+
 /* Function: p2001_eth_irq
  *
  * Description: Enable, Disable, or Force, interrupts
@@ -321,9 +324,11 @@ p2001_eth_irq(struct nic *nic __unused, irq_action_t action __unused)
 }
 
 
+
 /**************************************************************************
-INIT - Initialize device
-***************************************************************************/
+ * INIT - Initialize device
+ **************************************************************************/
+
 /* Function: p2001_init
  *
  * Description: resets the ethernet controller chip and various
@@ -335,6 +340,23 @@ static void p2001_eth_init()
 {
        static int i;
 
+       /* activate MII 3 */
+       if (cur_channel == 3)
+               P2001_GPIO->PIN_MUX |= (1<<8);  // MII_3_en = 1
+
+#ifdef RMII
+       /* RMII init sequence */
+       if (link & LPA_100) {
+               EU->CONF_RMII = (1<<2) | (1<<1);                // softres | 100Mbit
+               EU->CONF_RMII = (1<<2) | (1<<1) | (1<<0);       // softres | 100Mbit | RMII
+               EU->CONF_RMII = (1<<1) | (1<<0);                // 100 Mbit | RMII
+       } else {
+               EU->CONF_RMII = (1<<2);                         // softres
+               EU->CONF_RMII = (1<<2) | (1<<0);                // softres | RMII
+               EU->CONF_RMII = (1<<0);                         // RMII
+       }
+#endif
+
        /* disable transceiver */
 //     EU->TMAC_DMA_EN = 0;            /* clear run bit */
 //     EU->RMAC_DMA_EN = 0;            /* clear run bit */
@@ -353,7 +375,7 @@ static void p2001_eth_init()
 //     txd.stat = (1<<31) | (1<<30) | (1<<29);                 // DSC0 OWN|START|END
 //     txd.cntl = cur_channel << 16;                           // DSC1 CHANNEL
 //     txd.cntl |= DMA_BUF_SIZE;                               // DSC1 LEN
-       txd.buf = &txb;                                         // DSC2 BUFFER
+       txd.buf = (char *)&txb;                                 // DSC2 BUFFER
        txd.next = &txd;                                        // DSC3 NEXTDSC @self
        EU->TMAC_DMA_DESC = &txd;
 
@@ -371,9 +393,12 @@ static void p2001_eth_init()
        EU->RMAC_DMA_DESC = &rxd[0];
 
        /* set transmitter mode */
-       EU->TMAC_CNTL = (1<<4) |        /* COI: Collision ignore */
-                       //(1<<3) |      /* CSI: Carrier Sense ignore */
-                       (1<<2);         /* ATP: Automatic Transmit Padding */
+       if (link & LPA_DUPLEX)
+               EU->TMAC_CNTL = (1<<4) |        /* COI: Collision ignore */
+                               (1<<3) |        /* CSI: Carrier Sense ignore */
+                               (1<<2);         /* ATP: Automatic Transmit Padding */
+       else
+               EU->TMAC_CNTL = (1<<2);         /* ATP: Automatic Transmit Padding */
 
        /* set receive mode */
        EU->RMAC_CNTL = (1<<3) |        /* BROAD: Broadcast packets */
@@ -384,9 +409,10 @@ static void p2001_eth_init()
 }
 
 
+
 /**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
+ * DISABLE - Turn off ethernet interface
+ **************************************************************************/
 static void p2001_eth_disable(struct dev *dev __unused)
 {
        /* put the card in its initial state */
@@ -408,40 +434,52 @@ static void p2001_eth_disable(struct dev *dev __unused)
 }
 
 
+
 /**************************************************************************
-LINK - Check for valid link
-***************************************************************************/
+ * LINK - Check for valid link
+ **************************************************************************/
 static int p2001_eth_check_link(unsigned int phy)
 {
        static int status;
-       static unsigned int count;
-       count = 0;
+       static unsigned int i, physid;
+
+       /* print some information about out PHY */
+       physid = (p2001_eth_mdio_read(phy, MII_PHYSID2) << 16) |
+                 p2001_eth_mdio_read(phy, MII_PHYSID1);
+       printf("PHY %d, ID 0x%x ", phy, physid);
+       for (i = 0; mii_chip_table[i].physid; i++)
+               if (mii_chip_table[i].physid == physid) {
+                       printf("(%s).\n", mii_chip_table[i].name);
+                       break;
+               }
+       if (!mii_chip_table[i].physid)
+               printf("(unknown).\n");
 
        /* Use 0x3300 for restarting NWay */
        printf("Starting auto-negotiation... ");
-       p2001_eth_mdio_write(phy, Adr_LXT971A_Control, 0x3300);
-       if (mdio_error)
-               goto failed;
+       p2001_eth_mdio_write(phy, MII_BMCR, 0x3300);
 
-       /* Bits 1.5 and 17.7 are set to 1 once the Auto-Negotiation process to completed. */
+       /* Bit 1.5 is set once the Auto-Negotiation process is completed. */
+       i = 0;
        do {
                mdelay(500);
-               status = p2001_eth_mdio_read(phy, Adr_LXT971A_Status1);
-               if (mdio_error || (count++ > 6))        // 6*500ms = 3s timeout
+               status = p2001_eth_mdio_read(phy, MII_BMSR);
+               if (!status || (i++ > 6))       // 6*500ms = 3s timeout
                        goto failed;
-       } while (!(status & 0x20));
-       
-       /* Bits 1.2 and 17.10 are set to 1 once the link is established. */
-       if (p2001_eth_mdio_read(phy, Adr_LXT971A_Status1) & 0x04) {
-               /* Bits 17.14 and 17.9 can be used to determine the link operation conditions (speed and duplex). */
-               printf("Valid link, operating at: %sMb-%s\n",
-                       (p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x4000) ? "100" : "10",
-                       (p2001_eth_mdio_read(phy, Adr_LXT971A_Status2) & 0x0200) ? "FD" : "HD");
-                       return 1;
+       } while (!(status & BMSR_ANEGCOMPLETE));
+
+       /* Bits 1.2 is set once the link is established. */
+       if ((status = p2001_eth_mdio_read(phy, MII_BMSR)) & BMSR_LSTATUS) {
+               link = p2001_eth_mdio_read(phy, MII_ADVERTISE) &
+                      p2001_eth_mdio_read(phy, MII_LPA);
+               printf("  Valid link, operating at: %sMb-%s\n",
+                       (link & LPA_100) ? "100" : "10",
+                       (link & LPA_DUPLEX) ? "FD" : "HD");
+               return 1;
        }
 
 failed:
-       if (mdio_error)
+       if (!status)
                printf("Failed\n");
        else
                printf("No valid link\n");
@@ -449,49 +487,79 @@ failed:
 }
 
 
+
+/**************************************************************************
+ * PHYRESET - hardware reset all MII PHYs
+ **************************************************************************/
+
+/**
+ *     p2001_eth_phyreset - hardware reset all MII PHYs
+ */
+static void p2001_eth_phyreset()
+{
+       /* GPIO24/25: TX_ER2/TX_ER0 */
+       /* GPIO26/27: PHY_RESET/TX_ER1 */
+       P2001_GPIO->PIN_MUX |= 0x0018;
+       // 31-16: 0000 1111 0000 0000
+       P2001_GPIO->GPIO2_En |= 0x0400;
+
+       P2001_GPIO->GPIO2_Out |= 0x04000000;
+       P2001_GPIO->GPIO2_Out &= ~0x0400;
+       mdelay(500);
+       P2001_GPIO->GPIO2_Out |= 0x0400;
+
+#ifdef RMII
+       /* RMII_clk_sel = 0xxb  no RMII (default) */
+       /* RMII_clk_sel = 100b  COL_0 */
+       /* RMII_clk_sel = 101b  COL_1 */
+       /* RMII_clk_sel = 110b  COL_2 */
+       /* RMII_clk_sel = 111b  COL_3 */
+       P2001_GPIO->PIN_MUX |= (4 << 13);
+#endif
+}
+
+
+
 /**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
+ * PROBE - Look for an adapter, this routine's visible to the outside
+ **************************************************************************/
+
 static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused)
 {
        struct nic *nic = (struct nic *)dev;
        /* if probe_addrs is 0, then routine can use a hardwired default */
-       static int board_found;
-       static int valid_link;
 
        /* reset phys and configure mdio clk */
-       p2001_eth_mdio_init();
+       printf("Resetting PHYs...\n");
+       p2001_eth_phyreset();
+
+       /* set management unit clock divisor */
+       // max. MDIO CLK = 2.048 MHz (EU.doc)
+       P2001_MU->MU_DIV = (SYSCLK/4096000)-1;  // 2.048 MHz
+       //asm("nop \n nop");
 
        /* find the correct PHY/DMA/MAC combination */
-       MU = P2001_MU;  // MU for all PHYs is only in EU0
        printf("Searching for P2001 NICs...\n");
+       cur_phy = -1;
        for (cur_channel=0; cur_channel<4; cur_channel++) {
-               switch(cur_channel) {
-                       case 0:
-                               EU = P2001_EU0;
-                               cur_phy = 0;
-                               break;
-                       case 1:
-                               EU = P2001_EU1;
-                               cur_phy = 1;
-                               break;
-                       case 2:
-                               EU = P2001_EU2;
-                               cur_phy = 2;
-                               break;
-                       case 3:
-                               EU = P2001_EU3;
-                               cur_phy = 3;
+               EU = P2001_EU(cur_channel);
+
+               /* find next phy */
+               while (++cur_phy < 16) {
+                       //printf("phy detect %d\n", cur_phy);
+                       if (p2001_eth_mdio_read(cur_phy, MII_BMSR) != 0)
                                break;
                }
+               if (cur_phy == 16) {
+                       printf("no more MII PHYs found\n");
+                       break;
+               }
 
                /* first a non destructive test for initial value RMAC_TLEN=1518 */
-               board_found = (EU->RMAC_TLEN == 1518);
-               if (board_found) {
+               if (EU->RMAC_TLEN == 1518) {
                        printf("Checking EU%d...\n", cur_channel);
 
-                       valid_link = p2001_eth_check_link(cur_phy);
-                       if (valid_link) {
+                       if (p2001_eth_check_link(cur_phy)) {
                                /* initialize device */
                                p2001_eth_init(nic);
 
@@ -507,7 +575,6 @@ static int p2001_eth_probe(struct dev *dev, unsigned short *probe_addrs __unused
 
                                /* Report the ISA pnp id of the board */
                                dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
-                               dev->devid.vendor_id = htons(0x1234);
                                return 1;
                        }
                }
index 203b78b..49264d6 100644 (file)
@@ -100,10 +100,7 @@ typedef struct {                                   // 0x00130000U
 
 typedef union {                                                // 0x00140000U
        struct {        // write
-               volatile unsigned int TX1;              // 0x00000000U
-               volatile unsigned int TX2;              // 0x00000004U
-               volatile unsigned int TX3;              // 0x00000008U
-               volatile unsigned int TX4;              // 0x0000000CU
+               volatile unsigned int TX[4];            // 0x00000000-0x000CU
                volatile unsigned int Baudrate;         // 0x00000010U
                volatile unsigned int reserved1[0x3];
                volatile unsigned int Config;           // 0x00000020U
@@ -113,10 +110,7 @@ typedef union {                                            // 0x00140000U
        } w;            // write
        
        struct {        // read
-               volatile unsigned int RX1;              // 0x00000000U
-               volatile unsigned int RX2;              // 0x00000004U
-               volatile unsigned int RX3;              // 0x00000008U
-               volatile unsigned int RX4;              // 0x0000000CU
+               volatile unsigned int RX[4];            // 0x00000000-0x000CU
                volatile unsigned int reserved1[0x4];
                volatile unsigned int PRE_STATUS;       // 0x00000020U
                volatile unsigned int STATUS;           // 0x00000024U
@@ -168,11 +162,8 @@ typedef struct {                           // 0x0018_000U _=0,1,2,3
        volatile unsigned int TMAC_DMA_DATA;    // 0x00000FF8U
        volatile unsigned int TMAC_DMA_ADR;     // 0x00000FFCU
 } *P2001_ETH_regs_ptr;
-#define P2001_EU0 ((volatile P2001_ETH_regs_ptr) 0x00180000)
-#define P2001_EU1 ((volatile P2001_ETH_regs_ptr) 0x00181000)
-#define P2001_EU2 ((volatile P2001_ETH_regs_ptr) 0x00182000)
-#define P2001_EU3 ((volatile P2001_ETH_regs_ptr) 0x00183000)
-#define P2001_MU  P2001_EU0
+#define P2001_EU(x) ((volatile P2001_ETH_regs_ptr) ((unsigned int) 0x00180000UL+(0x1000UL*(x)))) /* x = 0..3 */
+#define P2001_MU  P2001_EU(0)
 
 #endif
 
diff --git a/src/arch/armnommu/include/lxt971a.h b/src/arch/armnommu/include/lxt971a.h
deleted file mode 100644 (file)
index 16314ec..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  Copyright (C) 2004 Tobias Lorenz
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * Intel LXT971ALE (MII-compatible PHY)
- */
-
-#define Adr_LXT971A_Control            0       /* Control Register */
-#define Adr_LXT971A_Status1            1       /* MII Status Register #1 */
-#define Adr_LXT971A_PHY_ID1            2       /* PHY Identification Register 1 */
-#define Adr_LXT971A_PHY_ID2            3       /* PHY Identification Register 2 */
-#define Adr_LXT971A_AN_Advertise       4       /* Auto Negotiation Advertisement Register */
-#define Adr_LXT971A_AN_Link_Ability    5       /* Auto Negotiation Link Partner Base Page Ability Register */
-#define Adr_LXT971A_AN_Expansion       6       /* Auto Negotiation Expansion */
-#define Adr_LXT971A_AN_Next_Page_Txmit 7       /* Auto Negotiation Next Page Transmit Register */
-#define Adr_LXT971A_AN_Link_Next_Page  8       /* Auto Negotiation Link Partner Next Page Receive Register */
-#define Adr_LXT971A_Fast_Control       9       /* Not Implemented */
-#define Adr_LXT971A_Fast_Status                10      /* Not Implemented */
-#define Adr_LXT971A_Extended_Status    15      /* Not Implemented */
-#define Adr_LXT971A_Port_Config                16      /* Configuration Register */
-#define Adr_LXT971A_Status2            17      /* Status Register #2 */
-#define Adr_LXT971A_Interrupt_Enable   18      /* Interrupt Enable Register */
-#define Adr_LXT971A_Interrupt_Status   19      /* Interrupt Status Register */
-#define Adr_LXT971A_LED_Config         20      /* LED Configuration Register */
-#define Adr_LXT971A_Transmit_Control   30      /* Transmit Control Register */
index 3f5dc3f..1cb0085 100644 (file)
@@ -20,4 +20,16 @@ typedef signed short       int16_t;
 typedef signed int         int32_t;
 typedef signed long long   int64_t;
 
+typedef signed char        s8;
+typedef unsigned char      u8;
+
+typedef signed short       s16;
+typedef unsigned short     u16;
+
+typedef signed long        s32;
+typedef unsigned int       u32;
+
+typedef signed long long   s64;
+typedef unsigned long long u64;
+
 #endif /* STDINT_H */
index 8a7ad97..505cc37 100644 (file)
@@ -13,4 +13,16 @@ typedef signed short       int16_t;
 typedef signed int         int32_t;
 typedef signed long long   int64_t;
 
+typedef signed char        s8;
+typedef unsigned char      u8;
+
+typedef signed short       s16;
+typedef unsigned short     u16;
+
+typedef signed long        s32;
+typedef unsigned int       u32;
+
+typedef signed long long   s64;
+typedef unsigned long long u64;
+
 #endif /* STDINT_H */
index db80b38..03836c8 100644 (file)
@@ -133,7 +133,7 @@ CFLAGS+=    -falign-jumps=1 -falign-loops=1 -falign-functions=1
 endif
 GCC_MINORVERSION = $(word 2, $(GCC_VERSION))
 ifneq ($(GCC_MINORVERSION),4)
-CFLAGS+=       -mcpu=i386
+CFLAGS+=       -march=i386
 endif
 
 LDFLAGS+=      -N
index 9f207ea..0c258ae 100644 (file)
@@ -1,7 +1,7 @@
 # i386-specific directories containing source files
 #
 SRCDIRS                += arch/i386/core arch/i386/transitions arch/i386/prefix
-SRCDIRS                += arch/i386/firmware/pcbios arch/i386/firmware/linuxbios
+SRCDIRS                += arch/i386/firmware/pcbios
 SRCDIRS                += arch/i386/image
 SRCDIRS                += arch/i386/drivers/bus
 SRCDIRS                += arch/i386/drivers/net
index 4e820e8..464f6d9 100644 (file)
@@ -216,7 +216,7 @@ static int elf_freebsd_debug_loader(unsigned int offset)
                                        estate.toread, estate.curaddr);
 #endif
                                /* Save where we are loading this... */
-                               symtab_load = phys_to_virt(estate.curaddr);
+                               symtab_load = estate.curaddr;
                                
                                *((long *)phys_to_virt(estate.curaddr)) = estate.toread;
                                estate.curaddr += sizeof(long);
@@ -244,7 +244,7 @@ static int elf_freebsd_debug_loader(unsigned int offset)
                                        estate.toread, estate.curaddr);
 #endif
                                /* Save where we are loading this... */
-                               symstr_load = phys_to_virt(estate.curaddr);
+                               symstr_load = estate.curaddr;
                                
                                *((long *)phys_to_virt(estate.curaddr)) = estate.toread;
                                estate.curaddr += sizeof(long);
@@ -290,7 +290,7 @@ static void elf_freebsd_boot(unsigned long entry)
                /* Assumes size of long is a power of 2... */
                bsdinfo.bi_esymtab = (symstr_load +
                        sizeof(long) +
-                       *((long *)symstr_load) +
+                       *((long *)phys_to_virt(symstr_load)) +
                        sizeof(long) - 1) & ~(sizeof(long) - 1);
                
                /* Where we will build the meta data... */
index b2c82a1..313dc61 100644 (file)
  * the prefix requested.
  *
  */
-void arch_main ( struct i386_all_regs *regs ) {
-       void (*exit_path) ( struct i386_all_regs *regs );
+void arch_main ( struct i386_all_regs *ix86 ) {
+       void (*exit_path) ( struct i386_all_regs *ix86 );
 
        /* Determine exit path requested by prefix */
-       exit_path = ( typeof ( exit_path ) ) regs->eax;
+       exit_path = ( typeof ( exit_path ) ) ix86->regs.eax;
 
        /* Call to main() */
-       regs->eax = main();
+       ix86->regs.eax = main();
 
        if ( exit_path ) {
                /* Prefix requested that we use a particular function
                 * as the exit path, so we call this function, which
                 * must not return.
                 */
-               exit_path ( regs );
+               exit_path ( ix86 );
        }
 }
index 0bc9ca9..7dad640 100644 (file)
@@ -130,8 +130,8 @@ void free_base_memory ( void *ptr, size_t size ) {
         */
        for ( ; size_kb > 0 ; free_block++, size_kb-- ) {
                /* Mark this block as unused */
-               free_block->magic = FREE_BLOCK_MAGIC;
-               free_block->size_kb = size_kb;
+               free_block->header.magic = FREE_BLOCK_MAGIC;
+               free_block->header.size_kb = size_kb;
        }
 
        /* Free up unused base memory */
@@ -161,12 +161,12 @@ static void free_unused_base_memory ( void ) {
                 * if this is not a free block
                 */
                if ( ( fbms == FBMS_MAX ) ||
-                    ( free_block->magic != FREE_BLOCK_MAGIC ) ) {
+                    ( free_block->header.magic != FREE_BLOCK_MAGIC ) ) {
                        break;
                }
 
                /* Return memory to BIOS */
-               fbms += free_block->size_kb;
+               fbms += free_block->header.size_kb;
 
                DBG ( "Freed %d kB of base memory at [%hx:0000,%hx:0000), "
                      "%d kB now free\n",
index f361aa9..f5d9e38 100644 (file)
@@ -4,22 +4,44 @@
 #include "gateA20.h"
 #include "osloader.h"
 #include "etherboot.h"
+#include "errno.h"
 
-/* An NBI image header */
+/** @file
+ *
+ * NBI image format.
+ *
+ * The Net Boot Image format is defined by the "Draft Net Boot Image
+ * Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap.  It is now
+ * considered to be a legacy format, but it still included because a
+ * large amount of software (e.g. nymph, LTSP) makes use of NBI files.
+ *
+ * Etherboot does not implement the INT 78 callback interface
+ * described by the NBI specification.  For a callback interface on
+ * x86 architecture, use PXE.
+ *
+ */
+
+/**
+ * An NBI image header
+ *
+ * Note that the length field uses a peculiar encoding; use the
+ * NBI_LENGTH() macro to decode the actual header length.
+ *
+ */
 struct imgheader {
-       unsigned long magic;
+       unsigned long magic;            /**< Magic number (NBI_MAGIC) */
        union {
-               unsigned char length;
-               unsigned long flags;
+               unsigned char length;   /**< Nibble-coded header length */
+               unsigned long flags;    /**< Image flags */
        };
-       segoff_t location;
+       segoff_t location;              /**< 16-bit seg:off header location */
        union {
-               segoff_t segoff;
-               unsigned long linear;
+               segoff_t segoff;        /**< 16-bit seg:off entry point */
+               unsigned long linear;   /**< 32-bit entry point */
        } execaddr;
 } __attribute__ (( packed ));
 
-/* NBI magic number */
+/** NBI magic number */
 #define NBI_MAGIC 0x1B031336UL
 
 /* Interpretation of the "length" fields */
@@ -31,18 +53,24 @@ struct imgheader {
 #define        NBI_PROGRAM_RETURNS(flags)      ( (flags) & ( 1 << 8 ) )
 #define        NBI_LINEAR_EXEC_ADDR(flags)     ( (flags) & ( 1 << 31 ) )
 
-/* NBI header length */
+/** NBI header length */
 #define NBI_HEADER_LENGTH      512
 
-/* An NBI segment header */
+/**
+ * An NBI segment header
+ *
+ * Note that the length field uses a peculiar encoding; use the
+ * NBI_LENGTH() macro to decode the actual header length.
+ *
+ */
 struct segheader {
-       unsigned char length;
-       unsigned char vendortag;
+       unsigned char length;           /**< Nibble-coded header length */
+       unsigned char vendortag;        /**< Vendor-defined private tag */
        unsigned char reserved;
-       unsigned char flags;
-       unsigned long loadaddr;
-       unsigned long imglength;
-       unsigned long memlength;
+       unsigned char flags;            /**< Segment flags */
+       unsigned long loadaddr;         /**< Load address */
+       unsigned long imglength;        /**< Segment length in NBI file */
+       unsigned long memlength;        /**< Segment length in memory */
 };
 
 /* Interpretation of the "flags" fields */
@@ -53,28 +81,41 @@ struct segheader {
 #define NBI_LOADADDR_BEFORE            0x03
 #define NBI_LAST_SEGHEADER(flags)      ( (flags) & ( 1 << 2 ) )
 
-/* Info passed to NBI image */
+/** Info passed to NBI image */
 static struct ebinfo loaderinfo = {
        VERSION_MAJOR, VERSION_MINOR,
        0
 };
 
-/*
+/**
  * Determine whether or not this is a valid NBI image
  *
+ * @v start            Address of the image
+ * @v len              Length of the image
+ * @v context          NBI image context
+ * @ret        True            Image is a valid NBI image
+ * @ret        False           Image is not a valid NBI image
+ * @err        EBADIMG         Image is not a valid NBI image
+ * 
+ * "context" is filled in with a context pointer suitable for passing to
+ * nbi_load() and nbi_boot().
+ *
  */
 static int nbi_probe ( physaddr_t start, off_t len, void **context ) {
        static struct imgheader imgheader;
 
        if ( (unsigned)len < sizeof ( imgheader ) ) {
                DBG ( "NBI image too small\n" );
+               errno = EBADIMG;
                return 0;
        }
 
        copy_from_phys ( &imgheader, start, sizeof ( imgheader ) );
 
-       if ( imgheader.magic != NBI_MAGIC )
+       if ( imgheader.magic != NBI_MAGIC ) {
+               errno = EBADIMG;
                return 0;
+       }
 
        /* Record image context */
        DBG ( "NBI found valid image\n" );
@@ -82,9 +123,17 @@ static int nbi_probe ( physaddr_t start, off_t len, void **context ) {
        return 1;
 }
 
-/*
+/**
  * Prepare a segment for an NBI image
  *
+ * @v dest             Address of segment
+ * @v imglen           Length of initialised-data portion of the segment
+ * @v memlen           Total length of the segment
+ * @v src              Source for initialised data
+ * @ret True           Segment can be used
+ * @ret False          Segment cannot be used
+ * @err other          As returned by prep_segment()
+ *
  */
 static int nbi_prepare_segment ( physaddr_t dest, off_t imglen, off_t memlen,
                                 physaddr_t src __unused ) {
@@ -93,9 +142,15 @@ static int nbi_prepare_segment ( physaddr_t dest, off_t imglen, off_t memlen,
        return prep_segment ( dest, dest + imglen, dest + memlen );
 }
 
-/*
+/**
  * Load a segment for an NBI image
  *
+ * @v dest             Address of segment
+ * @v imglen           Length of initialised-data portion of the segment
+ * @v memlen           Total length of the segment
+ * @v src              Source for initialised data
+ * @ret True           Always
+ *
  */
 static int nbi_load_segment ( physaddr_t dest, off_t imglen,
                              off_t memlen __unused, physaddr_t src ) {
@@ -104,9 +159,18 @@ static int nbi_load_segment ( physaddr_t dest, off_t imglen,
        return 1;
 }
 
-/*
+/**
  * Process segments of an NBI image
  *
+ * @v start            Address of the image
+ * @v len              Length of the image
+ * @v imgheader                Image header information
+ * @v process          Function to call for each segment
+ * @ret True           All segments were processed successfully
+ * @ret False          An error occurred processing a segment
+ * @err EBADIMG                Image is not a valid NBI image
+ * @err other          As returned by the "process" function
+ *
  */
 static int nbi_process_segments ( physaddr_t start, off_t len,
                                  struct imgheader *imgheader,
@@ -136,6 +200,7 @@ static int nbi_process_segments ( physaddr_t start, off_t len,
                if ( sh.length == 0 ) {
                        /* Avoid infinite loop? */
                        DBG ( "NBI invalid segheader length 0\n" );
+                       errno = EBADIMG;
                        return 0;
                }
                
@@ -159,8 +224,8 @@ static int nbi_process_segments ( physaddr_t start, off_t len,
                                - sh.loadaddr;
                        break;
                default:
-                       DBG ( "NBI can't count up to three\n" );
-                       return 0;
+                       /* Cannot be reached */
+                       DBG ( "NBI can't count up to three!\n" );
                }
 
                /* Process this segment */
@@ -175,6 +240,7 @@ static int nbi_process_segments ( physaddr_t start, off_t len,
                sh_off += NBI_LENGTH ( sh.length );
                if ( sh_off >= NBI_HEADER_LENGTH ) {
                        DBG ( "NBI header overflow\n" );
+                       errno = EBADIMG;
                        return 0;
                }
 
@@ -183,22 +249,35 @@ static int nbi_process_segments ( physaddr_t start, off_t len,
        if ( offset != len ) {
                DBG ( "NBI length mismatch (file %d, metadata %d)\n",
                      len, offset );
+               errno = EBADIMG;
                return 0;
        }
 
        return 1;
 }
 
-/*
+/**
  * Load an NBI image into memory
  *
+ * @v start            Address of image
+ * @v len              Length of image
+ * @v context          NBI context (as returned by nbi_probe())
+ * @ret True           Image loaded into memory
+ * @ret False          Image not loaded into memory
+ * @err EBADIMG                Image is not a valid NBI image
+ * @err other          As returned by nbi_process_segments()
+ * @err other          As returned by nbi_prepare_segment()
+ * @err other          As returned by nbi_load_segment()
+ *
  */
 static int nbi_load ( physaddr_t start, off_t len, void *context ) {
        struct imgheader *imgheader = context;
 
        /* If we don't have enough data give up */
-       if ( len < NBI_HEADER_LENGTH )
+       if ( len < NBI_HEADER_LENGTH ) {
+               errno = EBADIMG;
                return 0;
+       }
        
        DBG ( "NBI placing header at %hx:%hx\n",
              imgheader->location.segment, imgheader->location.offset );
@@ -220,9 +299,14 @@ static int nbi_load ( physaddr_t start, off_t len, void *context ) {
        return 1;
 }
 
-/*
+/**
  * Boot a 16-bit NBI image
  *
+ * @v imgheader                Image header information
+ * @ret Never          NBI program booted successfully
+ * @ret False          NBI program returned
+ * @err EIMGRET                NBI program returned
+ *
  */
 static int nbi_boot16 ( struct imgheader *imgheader ) {
        uint16_t basemem_bootp;
@@ -256,12 +340,23 @@ static int nbi_boot16 ( struct imgheader *imgheader ) {
                    CLOBBER ( "eax", "ecx", "edx", "ebp" ) );
        BASEMEM_PARAMETER_DONE ( bootp_data );
        
+       errno = EIMGRET;
        return 0;
 }
 
-/*
+/**
  * Boot a 32-bit NBI image
  *
+ * @v imgheader                Image header information
+ * @ret False          NBI program should not have returned
+ * @ret other          As returned by NBI program
+ * @err EIMGRET                NBI program should not have returned
+ *
+ * To distinguish between the case of an NBI program returning false,
+ * and an NBI program that should not have returned, check errno.
+ * errno will be set to EIMGRET only if the NBI program should not
+ * have returned.
+ *
  */
 static int nbi_boot32 ( struct imgheader *imgheader ) {
        int rc = 0;
@@ -270,6 +365,7 @@ static int nbi_boot32 ( struct imgheader *imgheader ) {
              imgheader->execaddr.linear );
 
        /* no gateA20_unset for PM call */
+       errno = ENOERR;
        rc = xstart32 ( imgheader->execaddr.linear,
                        virt_to_phys ( &loaderinfo ),
                        ( ( imgheader->location.segment << 4 ) +
@@ -278,15 +374,24 @@ static int nbi_boot32 ( struct imgheader *imgheader ) {
        printf ( "Secondary program returned %d\n", rc );
        if ( ! NBI_PROGRAM_RETURNS ( imgheader->flags ) ) {
                /* We shouldn't have returned */
+               errno = EIMGRET;
                rc = 0;
        }
 
        return rc;
 }
 
-/*
+/**
  * Boot a loaded NBI image
  *
+ * @v context          NBI context (as returned by nbi_probe())
+ * @ret Never          NBI program booted successfully
+ * @ret False          NBI program should not have returned
+ * @ret other          As returned by NBI program
+ * @err EIMGRET                NBI program should not have returned
+ *
+ * See also nbi_boot16() and nbi_boot32().
+ *
  */
 static int nbi_boot ( void *context ) {
        struct imgheader *imgheader = context;
@@ -298,6 +403,7 @@ static int nbi_boot ( void *context ) {
        }
 }
 
+/** Declaration of the NBI image format */
 static struct image nbi_image __image = {
        .name   = "NBI",
        .probe  = nbi_probe,
similarity index 99%
rename from src/arch/i386/core/pxe_loader.c
rename to src/arch/i386/image/pxe_image.c
index 1b61189..bd1bad3 100644 (file)
@@ -13,7 +13,6 @@
 
 #include "etherboot.h"
 #include "pxe_callbacks.h"
-#include "pxe_export.h"
 #include "pxe.h"
 
 unsigned long pxe_load_offset;
index 6e7c22d..289824e 100644 (file)
@@ -19,7 +19,7 @@ struct free_base_memory_header {
 };
 
 union free_base_memory_block {
-       struct free_base_memory_header;
+       struct free_base_memory_header header;
        char bytes[1024];
 };
 
index 73f43c3..9d090fc 100644 (file)
@@ -1,9 +1,16 @@
 #ifndef BOCHS_H
 #define BOCHS_H
 
-/*
- * This file defines "bochsbp", the magic breakpoint instruction that
- * is incredibly useful when debugging under bochs.
+/** @file
+ *
+ * bochs breakpoints
+ *
+ * This file defines @c bochsbp, the magic breakpoint instruction that
+ * is incredibly useful when debugging under bochs.  This file should
+ * never be included in production code.
+ *
+ * Use the pseudo-instruction @c bochsbp in assembly code, or the
+ * bochsbp() function in C code.
  *
  */
 
@@ -15,7 +22,7 @@
 
 #else /* ASSEMBLY */
 
-/* Breakpoint for when debugging under bochs */
+/** Breakpoint for when debugging under bochs */
 static inline void bochsbp ( void ) {
        __asm__ __volatile__ ( "xchgw %bx, %bx" );
 }
index 95b9aaa..3cef262 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef HOOKS_H
 #define HOOKS_H
 
-extern void arch_main ( struct i386_all_regs *regs );
+extern void arch_main ( struct i386_all_regs *ix86 );
 
 #endif /* HOOKS_H */
index 2edc109..1b82a98 100644 (file)
@@ -17,8 +17,8 @@
 
 /* Real-mode call parameter block, as passed to real_call */
 struct real_call_params {
-       struct i386_seg_regs;
-       struct i386_regs;
+       struct i386_seg_regs segs;
+       struct i386_regs regs;
        segoff_t rm_code;
        segoff_t reserved;
 } PACKED;
diff --git a/src/arch/i386/include/pxe_addr.h b/src/arch/i386/include/pxe_addr.h
new file mode 100644 (file)
index 0000000..954551e
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Architecture-specific portion of pxe.h for Etherboot
+ *
+ * This file has to define the types SEGOFF16_t, SEGDESC_t and
+ * SEGSEL_t for use in other PXE structures.  See pxe.h for details.
+ */
+
+#ifndef PXE_ADDR_H
+#define PXE_ADDR_H
+
+#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) )
+#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) )
+#define PTR_TO_SEGOFF16(ptr,segoff16) \
+       (segoff16).segment = SEGMENT(ptr); \
+       (segoff16).offset  = OFFSET(ptr);
+
+#endif /* PXE_ADDR_H */
index cf5a7a8..974a3c3 100644 (file)
@@ -5,12 +5,12 @@
 #define PXE_CALLBACKS_H
 
 #include "etherboot.h"
-#include "pxe.h"
+#include "pxe_types.h"
 
 typedef struct {
-       segoff_t        orig_retaddr;
-       uint16_t        opcode;
-       segoff_t        segoff;
+       SEGOFF16_t      orig_retaddr;
+       UINT16_t        opcode;
+       SEGOFF16_t      segoff;
 } PACKED pxe_call_params_t;
 
 /*
@@ -22,7 +22,7 @@ typedef struct {
 
 /* Function prototypes
  */
-extern pxe_stack_t * install_pxe_stack ( void *base );
+extern struct pxe_stack * install_pxe_stack ( void *base );
 extern void use_undi_ds_for_rm_stack ( uint16_t ds );
 extern int hook_pxe_stack ( void );
 extern int unhook_pxe_stack ( void );
diff --git a/src/arch/i386/include/pxe_types.h b/src/arch/i386/include/pxe_types.h
deleted file mode 100644 (file)
index 45736a2..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Architecture-specific portion of pxe.h for Etherboot
- *
- * This file has to define the types SEGOFF16_t, SEGDESC_t and
- * SEGSEL_t for use in other PXE structures.  See pxe.h for details.
- */
-
-#ifndef PXE_TYPES_H
-#define PXE_TYPES_H
-
-/* SEGOFF16_t defined in separate header
- */
-#include "realmode.h"
-typedef segoff_t I386_SEGOFF16_t;
-#define SEGOFF16_t I386_SEGOFF16_t
-
-#define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) )
-#define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) )
-#define PTR_TO_SEGOFF16(ptr,segoff16) \
-       (segoff16).segment = SEGMENT(ptr); \
-       (segoff16).offset  = OFFSET(ptr);
-
-typedef struct {
-       uint16_t                Seg_Addr;
-       uint32_t                Phy_Addr;
-       uint16_t                Seg_Size;
-} PACKED I386_SEGDESC_t;  /* PACKED is required, otherwise gcc pads
-                         * this out to 12 bytes -
-                         * mbrown@fensystems.co.uk (mcb30) 17/5/03 */
-#define SEGDESC_t I386_SEGDESC_t
-
-typedef        uint16_t I386_SEGSEL_t;
-#define SEGSEL_t I386_SEGSEL_t
-
-#endif /* PXE_TYPES_H */
index cd6fcfc..fe01118 100644 (file)
  *
  */
 
-/* All i386 registers, as passed in by prot_call or kir_call */
-struct real_mode_regs {
-       struct i386_all_regs;
-} PACKED;
-
 /* Segment:offset structure.  Note that the order within the structure
  * is offset:segment.
  */
index 155fffb..6665323 100644 (file)
@@ -1,9 +1,25 @@
 #ifndef REGISTERS_H
 #define REGISTERS_H
 
+/** @file
+ *
+ * i386 registers.
+ *
+ * This file defines data structures that allow easy access to i386
+ * register dumps.
+ *
+ */
+
+#include "compiler.h" /* for doxygen */
 #include "stdint.h"
 
-/* Basic 16-bit and 32-bit register types */
+/**
+ * A 16-bit general register.
+ *
+ * This type encapsulates a 16-bit register such as %ax, %bx, %cx,
+ * %dx, %si, %di, %bp or %sp.
+ *
+ */
 typedef union {
        struct {
                union {
@@ -15,12 +31,33 @@ typedef union {
        uint16_t word;
 } PACKED reg16_t;
 
+/**
+ * A 32-bit general register.
+ *
+ * This type encapsulates a 32-bit register such as %eax, %ebx, %ecx,
+ * %edx, %esi, %edi, %ebp or %esp.
+ *
+ */
 typedef union {
-       reg16_t;
+       struct {
+               union {
+                       uint8_t l;
+                       uint8_t byte;
+               };
+               uint8_t h;
+       } PACKED;
+       uint16_t word;
        uint32_t dword;
 } PACKED reg32_t;
 
-/* As created by pushal / read by popal */
+/**
+ * A 32-bit general register dump.
+ *
+ * This is the data structure that is created on the stack by the @c
+ * pushal instruction, and can be read back using the @c popal
+ * instruction.
+ *
+ */
 struct i386_regs {
        union {
                uint16_t di;
@@ -72,7 +109,31 @@ struct i386_regs {
        };
 } PACKED;
 
-/* Our pushal/popal equivalent for segment registers */
+/**
+ * A segment register dump.
+ *
+ * The i386 has no equivalent of the @c pushal or @c popal
+ * instructions for the segment registers.  We adopt the convention of
+ * always using the sequences
+ *
+ * @code
+ *
+ *   pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
+ *
+ * @endcode
+ *
+ * and
+ *
+ * @code
+ *
+ *   addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
+ *
+ * @endcode
+ *
+ * This is the data structure that is created and read back by these
+ * instruction sequences.
+ *
+ */
 struct i386_seg_regs {
        uint16_t cs;
        uint16_t ss;
@@ -82,11 +143,37 @@ struct i386_seg_regs {
        uint16_t gs;
 } PACKED;
 
-/* All i386 registers, as passed in by prot_call or kir_call */
+/**
+ * A full register dump.
+ *
+ * This data structure is created by the instructions
+ *
+ * @code
+ *
+ *   pushfl
+ *   pushal
+ *   pushw %gs ; pushw %fs ; pushw %es ; pushw %ds ; pushw %ss ; pushw %cs
+ *
+ * @endcode
+ *
+ * and can be read back using the instructions
+ *
+ * @code
+ *
+ *   addw $4, %sp ; popw %ds ; popw %es ; popw %fs ; popw %gs
+ *   popal
+ *   popfl
+ *
+ * @endcode
+ *
+ * prot_call() and kir_call() create this data structure on the stack
+ * and pass in a pointer to this structure.
+ *
+ */
 struct i386_all_regs {
-       struct i386_seg_regs;
-       struct i386_regs;
-       uint32_t i386_flags;
+       struct i386_seg_regs segs;
+       struct i386_regs regs;
+       uint32_t flags;
 } PACKED;
 
 #endif /* REGISTERS_H */
index b9ade4e..c801cf6 100644 (file)
@@ -16,4 +16,16 @@ typedef signed long long     int64_t;
 
 typedef unsigned long          physaddr_t;
 
+typedef signed char       s8;
+typedef unsigned char      u8;
+
+typedef signed short       s16;
+typedef unsigned short     u16;
+
+typedef signed int         s32;
+typedef unsigned int       u32;
+
+typedef signed long long   s64;
+typedef unsigned long long u64;
+
 #endif /* STDINT_H */
index d48b6c6..4d248b0 100644 (file)
@@ -46,7 +46,8 @@ static inline void * phys_to_virt ( unsigned long phys_addr ) {
        return ( void * ) ( phys_addr - virt_offset );
 }
 
-static inline void copy_to_phys ( physaddr_t dest, void *src, size_t len ) {
+static inline void copy_to_phys ( physaddr_t dest, const void *src,
+                                 size_t len ) {
        memcpy ( phys_to_virt ( dest ), src, len );
 }
 
index e7be062..e133392 100644 (file)
@@ -1,13 +1,31 @@
 #include "bochs.h"
 #include "realmode.h"
 
-/*
- * The "exit via INT 19" exit path.  INT 19 is the old (pre-BBS) "boot
- * system" interrupt.
+/** @file
+ *
+ * The "exit via INT 19" exit path.
+ *
+ * INT 19 is the old (pre-BBS) "boot system" interrupt.  It is
+ * conventionally used now to return from a failed boot from floppy
+ * disk.
  *
  */
 
-void exit_via_int19 ( struct real_mode_regs *rm_regs ) {
+/**
+ * Exit via INT19
+ *
+ * @v ix86             i386 register values to be loaded on exit
+ * @ret Never          -
+ * @err None           -
+ *
+ * Exit back to the BIOS by switching to real mode, reloading the
+ * registers as they were before Etherboot started, and executing INT
+ * 19.
+ *
+ * @bug Not yet implemented
+ *
+ */
+void exit_via_int19 ( struct i386_all_regs *ix86 ) {
        bochsbp();
        /* Placeholder */
 }
index 9bdc4a0..4a5bd2e 100644 (file)
@@ -110,9 +110,9 @@ UNDIROMID:
        .byte   0                       /* Structure revision */
        .byte   0,1,2                   /* PXE version 2.1.0 */
        .word   UNDILoader - _prefix    /* Offset to loader routine */
-       .word   UNDIStackSize           /* Stack segment size */
-       .word   UNDIDataSize            /* Data segment size */
-       .word   UNDICodeSize            /* Code segment size */
+       .word   _real_mode_stack_size   /* Stack segment size */
+       .word   _real_mode_stack_size   /* Data segment size */
+       .word   _pxe_stack_size         /* Code segment size */
        .ascii  "PCIR"
 
        /* The code segment contains our pxe_stack_t plus the PXE and
index 54ac1c9..6a539eb 100644 (file)
@@ -11,7 +11,7 @@
  * would cause linker symbol pollution.
  *
  */
-void i386_select_isapnp_device ( struct i386_all_regs *regs ) {
+void i386_select_isapnp_device ( struct i386_all_regs *ix86 ) {
        /*
         * PnP BIOS passes card select number in %bx and read port
         * address in %dx.
@@ -23,10 +23,10 @@ void i386_select_isapnp_device ( struct i386_all_regs *regs ) {
        } u;
 
        /* Set ISAPnP read port */
-       isapnp_read_port = regs->dx;
+       isapnp_read_port = ix86->regs.dx;
        
        /* Select ISAPnP bus and specified CSN as first boot device */
        memset ( &u, 0, sizeof ( u ) );
-       u.isapnp_loc.csn = regs->bx;
+       u.isapnp_loc.csn = ix86->regs.bx;
        select_device ( &dev, &isapnp_driver, &u.bus_loc );
 }
index c9a62d5..e143b99 100644 (file)
@@ -11,7 +11,7 @@
  * that would cause linker symbol pollution.
  *
  */
-void i386_select_pci_device ( struct i386_all_regs *regs ) {
+void i386_select_pci_device ( struct i386_all_regs *ix86 ) {
        /*
         * PCI BIOS passes busdevfn in %ax
         *
@@ -23,6 +23,6 @@ void i386_select_pci_device ( struct i386_all_regs *regs ) {
        
        /* Select PCI bus and specified busdevfn as first boot device */
        memset ( &u, 0, sizeof ( u ) );
-       u.pci_loc.busdevfn = regs->ax;
+       u.pci_loc.busdevfn = ix86->regs.ax;
        select_device ( &dev, &pci_driver, &u.bus_loc );
 }
index 79a0aa0..e0d6c57 100644 (file)
@@ -135,12 +135,12 @@ kir_to_ext:
  *
  * Call a specific C function in the internal code.  The prototype of
  * the C function must be
- *   void function ( struct real_mode_regs *rm_regs ); 
- * rm_regs will point to a struct containing the real-mode registers
+ *   void function ( struct i386_all_resg *ix86 ); 
+ * ix86 will point to a struct containing the real-mode registers
  * at entry to kir_call.
  *
  * All registers will be preserved across kir_call(), unless the C
- * function explicitly overwrites values in rm_regs.  Interrupt status
+ * function explicitly overwrites values in ix86.  Interrupt status
  * will also be preserved.
  *
  * Parameters:
@@ -151,7 +151,7 @@ kir_to_ext:
  *     lcall   $UNDI_CS, $kir_call
  *     addw    $2, %sp
  * to call in to the C function
- *      void pxe_api_call ( struct real_mode_regs *rm_regs );
+ *      void pxe_api_call ( struct i386_all_regs *ix86 );
  ****************************************************************************
  */
 
@@ -190,7 +190,7 @@ kir_call:
        pushl   %cs:ext_ds_and_es
        pushl   %cs:ext_cs_and_ss
 
-       /* Push &rm_regs on stack and call function */
+       /* Push &ix86 on stack and call function */
        pushl   %esp
        data32 call *%cs:save_function
        popl    %eax /* discard */
index 6e2f122..2e6ac47 100644 (file)
 /* Size of various C data structures */
 #define SIZEOF_I386_SEG_REGS   12
 #define SIZEOF_I386_REGS       32
-#define SIZEOF_I386_ALL_REGS   ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
+#define SIZEOF_REAL_MODE_REGS  ( SIZEOF_I386_SEG_REGS + SIZEOF_I386_REGS )
 #define SIZEOF_I386_FLAGS      4
-#define SIZEOF_REAL_MODE_REGS   ( SIZEOF_I386_ALL_REGS + SIZEOF_I386_FLAGS )
+#define SIZEOF_I386_ALL_REGS   ( SIZEOF_REAL_MODE_REGS + SIZEOF_I386_FLAGS )
 #define SIZEOF_SEGOFF_T                4
-#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_I386_ALL_REGS + 2 * SIZEOF_SEGOFF_T )
+#define SIZEOF_REAL_CALL_PARAMS ( SIZEOF_REAL_MODE_REGS + 2 * SIZEOF_SEGOFF_T )
        
        .text
        .arch i386
@@ -461,12 +461,12 @@ p2r_ljmp:
  *
  * Call a specific C function in the protected-mode code.  The
  * prototype of the C function must be
- *   void function ( struct real_mode_regs *rm_regs ); 
- * rm_regs will point to a struct containing the real-mode registers
+ *   void function ( struct i386_all_regs *ix86 ); 
+ * ix86 will point to a struct containing the real-mode registers
  * at entry to prot_call.  
  *
  * All registers will be preserved across prot_call(), unless the C
- * function explicitly overwrites values in rm_regs.  Interrupt status
+ * function explicitly overwrites values in ix86.  Interrupt status
  * will also be preserved.  Gate A20 will be enabled.
  *
  * The protected-mode code may install librm to a new location.  If it
@@ -495,12 +495,12 @@ p2r_ljmp:
  *     lcall   $LIBRM_SEGMENT, $prot_call
  *     addw    $4, %sp
  * to call in to the C function
- *      void pxe_api_call ( struct real_mode_regs *rm_regs );
+ *      void pxe_api_call ( struct i386_all_regs *ix86 );
  ****************************************************************************
  */
 
-#define PC_OFFSET_RM_REGS ( 0 )
-#define PC_OFFSET_RETADDR ( PC_OFFSET_RM_REGS + SIZEOF_REAL_MODE_REGS )
+#define PC_OFFSET_IX86 ( 0 )
+#define PC_OFFSET_RETADDR ( PC_OFFSET_IX86 + SIZEOF_I386_ALL_REGS )
 #define PC_OFFSET_FUNCTION ( PC_OFFSET_RETADDR + 4 )
        
        .code16
@@ -534,14 +534,14 @@ EXPORT(prot_call):
        call    real_to_prot
        .code32
 
-       /* Copy rm_regs from RM stack to PM stack */
-       movl    $SIZEOF_REAL_MODE_REGS, %ecx
+       /* Copy ix86 from RM stack to PM stack */
+       movl    $SIZEOF_I386_ALL_REGS, %ecx
        subl    %ecx, %esp
        movl    %esp, %edi
        pushl   %esi
        cld
        rep movsb
-       popl    %edi            /* %edi = phys addr of RM copy of rm_regs */
+       popl    %edi            /* %edi = phys addr of RM copy of ix86 */
        
        /* Switch to virtual addresses. */
        call    1f
@@ -555,7 +555,7 @@ EXPORT(prot_call):
        popl    %eax    /* discard */
        popal
 
-       /* Push &rm_regs on the stack, and call function */
+       /* Push &ix86 on the stack, and call function */
        pushl   %esp
        call    *%ebx
        popl    %eax /* discard */
@@ -564,16 +564,16 @@ EXPORT(prot_call):
        lcall   $VIRTUAL_CS, $_virt_to_phys
        popl    %eax /* discard */
 
-       /* Copy rm_regs from PM stack to RM stack, and remove rm_regs
+       /* Copy ix86 from PM stack to RM stack, and remove ix86
         * from PM stack.  (%edi still contains physical address of
-        * rm_regs on RM stack from earlier, since C code preserves
+        * ix86 on RM stack from earlier, since C code preserves
         * %edi).
         */
        movl    %esp, %esi
-       movl    $SIZEOF_REAL_MODE_REGS, %ecx
+       movl    $SIZEOF_I386_ALL_REGS, %ecx
        cld
        rep movsb
-       movl    %esi, %esp      /* remove rm_regs from PM stack */
+       movl    %esi, %esp      /* remove ix86 from PM stack */
 
        /* Obtain physical base address of installed copy of librm in
         * %ebx.  (It's possible that this *isn't* the physical base
index ffd55ff..956408f 100644 (file)
@@ -139,7 +139,7 @@ POST_RELOC_FN ( POST_RELOC_LIBRM, librm_post_reloc );
  * pointer to this new librm's entry point via es:di.
  *
  */
-void initialise_via_librm ( struct i386_all_regs *regs ) {
+void initialise_via_librm ( struct i386_all_regs *ix86 ) {
        /* Hand off to initialise() */
        initialise ();
 
@@ -147,7 +147,7 @@ void initialise_via_librm ( struct i386_all_regs *regs ) {
         * already set up by setup16, so all we need to do is point
         * es:0000 to the start of the new librm.
         */
-       regs->es = librm_base >> 4;
+       ix86->segs.es = librm_base >> 4;
 }
 
 /*
index 2f9c592..8d8270b 100644 (file)
@@ -13,4 +13,16 @@ typedef signed short       int16_t;
 typedef signed int         int32_t;
 typedef signed long        int64_t;
 
+typedef signed char        s8;
+typedef unsigned char      u8;
+
+typedef signed short       s16;
+typedef unsigned short     u16;
+
+typedef signed int         s32;
+typedef unsigned int       u32;
+
+typedef signed long       s64;
+typedef unsigned long      u64;
+
 #endif /* STDINT_H */
index d41a403..ec4b180 100644 (file)
@@ -75,6 +75,7 @@
 #undef DOWNLOAD_PROTO_HTTP     /* Hypertext Transfer Protocol */
 #undef DOWNLOAD_PROTO_TFTM     /* Multicast Trivial File Transfer Protocol */
 #undef DOWNLOAD_PROTO_SLAM     /* Scalable Local Area Multicast */
+#undef DOWNLOAD_PROTO_FSP      /* FSP? */
 
 /* @END general.h */
 
 
 /* @END general.h */
 
+/* @BEGIN general.h
+ *
+ * Image types
+ *
+ * Etherboot supports various image formats.  Select whichever ones
+ * you want to use.
+ *
+ */
+#define TAGGED_IMAGE           /* NBI image support */
+#undef ELF64_IMAGE             /* ELF64 image support */
+#undef ELF_IMAGE               /* ELF image support */
+#undef COFF_IMAGE              /* COFF image support */
+#undef IMAGE_FREEBSD           /* FreeBSD kernel image support */
+#undef IMAGE_MULTIBOOT         /* MultiBoot image support */
+#undef AOUT_IMAGE              /* a.out image support */
+#undef WINCE_IMAGE             /* WinCE image support */
+#undef PXE_IMAGE               /* PXE image support */
+
+/* @END general.h */ 
+
 /* @BEGIN general.h
  *
  * Obscure configuration options
diff --git a/src/core/background.c b/src/core/background.c
new file mode 100644 (file)
index 0000000..1cec05a
--- /dev/null
@@ -0,0 +1,47 @@
+#include "background.h"
+
+static struct background backgrounds[0] __table_start ( background );
+static struct background backgrounds_end[0] __table_end ( background );
+
+/** @file */
+
+/**
+ * Call send method of all background protocols
+ *
+ * @v timestamp                Current time
+ * @ret None           -
+ * @err None           -
+ *
+ * This calls each background protocol's background::send() method.
+ */
+void background_send ( unsigned long timestamp ) {
+       struct background *background;
+
+       for ( background = backgrounds ; background < backgrounds_end ;
+             background++ ) {
+               if ( background->send )
+                       background->send ( timestamp );
+       }
+}
+
+/**
+ * Call process method of all background protocols
+ *
+ * @v timestamp                Current time
+ * @v ptype            Packet type
+ * @v ip               IP header, if present
+ * @ret None           -
+ * @err None           -
+ *
+ * This calls each background protocol's background::process() method.
+ */
+void background_process ( unsigned long timestamp, unsigned short ptype,
+                         struct iphdr *ip ) {
+       struct background *background;
+
+       for ( background = backgrounds ; background < backgrounds_end ;
+             background++ ) {
+               if ( background->process )
+                       background->process ( timestamp, ptype, ip );
+       }
+}
index b300d4e..b1a0464 100644 (file)
@@ -1,35 +1,59 @@
-/*
- * Routines for filling a buffer with data received piecemeal, where
- * the size of the data is not necessarily known in advance.
+
+/** @file
+ *
+ * Buffer internals.
  *
- * Some protocols do not provide a mechanism for us to know the size
- * of the file before we happen to receive a particular block
- * (e.g. the final block in an MTFTP transfer).  In addition, some
- * protocols (all the multicast protocols plus any TCP-based protocol)
- * can, in theory, provide the data in any order.
+ * A buffer consists of a single, contiguous area of memory, some of
+ * which is "filled" and the remainder of which is "free".  The
+ * "filled" and "free" spaces are not necessarily contiguous.
  *
- * Rather than requiring each protocol to implement its own equivalent
- * of "dd" to arrange the data into well-sized pieces before handing
- * off to the image loader, we provide these generic buffer functions
- * which assemble a file into a single contiguous block.  The whole
- * block is then passed to the image loader.
+ * When a buffer is initialised via init_buffer(), it consists of a
+ * single free space.  As data is added to the buffer via
+ * fill_buffer(), this free space decreases and can become fragmented.
  *
+ * Each free block within a buffer starts with a "tail byte".  If the
+ * tail byte is non-zero, this indicates that the free block is the
+ * tail of the buffer, i.e. occupies all the remaining space up to the
+ * end of the buffer.  When the tail byte is non-zero, it indicates
+ * that a descriptor (a @c struct @c buffer_free_block) follows the
+ * tail byte.  The descriptor describes the size of the free block and
+ * the address of the next free block.
  *
+ * We cannot simply always start a free block with a descriptor,
+ * because it is conceivable that we will, at some point, encounter a
+ * situation in which the final free block of a buffer is too small to
+ * contain a descriptor.  Consider a protocol with a blocksize of 512
+ * downloading a 1025-byte file into a 1025-byte buffer.  Suppose that
+ * the first two blocks are received; we have now filled 1024 of the
+ * 1025 bytes in the buffer, and our only free block consists of the
+ * 1025th byte.  Using a "tail byte" solves this problem.
+ *
+ * 
  * Note that the rather convoluted way of manipulating the buffer
  * descriptors (using copy_{to,from}_phys rather than straightforward
  * pointers) is needed to cope with operation as a PXE stack, when we
  * may be running in real mode or 16-bit protected mode, and therefore
- * cannot directly access arbitrary areas of memory.
+ * cannot directly access arbitrary areas of memory using simple
+ * pointers.
  *
  */
 
 #include "stddef.h"
 #include "string.h"
 #include "io.h"
+#include "errno.h"
 #include "buffer.h"
 
-/*
- * Initialise a buffer
+/**
+ * Initialise a buffer.
+ *
+ * @v buffer           The buffer to be initialised
+ * @ret None           -
+ * @err None           -
+ *
+ * Set @c buffer->start and @c buffer->end before calling init_buffer().
+ * init_buffer() will initialise the buffer to the state of being
+ * empty.
  *
  */
 void init_buffer ( struct buffer *buffer ) {
@@ -42,77 +66,107 @@ void init_buffer ( struct buffer *buffer ) {
        DBG ( "BUFFER [%x,%x) initialised\n", buffer->start, buffer->end );
 }
 
-/*
- * Split a free block
+/**
+ * Move to the next block in the free list
  *
- */
-static void split_free_block ( struct buffer_free_block *desc,
-                              physaddr_t block, physaddr_t split ) {
-       /* If split point is before start of block, do nothing */
-       if ( split <= block )
-               return;
-
-       /* If split point is after end of block, do nothing */
-       if ( split >= desc->end )
-               return;
-
-       DBG ( "BUFFER splitting [%x,%x) -> [%x,%x) [%x,%x)\n",
-             block, desc->end, block, split, split, desc->end );
-
-       /* Create descriptor for new free block */
-       copy_to_phys ( split, &desc->tail, sizeof ( desc->tail ) );
-       if ( ! desc->tail )
-               copy_to_phys ( split, desc, sizeof ( *desc ) );
-
-       /* Update descriptor for old free block */
-       desc->tail = 0;
-       desc->next_free = split;
-       desc->end = split;
-       copy_to_phys ( block, desc, sizeof ( *desc ) );
-}
-
-/*
- * Mark a free block as used
+ * @v block            The current free block
+ * @v buffer           The buffer
+ * @ret True           Successfully moved to the next free block
+ * @ret False          There are no more free blocks
+ * @ret block          The next free block
+ * @err None           -
  *
+ * Move to the next block in the free block list, filling in @c block
+ * with the descriptor for this next block.  If the next block is the
+ * tail block, @c block will be filled with the values calculated for
+ * the tail block, otherwise the descriptor will be read from the free
+ * block itself.
+ *
+ * If there are no more free blocks, next_free_block() returns False
+ * and leaves @c block with invalid contents.
+ *
+ * Set <tt> block->next = buffer->start + buffer->fill </tt> for the
+ * first call to next_free_block().
  */
-static inline void unfree_block ( struct buffer *buffer,
-                                 struct buffer_free_block *desc,
-                                 physaddr_t prev_block ) {
-       struct buffer_free_block prev_desc;
-       
-       /* If this is the first block, just update buffer->fill */
-       if ( ! prev_block ) {
-               DBG ( "BUFFER marking [%x,%x) as used\n",
-                     buffer->start + buffer->fill, desc->end );
-               buffer->fill = desc->next_free - buffer->start;
-               return;
-       }
+static inline int next_free_block ( struct buffer_free_block *block,
+                                   struct buffer *buffer ) {
+       /* Move to next block */
+       block->start = block->next;
+
+       /* If at end of buffer, return 0 */
+       if ( block->start >= buffer->end )
+               return 0;
+
+       /* Set up ->next and ->end as for a tail block */
+       block->next = block->end = buffer->end;
+
+       /* Read tail marker from block */
+       copy_from_phys ( &block->tail, block->start, sizeof ( block->tail ) );
 
-       /* Get descriptor for previous block (which cannot be a tail block) */
-       copy_from_phys ( &prev_desc, prev_block, sizeof ( prev_desc ) );
+       /* If not a tail block, read whole block descriptor from block */
+       if ( ! block->tail ) {
+               copy_from_phys ( block, block->start, sizeof ( *block ) );
+       }
 
-       DBG ( "BUFFER marking [%x,%x) as used\n",
-             prev_desc.next_free, desc->end );
+       return 1;
+}
 
-       /* Modify descriptor for previous block and write it back */
-       prev_desc.next_free = desc->next_free;
-       copy_to_phys ( prev_block, &prev_desc, sizeof ( prev_desc ) );
+/**
+ * Store a free block descriptor
+ *
+ * @v block            The free block descriptor to store
+ * @ret None           -
+ * @err None           -
+ *
+ * Writes a free block descriptor back to a free block.  If the block
+ * is a tail block, only the tail marker will be written, otherwise
+ * the whole block descriptor will be written.
+ */
+static inline void store_free_block ( struct buffer_free_block *block ) {
+       copy_to_phys ( block->start, block,
+                      ( block->tail ?
+                        sizeof ( block->tail ) : sizeof ( *block ) ) );
 }
 
-/*
- * Write data into a buffer
+/**
+ * Write data into a buffer.
+ *
+ * @v buffer           The buffer into which to write the data
+ * @v data             The data to be written
+ * @v offset           Offset within the buffer at which to write the data
+ * @v len              Length of data to be written
+ * @ret True           Data was successfully written
+ * @ret False          Data was not written
+ * @err ENOMEM         Buffer is too small to contain the data
+ *
+ * Writes a block of data into the buffer.  The block need not be
+ * aligned to any particular boundary, or be of any particular size,
+ * and it may overlap blocks already in the buffer (i.e. duplicate
+ * calls to fill_buffer() are explicitly permitted).
  *
- * It is the caller's responsibility to ensure that the boundaries
- * between data blocks are more than sizeof(struct buffer_free_block)
- * apart.  If this condition is not satisfied, data corruption will
- * occur.
+ * @c buffer->fill will be updated to indicate the fill level of the
+ * buffer, i.e. the offset to the first gap within the buffer.  If the
+ * filesize is known (e.g. as with the SLAM protocol), you can test
+ * for end-of-file by checking for @c buffer->fill==filesize.  If the
+ * filesize is not known, but there is a well-defined end-of-file test
+ * (e.g. as with the TFTP protocol), you can read @c buffer->fill to
+ * determine the final filesize.  If blocks are known to be delivered
+ * in a strictly sequential order with no packet loss or duplication,
+ * then you can pass in @c offset==buffer->fill.
+ *
+ * @b NOTE: It is the caller's responsibility to ensure that the
+ * boundaries between data blocks are more than @c sizeof(struct @c
+ * buffer_free_block) apart.  If this condition is not satisfied, data
+ * corruption will occur.
+ *
+ * In practice this is not a problem.  Callers of fill_buffer() will
+ * be download protocols such as TFTP, and very few protocols have a
+ * block size smaller than @c sizeof(struct @c buffer_free_block).
  *
- * Returns 1 for success, 0 for failure (e.g. buffer too small).
  */
 int fill_buffer ( struct buffer *buffer, const void *data,
                  off_t offset, size_t len ) {
-       struct buffer_free_block desc;
-       physaddr_t block, prev_block;
+       struct buffer_free_block block, before, after;
        physaddr_t data_start, data_end;
 
        /* Calculate start and end addresses of data */
@@ -125,41 +179,57 @@ int fill_buffer ( struct buffer *buffer, const void *data,
        if ( data_end > buffer->end ) {
                DBG ( "BUFFER [%x,%x) too small for data!\n",
                      buffer->start, buffer->end );
+               errno = ENOMEM;
                return 0;
        }
 
-       /* Iterate through the buffer's free blocks */
-       prev_block = 0;
-       block = buffer->start + buffer->fill;
-       while ( block < buffer->end ) {
-               /* Read block descriptor */
-               desc.next_free = buffer->end;
-               desc.end = buffer->end;
-               copy_from_phys ( &desc.tail, block, sizeof ( desc.tail ) );
-               if ( ! desc.tail )
-                       copy_from_phys ( &desc, block, sizeof ( desc ) );
-
-               /* Split block at data start and end markers */
-               split_free_block ( &desc, block, data_start );
-               split_free_block ( &desc, block, data_end );
-
-               /* Block is now either completely contained by or
-                * completely outside the data area
-                */
-               if ( ( block >= data_start ) && ( block < data_end ) ) {
-                       /* Block is within the data area */
-                       unfree_block ( buffer, &desc, prev_block );
-                       copy_to_phys ( block, data + ( block - data_start ),
-                                      desc.end - block );
-               } else {
-                       /* Block is outside the data area */
-                       prev_block = block;
-               }
-
-               /* Move to next free block */
-               block = desc.next_free;
+       /* Find 'before' and 'after' blocks, if any */
+       before.start = before.end = 0;
+       after.start = after.end = buffer->end;
+       block.next = buffer->start + buffer->fill;
+       while ( next_free_block ( &block, buffer ) ) {
+               if ( ( block.start < data_start ) &&
+                    ( block.start >= before.start ) )
+                       memcpy ( &before, &block, sizeof ( before ) );
+               if ( ( block.end > data_end ) &&
+                    ( block.end <= after.end ) )
+                       memcpy ( &after, &block, sizeof ( after ) );
+       }
+
+       /* Truncate 'before' and 'after' blocks around data. */
+       if ( data_start < before.end )
+               before.end = data_start;
+       if ( data_end > after.start )
+               after.start = data_end;
+
+       /* Link 'after' block to 'before' block */
+       before.next = after.start;
+
+       /* Write back 'before' block, if any */
+       if ( before.start ) {
+               before.tail = 0;
+               ASSERT ( ( before.end - before.start ) >=
+                        sizeof ( struct buffer_free_block ) );
+               store_free_block ( &before );
+       } else {
+               buffer->fill = before.next - buffer->start;
        }
 
+       /* Write back 'after' block, if any */
+       if ( after.start < buffer->end ) {
+               ASSERT ( after.tail ||
+                        ( ( after.end - after.start ) >=
+                          sizeof ( struct buffer_free_block ) ) );
+               store_free_block ( &after );
+       }
+       
+       DBG ( "BUFFER [%x,%x) before [%x,%x) after [%x,%x)\n",
+             buffer->start, buffer->end, before.start, before.end,
+             after.start, after.end );
+       
+       /* Copy data into buffer */
+       copy_to_phys ( data_start, data, len );
+
        DBG ( "BUFFER [%x,%x) full up to %x\n",
              buffer->start, buffer->end, buffer->start + buffer->fill );
 
index f868306..7756c63 100644 (file)
@@ -74,6 +74,9 @@ void print_config ( void ) {
 #ifdef DOWNLOAD_PROTO_TFTP
                "TFTP "
 #endif
+#ifdef  DOWNLOAD_PROTO_FSP
+               "FSP "
+#endif                         
 #ifdef  DOWNLOAD_PROTO_NFS
                "NFS "
 #endif
index 2fbf863..cd3239d 100644 (file)
@@ -1,31 +1,24 @@
-/*
- * Central console switch.  Various console devices can be selected
- * via the build options CONSOLE_FIRMWARE, CONSOLE_SERIAL etc.
- * config.c picks up on these definitions and drags in the relevant
- * objects.  The linker compiles the console_drivers table for us; we
- * simply delegate to each console_driver that we find in the table.
- *
- * Doing it this way allows for changing CONSOLE_XXX without
- * rebuilding anything other than config.o.  This is extremely useful
- * for rom-o-matic.
- */
-
 #include "stddef.h"
 #include "console.h"
 
-/* FIXME: we need a cleaner way to pick up cpu_nap().  It makes a
- * real-mode call, and so we don't want to use it with LinuxBIOS.
- */
+/** @file */
+
 #include "bios.h"
 
 static struct console_driver console_drivers[0] __table_start ( console );
 static struct console_driver console_drivers_end[0] __table_end ( console );
 
-/*****************************************************************************
- * putchar : write a single character to each console
- *****************************************************************************
+/**
+ * Write a single character to each console device.
+ *
+ * @v character                Character to be written
+ * @ret None           -
+ * @err None           -
+ *
+ * The character is written out to all enabled console devices, using
+ * each device's console_driver::putchar() method.
+ *
  */
-
 void putchar ( int character ) {
        struct console_driver *console;
 
@@ -40,10 +33,18 @@ void putchar ( int character ) {
        }
 }
 
-/*****************************************************************************
- * has_input : check to see if any input is available on any console,
- * and return a pointer to the console device if so
- *****************************************************************************
+/**
+ * Check to see if any input is available on any console.
+ *
+ * @v None             -
+ * @ret console                Console device that has input available, if any.
+ * @ret NULL           No console device has input available.
+ * @err None           -
+ *
+ * All enabled console devices are checked once for available input
+ * using each device's console_driver::iskey() method.  The first
+ * console device that has available input will be returned, if any.
+ *
  */
 static struct console_driver * has_input ( void ) {
        struct console_driver *console;
@@ -58,13 +59,30 @@ static struct console_driver * has_input ( void ) {
        return NULL;
 }
 
-/*****************************************************************************
- * getchar : read a single character from any console
+/**
+ * Read a single character from any console.
+ *
+ * @v None             -
+ * @ret character      Character read from a console.
+ * @err None           -
+ *
+ * A character will be read from the first enabled console device that
+ * has input available using that console's console_driver::getchar()
+ * method.  If no console has input available to be read, this method
+ * will block.  To perform a non-blocking read, use something like
+ *
+ * @code
+ *
+ *   int key = iskey() ? getchar() : -1;
+ *
+ * @endcode
+ *
+ * The character read will not be echoed back to any console.
+ *
+ * @bug We need a cleaner way to pick up cpu_nap().  It makes a
+ * real-mode call, and so we don't want to use it with LinuxBIOS.
  *
- * NOTE : this function does not echo the character, and it does block
- *****************************************************************************
  */
-
 int getchar ( void ) {
        struct console_driver *console;
        int character = 256;
@@ -92,11 +110,20 @@ int getchar ( void ) {
        return character;
 }
 
-/*****************************************************************************
- * iskey : check to see if any input is available on any console
- *****************************************************************************
+/** Check for available input on any console.
+ *
+ * @v None             -
+ * @ret True           Input is available on a console
+ * @ret False          Input is not available on any console
+ * @err None           -
+ *
+ * All enabled console devices are checked once for available input
+ * using each device's console_driver::iskey() method.  If any console
+ * device has input available, this call will return True.  If this
+ * call returns True, you can then safely call getchar() without
+ * blocking.
+ *
  */
-
 int iskey ( void ) {
        return has_input() ? 1 : 0;
 }
diff --git a/src/core/errno.c b/src/core/errno.c
new file mode 100644 (file)
index 0000000..83c8564
--- /dev/null
@@ -0,0 +1,61 @@
+#include "etherboot.h"
+#include "errno.h"
+#include "vsprintf.h"
+
+/** @file
+ *
+ * Error codes and descriptions.
+ *
+ * This file provides the global variable #errno and the function
+ * strerror().  These function much like their standard C library
+ * equivalents.
+ *
+ * The error numbers used by Etherboot are a superset of those defined
+ * by the PXE specification version 2.1.  See errno.h for a listing of
+ * the error values.
+ *
+ * To save space in ROM images, error string tables are optional.  Use
+ * the ERRORMSG_XXX options in config.h to select which error string
+ * tables you want to include.  If an error string table is omitted,
+ * strerror() will simply return the text "Error 0x<errno>".
+ *
+ */
+
+/**
+ * Global "last error" number.
+ *
+ * This is valid only when a function has just returned indicating a
+ * failure.
+ *
+ */
+int errno;
+
+static struct errortab errortab_start[0] __table_start(errortab);
+static struct errortab errortab_end[0] __table_end(errortab);
+
+/**
+ * Retrieve string representation of error number.
+ *
+ * @v errno            Error number
+ * @ret strerror       Pointer to error text
+ *
+ * If the error is not found in the linked-in error tables, generates
+ * a generic "Error 0x<errno>" message.
+ *
+ * The pointer returned by strerror() is valid only until the next
+ * call to strerror().
+ *
+ */
+const char * strerror ( int errno ) {
+       static char *generic_message = "Error 0x0000";
+       struct errortab *errortab;
+
+       for ( errortab = errortab_start ; errortab < errortab_end ;
+             errortab++ ) {
+               if ( errortab->errno == errno )
+                       return errortab->text;
+       }
+
+       sprintf ( generic_message + 8, "%hx", errno );
+       return generic_message;
+}
index 3a112ee..e0cac22 100644 (file)
@@ -31,6 +31,9 @@ Literature dealing with the network protocols:
 #include <lib.h>
 #endif
 
+/* Linker symbols */
+extern char _bss[], _ebss[];
+
 jmp_buf        restart_etherboot;
 int    url_port;               
 
@@ -199,7 +202,7 @@ int main ( void ) {
                /* Probe boot device */
                if ( ! probe ( &dev ) ) {
                        /* Device found on bus, but probe failed */
-                       printf ( "...probe failed\n" );
+                       printf ( "...probe failed: %m\n" );
                        continue;
                }
 
@@ -212,14 +215,14 @@ int main ( void ) {
                /* Configure boot device */
                if ( ! configure ( &dev ) ) {
                        /* Configuration (e.g. DHCP) failed */
-                       printf ( "...configuration failed\n" );
+                       printf ( "...configuration failed: %m\n" );
                        continue;
                }
 
                /* Load boot file from the device */
                if ( ! autoload ( &dev, &image, &image_context ) ) {
                        /* Load (e.g. TFTP) failed */
-                       printf ( "...load failed\n" );
+                       printf ( "...load failed: %m\n" );
                        continue;
                }
 
@@ -233,7 +236,7 @@ int main ( void ) {
                /* Boot the image */
                if ( ! image->boot ( image_context ) ) {
                        /* Boot failed */
-                       printf ( "...boot failed\n" );
+                       printf ( "...boot failed: %m\n" );
                        continue;
                }
                
index 3909f54..f80caab 100644 (file)
@@ -21,13 +21,10 @@ Literature dealing with the network protocols:
 #include "resolv.h"
 #include "dev.h"
 #include "nic.h"
+#include "background.h"
 #include "elf.h" /* FOR EM_CURRENT */
 
 struct arptable_t      arptable[MAX_ARP];
-#if MULTICAST_LEVEL2
-unsigned long last_igmpv1 = 0;
-struct igmptable_t     igmptable[MAX_IGMP];
-#endif
 /* Put rom_info in .nocompress section so romprefix.S can write to it */
 struct rom_info        rom __attribute__ ((section (".text16.nocompress"))) = {0,0};
 static unsigned long   netmask;
@@ -427,7 +424,6 @@ int ip_transmit(int len, const void *buf)
        destip = ip->dest.s_addr;
        if (destip == IP_BROADCAST) {
                eth_transmit(broadcast, ETH_P_IP, len, buf);
-#ifdef MULTICAST_LEVEL1 
        } else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
                unsigned char multicast[6];
                unsigned long hdestip;
@@ -439,7 +435,6 @@ int ip_transmit(int len, const void *buf)
                multicast[4] = (hdestip >> 8) & 0xff;
                multicast[5] = hdestip & 0xff;
                eth_transmit(multicast, ETH_P_IP, len, buf);
-#endif
        } else {
                if (((destip & netmask) !=
                        (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
@@ -740,7 +735,7 @@ static int bootp(void)
                remaining_time = rfc2131_sleep_interval(BOOTP_TIMEOUT, retry++);
                stop_time = currticks() + remaining_time;
 #ifdef NO_DHCP_SUPPORT
-               if (await_reply(await_bootp, 0, NULL, timeout))
+               if (await_reply(await_bootp, 0, NULL, remaining_time))
                        return(1);
 #else
                while ( remaining_time > 0 ) {
@@ -827,140 +822,6 @@ uint16_t tcpudpchksum(struct iphdr *ip)
        return checksum;
 }
 
-#ifdef MULTICAST_LEVEL2
-static void send_igmp_reports(unsigned long now)
-{
-       int i;
-       for(i = 0; i < MAX_IGMP; i++) {
-               if (igmptable[i].time && (now >= igmptable[i].time)) {
-                       struct igmp_ip_t igmp;
-                       igmp.router_alert[0] = 0x94;
-                       igmp.router_alert[1] = 0x04;
-                       igmp.router_alert[2] = 0;
-                       igmp.router_alert[3] = 0;
-                       build_ip_hdr(igmptable[i].group.s_addr, 
-                               1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
-                       igmp.igmp.type = IGMPv2_REPORT;
-                       if (last_igmpv1 && 
-                               (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
-                               igmp.igmp.type = IGMPv1_REPORT;
-                       }
-                       igmp.igmp.response_time = 0;
-                       igmp.igmp.chksum = 0;
-                       igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
-                       igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
-                       ip_transmit(sizeof(igmp), &igmp);
-#ifdef MDEBUG
-                       printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
-#endif
-                       /* Don't send another igmp report until asked */
-                       igmptable[i].time = 0;
-               }
-       }
-}
-
-static void process_igmp(struct iphdr *ip, unsigned long now)
-{
-       struct igmp *igmp;
-       int i;
-       unsigned iplen;
-       if (!ip || (ip->protocol == IP_IGMP) ||
-               (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
-               return;
-       }
-       iplen = (ip->verhdrlen & 0xf)*4;
-       igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
-       if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
-               return;
-       if ((igmp->type == IGMP_QUERY) && 
-               (ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
-               unsigned long interval = IGMP_INTERVAL;
-               if (igmp->response_time == 0) {
-                       last_igmpv1 = now;
-               } else {
-                       interval = (igmp->response_time * TICKS_PER_SEC)/10;
-               }
-               
-#ifdef MDEBUG
-               printf("Received IGMP query for: %@\n", igmp->group.s_addr);
-#endif                        
-               for(i = 0; i < MAX_IGMP; i++) {
-                       uint32_t group = igmptable[i].group.s_addr;
-                       if ((group == 0) || (group == igmp->group.s_addr)) {
-                               unsigned long time;
-                               time = currticks() + rfc1112_sleep_interval(interval, 0);
-                               if (time < igmptable[i].time) {
-                                       igmptable[i].time = time;
-                               }
-                       }
-               }
-       }
-       if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
-               (ip->dest.s_addr == igmp->group.s_addr)) {
-#ifdef MDEBUG
-               printf("Received IGMP report for: %@\n", igmp->group.s_addr);
-#endif                        
-               for(i = 0; i < MAX_IGMP; i++) {
-                       if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
-                               igmptable[i].time != 0) {
-                               igmptable[i].time = 0;
-                       }
-               }
-       }
-}
-
-void leave_group(int slot)
-{
-       /* Be very stupid and always send a leave group message if 
-        * I have subscribed.  Imperfect but it is standards
-        * compliant, easy and reliable to implement.
-        *
-        * The optimal group leave method is to only send leave when,
-        * we were the last host to respond to a query on this group,
-        * and igmpv1 compatibility is not enabled.
-        */
-       if (igmptable[slot].group.s_addr) {
-               struct igmp_ip_t igmp;
-               igmp.router_alert[0] = 0x94;
-               igmp.router_alert[1] = 0x04;
-               igmp.router_alert[2] = 0;
-               igmp.router_alert[3] = 0;
-               build_ip_hdr(htonl(GROUP_ALL_HOSTS),
-                       1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
-               igmp.igmp.type = IGMP_LEAVE;
-               igmp.igmp.response_time = 0;
-               igmp.igmp.chksum = 0;
-               igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
-               igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
-               ip_transmit(sizeof(igmp), &igmp);
-#ifdef MDEBUG
-               printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
-#endif 
-       }
-       memset(&igmptable[slot], 0, sizeof(igmptable[0]));
-}
-
-void join_group(int slot, unsigned long group)
-{
-       /* I have already joined */
-       if (igmptable[slot].group.s_addr == group)
-               return;
-       if (igmptable[slot].group.s_addr) {
-               leave_group(slot);
-       }
-       /* Only join a group if we are given a multicast ip, this way
-        * code can be given a non-multicast (broadcast or unicast ip)
-        * and still work... 
-        */
-       if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
-               igmptable[slot].group.s_addr = group;
-               igmptable[slot].time = currticks();
-       }
-}
-#else
-#define send_igmp_reports(now) do {} while(0)
-#define process_igmp(ip, now)  do {} while(0)
-#endif
 
 #include "proto_eth_slow.c"
 
@@ -985,8 +846,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
         */
        for (;;) {
                now = currticks();
+               background_send(now);
                send_eth_slow_reports(now);
-               send_igmp_reports(now);
                result = eth_poll(1);
                if (result == 0) {
                        /* We don't have anything */
@@ -1104,8 +965,8 @@ int await_reply(reply_t reply, int ival, void *ptr, long timeout)
 #endif /* MDEBUG */
                        }
                }
+               background_process(now, ptype, ip);
                process_eth_slow(ptype, now);
-               process_igmp(ip, now);
        }
        return(0);
 }
@@ -1289,28 +1150,10 @@ RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1
 long rfc2131_sleep_interval(long base, int exp)
 {
        unsigned long tmo;
-#ifdef BACKOFF_LIMIT
        if (exp > BACKOFF_LIMIT)
                exp = BACKOFF_LIMIT;
-#endif
        tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
        return tmo;
 }
 
-#ifdef MULTICAST_LEVEL2
-/**************************************************************************
-RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
-**************************************************************************/
-long rfc1112_sleep_interval(long base, int exp)
-{
-       unsigned long divisor, tmo;
-#ifdef BACKOFF_LIMIT
-       if (exp > BACKOFF_LIMIT)
-               exp = BACKOFF_LIMIT;
-#endif
-       divisor = RAND_MAX/(base << exp);
-       tmo = random()/divisor;
-       return tmo;
-}
-#endif /* MULTICAST_LEVEL_2 */
 
diff --git a/src/core/pxe_export.c b/src/core/pxe_export.c
deleted file mode 100644 (file)
index 8b87894..0000000
+++ /dev/null
@@ -1,1445 +0,0 @@
-/* PXE API interface for Etherboot.
- *
- * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Tags used in this file:
- *
- * FIXME : obvious
- * PXESPEC : question over interpretation of the PXE spec.
- */
-
-#ifdef PXE_EXPORT
-
-#include "etherboot.h"
-#include "pxe.h"
-#include "pxe_export.h"
-#include "pxe_callbacks.h"
-#include "dev.h"
-#include "nic.h"
-#include "pci.h"
-#include "cpu.h"
-#include "timer.h"
-
-#undef DBG
-#if TRACE_PXE
-#define DBG(...) printf ( __VA_ARGS__ )
-#else
-#define DBG(...)
-#endif
-
-/* Not sure why this isn't a globally-used structure within Etherboot.
- * (Because I didn't want to use packed to prevent gcc from aligning
- * source however it liked. Also nstype is a u16, not a uint. - Ken)
- */
-typedef        struct {
-       char dest[ETH_ALEN];
-       char source[ETH_ALEN];
-       unsigned int nstype;
-} media_header_t;
-static const char broadcast_mac[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
-
-/* Global pointer to currently installed PXE stack */
-pxe_stack_t *pxe_stack = NULL;
-
-/* Various startup/shutdown routines.  The startup/shutdown call
- * sequence is incredibly badly defined in the Intel PXE spec, for
- * example:
- *
- *   PXENV_UNDI_INITIALIZE says that the parameters used to initialize
- *   the adaptor should be those supplied to the most recent
- *   PXENV_UNDI_STARTUP call.  PXENV_UNDI_STARTUP takes no parameters.
- *
- *   PXENV_UNDI_CLEANUP says that the rest of the API will not be
- *   available after making this call.  Figure 3-3 ("Early UNDI API
- *   usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
- *   call to the supposedly now unavailable PXENV_STOP_UNDI.
- *
- *   PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
- *   occupied by the PXE stack.  Figure 4-3 ("PXE IPL") shows a call
- *   to PXENV_STOP_UNDI being made after the call to
- *   PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
- *   should have been freed (and, potentially, zeroed).
- *
- *   Nothing, anywhere, seems to mention who's responsible for freeing
- *   up the base memory allocated for the stack segment.  It's not
- *   even clear whether or not this is expected to be in free base
- *   memory rather than claimed base memory.
- *
- * Consequently, we adopt a rather defensive strategy, designed to
- * work with any conceivable sequence of initialisation or shutdown
- * calls.  We have only two things that we care about:
- *
- *   1. Have we hooked INT 1A and INT 15,E820(etc.)?
- *   2. Is the NIC initialised?
- *
- * The NIC should never be initialised without the vectors being
- * hooked, similarly the vectors should never be unhooked with the NIC
- * still initialised.  We do, however, want to be able to have the
- * vectors hooked with the NIC shutdown.  We therefore have three
- * possible states:
- *
- *   1. Ready to unload: interrupts unhooked, NIC shutdown.
- *   2. Midway: interrupts hooked, NIC shutdown.
- *   3. Fully ready: interrupts hooked, NIC initialised.
- *
- * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
- * these, and the call pxe_ensure_state() to ensure that the stack is
- * in the specified state.  All our PXE API call implementations
- * should use this call to ensure that the state is as required for
- * that PXE API call.  This enables us to cope with whatever the
- * end-user's interpretation of the PXE spec may be.  It even allows
- * for someone calling e.g. PXENV_START_UNDI followed by
- * PXENV_UDP_WRITE, without bothering with any of the intervening
- * calls.
- *
- * pxe_ensure_state() returns 1 for success, 0 for failure.  In the
- * event of failure (which can arise from e.g. asking for state READY
- * when we don't know where our NIC is), the error code
- * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
- * The macros ENSURE_XXX() can be used to achieve this without lots of
- * duplicated code.
- */
-
-/* pxe_[un]hook_stack are architecture-specific and provided in
- * pxe_callbacks.c
- */
-
-int pxe_initialise_nic ( void ) {
-       if ( pxe_stack->state >= READY ) return 1;
-
-#warning "device probing mechanism has completely changed"
-#if 0
-
-       /* Check if NIC is initialised.  dev.disable is set to 0
-        * when disable() is called, so we use this.
-        */
-       if ( dev.disable ) {
-               /* NIC may have been initialised independently
-                * (e.g. when we set up the stack prior to calling the
-                * NBP).
-                */
-               pxe_stack->state = READY;
-               return 1;
-       }
-
-       /* If we already have a NIC defined, reuse that one with
-        * PROBE_AWAKE.  If one was specifed via PXENV_START_UNDI, try
-        * that one first.  Otherwise, set PROBE_FIRST.
-        */
-
-       if ( dev.state.pci.dev.use_specified == 1 ) {
-               dev.how_probe = PROBE_NEXT;
-               DBG ( " initialising NIC specified via START_UNDI" );
-       } else if ( dev.state.pci.dev.driver ) {
-               DBG ( " reinitialising NIC" );
-               dev.how_probe = PROBE_AWAKE;
-       } else {
-               DBG ( " probing for any NIC" );
-               dev.how_probe = PROBE_FIRST;
-       }
-
-       /* Call probe routine to bring up the NIC */
-       if ( eth_probe ( &dev ) != PROBE_WORKED ) {
-               DBG ( " failed" );
-               return 0;
-       }
-#endif
-       
-
-       pxe_stack->state = READY;
-       return 1;
-}
-
-int pxe_shutdown_nic ( void ) {
-       if ( pxe_stack->state <= MIDWAY ) return 1;
-
-       eth_irq ( DISABLE );
-       disable ( &dev );
-       pxe_stack->state = MIDWAY;
-       return 1;
-}
-
-int ensure_pxe_state ( pxe_stack_state_t wanted ) {
-       int success = 1;
-
-       if ( ! pxe_stack ) return 0;
-       if ( wanted >= MIDWAY )
-               success = success & hook_pxe_stack();
-       if ( wanted > MIDWAY ) {
-               success = success & pxe_initialise_nic();
-       } else {
-               success = success & pxe_shutdown_nic();
-       }
-       if ( wanted < MIDWAY )
-               success = success & unhook_pxe_stack();
-       return success;
-}
-
-#define ENSURE_CAN_UNLOAD(structure) if ( ! ensure_pxe_state(CAN_UNLOAD) ) { \
-                       structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
-                       return PXENV_EXIT_FAILURE; }
-#define ENSURE_MIDWAY(structure) if ( ! ensure_pxe_state(MIDWAY) ) { \
-                       structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
-                       return PXENV_EXIT_FAILURE; }
-#define ENSURE_READY(structure) if ( ! ensure_pxe_state(READY) ) { \
-                       structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
-                       return PXENV_EXIT_FAILURE; }
-
-/*****************************************************************************
- *
- * Actual PXE API calls
- *
- *****************************************************************************/
-
-/* PXENV_START_UNDI
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_start_undi ( t_PXENV_START_UNDI *start_undi ) {
-       unsigned char bus, devfn;
-
-       DBG ( "PXENV_START_UNDI" );
-       ENSURE_MIDWAY(start_undi);
-
-       /* Record PCI bus & devfn passed by caller, so we know which
-        * NIC they want to use.
-        *
-        * If they don't match our already-existing NIC structure, set
-        * values to ensure that the specified NIC is used at the next
-        * call to pxe_intialise_nic().
-        */
-       bus = ( start_undi->ax >> 8 ) & 0xff;
-       devfn = start_undi->ax & 0xff;
-
-#warning "device probing mechanism has completely changed"
-#if 0
-       if ( ( pci->dev.driver == NULL ) ||
-            ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
-               /* This is quite a bit of a hack and relies on
-                * knowledge of the internal operation of Etherboot's
-                * probe mechanism.
-                */
-               DBG ( " set PCI %hhx:%hhx.%hhx",
-                     bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
-               dev->type = BOOT_NIC;
-               dev->to_probe = PROBE_PCI;
-               memset ( &dev->state, 0, sizeof(dev->state) );
-               pci->advance = 1;
-               pci->dev.use_specified = 1;
-               pci->dev.bus = bus;
-               pci->dev.devfn = devfn;
-       }
-#endif
-
-       start_undi->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_STARTUP
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_startup ( t_PXENV_UNDI_STARTUP *undi_startup ) {
-       DBG ( "PXENV_UNDI_STARTUP" );
-       ENSURE_MIDWAY(undi_startup);
-
-       undi_startup->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_CLEANUP
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_cleanup ( t_PXENV_UNDI_CLEANUP *undi_cleanup ) {
-       DBG ( "PXENV_UNDI_CLEANUP" );
-       ENSURE_CAN_UNLOAD ( undi_cleanup );
-
-       undi_cleanup->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_INITIALIZE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_initialize ( t_PXENV_UNDI_INITIALIZE
-                                    *undi_initialize ) {
-       DBG ( "PXENV_UNDI_INITIALIZE" );
-       ENSURE_MIDWAY ( undi_initialize );
-
-       undi_initialize->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_RESET_ADAPTER
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_reset_adapter ( t_PXENV_UNDI_RESET_ADAPTER
-                                       *undi_reset_adapter ) {
-       DBG ( "PXENV_UNDI_RESET_ADAPTER" );
-
-       ENSURE_MIDWAY ( undi_reset_adapter );
-       ENSURE_READY ( undi_reset_adapter );
-
-       undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_SHUTDOWN
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_shutdown ( t_PXENV_UNDI_SHUTDOWN *undi_shutdown ) {
-       DBG ( "PXENV_UNDI_SHUTDOWN" );
-       ENSURE_MIDWAY ( undi_shutdown );
-
-       undi_shutdown->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_OPEN
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_open ( t_PXENV_UNDI_OPEN *undi_open ) {
-       DBG ( "PXENV_UNDI_OPEN" );
-       ENSURE_READY ( undi_open );
-
-       /* PXESPEC: This is where we choose to enable interrupts.
-        * Can't actually find where we're meant to in the PXE spec,
-        * but this should work.
-        */
-       eth_irq ( ENABLE );
-
-       undi_open->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_CLOSE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_close ( t_PXENV_UNDI_CLOSE *undi_close ) {
-       DBG ( "PXENV_UNDI_CLOSE" );
-       ENSURE_MIDWAY ( undi_close );
-
-       undi_close->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_TRANSMIT
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_transmit ( t_PXENV_UNDI_TRANSMIT *undi_transmit ) {
-       t_PXENV_UNDI_TBD *tbd;
-       const char *dest;
-       unsigned int type;
-       unsigned int length;
-       const char *data;
-       media_header_t *media_header;
-
-       DBG ( "PXENV_UNDI_TRANSMIT" );
-       ENSURE_READY ( undi_transmit );
-
-       /* We support only the "immediate" portion of the TBD.  Who
-        * knows what Intel's "engineers" were smoking when they came
-        * up with the array of transmit data blocks...
-        */
-       tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD );
-       if ( tbd->DataBlkCount > 0 ) {
-               undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
-               return PXENV_EXIT_FAILURE;
-       }
-       data = SEGOFF16_TO_PTR ( tbd->Xmit );
-       length = tbd->ImmedLength;
-
-       /* If destination is broadcast, we need to supply the MAC address */
-       if ( undi_transmit->XmitFlag == XMT_BROADCAST ) {
-               dest = broadcast_mac;
-       } else {
-               dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr );
-       }
-
-       /* We can't properly support P_UNKNOWN without rewriting all
-        * the driver transmit() methods, so we cheat: if P_UNKNOWN is
-        * specified we rip the destination address and type out of
-        * the pre-assembled packet, then skip over the header.
-        */
-       switch ( undi_transmit->Protocol ) {
-       case P_IP:      type = IP;      break;
-       case P_ARP:     type = ARP;     break;
-       case P_RARP:    type = RARP;    break;
-       case P_UNKNOWN:
-               media_header = (media_header_t*)data;
-               dest = media_header->dest;
-               type = ntohs ( media_header->nstype );
-               data += ETH_HLEN;
-               length -= ETH_HLEN;
-               break;
-       default:
-               undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
-               return PXENV_EXIT_FAILURE;
-       }
-
-       /* Send the packet */
-       eth_transmit ( dest, type, length, data );
-       
-       undi_transmit->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_SET_MCAST_ADDRESS
- *
- * Status: stub (no PXE multicast support)
- */
-PXENV_EXIT_t pxenv_undi_set_mcast_address ( t_PXENV_UNDI_SET_MCAST_ADDRESS
-                                           *undi_set_mcast_address ) {
-       DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
-       /* ENSURE_READY ( undi_set_mcast_address ); */
-       undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_SET_STATION_ADDRESS
- *
- * Status: working (deliberately incomplete)
- */
-PXENV_EXIT_t pxenv_undi_set_station_address ( t_PXENV_UNDI_SET_STATION_ADDRESS
-                                             *undi_set_station_address ) {
-       DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
-       ENSURE_READY ( undi_set_station_address );
-
-       /* We don't offer a facility to set the MAC address; this
-        * would require adding extra code to all the Etherboot
-        * drivers, for very little benefit.  If we're setting it to
-        * the current value anyway then return success, otherwise
-        * return UNSUPPORTED.
-        */
-       if ( memcmp ( nic.node_addr,
-                     &undi_set_station_address->StationAddress,
-                     ETH_ALEN ) == 0 ) {
-               undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
-               return PXENV_EXIT_SUCCESS;
-       }
-       undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_SET_PACKET_FILTER
- *
- * Status: won't implement (would require driver API changes for no
- * real benefit)
- */
-PXENV_EXIT_t pxenv_undi_set_packet_filter ( t_PXENV_UNDI_SET_PACKET_FILTER
-                                           *undi_set_packet_filter ) {
-       DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
-       /* ENSURE_READY ( undi_set_packet_filter ); */
-       undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_GET_INFORMATION
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_get_information ( t_PXENV_UNDI_GET_INFORMATION
-                                         *undi_get_information ) {
-       DBG ( "PXENV_UNDI_GET_INFORMATION" );
-       ENSURE_READY ( undi_get_information );
-
-       undi_get_information->BaseIo = nic.ioaddr;
-       undi_get_information->IntNumber = nic.irqno;
-       /* Cheat: assume all cards can cope with this */
-       undi_get_information->MaxTranUnit = ETH_MAX_MTU;
-       /* Cheat: we only ever have Ethernet cards */
-       undi_get_information->HwType = ETHER_TYPE;
-       undi_get_information->HwAddrLen = ETH_ALEN;
-       /* Cheat: assume card is always configured with its permanent
-        * node address.  This is a valid assumption within Etherboot
-        * at the time of writing.
-        */
-       memcpy ( &undi_get_information->CurrentNodeAddress, nic.node_addr,
-                ETH_ALEN );
-       memcpy ( &undi_get_information->PermNodeAddress, nic.node_addr,
-                ETH_ALEN );
-       undi_get_information->ROMAddress = 0;
-               /* nic.rom_info->rom_segment; */
-       /* We only provide the ability to receive or transmit a single
-        * packet at a time.  This is a bootloader, not an OS.
-        */
-       undi_get_information->RxBufCt = 1;
-       undi_get_information->TxBufCt = 1;
-       undi_get_information->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_GET_STATISTICS
- *
- * Status: won't implement (would require driver API changes for no
- * real benefit)
- */
-PXENV_EXIT_t pxenv_undi_get_statistics ( t_PXENV_UNDI_GET_STATISTICS
-                                        *undi_get_statistics ) {
-       DBG ( "PXENV_UNDI_GET_STATISTICS" );
-       /* ENSURE_READY ( undi_get_statistics ); */
-       undi_get_statistics->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_CLEAR_STATISTICS
- *
- * Status: won't implement (would require driver API changes for no
- * real benefit)
- */
-PXENV_EXIT_t pxenv_undi_clear_statistics ( t_PXENV_UNDI_CLEAR_STATISTICS
-                                          *undi_clear_statistics ) {
-       DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
-       /* ENSURE_READY ( undi_clear_statistics ); */
-       undi_clear_statistics->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_INITIATE_DIAGS
- *
- * Status: won't implement (would require driver API changes for no
- * real benefit)
- */
-PXENV_EXIT_t pxenv_undi_initiate_diags ( t_PXENV_UNDI_INITIATE_DIAGS
-                                        *undi_initiate_diags ) {
-       DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
-       /* ENSURE_READY ( undi_initiate_diags ); */
-       undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_FORCE_INTERRUPT
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_force_interrupt ( t_PXENV_UNDI_FORCE_INTERRUPT
-                                         *undi_force_interrupt ) {
-       DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
-       ENSURE_READY ( undi_force_interrupt );
-
-       eth_irq ( FORCE );
-       undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_GET_MCAST_ADDRESS
- *
- * Status: stub (no PXE multicast support)
- */
-PXENV_EXIT_t pxenv_undi_get_mcast_address ( t_PXENV_UNDI_GET_MCAST_ADDRESS
-                                           *undi_get_mcast_address ) {
-       DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
-       /* ENSURE_READY ( undi_get_mcast_address ); */
-       undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_UNDI_GET_NIC_TYPE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_get_nic_type ( t_PXENV_UNDI_GET_NIC_TYPE
-                                      *undi_get_nic_type ) {
-#warning "device probing mechanism has changed completely"
-
-#if 0
-       struct dev *dev = &dev;
-       
-       DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
-       ENSURE_READY ( undi_get_nic_type );
-       
-       if ( dev->to_probe == PROBE_PCI ) {
-               struct pci_device *pci = &dev->state.pci.dev;
-
-               undi_get_nic_type->NicType = PCI_NIC;
-               undi_get_nic_type->info.pci.Vendor_ID = pci->vendor;
-               undi_get_nic_type->info.pci.Dev_ID = pci->dev_id;
-               undi_get_nic_type->info.pci.Base_Class = pci->class >> 8;
-               undi_get_nic_type->info.pci.Sub_Class = pci->class & 0xff;
-               undi_get_nic_type->info.pci.BusDevFunc =
-                       ( pci->bus << 8 ) | pci->devfn;
-               /* Cheat: these fields are probably unnecessary, and
-                * would require adding extra code to pci.c.
-                */
-               undi_get_nic_type->info.pci.Prog_Intf = 0;
-               undi_get_nic_type->info.pci.Rev = 0;
-               undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
-               undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
-       } else if ( dev->to_probe == PROBE_ISA ) {
-               /* const struct isa_driver *isa = dev->state.isa.driver; */
-
-               undi_get_nic_type->NicType = PnP_NIC;
-               /* Don't think anything fills these fields in, and
-                * probably no-one will ever be interested in them.
-                */
-               undi_get_nic_type->info.pnp.EISA_Dev_ID = 0;
-               undi_get_nic_type->info.pnp.Base_Class = 0;
-               undi_get_nic_type->info.pnp.Sub_Class = 0;
-               undi_get_nic_type->info.pnp.Prog_Intf = 0;
-               undi_get_nic_type->info.pnp.CardSelNum = 0;
-       } else {
-               /* PXESPEC: There doesn't seem to be an "unknown type"
-                * defined.
-                */
-               undi_get_nic_type->NicType = 0;
-       }
-       undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-
-#endif
-}
-
-/* PXENV_UNDI_GET_IFACE_INFO
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_get_iface_info ( t_PXENV_UNDI_GET_IFACE_INFO
-                                        *undi_get_iface_info ) {
-       DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
-       ENSURE_READY ( undi_get_iface_info );
-
-       /* Just hand back some info, doesn't really matter what it is.
-        * Most PXE stacks seem to take this approach.
-        */
-       sprintf ( undi_get_iface_info->IfaceType, "Etherboot" );
-       undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
-       undi_get_iface_info->ServiceFlags = 0;
-       memset ( undi_get_iface_info->Reserved, 0,
-                sizeof(undi_get_iface_info->Reserved) );
-       undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_ISR
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR *undi_isr ) {
-       media_header_t *media_header = (media_header_t*)nic.packet;
-
-       DBG ( "PXENV_UNDI_ISR" );
-       /* We can't call ENSURE_READY, because this could be being
-        * called as part of an interrupt service routine.  Instead,
-        * we should simply die if we're not READY.
-        */
-       if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) {
-               undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
-               return PXENV_EXIT_FAILURE;
-       }
-       
-       /* Just in case some idiot actually looks at these fields when
-        * we weren't meant to fill them in...
-        */
-       undi_isr->BufferLength = 0;
-       undi_isr->FrameLength = 0;
-       undi_isr->FrameHeaderLength = 0;
-       undi_isr->ProtType = 0;
-       undi_isr->PktType = 0;
-
-       switch ( undi_isr->FuncFlag ) {
-       case PXENV_UNDI_ISR_IN_START :
-               /* Is there a packet waiting?  If so, disable
-                * interrupts on the NIC and return "it's ours".  Do
-                * *not* necessarily acknowledge the interrupt; this
-                * can happen later when eth_poll(1) is called.  As
-                * long as the interrupt is masked off so that it
-                * doesn't immediately retrigger the 8259A then all
-                * should be well.
-                */
-               DBG ( " START" );
-               if ( eth_poll ( 0 ) ) {
-                       DBG ( " OURS" );
-                       eth_irq ( DISABLE );
-                       undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
-               } else {
-                       DBG ( " NOT_OURS" );
-                       undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
-               }
-               break;
-       case PXENV_UNDI_ISR_IN_PROCESS :
-               /* Call poll(), return packet.  If no packet, return "done".
-                */
-               DBG ( " PROCESS" );
-               if ( eth_poll ( 1 ) ) {
-                       DBG ( " RECEIVE %d", nic.packetlen );
-                       if ( nic.packetlen > sizeof(pxe_stack->packet) ) {
-                               /* Should never happen */
-                               undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
-                               undi_isr->Status =
-                                       PXENV_STATUS_OUT_OF_RESOURCES;
-                               return PXENV_EXIT_FAILURE;
-                       }
-                       undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
-                       undi_isr->BufferLength = nic.packetlen;
-                       undi_isr->FrameLength = nic.packetlen;
-                       undi_isr->FrameHeaderLength = ETH_HLEN;
-                       memcpy ( pxe_stack->packet, nic.packet, nic.packetlen);
-                       PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
-                       switch ( ntohs(media_header->nstype) ) {
-                       case IP :       undi_isr->ProtType = P_IP;      break;
-                       case ARP :      undi_isr->ProtType = P_ARP;     break;
-                       case RARP :     undi_isr->ProtType = P_RARP;    break;
-                       default :       undi_isr->ProtType = P_UNKNOWN;
-                       }
-                       if ( memcmp ( media_header->dest, broadcast_mac,
-                                     sizeof(broadcast_mac) ) ) {
-                               undi_isr->PktType = XMT_BROADCAST;
-                       } else {
-                               undi_isr->PktType = XMT_DESTADDR;
-                       }
-                       break;
-               } else {
-                       /* No break - fall through to IN_GET_NEXT */
-               }
-       case PXENV_UNDI_ISR_IN_GET_NEXT :
-               /* We only ever return one frame at a time */
-               DBG ( " GET_NEXT DONE" );
-               /* Re-enable interrupts */
-               eth_irq ( ENABLE );
-               /* Force an interrupt if there's a packet still
-                * waiting, since we only handle one packet per
-                * interrupt.
-                */
-               if ( eth_poll ( 0 ) ) {
-                       DBG ( " (RETRIGGER)" );
-                       eth_irq ( FORCE );
-               }
-               undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
-               break;
-       default :
-               /* Should never happen */
-               undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
-               undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
-               return PXENV_EXIT_FAILURE;
-       }
-
-       undi_isr->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_STOP_UNDI
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_stop_undi ( t_PXENV_STOP_UNDI *stop_undi ) {
-       DBG ( "PXENV_STOP_UNDI" );
-
-       if ( ! ensure_pxe_state(CAN_UNLOAD) ) {
-               stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
-               return PXENV_EXIT_FAILURE;
-       }
-
-       stop_undi->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_OPEN
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_tftp_open ( t_PXENV_TFTP_OPEN *tftp_open ) {
-       struct sockaddr_in tftp_server;
-       struct tftpreq_info_t request;
-       struct tftpblk_info_t block;
-
-       DBG ( "PXENV_TFTP_OPEN" );
-       ENSURE_READY ( tftp_open );
-
-       /* Set server address and port */
-       tftp_server.sin_addr.s_addr = tftp_open->ServerIPAddress
-               ? tftp_open->ServerIPAddress
-               : arptable[ARP_SERVER].ipaddr.s_addr;
-       tftp_server.sin_port = ntohs ( tftp_open->TFTPPort );
-#ifdef WORK_AROUND_BPBATCH_BUG        
-       /* Force use of port 69; BpBatch tries to use port 4 for some         
-       * bizarre reason.         */        
-       tftp_server.sin_port = TFTP_PORT;
-#endif
-       /* Ignore gateway address; we can route properly */
-       /* Fill in request structure */
-       request.server = &tftp_server;
-       request.name = tftp_open->FileName;
-       request.blksize = tftp_open->PacketSize;
-       DBG ( " %@:%d/%s (%d)", tftp_open->ServerIPAddress,
-             tftp_open->TFTPPort, request.name, request.blksize );
-       if ( !request.blksize ) request.blksize = TFTP_DEFAULTSIZE_PACKET;
-       /* Make request and get first packet */
-       if ( !tftp_block ( &request, &block ) ) {
-               tftp_open->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
-               return PXENV_EXIT_FAILURE;
-       }
-       /* Fill in PacketSize */
-       tftp_open->PacketSize = request.blksize;
-       /* Store first block for later retrieval by TFTP_READ */
-       pxe_stack->tftpdata.magic_cookie = PXE_TFTP_MAGIC_COOKIE;
-       pxe_stack->tftpdata.len = block.len;
-       pxe_stack->tftpdata.eof = block.eof;
-       memcpy ( pxe_stack->tftpdata.data, block.data, block.len );
-
-       tftp_open->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_CLOSE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_tftp_close ( t_PXENV_TFTP_CLOSE *tftp_close ) {
-       DBG ( "PXENV_TFTP_CLOSE" );
-       ENSURE_READY ( tftp_close );
-       tftp_close->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_READ
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_tftp_read ( t_PXENV_TFTP_READ *tftp_read ) {
-       struct tftpblk_info_t block;
-
-       DBG ( "PXENV_TFTP_READ" );
-       ENSURE_READY ( tftp_read );
-
-       /* Do we have a block pending */
-       if ( pxe_stack->tftpdata.magic_cookie == PXE_TFTP_MAGIC_COOKIE ) {
-               block.data = pxe_stack->tftpdata.data;
-               block.len = pxe_stack->tftpdata.len;
-               block.eof = pxe_stack->tftpdata.eof;
-               block.block = 1; /* Will be the first block */
-               pxe_stack->tftpdata.magic_cookie = 0;
-       } else {
-               if ( !tftp_block ( NULL, &block ) ) {
-                       tftp_read->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
-                       return PXENV_EXIT_FAILURE;
-               }
-       }
-
-       /* Return data */
-       tftp_read->PacketNumber = block.block;
-       tftp_read->BufferSize = block.len;
-       memcpy ( SEGOFF16_TO_PTR(tftp_read->Buffer), block.data, block.len );
-       DBG ( " %d to %hx:%hx", block.len, tftp_read->Buffer.segment,
-             tftp_read->Buffer.offset );
-       tftp_read->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_READ_FILE
- *
- * Status: working
- */
-
-int pxe_tftp_read_block ( unsigned char *data, unsigned int block __unused,
-                         unsigned int len, int eof ) {
-       if ( pxe_stack->readfile.buffer ) {
-               if ( pxe_stack->readfile.offset + len >=
-                    pxe_stack->readfile.bufferlen ) return -1;
-               memcpy ( pxe_stack->readfile.buffer +
-                        pxe_stack->readfile.offset, data, len );
-       }
-       pxe_stack->readfile.offset += len;
-       return eof ? 0 : 1;
-}
-
-PXENV_EXIT_t pxenv_tftp_read_file ( t_PXENV_TFTP_READ_FILE *tftp_read_file ) {
-       struct sockaddr_in tftp_server;
-       int rc;
-
-       DBG ( "PXENV_TFTP_READ_FILE %s to [%x,%x)", tftp_read_file->FileName,
-             tftp_read_file->Buffer,
-             tftp_read_file->Buffer + tftp_read_file->BufferSize );
-       ENSURE_READY ( tftp_read_file );
-
-       /* inserted by Klaus Wittemeier */
-       /* KERNEL_BUF stores the name of the last required file */
-       /* This is a fix to make Microsoft Remote Install Services work (RIS) */
-       memcpy(KERNEL_BUF, tftp_read_file->FileName, sizeof(KERNEL_BUF));
-       /* end of insertion */
-
-       /* Set server address and port */
-       tftp_server.sin_addr.s_addr = tftp_read_file->ServerIPAddress
-               ? tftp_read_file->ServerIPAddress
-               : arptable[ARP_SERVER].ipaddr.s_addr;
-       tftp_server.sin_port = ntohs ( tftp_read_file->TFTPSrvPort );
-
-       pxe_stack->readfile.buffer = phys_to_virt ( tftp_read_file->Buffer );
-       pxe_stack->readfile.bufferlen = tftp_read_file->BufferSize;
-       pxe_stack->readfile.offset = 0;
-
-       rc = tftp ( NULL, &tftp_server, tftp_read_file->FileName,
-                   pxe_tftp_read_block );
-       if ( rc ) {
-               tftp_read_file->Status = PXENV_STATUS_FAILURE;
-               return PXENV_EXIT_FAILURE;
-       }
-       tftp_read_file->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_TFTP_GET_FSIZE
- *
- * Status: working, though ugly (we actually read the whole file,
- * because it's too ugly to make Etherboot request the tsize option
- * and hand it to us).
- */
-PXENV_EXIT_t pxenv_tftp_get_fsize ( t_PXENV_TFTP_GET_FSIZE *tftp_get_fsize ) {
-       int rc;
-
-       DBG ( "PXENV_TFTP_GET_FSIZE" );
-       ENSURE_READY ( tftp_get_fsize );
-
-       pxe_stack->readfile.buffer = NULL;
-       pxe_stack->readfile.bufferlen = 0;
-       pxe_stack->readfile.offset = 0;
-
-#warning "Rewrite pxenv_tftp_get_fsize, please"
-       if ( rc ) {
-               tftp_get_fsize->FileSize = 0;
-               tftp_get_fsize->Status = PXENV_STATUS_FAILURE;
-               return PXENV_EXIT_FAILURE;
-       }
-       tftp_get_fsize->FileSize = pxe_stack->readfile.offset;
-       tftp_get_fsize->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UDP_OPEN
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_udp_open ( t_PXENV_UDP_OPEN *udp_open ) {
-       DBG ( "PXENV_UDP_OPEN" );
-       ENSURE_READY ( udp_open );
-
-       if ( udp_open->src_ip &&
-            udp_open->src_ip != arptable[ARP_CLIENT].ipaddr.s_addr ) {
-               /* Overwrite our IP address */
-               DBG ( " with new IP %@", udp_open->src_ip );
-               arptable[ARP_CLIENT].ipaddr.s_addr = udp_open->src_ip;
-       }
-
-       udp_open->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UDP_CLOSE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_udp_close ( t_PXENV_UDP_CLOSE *udp_close ) {
-       DBG ( "PXENV_UDP_CLOSE" );
-       ENSURE_READY ( udp_close );
-       udp_close->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UDP_READ
- *
- * Status: working
- */
-int await_pxe_udp ( int ival __unused, void *ptr,
-                   unsigned short ptype __unused,
-                   struct iphdr *ip, struct udphdr *udp,
-                   struct tcphdr *tcp __unused ) {
-       t_PXENV_UDP_READ *udp_read = (t_PXENV_UDP_READ*)ptr;
-       uint16_t d_port;
-       size_t size;
-
-       /* Ignore non-UDP packets */
-       if ( !udp ) {
-               DBG ( " non-UDP" );
-               return 0;
-       }
-       
-       /* Check dest_ip */
-       if ( udp_read->dest_ip && ( udp_read->dest_ip != ip->dest.s_addr ) ) {
-               DBG ( " wrong dest IP (got %@, wanted %@)",
-                     ip->dest.s_addr, udp_read->dest_ip );
-               return 0;
-       }
-
-       /* Check dest_port */
-       d_port = ntohs ( udp_read->d_port );
-       if ( d_port && ( d_port != ntohs(udp->dest) ) ) {
-               DBG ( " wrong dest port (got %d, wanted %d)",
-                     ntohs(udp->dest), d_port );
-               return 0;
-       }
-
-       /* Copy packet to buffer and fill in information */
-       udp_read->src_ip = ip->src.s_addr;
-       udp_read->s_port = udp->src; /* Both in network order */
-       size = ntohs(udp->len) - sizeof(*udp);
-       /* Workaround: NTLDR expects us to fill these in, even though
-        * PXESPEC clearly defines them as input parameters.
-        */
-       udp_read->dest_ip = ip->dest.s_addr;
-       udp_read->d_port = udp->dest;
-       DBG ( " %@:%d->%@:%d (%d)",
-             udp_read->src_ip, ntohs(udp_read->s_port),
-             udp_read->dest_ip, ntohs(udp_read->d_port), size );
-       if ( udp_read->buffer_size < size ) {
-               /* PXESPEC: what error code should we actually return? */
-               DBG ( " buffer too small (%d)", udp_read->buffer_size );
-               udp_read->Status = PXENV_STATUS_OUT_OF_RESOURCES;
-               return 0;
-       }
-       memcpy ( SEGOFF16_TO_PTR ( udp_read->buffer ), &udp->payload, size );
-       udp_read->buffer_size = size;
-
-       return 1;
-}
-
-PXENV_EXIT_t pxenv_udp_read ( t_PXENV_UDP_READ *udp_read ) {
-       DBG ( "PXENV_UDP_READ" );
-       ENSURE_READY ( udp_read );
-
-       /* Use await_reply with a timeout of zero */
-       /* Allow await_reply to change Status if necessary */
-       udp_read->Status = PXENV_STATUS_FAILURE;
-       if ( ! await_reply ( await_pxe_udp, 0, udp_read, 0 ) ) {
-               return PXENV_EXIT_FAILURE;
-       }
-
-       udp_read->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UDP_WRITE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_udp_write ( t_PXENV_UDP_WRITE *udp_write ) {
-       uint16_t src_port;
-       uint16_t dst_port;
-       struct udppacket *packet = (struct udppacket *)nic.packet;
-       int packet_size;
-
-       DBG ( "PXENV_UDP_WRITE" );
-       ENSURE_READY ( udp_write );
-
-       /* PXE spec says source port is 2069 if not specified */
-       src_port = ntohs(udp_write->src_port);
-       if ( src_port == 0 ) src_port = 2069;
-       dst_port = ntohs(udp_write->dst_port);
-       DBG ( " %d->%@:%d (%d)", src_port, udp_write->ip, dst_port,
-             udp_write->buffer_size );
-       
-       /* FIXME: we ignore the gateway specified, since we're
-        * confident of being able to do our own routing.  We should
-        * probably allow for multiple gateways.
-        */
-       
-       /* Copy payload to packet buffer */
-       packet_size = ( (void*)&packet->payload - (void*)packet )
-               + udp_write->buffer_size;
-       if ( packet_size > ETH_FRAME_LEN ) {
-               udp_write->Status = PXENV_STATUS_OUT_OF_RESOURCES;
-               return PXENV_EXIT_FAILURE;
-       }
-       memcpy ( &packet->payload, SEGOFF16_TO_PTR(udp_write->buffer),
-                udp_write->buffer_size );
-
-       /* Transmit packet */
-       if ( ! udp_transmit ( udp_write->ip, src_port, dst_port,
-                             packet_size, packet ) ) {
-               udp_write->Status = PXENV_STATUS_FAILURE;
-               return PXENV_EXIT_FAILURE;
-       }
-
-       udp_write->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNLOAD_STACK
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_unload_stack ( t_PXENV_UNLOAD_STACK *unload_stack ) {
-       int success;
-
-       DBG ( "PXENV_UNLOAD_STACK" );
-       success = ensure_pxe_state ( CAN_UNLOAD );
-
-       /* We need to call cleanup() at some point.  The network card
-        * has already been disabled by ENSURE_CAN_UNLOAD(), but for
-        * the sake of completeness we should call the console_fini()
-        * etc. that are part of cleanup().
-        *
-        * There seems to be a lack of consensus on which is the final
-        * PXE API call to make, but it's a fairly safe bet that all
-        * the potential shutdown sequences will include a call to
-        * PXENV_UNLOAD_STACK at some point, so we may as well do it
-        * here.
-        */
-       cleanup();
-
-       if ( ! success ) {
-               unload_stack->Status = PXENV_STATUS_KEEP_ALL;
-               return PXENV_EXIT_FAILURE;
-       }
-
-       unload_stack->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_GET_CACHED_INFO
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_get_cached_info ( t_PXENV_GET_CACHED_INFO
-                                    *get_cached_info ) {
-       BOOTPLAYER *cached_info = &pxe_stack->cached_info;
-       DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
-       ENSURE_READY ( get_cached_info );
-
-       /* Fill in cached_info structure in our pxe_stack */
-
-       /* I don't think there's actually any way we can be called in
-        * the middle of a DHCP request... 
-        */
-       cached_info->opcode = BOOTP_REP;
-       /* We only have Ethernet drivers */
-       cached_info->Hardware = ETHER_TYPE;
-       cached_info->Hardlen = ETH_ALEN;
-       /* PXESPEC: "Client sets" says the spec, but who's filling in
-        * this structure?  It ain't the client.
-        */
-       cached_info->Gatehops = 0;
-       cached_info->ident = 0;
-       cached_info->seconds = 0;
-       cached_info->Flags = BOOTP_BCAST;
-       /* PXESPEC: What do 'Client' and 'Your' IP address refer to? */
-       cached_info->cip = arptable[ARP_CLIENT].ipaddr.s_addr;
-       cached_info->yip = arptable[ARP_CLIENT].ipaddr.s_addr;
-       cached_info->sip = arptable[ARP_SERVER].ipaddr.s_addr;
-       /* PXESPEC: Does "GIP" mean "Gateway" or "Relay agent"? */
-       cached_info->gip = arptable[ARP_GATEWAY].ipaddr.s_addr;
-       memcpy ( cached_info->CAddr, arptable[ARP_CLIENT].node, ETH_ALEN );
-       /* Nullify server name */
-       cached_info->Sname[0] = '\0';
-       memcpy ( cached_info->bootfile, KERNEL_BUF,
-                sizeof(cached_info->bootfile) );
-       /* Copy DHCP vendor options */
-       memcpy ( &cached_info->vendor.d, BOOTP_DATA_ADDR->bootp_reply.bp_vend,
-                sizeof(cached_info->vendor.d) );
-       
-       /* Copy to user-specified buffer, or set pointer to our buffer */
-       get_cached_info->BufferLimit = sizeof(*cached_info);
-       /* PXESPEC: says to test for Buffer == NULL *and* BufferSize =
-        * 0, but what are we supposed to do with a null buffer of
-        * non-zero size?!
-        */
-       if ( IS_NULL_SEGOFF16 ( get_cached_info->Buffer ) ) {
-               /* Point back to our buffer */
-               PTR_TO_SEGOFF16 ( cached_info, get_cached_info->Buffer );
-               get_cached_info->BufferSize = sizeof(*cached_info);
-       } else {
-               /* Copy to user buffer */
-               size_t size = sizeof(*cached_info);
-               void *buffer = SEGOFF16_TO_PTR ( get_cached_info->Buffer );
-               if ( get_cached_info->BufferSize < size )
-                       size = get_cached_info->BufferSize;
-               DBG ( " to %x", virt_to_phys ( buffer ) );
-               memcpy ( buffer, cached_info, size );
-               /* PXESPEC: Should we return an error if the user
-                * buffer is too small?  We do return the actual size
-                * of the buffer via BufferLimit, so the user does
-                * have a way to detect this already.
-                */
-       }
-
-       get_cached_info->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_RESTART_TFTP
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_restart_tftp ( t_PXENV_RESTART_TFTP *restart_tftp ) {
-       PXENV_EXIT_t tftp_exit;
-
-       DBG ( "PXENV_RESTART_TFTP" );
-       ENSURE_READY ( restart_tftp );
-
-       /* Words cannot describe the complete mismatch between the PXE
-        * specification and any possible version of reality...
-        */
-       restart_tftp->Buffer = PXE_LOAD_ADDRESS; /* Fixed by spec, apparently */
-       restart_tftp->BufferSize = get_free_base_memory() - PXE_LOAD_ADDRESS; /* Near enough */
-       DBG ( "(" );
-       tftp_exit = pxe_api_call ( PXENV_TFTP_READ_FILE, (t_PXENV_ANY*)restart_tftp );
-       DBG ( ")" );
-       if ( tftp_exit != PXENV_EXIT_SUCCESS ) return tftp_exit;
-
-       /* Fire up the new NBP */
-       restart_tftp->Status = xstartpxe();
-
-       /* Not sure what "SUCCESS" actually means, since we can only
-        * return if the new NBP failed to boot...
-        */
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_START_BASE
- *
- * Status: won't implement (requires major structural changes)
- */
-PXENV_EXIT_t pxenv_start_base ( t_PXENV_START_BASE *start_base ) {
-       DBG ( "PXENV_START_BASE" );
-       /* ENSURE_READY ( start_base ); */
-       start_base->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
-}
-
-/* PXENV_STOP_BASE
- *
- * Status: working
- */
-PXENV_EXIT_t pxenv_stop_base ( t_PXENV_STOP_BASE *stop_base ) {
-       DBG ( "PXENV_STOP_BASE" );
-
-       /* The only time we will be called is when the NBP is trying
-        * to shut down the PXE stack.  There's nothing we need to do
-        * in this call.
-        */
-
-       stop_base->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* PXENV_UNDI_LOADER
- *
- * Status: working
- *
- * NOTE: This is not a genuine PXE API call; the loader has a separate
- * entry point.  However, to simplify the mapping of the PXE API to
- * the internal Etherboot API, both are directed through the same
- * interface.
- */
-PXENV_EXIT_t pxenv_undi_loader ( undi_loader_t *loader ) {
-       uint32_t loader_phys = virt_to_phys ( loader );
-
-       DBG ( "PXENV_UNDI_LOADER" );
-       
-       /* Set UNDI DS as our real-mode stack */
-       use_undi_ds_for_rm_stack ( loader->undi_ds );
-
-       /* FIXME: These lines are borrowed from main.c.  There should
-        * probably be a single initialise() function that does all
-        * this, but it's currently split interestingly between main()
-        * and main_loop()...
-        */
-
-
-       /* CHECKME: Our init functions have probably already been
-          called by the ROM prefix's call to setup(), haven't
-          they? */
-
-
-
-       /* We have relocated; the loader pointer is now invalid */
-       loader = phys_to_virt ( loader_phys );
-
-       /* Install PXE stack to area specified by NBP */
-       install_pxe_stack ( VIRTUAL ( loader->undi_cs, 0 ) );
-       
-       /* Call pxenv_start_undi to set parameters.  Why the hell PXE
-        * requires these parameters to be provided twice is beyond
-        * the wit of any sane man.  Don't worry if it fails; the NBP
-        * should call PXENV_START_UNDI separately anyway.
-        */
-       pxenv_start_undi ( &loader->start_undi );
-       /* Unhook stack; the loader is not meant to hook int 1a etc,
-        * but the call the pxenv_start_undi will cause it to happen.
-        */
-       ENSURE_CAN_UNLOAD ( loader );
-
-       /* Fill in addresses of !PXE and PXENV+ structures */
-       PTR_TO_SEGOFF16 ( &pxe_stack->pxe, loader->pxe_ptr );
-       PTR_TO_SEGOFF16 ( &pxe_stack->pxenv, loader->pxenv_ptr );
-       
-       loader->Status = PXENV_STATUS_SUCCESS;
-       return PXENV_EXIT_SUCCESS;
-}
-
-/* API call dispatcher
- *
- * Status: complete
- */
-PXENV_EXIT_t pxe_api_call ( int opcode, t_PXENV_ANY *params ) {
-       PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
-
-       /* Set default status in case child routine fails to do so */
-       params->Status = PXENV_STATUS_FAILURE;
-
-       DBG ( "[" );
-
-       /* Hand off to relevant API routine */
-       switch ( opcode ) {
-       case PXENV_START_UNDI:
-               ret = pxenv_start_undi ( &params->start_undi );
-               break;
-       case PXENV_UNDI_STARTUP:
-               ret = pxenv_undi_startup ( &params->undi_startup );
-               break;
-       case PXENV_UNDI_CLEANUP:
-               ret = pxenv_undi_cleanup ( &params->undi_cleanup );
-               break;
-       case PXENV_UNDI_INITIALIZE:
-               ret = pxenv_undi_initialize ( &params->undi_initialize );
-               break;
-       case PXENV_UNDI_RESET_ADAPTER:
-               ret = pxenv_undi_reset_adapter ( &params->undi_reset_adapter );
-               break;
-       case PXENV_UNDI_SHUTDOWN:
-               ret = pxenv_undi_shutdown ( &params->undi_shutdown );
-               break;
-       case PXENV_UNDI_OPEN:
-               ret = pxenv_undi_open ( &params->undi_open );
-               break;
-       case PXENV_UNDI_CLOSE:
-               ret = pxenv_undi_close ( &params->undi_close );
-               break;
-       case PXENV_UNDI_TRANSMIT:
-               ret = pxenv_undi_transmit ( &params->undi_transmit );
-               break;
-       case PXENV_UNDI_SET_MCAST_ADDRESS:
-               ret = pxenv_undi_set_mcast_address (
-                                            &params->undi_set_mcast_address );
-               break;
-       case PXENV_UNDI_SET_STATION_ADDRESS:
-               ret = pxenv_undi_set_station_address (
-                                          &params->undi_set_station_address );
-               break;
-       case PXENV_UNDI_SET_PACKET_FILTER:
-               ret = pxenv_undi_set_packet_filter (
-                                            &params->undi_set_packet_filter );
-               break;
-       case PXENV_UNDI_GET_INFORMATION:
-               ret = pxenv_undi_get_information (
-                                              &params->undi_get_information );
-               break;
-       case PXENV_UNDI_GET_STATISTICS:
-               ret = pxenv_undi_get_statistics (
-                                               &params->undi_get_statistics );
-               break;
-       case PXENV_UNDI_CLEAR_STATISTICS:
-               ret = pxenv_undi_clear_statistics (
-                                             &params->undi_clear_statistics );
-               break;
-       case PXENV_UNDI_INITIATE_DIAGS:
-               ret = pxenv_undi_initiate_diags (
-                                               &params->undi_initiate_diags );
-               break;
-       case PXENV_UNDI_FORCE_INTERRUPT:
-               ret = pxenv_undi_force_interrupt (
-                                              &params->undi_force_interrupt );
-               break;
-       case PXENV_UNDI_GET_MCAST_ADDRESS:
-               ret = pxenv_undi_get_mcast_address (
-                                            &params->undi_get_mcast_address );
-               break;
-       case PXENV_UNDI_GET_NIC_TYPE:
-               ret = pxenv_undi_get_nic_type ( &params->undi_get_nic_type );
-               break;
-       case PXENV_UNDI_GET_IFACE_INFO:
-               ret = pxenv_undi_get_iface_info (
-                                               &params->undi_get_iface_info );
-               break;
-       case PXENV_UNDI_ISR:
-               ret = pxenv_undi_isr ( &params->undi_isr );
-               break;
-       case PXENV_STOP_UNDI:
-               ret = pxenv_stop_undi ( &params->stop_undi );
-               break;
-       case PXENV_TFTP_OPEN:
-               ret = pxenv_tftp_open ( &params->tftp_open );
-               break;
-       case PXENV_TFTP_CLOSE:
-               ret = pxenv_tftp_close ( &params->tftp_close );
-               break;
-       case PXENV_TFTP_READ:
-               ret = pxenv_tftp_read ( &params->tftp_read );
-               break;
-       case PXENV_TFTP_READ_FILE:
-               ret = pxenv_tftp_read_file ( &params->tftp_read_file );
-               break;
-       case PXENV_TFTP_GET_FSIZE:
-               ret = pxenv_tftp_get_fsize ( &params->tftp_get_fsize );
-               break;
-       case PXENV_UDP_OPEN:
-               ret = pxenv_udp_open ( &params->udp_open );
-               break;
-       case PXENV_UDP_CLOSE:
-               ret = pxenv_udp_close ( &params->udp_close );
-               break;
-       case PXENV_UDP_READ:
-               ret = pxenv_udp_read ( &params->udp_read );
-               break;
-       case PXENV_UDP_WRITE:
-               ret = pxenv_udp_write ( &params->udp_write );
-               break;
-       case PXENV_UNLOAD_STACK:
-               ret = pxenv_unload_stack ( &params->unload_stack );
-               break;
-       case PXENV_GET_CACHED_INFO:
-               ret = pxenv_get_cached_info ( &params->get_cached_info );
-               break;
-       case PXENV_RESTART_TFTP:
-               ret = pxenv_restart_tftp ( &params->restart_tftp );
-               break;
-       case PXENV_START_BASE:
-               ret = pxenv_start_base ( &params->start_base );
-               break;
-       case PXENV_STOP_BASE:
-               ret = pxenv_stop_base ( &params->stop_base );
-               break;
-       case PXENV_UNDI_LOADER:
-               ret = pxenv_undi_loader ( &params->loader );
-               break;
-               
-       default:
-               DBG ( "PXENV_UNKNOWN_%hx", opcode );
-               params->Status = PXENV_STATUS_UNSUPPORTED;
-               ret = PXENV_EXIT_FAILURE;
-               break;
-       }
-
-       if ( params->Status != PXENV_STATUS_SUCCESS ) {
-               DBG ( " %hx", params->Status );
-       }
-       if ( ret != PXENV_EXIT_SUCCESS ) {
-               DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
-       }
-       DBG ( "]" );
-
-       return ret;
-}
-
-#endif /* PXE_EXPORT */
index 414b450..fda0e96 100644 (file)
@@ -2,6 +2,7 @@
 #include "if_ether.h" /* for ETH_ALEN */
 #include "limits.h" /* for CHAR_BIT */
 #include "console.h"
+#include "errno.h"
 #include "vsprintf.h"
 
 #define LONG_SHIFT  ((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
 #define SHRT_SHIFT  ((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
 #define CHAR_SHIFT  ((int)((sizeof(unsigned char)*CHAR_BIT) - 4))
 
-/**************************************************************************
-PRINTF and friends
+/** @file */
 
-       Formats:
-               %[#]x   - 4 bytes int (8 hex digits, lower case)
-               %[#]X   - 4 bytes int (8 hex digits, upper case)
-               %[#]lx  - 8 bytes long (16 hex digits, lower case)
-               %[#]lX  - 8 bytes long (16 hex digits, upper case)
-               %[#]hx  - 2 bytes int (4 hex digits, lower case)
-               %[#]hX  - 2 bytes int (4 hex digits, upper case)
-               %[#]hhx - 1 byte int (2 hex digits, lower case)
-               %[#]hhX - 1 byte int (2 hex digits, upper case)
-                       - optional # prefixes 0x or 0X
-               %d      - decimal int
-               %c      - char
-               %s      - string
-               %@      - Internet address in ddd.ddd.ddd.ddd notation
-               %!      - Ethernet address in xx:xx:xx:xx:xx:xx notation
-       Note: width specification ignored
-**************************************************************************/
+/**
+ * Write a formatted string to a buffer.
+ *
+ * @v buf              Buffer into which to write the string, or NULL
+ * @v fmt              Format string
+ * @v args             Arguments corresponding to the format string
+ * @ret len            Length of string written to buffer (if buf != NULL)
+ * @ret        0               (if buf == NULL)
+ * @err None           -
+ *
+ * If #buf==NULL, then the string will be written to the console
+ * directly using putchar().
+ *
+ */
 static int vsprintf(char *buf, const char *fmt, va_list args)
 {
-       char *p, *s;
+       const char *p;
+       char *s;
        s = buf;
        for ( ; *fmt != '\0'; ++fmt) {
                if (*fmt != '%') {
@@ -49,8 +47,10 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
                if (*fmt == 's') {
                        for(p = va_arg(args, char *); *p != '\0'; p++) 
                                buf ? *s++ = *p : putchar(*p);
-               }
-               else {  /* Length of item is bounded */
+               } else if (*fmt == 'm') {
+                       for(p = strerror(errno); *p != '\0'; p++)
+                               buf ? *s++ = *p : putchar(*p);
+               } else {        /* Length of item is bounded */
                        char tmp[40], *q = tmp;
                        int alt = 0;
                        int shift = INT_SHIFT;
@@ -93,7 +93,7 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
                                        *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
                        }
                        else if (*fmt == 'd') {
-                               char *r;
+                               char *r, *t;
                                long i;
                                if (shift > INT_SHIFT) {
                                        i = va_arg(args, long);
@@ -104,17 +104,17 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
                                        *q++ = '-';
                                        i = -i;
                                }
-                               p = q;          /* save beginning of digits */
+                               t = q;          /* save beginning of digits */
                                do {
                                        *q++ = '0' + (i % 10);
                                        i /= 10;
                                } while (i);
                                /* reverse digits, stop in middle */
                                r = q;          /* don't alter q */
-                               while (--r > p) {
+                               while (--r > t) {
                                        i = *r;
-                                       *r = *p;
-                                       *p++ = i;
+                                       *r = *t;
+                                       *t++ = i;
                                }
                        }
                        else if (*fmt == '@') {
@@ -129,7 +129,7 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
                                --q;
                        }
                        else if (*fmt == '!') {
-                               char *r;
+                               const char *r;
                                p = va_arg(args, char *);
                                for (r = p + ETH_ALEN; p < r; ++p)
                                        q += sprintf(q, "%hhX:", *p);
@@ -149,6 +149,20 @@ static int vsprintf(char *buf, const char *fmt, va_list args)
        return (s - buf);
 }
 
+/**
+ * Write a formatted string to a buffer.
+ *
+ * @v buf              Buffer into which to write the string, or NULL
+ * @v fmt              Format string
+ * @v ...              Arguments corresponding to the format string
+ * @ret len            Length of string written to buffer (if buf != NULL)
+ * @ret        0               (if buf == NULL)
+ * @err None           -
+ *
+ * If #buf==NULL, then the string will be written to the console
+ * directly using putchar().
+ *
+ */
 int sprintf(char *buf, const char *fmt, ...)
 {
        va_list args;
@@ -159,6 +173,15 @@ int sprintf(char *buf, const char *fmt, ...)
        return i;
 }
 
+/**
+ * Write a formatted string to the console.
+ *
+ * @v fmt              Format string
+ * @v ...              Arguments corresponding to the format string
+ * @ret        None            -
+ * @err None           -
+ *
+ */
 void printf(const char *fmt, ...)
 {
        va_list args;
diff --git a/src/doc/build_sys.dox b/src/doc/build_sys.dox
new file mode 100644 (file)
index 0000000..9466f66
--- /dev/null
@@ -0,0 +1,419 @@
+/** @page build_sys Build system
+
+@section overview Overview
+
+Building an Etherboot image consists of three stages:
+
+  -# @ref compilation : Compiling all the source files into object files
+  -# @ref linking : Linking a particular image from selected object files
+  -# @ref finalisation : Producing the final output binary
+
+Though this is a remarkably complex process, it is important to note
+that it all happens automatically.  Whatever state your build tree is
+in, you can always type, for example
+
+@code
+
+       make bin/rtl8139.dsk
+
+@endcode
+
+and know that you will get a floppy disk image with an RTL8139 driver
+built from the current sources.
+
+@section compilation Compilation
+
+@subsection comp_overview Overview
+
+Each source file (a @c .c or a @c .S file) is compiled into a @c .o
+file in the @c bin/ directory.  Etherboot makes minimal use of
+conditional compilation (see @ref ifdef_harmful), and so you will find
+that all objects get built, even the objects that correspond to
+features that you are not intending to include in your image.  For
+example, all network card drivers will be compiled even if you are
+just building a ROM for a 3c509 card.  This is a deliberate design
+decision; please do @b not attempt to "fix" the build system to avoid
+doing this.
+
+Source files are defined to be any @c .c or @c .S files found in a
+directory listed in the Makefile variable #SRCDIRS.  You therefore do
+@b not need to edit the Makefile just because you have added a new
+source file (although you will need to edit the Makefile if you have
+added a new source directory).  To see a list of all source
+directories and source files that the build system currently knows
+about, you can use the commands
+
+@code
+
+       make srcdirs
+       make srcs
+
+@endcode
+
+Rules for compiling @c .c and @c .S files are defined in the Makefile
+variables #RULE_c and #RULE_S.  Makefile rules are automatically
+generated for each source file using these rules.  The generated rules
+can be found in the @c .d file corresponding to each source file;
+these are located in <tt>bin/deps/</tt>.  For example, the rules
+generated for <tt>drivers/net/rtl8139.c</tt> can be found in
+<tt>bin/deps/drivers/net/rtl8139.c.d</tt>.  These rules allow you to
+type, for example
+
+@code
+
+       make bin/rtl8139.o
+
+@endcode
+
+and have <tt>rtl8139.o</tt> be built from
+<tt>drivers/net/rtl8139.c</tt> using the generic rule #RULE_c for
+compiling @c .c files.
+
+You can see the full list of object files that will be built using
+
+@code
+
+       make bobjs
+
+@endcode
+
+@subsection comp_ar After compilation
+
+Once all objects have been compiled, they will be collected into a
+build library ("blib") in <tt>bin/blib.a</tt>.
+
+@subsection comp_custom Customising compilation
+
+The Makefile rules for a particular object can be customised to a
+certain extent by defining the Makefile variable CFLAGS_@<object@>.
+For example, if you were to set
+
+@code
+
+       CFLAGS_rtl8139 = -DFOO
+
+@endcode
+
+then <tt>bin/rtl8139.o</tt> would be compiled with the additional
+flags <tt>-DFOO</tt>.  To see the flags that will be used when
+compiling a particular object, you can use e.g.
+
+@code
+
+       make bin/rtl8139.flags
+
+@endcode
+
+If you need more flexibility than the CFLAGS_@<object@> mechanism
+provides, then you can exclude source files from the automatic rule
+generation process by listing them in the Makefile variable
+#NON_AUTO_SRCS.  The command
+
+@code
+
+       make autosrcs
+
+@endcode
+
+will show you which files are currently part of the automatic rule
+generation process.
+
+@subsection comp_multiobj Multiple objects
+
+A single source file can be used to generate multiple object files.
+This is used, for example, to generate the decompressing and the
+non-decompressing prefixes from the same source files.
+
+By default, a single object will be built from each source file.  To
+override the list of objects for a source file, you can define the
+Makefile variable OBJS_@<object@>.  For example, the
+<tt>arch/i386/prefix/dskprefix.S</tt> source file is built into two
+objects, <tt>bin/dskprefix.o</tt> and <tt>zdskprefix.o</tt> by
+defining the Makefile variable
+
+@code
+
+       OBJS_dskprefix = dskprefix zdskprefix
+
+@endcode
+
+Since there would be little point in building two identical objects,
+customised compilation flags (see @ref comp_custom) are defined as
+
+@code
+
+       CFLAGS_zdskprefix = -DCOMPRESS
+
+@endcode
+
+Thus, <tt>arch/i386/prefix/dskprefix.S</tt> is built into @c
+dskprefix.o using the normal set of flags, and into @c zdskprefix.o
+using the normal set of flags plus <tt>-DCOMPRESS</tt>.
+
+@subsection comp_debug Special debugging targets
+
+In addition to the basic rules #RULE_c and #RULE_S for compiling
+source files into object files, there are various other rules that can
+be useful for debugging.
+
+@subsubsection comp_debug_c_to_c Preprocessed C
+
+You can see the results of preprocessing a @c .c file (including the
+per-object flags defined via CFLAGS_@<object@> if applicable) using
+e.g.
+
+@code
+
+       make bin/rtl8139.c
+
+@endcode
+
+and examining the resulting file (<tt>bin/rtl8139.c</tt> in this
+case).
+
+@subsubsection comp_debug_x_to_s Assembler
+
+You can see the results of assembling a @c .c file, or of
+preprocessing a @c .S file, using e.g.
+
+@code
+
+       make bin/rtl8139.s
+       make bin/zdskprefix.s
+
+@endcode
+
+@subsubsection comp_debug_dbg Debugging-enabled targets
+
+You can build targets with debug messages (DBG()) enabled using e.g.
+
+@code
+
+       make bin/rtl8139.dbg.o
+       make bin/rtl8139.dbg2.o
+
+@endcode
+
+You will probably not need to use these targets directly, since a
+mechanism exists to select debugging levels at build time; see @ref
+debug.
+
+@section linking Linking
+
+@subsection link_overview Overview
+
+Etherboot is designed to be small and extremely customisable.  This is
+achieved by linking in only the features that are really wanted in any
+particular build.
+
+There are two places from which the list of desired features is
+obtained:
+
+  -# @ref link_config_h
+  -# @ref link_cmdline
+
+@subsection link_config_h config.h
+
+The config.h file is used to define global build options that are
+likely to apply to all images that you build, such as the console
+types, supported download protocols etc.  See the documentation for
+config.h for more details.
+
+@subsection link_cmdline The make command line
+
+When you type a command such as
+
+@code
+
+       make bin/dfe538.zrom
+
+@endcode
+
+it is used to derive the following information:
+
+   - We are building a compressed ROM image
+   - The DFE538 is a PCI NIC, so we need the decompressing PCI ROM prefix
+   - The PCI IDs for the DFE538 are 1186:1300
+   - The DFE538 is an rtl8139-based card, therefore we need the rtl8139 driver
+
+You can see this process in action using the command
+
+@code
+
+       make bin/dfe538.zrom.info
+
+@endcode
+
+which will print
+
+@code
+
+       Elements             : dfe538
+       Prefix               : zrom
+       Drivers              : rtl8139
+       ROM name             : dfe538
+       Media                : rom
+
+       ROM type             : pci
+       PCI vendor           : 0x1186
+       PCI device           : 0x1300
+
+       LD driver symbols    : obj_rtl8139
+       LD prefix symbols    : obj_zpciprefix
+       LD ID symbols        : pci_vendor_id=0x1186 pci_device_id=0x1300
+
+       LD target flags      :  -u obj_zpciprefix --defsym check_obj_zpciprefix=obj_zpciprefix   -u obj_rtl8139 --defsym check_obj_rtl8139=obj_rtl8139   -u obj_config --defsym check_obj_config=obj_config  --defsym pci_vendor_id=0x1186 --defsym pci_device_id=0x1300
+
+@endcode
+
+This should be interpreted as follows:
+
+@code
+
+       Elements             : dfe538
+       Prefix               : zrom
+
+@endcode
+
+"Elements" is the list of components preceding the first dot in the
+target name.  "Prefix" is the component following the first dot in the
+target name.  (It's called a "prefix" because the code that makes it a
+@c .zrom (rather than a @c .dsk, @c .zpxe or any other type of target)
+usually ends up at the start of the resulting binary image.)
+
+@code
+
+       Drivers              : rtl8139
+
+@endcode
+
+"Drivers" is the list of drivers corresponding to the "Elements".
+Most drivers support several network cards.  The PCI_ROM() and
+ISA_ROM() macros are used in the driver source files to list the cards
+that a particular driver can support.
+
+@code
+
+       ROM name             : dfe538
+
+@endcode
+
+"ROM name" is the first element in the "Elements" list.  It is used to
+select the PCI IDs for a PCI ROM.
+
+@code
+
+       Media                : rom
+
+@endcode
+
+"Media" is the "Prefix" minus the leading @c z, if any.
+
+@code
+
+       ROM type             : pci
+       PCI vendor           : 0x1186
+       PCI device           : 0x1300
+
+@endcode
+
+These are derived from the "ROM name" and the PCI_ROM() or ISA_ROM()
+macros in the driver source files.
+
+@code
+
+       LD driver symbols    : obj_rtl8139
+       LD prefix symbols    : obj_zpciprefix
+
+@endcode
+
+This is the interesting part.  At this point, we have established that
+we need the rtl8139 driver (i.e. @c rtl8139.o) and the decompressing
+PCI prefix (i.e. @c zpciprefix.o).  Our build system (via the
+compiler.h header file) arranges that every object exports a symbol
+obj_@<object@>; this can be seen by e.g.
+
+@code
+
+       objdump -t bin/rtl8139.o
+
+@endcode
+
+which will show the line
+
+@code
+
+       00000000 g       *ABS*  00000000 obj_rtl8139
+
+@endcode
+
+By instructing the linker that we need the symbols @c obj_rtl8139 and
+@c obj_zpciprefix, we can therefore ensure that these two objects are
+included in our build.  (The linker will also include any objects that
+these two objects require, since that's the whole purpose of the
+linker.)
+
+In a similar way, we always instruct the linker that we need the
+symbol @c obj_config, in order to include the object @c config.o.  @c
+config.o is used to drag in the objects that were specified via
+config.h; see @ref link_config_h.
+
+@code
+
+       LD target flags      :  -u obj_zpciprefix --defsym check_obj_zpciprefix=obj_zpciprefix   -u obj_rtl8139 --defsym check_obj_rtl8139=obj_rtl8139   -u obj_config --defsym check_obj_config=obj_config  --defsym pci_vendor_id=0x1186 --defsym pci_device_id=0x1300
+
+@endcode
+
+These are the flags that we pass to the linker in order to include the
+objects that we want in our build, and to check that they really get
+included.  (This latter check is needed to work around what seems to
+be a bug in @c ld).
+
+The linker does its job of linking all the required objects together
+into a coherent build.  The best way to see what is happening is to
+look at one of the resulting linker maps; try, for example
+
+@code
+
+       make bin/dfe538.dsk.map
+
+@endcode
+
+The linker map includes, amongst others:
+
+  - A list of which objects are included in the build, and why.
+  - The results of processing the linker script, line-by-line.
+  - A complete symbol table of the resulting build.
+
+It is worth spending time examining the linker map to see how an
+Etherboot image is assembled.
+
+Whatever format is selected, the Etherboot image is built into an ELF
+file, simply because this is the default format used by @c ld.
+
+@section finalisation Finalisation
+
+@subsection final_overview Overview
+
+The ELF file resulting from @ref linking "linking" needs to be
+converted into the final binary image.  Usually, this is just a case
+of running
+
+@code
+
+       objcopy -O binary <elf file> <output file>
+
+@endcode
+
+to convert the ELF file into a raw binary image.  Certain image
+formats require special additional treatment.
+
+@subsection final_rom ROM images
+
+ROM images must be rounded up to a suitable ROM size (e.g. 16kB or
+32kB), and certain header information such as checksums needs to be
+filled in.  This is done by the @c makerom.pl program.
+
+@section debug Debugging-enabled builds
+
+*/
diff --git a/src/doxygen.cfg b/src/doxygen.cfg
new file mode 100644 (file)
index 0000000..b0bc4b9
--- /dev/null
@@ -0,0 +1,208 @@
+# Doxyfile 1.2.17
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = Etherboot
+PROJECT_NUMBER         = 
+OUTPUT_DIRECTORY       = @BIN@/doc
+OUTPUT_LANGUAGE        = English
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = YES
+EXTRACT_STATIC         = YES
+EXTRACT_LOCAL_CLASSES  = YES
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = NO
+STRIP_FROM_PATH        = 
+INTERNAL_DOCS          = YES
+STRIP_CODE_COMMENTS    = NO
+CASE_SENSE_NAMES       = YES
+SHORT_NAMES            = NO
+HIDE_SCOPE_NAMES       = NO
+VERBATIM_HEADERS       = YES
+SHOW_INCLUDE_FILES     = NO
+JAVADOC_AUTOBRIEF      = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = YES
+INHERIT_DOCS           = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = NO
+DISTRIBUTE_GROUP_DOC   = NO
+TAB_SIZE               = 8
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ALIASES                = v=@param \
+                         ret=@retval \
+                         err=@exception
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+SHOW_USED_FILES        = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_FORMAT            = 
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = @SRCDIRS@ \
+                         include \
+                         arch/@ARCH@/include \
+                         doc
+FILE_PATTERNS          = *.c \
+                         *.h \
+                         *.S \
+                         *.dox
+RECURSIVE              = NO
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = 
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = 
+INPUT_FILTER           = 
+FILTER_SOURCE_FILES    = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = NO
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 5
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = 
+HTML_FILE_EXTENSION    = 
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = YES
+LATEX_OUTPUT           = 
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = YES
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = NO
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = YES
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = 
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = YES
+MAN_OUTPUT             = 
+MAN_EXTENSION          = 
+MAN_LINKS              = YES
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_SCHEMA             = 
+XML_DTD                = 
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = YES
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = include \
+                         arch/@ARCH@/include
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = DOXYGEN=1
+EXPAND_AS_DEFINED      = __attribute__ \
+                         PACKED \
+                         __unused \
+                         __used \
+                         __aligned \
+                         __table \
+                         __table_start \
+                         __table_end
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = 
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = YES
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = NO
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+TEMPLATE_RELATIONS     = YES
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+GRAPHICAL_HIERARCHY    = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               = 
+DOTFILE_DIRS           = 
+MAX_DOT_GRAPH_WIDTH    = 1024
+MAX_DOT_GRAPH_HEIGHT   = 1024
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO
+CGI_NAME               = 
+CGI_URL                = 
+DOC_URL                = 
+DOC_ABSPATH            = 
+BIN_ABSPATH            = 
+EXT_DOC_PATHS          = 
index 6b7c79e..6476398 100644 (file)
 *
 ***************************************************************************/
 
-#include "string.h"
-#include "timer.h"
-#include "io.h"
-#include "console.h"
-#include "isapnp.h"
-
-/*
- * We can have only one ISAPnP bus in a system.  Once the read port is
- * known and all cards have been allocated CSNs, there's nothing to be
- * gained by re-scanning for cards.
+/** @file
+ *
+ * ISAPnP bus support
+ *
+ * Etherboot orignally gained ISAPnP support in a very limited way for
+ * the 3c515 NIC.  The current implementation is almost a complete
+ * rewrite based on the ISAPnP specification, with passing reference
+ * to the Linux ISAPnP code.
+ *
+ * There can be only one ISAPnP bus in a system.  Once the read port
+ * is known and all cards have been allocated CSNs, there's nothing to
+ * be gained by re-scanning for cards.
  *
  * However, we shouldn't make scanning the ISAPnP bus an INIT_FN(),
  * because even ISAPnP probing can still screw up other devices on the
  * an ISAPnP device.
  *
  * External code (e.g. the ISAPnP ROM prefix) may already know the
- * read port address, in which case it can initialise this value.
- * Note that setting the read port address will prevent further
- * isolation from taking place; you should set the read port address
- * only if you know that devices have already been allocated CSNs.
+ * read port address, in which case it can store it in
+ * #isapnp_read_port.  Note that setting the read port address in this
+ * way will prevent further isolation from taking place; you should
+ * set the read port address only if you know that devices have
+ * already been allocated CSNs.
+ *
+ */
+
+#include "string.h"
+#include "timer.h"
+#include "io.h"
+#include "console.h"
+#include "isapnp.h"
+
+/**
+ * ISAPnP Read Port address.
  *
  */
 uint16_t isapnp_read_port;
 
-/*
+/**
  * Highest assigned CSN.
  *
- * Note that *we* do not necessarily assign CSNs; it could be done by
+ * Note that @b we do not necessarily assign CSNs; it could be done by
  * the PnP BIOS instead.  We therefore set this only when we first try
  * to Wake[CSN] a device and find that there's nothing there.  Page 16
  * (PDF page 22) of the ISAPnP spec states that "Valid Card Select
@@ -116,22 +130,56 @@ static inline uint16_t isapnp_read_word ( uint8_t address ) {
                 + isapnp_read_byte ( address + 1 ) );
 }
 
+/** Inform cards of a new read port address */
 static inline void isapnp_set_read_port ( void ) {
        isapnp_write_byte ( ISAPNP_READPORT, isapnp_read_port >> 2 );
 }
 
+/**
+ * Enter the Isolation state.
+ *
+ * Only cards currently in the Sleep state will respond to this
+ * command.
+ *
+ */
 static inline void isapnp_serialisolation ( void ) {
        isapnp_write_address ( ISAPNP_SERIALISOLATION );
 }
 
+/**
+ * Enter the Wait for Key state.
+ *
+ * All cards will respond to this command, regardless of their current
+ * state.
+ *
+ */
 static inline void isapnp_wait_for_key ( void ) {
        isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY );
 }
 
+/**
+ * Reset (i.e. remove) Card Select Number.
+ *
+ * Only cards currently in the Sleep state will respond to this
+ * command.
+ *
+ */
 static inline void isapnp_reset_csn ( void ) {
        isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN );
 }
 
+/**
+ * Place a specified card into the Config state.
+ *
+ * @v csn              Card Select Number
+ * @ret None           -
+ * @err None           -
+ *
+ * Only cards currently in the Sleep, Isolation, or Config states will
+ * respond to this command.  The card that has the specified CSN will
+ * enter the Config state, all other cards will enter the Sleep state.
+ *
+ */
 static inline void isapnp_wake ( uint8_t csn ) {
        isapnp_write_byte ( ISAPNP_WAKE, csn );
 }
@@ -144,6 +192,19 @@ static inline uint8_t isapnp_read_status ( void ) {
        return isapnp_read_byte ( ISAPNP_STATUS );
 }
 
+/**
+ * Assign a Card Select Number to a card, and enter the Config state.
+ *
+ * @v csn              Card Select Number
+ * @ret None           -
+ * @err None           -
+ *
+ * Only cards in the Isolation state will respond to this command.
+ * The isolation protocol is designed so that only one card will
+ * remain in the Isolation state by the time the isolation protocol
+ * completes.
+ *
+ */
 static inline void isapnp_write_csn ( uint8_t csn ) {
        isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
 }
@@ -174,12 +235,20 @@ static void isapnp_delay ( void ) {
        udelay ( 1000 );
 }
 
-/*
- * The linear feedback shift register as described in Appendix B of
- * the PnP ISA spec.  The hardware implementation uses eight D-type
- * latches and two XOR gates.  I think this is probably the smallest
- * possible implementation in software.  Six instructions when input_bit
- * is a constant 0 (for isapnp_send_key).  :)
+/**
+ * Linear feedback shift register.
+ *
+ * @v lfsr             Current value of the LFSR
+ * @v input_bit                Current input bit to the LFSR
+ * @ret lfsr           Next value of the LFSR
+ * @err None           -
+ *
+ * This routine implements the linear feedback shift register as
+ * described in Appendix B of the PnP ISA spec.  The hardware
+ * implementation uses eight D-type latches and two XOR gates.  I
+ * think this is probably the smallest possible implementation in
+ * software.  Six instructions when input_bit is a constant 0 (for
+ * isapnp_send_key).  :)
  *
  */
 static inline uint8_t isapnp_lfsr_next ( uint8_t lfsr, int input_bit ) {
@@ -190,8 +259,11 @@ static inline uint8_t isapnp_lfsr_next ( uint8_t lfsr, int input_bit ) {
        return lfsr_next;
 }
 
-/*
- * Send the ISAPnP initiation key
+/**
+ * Send the ISAPnP initiation key.
+ *
+ * Sending the key causes all ISAPnP cards that are currently in the
+ * Wait for Key state to transition into the Sleep state.
  *
  */
 static void isapnp_send_key ( void ) {
@@ -209,8 +281,12 @@ static void isapnp_send_key ( void ) {
        }
 }
 
-/*
- *  Compute ISAPnP identifier checksum
+/**
+ * Compute ISAPnP identifier checksum
+ *
+ * @v identifier               ISAPnP identifier
+ * @ret checksum               Expected checksum value
+ * @err None                   -
  *
  */
 static uint8_t isapnp_checksum ( struct isapnp_identifier *identifier ) {
@@ -248,9 +324,16 @@ static inline uint8_t isapnp_peek_byte ( void ) {
        return 0xff;
 }
 
-/*
- * Read n bytes of resource data from the current location.  If buf is
- * NULL, discard data.
+/**
+ * Read resource data.
+ *
+ * @v buf              Buffer in which to store data, or NULL
+ * @v bytes            Number of bytes to read
+ * @ret None           -
+ * @err None           -
+ *
+ * Resource data is read from the current location.  If #buf is NULL,
+ * the data is discarded.
  *
  */
 static void isapnp_peek ( uint8_t *buf, size_t bytes ) {
@@ -265,12 +348,19 @@ static void isapnp_peek ( uint8_t *buf, size_t bytes ) {
        }
 }
 
-/*
- * Scan through the resource data until we find a particular tag, and
- * read its contents into a buffer.
+/**
+ * Find a tag within the resource data.
  *
- * It is the caller's responsibility to ensure that buf is large
- * enough to contain a tag of the requested size.
+ * @v wanted_tag       The tag that we're looking for
+ * @v buf              Buffer in which to store the tag's contents
+ * @ret True           Tag was found
+ * @ret False          Tag was not found
+ * @err None           -
+ *
+ * Scan through the resource data until we find a particular tag, and
+ * read its contents into a buffer.  It is the caller's responsibility
+ * to ensure that #buf is large enough to contain a tag of the
+ * requested size.
  *
  */
 static int isapnp_find_tag ( uint8_t wanted_tag, uint8_t *buf ) {
@@ -300,10 +390,13 @@ static int isapnp_find_tag ( uint8_t wanted_tag, uint8_t *buf ) {
        return 0;
 }
 
-/*
- * Try isolating ISAPnP cards at the current read port.  Return the
- * number of ISAPnP cards found.  <0 indicates "try a new read port",
- * 0 indicates "definitely no cards".
+/**
+ * Try isolating ISAPnP cards at the current read port.
+ *
+ * @ret \>0            Number of ISAPnP cards found
+ * @ret 0              There are no ISAPnP cards in the system
+ * @ret \<0            A conflict was detected; try a new read port
+ * @err None           -
  *
  * The state diagram on page 18 (PDF page 24) of the PnP ISA spec
  * gives the best overview of what happens here.
@@ -429,8 +522,8 @@ static int isapnp_try_isolate ( void ) {
        return csn;
 }
 
-/*
- * Isolate all ISAPnP cards, locating a valid read port in the process.
+/**
+ * Find a valid read port and isolate all ISAPnP cards.
  *
  */
 static void isapnp_isolate ( void ) {
@@ -450,10 +543,17 @@ static void isapnp_isolate ( void ) {
        }
 }
 
-/*
- * Increment a bus_loc structure to the next possible ISAPnP location.
- * Leave the structure zeroed and return 0 if there are no more valid
- * locations.
+/**
+ * Increment a #bus_loc structure to the next possible ISAPnP
+ * location.
+ *
+ * @v bus_loc          Bus location
+ * @ret True           #bus_loc contains a valid ISAPnP location
+ * @ret False          There are no more valid ISAPnP locations
+ * @err None           -
+ *
+ * If there are no more valid locations, the #bus_loc structure will
+ * be zeroed.
  *
  */
 static int isapnp_next_location ( struct bus_loc *bus_loc ) {
@@ -471,10 +571,14 @@ static int isapnp_next_location ( struct bus_loc *bus_loc ) {
        return ( ++isapnp_loc->logdev ? 1 : ++isapnp_loc->csn );
 }
 
-/*
- * Fill in parameters for an ISAPnP device based on CSN
+/**
+ * Fill in parameters for an ISAPnP device based on CSN.
  *
- * Return 1 if device present, 0 otherwise
+ * @v bus_dev          Bus device to be filled in
+ * @v bus_loc          Bus location as filled in by isapnp_next_location()
+ * @ret True           A device is present at this location
+ * @ret False          No device is present at this location
+ * @err None           -
  *
  */
 static int isapnp_fill_device ( struct bus_dev *bus_dev,
@@ -566,9 +670,15 @@ static int isapnp_fill_device ( struct bus_dev *bus_dev,
        return 1;
 }
 
-/*
+/**
  * Test whether or not a driver is capable of driving the device.
  *
+ * @v bus_dev          Bus device as filled in by isapnp_fill_device()
+ * @v device_driver    Device driver
+ * @ret True           Driver is capable of driving this device
+ * @ret False          Driver is not capable of driving this device
+ * @err None           -
+ *
  */
 static int isapnp_check_driver ( struct bus_dev *bus_dev,
                                 struct device_driver *device_driver ) {
@@ -598,8 +708,15 @@ static int isapnp_check_driver ( struct bus_dev *bus_dev,
        return 0;
 }
 
-/*
- * Describe an ISAPnP device
+/**
+ * Describe an ISAPnP device.
+ *
+ * @v bus_dev          Bus device as filled in by isapnp_fill_device()
+ * @ret string         Printable string describing the device
+ * @err None           -
+ *
+ * The string returned by isapnp_describe_device() is valid only until
+ * the next call to isapnp_describe_device().
  *
  */
 static char * isapnp_describe_device ( struct bus_dev *bus_dev ) {
@@ -611,8 +728,15 @@ static char * isapnp_describe_device ( struct bus_dev *bus_dev ) {
        return isapnp_description;
 }
 
-/*
- * Name an ISAPnP device
+/**
+ * Name an ISAPnP device.
+ *
+ * @v bus_dev          Bus device as filled in by isapnp_fill_device()
+ * @ret string         Printable string naming the device
+ * @err None           -
+ *
+ * The string returned by isapnp_name_device() is valid only until the
+ * next call to isapnp_name_device().
  *
  */
 static const char * isapnp_name_device ( struct bus_dev *bus_dev ) {
@@ -634,12 +758,17 @@ struct bus_driver isapnp_driver __bus_driver = {
        .name_device            = isapnp_name_device,
 };
 
-/*
- * Activate or deactivate an ISAPnP device
+/**
+ * Activate or deactivate an ISAPnP device.
+ *
+ * @v isapnp           ISAPnP device
+ * @v activation       True to enable, False to disable the device
+ * @ret None           -
+ * @err None           -
  *
  * This routine simply activates the device in its current
- * configuration.  It does not attempt any kind of resource
- * arbitration.
+ * configuration, or deactivates the device.  It does not attempt any
+ * kind of resource arbitration.
  *
  */
 void isapnp_device_activation ( struct isapnp_device *isapnp,
@@ -662,8 +791,17 @@ void isapnp_device_activation ( struct isapnp_device *isapnp,
              isapnp->csn, isapnp->logdev );
 }
 
-/*
- * Fill in a nic structure
+/**
+ * Fill in a nic structure.
+ *
+ * @v nic              NIC structure to be filled in
+ * @v isapnp           ISAPnP device
+ * @ret None           -
+ * @err None           -
+ *
+ * This fills in generic NIC parameters (e.g. I/O address and IRQ
+ * number) that can be determined directly from the ISAPnP device,
+ * without any driver-specific knowledge.
  *
  */
 void isapnp_fill_nic ( struct nic *nic, struct isapnp_device *isapnp ) {
index 7fcc9f0..c874950 100644 (file)
@@ -61,10 +61,6 @@ static void t3c515_wait(unsigned int nticks)
 
 /* TJL definations */
 #define HZ      100
-#define u16 unsigned short
-#define u32 unsigned long
-#define s16 signed short
-#define s32 signed long
 static int if_port;
 static struct corkscrew_private *vp;
 /* Brought directly from 3c515.c by Becker */
diff --git a/src/drivers/net/amd8111e.c b/src/drivers/net/amd8111e.c
new file mode 100644 (file)
index 0000000..611cbc8
--- /dev/null
@@ -0,0 +1,681 @@
+/* Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
+ * Copyright (C) 2004 Advanced Micro Devices 
+ * Copyright (C) 2005 Liu Tao <liutao1980@gmail.com> [etherboot port]
+ * 
+ * Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ]
+ * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)[ tg3.c]
+ * Copyright 1996-1999 Thomas Bogendoerfer [ pcnet32.c ]
+ * Derived from the lance driver written 1993,1994,1995 by Donald Becker.
+ * Copyright 1993 United States Government as represented by the
+ *     Director, National Security Agency.[ pcnet32.c ]
+ * Carsten Langgaard, carstenl@mips.com [ pcnet32.c ]
+ * Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
+ * USA
+ */
+
+#include "etherboot.h"
+#include "nic.h"
+#include "mii.h"
+#include "pci.h"
+#include "timer.h"
+#include "string.h"
+#include "stdint.h"
+#include "amd8111e.h"
+
+
+/* driver definitions */
+#define NUM_TX_SLOTS   2
+#define NUM_RX_SLOTS   4
+#define TX_SLOTS_MASK  1
+#define RX_SLOTS_MASK  3
+
+#define TX_BUF_LEN     1536
+#define RX_BUF_LEN     1536
+
+#define TX_PKT_LEN_MAX (ETH_FRAME_LEN - ETH_HLEN)
+#define RX_PKT_LEN_MIN 60
+#define RX_PKT_LEN_MAX ETH_FRAME_LEN
+
+#define TX_TIMEOUT     3000
+#define TX_PROCESS_TIME        10
+#define TX_RETRY       (TX_TIMEOUT / TX_PROCESS_TIME)
+
+#define PHY_RW_RETRY   10
+
+
+struct amd8111e_tx_desc {
+       u16 buf_len;
+       u16 tx_flags;
+       u16 tag_ctrl_info;
+       u16 tag_ctrl_cmd;
+       u32 buf_phy_addr;
+       u32 reserved;
+}; 
+
+struct amd8111e_rx_desc {
+       u32 reserved;
+       u16 msg_len;
+       u16 tag_ctrl_info; 
+       u16 buf_len;
+       u16 rx_flags;
+       u32 buf_phy_addr;
+};
+
+struct eth_frame {
+       u8 dst_addr[ETH_ALEN];
+       u8 src_addr[ETH_ALEN];
+       u16 type;
+       u8 data[ETH_FRAME_LEN - ETH_HLEN];
+} __attribute__((packed));
+
+struct amd8111e_priv {
+       struct amd8111e_tx_desc tx_ring[NUM_TX_SLOTS];
+       struct amd8111e_rx_desc rx_ring[NUM_RX_SLOTS];
+       unsigned char tx_buf[NUM_TX_SLOTS][TX_BUF_LEN];
+       unsigned char rx_buf[NUM_RX_SLOTS][RX_BUF_LEN];
+       unsigned long tx_idx, rx_idx;
+       int tx_consistent;
+
+       char opened;
+       char link;
+       char speed;
+       char duplex;
+       int ext_phy_addr;
+       u32 ext_phy_id;
+
+       struct pci_device *pdev;
+       struct nic *nic;
+       void *mmio;
+};
+
+static struct amd8111e_priv amd8111e;
+
+
+/********************************************************
+ *             locale functions                        *
+ ********************************************************/
+static void amd8111e_init_hw_default(struct amd8111e_priv *lp);
+static int amd8111e_start(struct amd8111e_priv *lp);
+static int amd8111e_read_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 *val);
+#if 0
+static int amd8111e_write_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 val);
+#endif
+static void amd8111e_probe_ext_phy(struct amd8111e_priv *lp);
+static void amd8111e_disable_interrupt(struct amd8111e_priv *lp);
+static void amd8111e_enable_interrupt(struct amd8111e_priv *lp);
+static void amd8111e_force_interrupt(struct amd8111e_priv *lp);
+static int amd8111e_get_mac_address(struct amd8111e_priv *lp);
+static int amd8111e_init_rx_ring(struct amd8111e_priv *lp);
+static int amd8111e_init_tx_ring(struct amd8111e_priv *lp);
+static int amd8111e_wait_tx_ring(struct amd8111e_priv *lp, unsigned int index);
+static void amd8111e_wait_link(struct amd8111e_priv *lp);
+static void amd8111e_poll_link(struct amd8111e_priv *lp);
+static void amd8111e_restart(struct amd8111e_priv *lp);
+
+
+/* 
+ * This function clears necessary the device registers. 
+ */    
+static void amd8111e_init_hw_default(struct amd8111e_priv *lp)
+{
+       unsigned int reg_val;
+       unsigned int logic_filter[2] = {0,};
+       void *mmio = lp->mmio;
+
+        /* stop the chip */
+       writel(RUN, mmio + CMD0);
+
+       /* Clear RCV_RING_BASE_ADDR */
+       writel(0, mmio + RCV_RING_BASE_ADDR0);
+
+       /* Clear XMT_RING_BASE_ADDR */
+       writel(0, mmio + XMT_RING_BASE_ADDR0);
+       writel(0, mmio + XMT_RING_BASE_ADDR1);
+       writel(0, mmio + XMT_RING_BASE_ADDR2);
+       writel(0, mmio + XMT_RING_BASE_ADDR3);
+
+       /* Clear CMD0  */
+       writel(CMD0_CLEAR, mmio + CMD0);
+       
+       /* Clear CMD2 */
+       writel(CMD2_CLEAR, mmio + CMD2);
+
+       /* Clear CMD7 */
+       writel(CMD7_CLEAR, mmio + CMD7);
+
+       /* Clear DLY_INT_A and DLY_INT_B */
+       writel(0x0, mmio + DLY_INT_A);
+       writel(0x0, mmio + DLY_INT_B);
+
+       /* Clear FLOW_CONTROL */
+       writel(0x0, mmio + FLOW_CONTROL);
+
+       /* Clear INT0  write 1 to clear register */
+       reg_val = readl(mmio + INT0);
+       writel(reg_val, mmio + INT0);
+
+       /* Clear STVAL */
+       writel(0x0, mmio + STVAL);
+
+       /* Clear INTEN0 */
+       writel(INTEN0_CLEAR, mmio + INTEN0);
+
+       /* Clear LADRF */
+       writel(0x0, mmio + LADRF);
+
+       /* Set SRAM_SIZE & SRAM_BOUNDARY registers  */
+       writel(0x80010, mmio + SRAM_SIZE);
+
+       /* Clear RCV_RING0_LEN */
+       writel(0x0, mmio +  RCV_RING_LEN0);
+
+       /* Clear XMT_RING0/1/2/3_LEN */
+       writel(0x0, mmio +  XMT_RING_LEN0);
+       writel(0x0, mmio +  XMT_RING_LEN1);
+       writel(0x0, mmio +  XMT_RING_LEN2);
+       writel(0x0, mmio +  XMT_RING_LEN3);
+
+       /* Clear XMT_RING_LIMIT */
+       writel(0x0, mmio + XMT_RING_LIMIT);
+
+       /* Clear MIB */
+       writew(MIB_CLEAR, mmio + MIB_ADDR);
+
+       /* Clear LARF */
+       amd8111e_writeq(*(u64*)logic_filter, mmio + LADRF);
+
+       /* SRAM_SIZE register */
+       reg_val = readl(mmio + SRAM_SIZE);
+       
+       /* Set default value to CTRL1 Register */
+       writel(CTRL1_DEFAULT, mmio + CTRL1);
+
+       /* To avoid PCI posting bug */
+       readl(mmio + CMD2);
+}
+
+/* 
+ * This function initializes the device registers  and starts the device.  
+ */
+static int amd8111e_start(struct amd8111e_priv *lp)
+{
+       struct nic *nic = lp->nic;
+       void *mmio = lp->mmio;
+       int i, reg_val;
+
+       /* stop the chip */
+       writel(RUN, mmio + CMD0);
+
+       /* AUTOPOLL0 Register *//*TBD default value is 8100 in FPS */
+       writew(0x8100 | lp->ext_phy_addr, mmio + AUTOPOLL0);
+
+       /* enable the port manager and set auto negotiation always */
+       writel(VAL1 | EN_PMGR, mmio + CMD3 );
+       writel(XPHYANE | XPHYRST, mmio + CTRL2); 
+
+       /* set control registers */
+       reg_val = readl(mmio + CTRL1);
+       reg_val &= ~XMTSP_MASK;
+       writel(reg_val | XMTSP_128 | CACHE_ALIGN, mmio + CTRL1);
+
+       /* initialize tx and rx ring base addresses */
+       amd8111e_init_tx_ring(lp);
+       amd8111e_init_rx_ring(lp);
+       writel(virt_to_bus(lp->tx_ring), mmio + XMT_RING_BASE_ADDR0);
+       writel(virt_to_bus(lp->rx_ring), mmio + RCV_RING_BASE_ADDR0);
+       writew(NUM_TX_SLOTS, mmio + XMT_RING_LEN0);
+       writew(NUM_RX_SLOTS, mmio + RCV_RING_LEN0);
+       
+       /* set default IPG to 96 */
+       writew(DEFAULT_IPG, mmio + IPG);
+       writew(DEFAULT_IPG - IFS1_DELTA, mmio + IFS1); 
+
+       /* AutoPAD transmit, Retransmit on Underflow */
+       writel(VAL0 | APAD_XMT | REX_RTRY | REX_UFLO, mmio + CMD2);
+       
+       /* JUMBO disabled */
+       writel(JUMBO, mmio + CMD3);
+
+       /* Setting the MAC address to the device */
+       for(i = 0; i < ETH_ALEN; i++)
+               writeb(nic->node_addr[i], mmio + PADR + i); 
+
+       /* set RUN bit to start the chip, interrupt not enabled */
+       writel(VAL2 | RDMD0 | VAL0 | RUN, mmio + CMD0);
+       
+       /* To avoid PCI posting bug */
+       readl(mmio + CMD0);
+       return 0;
+}
+
+/* 
+This function will read the PHY registers.
+*/
+static int amd8111e_read_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 *val)
+{
+       void *mmio = lp->mmio;
+       unsigned int reg_val;
+       unsigned int retry = PHY_RW_RETRY;
+
+       reg_val = readl(mmio + PHY_ACCESS);
+       while (reg_val & PHY_CMD_ACTIVE)
+               reg_val = readl(mmio + PHY_ACCESS);
+
+       writel(PHY_RD_CMD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16),
+               mmio + PHY_ACCESS);
+       do {
+               reg_val = readl(mmio + PHY_ACCESS);
+               udelay(30);  /* It takes 30 us to read/write data */
+       } while (--retry && (reg_val & PHY_CMD_ACTIVE));
+
+       if (reg_val & PHY_RD_ERR) {
+               *val = 0;
+               return -1;
+       }
+       
+       *val = reg_val & 0xffff;
+       return 0;
+}
+
+/* 
+This function will write into PHY registers. 
+*/
+#if 0
+static int amd8111e_write_phy(struct amd8111e_priv *lp, int phy_addr, int reg, u32 val)
+{
+       void *mmio = lp->mmio;
+       unsigned int reg_val;
+       unsigned int retry = PHY_RW_RETRY;
+
+       reg_val = readl(mmio + PHY_ACCESS);
+       while (reg_val & PHY_CMD_ACTIVE)
+               reg_val = readl(mmio + PHY_ACCESS);
+
+       writel(PHY_WR_CMD | ((phy_addr & 0x1f) << 21) | ((reg & 0x1f) << 16) | val,
+               mmio + PHY_ACCESS);
+       do {
+               reg_val = readl(mmio + PHY_ACCESS);
+               udelay(30);  /* It takes 30 us to read/write the data */
+       } while (--retry && (reg_val & PHY_CMD_ACTIVE));
+       
+       if(reg_val & PHY_RD_ERR)
+               return -1;
+
+       return 0;
+}
+#endif
+
+static void amd8111e_probe_ext_phy(struct amd8111e_priv *lp)
+{
+       int i;
+
+       lp->ext_phy_id = 0;
+       lp->ext_phy_addr = 1;
+       
+       for (i = 0x1e; i >= 0; i--) {
+               u32 id1, id2;
+
+               if (amd8111e_read_phy(lp, i, MII_PHYSID1, &id1))
+                       continue;
+               if (amd8111e_read_phy(lp, i, MII_PHYSID2, &id2))
+                       continue;
+               lp->ext_phy_id = (id1 << 16) | id2;
+               lp->ext_phy_addr = i;
+               break;
+       }
+
+       if (lp->ext_phy_id)
+               printf("Found MII PHY ID 0x%08x at address 0x%02x\n",
+                       lp->ext_phy_id, lp->ext_phy_addr);
+       else
+               printf("Couldn't detect MII PHY, assuming address 0x01\n");
+}
+
+static void amd8111e_disable_interrupt(struct amd8111e_priv *lp)
+{
+       void *mmio = lp->mmio;
+       unsigned int int0;
+
+       writel(INTREN, mmio + CMD0);
+       writel(INTEN0_CLEAR, mmio + INTEN0);
+       int0 = readl(mmio + INT0);
+       writel(int0, mmio + INT0);
+       readl(mmio + INT0);
+}
+
+static void amd8111e_enable_interrupt(struct amd8111e_priv *lp)
+{
+       void *mmio = lp->mmio;
+
+       writel(VAL3 | LCINTEN | VAL1 | TINTEN0 | VAL0 | RINTEN0, mmio + INTEN0);
+       writel(VAL0 | INTREN, mmio + CMD0);
+       readl(mmio + CMD0);
+}
+
+static void amd8111e_force_interrupt(struct amd8111e_priv *lp)
+{
+       void *mmio = lp->mmio;
+
+       writel(VAL0 | UINTCMD, mmio + CMD0);
+       readl(mmio + CMD0);
+}
+
+static int amd8111e_get_mac_address(struct amd8111e_priv *lp)
+{
+       struct nic *nic = lp->nic;
+       void *mmio = lp->mmio;
+       int i;
+
+       /* BIOS should have set mac address to PADR register,
+        * so we read PADR to get it.
+        */
+       for (i = 0; i < ETH_ALEN; i++)
+               nic->node_addr[i] = readb(mmio + PADR + i);
+       printf("Ethernet addr: %!\n", nic->node_addr);
+
+       return 0;
+}
+
+static int amd8111e_init_rx_ring(struct amd8111e_priv *lp)
+{
+       int i;
+
+       lp->rx_idx = 0;
+       
+        /* Initilaizing receive descriptors */
+       for (i = 0; i < NUM_RX_SLOTS; i++) {
+               lp->rx_ring[i].buf_phy_addr = cpu_to_le32(virt_to_bus(lp->rx_buf[i]));
+               lp->rx_ring[i].buf_len = cpu_to_le16(RX_BUF_LEN);
+               wmb();
+               lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT);
+       }
+
+       return 0;
+}
+
+static int amd8111e_init_tx_ring(struct amd8111e_priv *lp)
+{
+       int i;
+
+       lp->tx_idx = 0;
+       lp->tx_consistent = 1;
+       
+       /* Initializing transmit descriptors */
+       for (i = 0; i < NUM_TX_SLOTS; i++) {
+               lp->tx_ring[i].tx_flags = 0;
+               lp->tx_ring[i].buf_phy_addr = 0;
+               lp->tx_ring[i].buf_len = 0;
+       }
+
+       return 0;
+}
+
+static int amd8111e_wait_tx_ring(struct amd8111e_priv *lp, unsigned int index)
+{
+       volatile u16 status;
+       int retry = TX_RETRY;
+
+       status = le16_to_cpu(lp->tx_ring[index].tx_flags);
+       while (--retry && (status & OWN_BIT)) {
+               mdelay(TX_PROCESS_TIME);
+               status = le16_to_cpu(lp->tx_ring[index].tx_flags);
+       }
+       if (status & OWN_BIT) {
+               printf("Error: tx slot %d timeout, stat = 0x%x\n", index, status);
+               amd8111e_restart(lp);
+               return -1;
+       }
+
+       return 0;
+}
+
+static void amd8111e_wait_link(struct amd8111e_priv *lp)
+{
+       unsigned int status;
+       u32 reg_val;
+
+       do {
+               /* read phy to update STAT0 register */
+               amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMCR, &reg_val);
+               amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, &reg_val);
+               amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, &reg_val);
+               amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, &reg_val);
+               status = readl(lp->mmio + STAT0);
+       } while (!(status & AUTONEG_COMPLETE) || !(status & LINK_STATS));
+}
+
+static void amd8111e_poll_link(struct amd8111e_priv *lp)
+{
+       unsigned int status, speed;
+       u32 reg_val;
+
+       if (!lp->link) {
+               /* read phy to update STAT0 register */
+               amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMCR, &reg_val);
+               amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, &reg_val);
+               amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, &reg_val);
+               amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, &reg_val);
+               status = readl(lp->mmio + STAT0);
+
+               if (status & LINK_STATS) {
+                       lp->link = 1;
+                       speed = (status & SPEED_MASK) >> 7;
+                       if (speed == PHY_SPEED_100)
+                               lp->speed = 1;
+                       else
+                               lp->speed = 0;
+                       if (status & FULL_DPLX)
+                               lp->duplex = 1;
+                       else
+                               lp->duplex = 0;
+
+                       printf("Link is up: %s Mbps %s duplex\n",
+                               lp->speed ? "100" : "10", lp->duplex ? "full" : "half");
+               }
+       } else {
+               status = readl(lp->mmio + STAT0);
+               if (!(status & LINK_STATS)) {
+                       lp->link = 0;
+                       printf("Link is down\n");
+               }
+       }
+}
+
+static void amd8111e_restart(struct amd8111e_priv *lp)
+{
+       printf("\nStarting nic...\n");
+       amd8111e_disable_interrupt(lp);
+       amd8111e_init_hw_default(lp);
+       amd8111e_probe_ext_phy(lp);
+       amd8111e_get_mac_address(lp);
+       amd8111e_start(lp);
+
+       printf("Waiting link up...\n");
+       lp->link = 0;
+       amd8111e_wait_link(lp);
+       amd8111e_poll_link(lp);
+}
+
+
+/********************************************************
+ *             Interface Functions                     *
+ ********************************************************/
+
+static void amd8111e_transmit(struct nic *nic, const char *dst_addr,
+               unsigned int type, unsigned int size, const char *packet)
+{
+       struct amd8111e_priv *lp = nic->priv_data;
+       struct eth_frame *frame;
+       unsigned int index;
+
+       /* check packet size */
+       if (size > TX_PKT_LEN_MAX) {
+               printf("amd8111e_transmit(): too large packet, drop\n");
+               return;
+       }
+
+       /* get tx slot */
+       index = lp->tx_idx;
+       if (amd8111e_wait_tx_ring(lp, index))
+               return;
+
+       /* fill frame */
+       frame = (struct eth_frame *)lp->tx_buf[index];
+       memset(frame->data, 0, TX_PKT_LEN_MAX);
+       memcpy(frame->dst_addr, dst_addr, ETH_ALEN);
+       memcpy(frame->src_addr, nic->node_addr, ETH_ALEN);
+       frame->type = htons(type);
+       memcpy(frame->data, packet, size);
+
+       /* start xmit */
+       lp->tx_ring[index].buf_len = cpu_to_le16(ETH_HLEN + size);
+       lp->tx_ring[index].buf_phy_addr = cpu_to_le32(virt_to_bus(frame));
+       wmb();
+       lp->tx_ring[index].tx_flags = 
+               cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT | ADD_FCS_BIT | LTINT_BIT);
+       writel(VAL1 | TDMD0, lp->mmio + CMD0);
+       readl(lp->mmio + CMD0);
+
+       /* update slot pointer */
+       lp->tx_idx = (lp->tx_idx + 1) & TX_SLOTS_MASK;
+}
+
+static int amd8111e_poll(struct nic *nic, int retrieve)
+{
+       /* return true if there's an ethernet packet ready to read */
+       /* nic->packet should contain data on return */
+       /* nic->packetlen should contain length of data */
+
+       struct amd8111e_priv *lp = nic->priv_data;
+       u16 status, pkt_len;
+       unsigned int index, pkt_ok;
+
+       amd8111e_poll_link(lp);
+
+       index = lp->rx_idx;
+       status = le16_to_cpu(lp->rx_ring[index].rx_flags);
+       pkt_len = le16_to_cpu(lp->rx_ring[index].msg_len) - 4;  /* remove 4bytes FCS */
+       
+       if (status & OWN_BIT)
+               return 0;
+
+       if (status & ERR_BIT)
+               pkt_ok = 0;
+       else if (!(status & STP_BIT))
+               pkt_ok = 0;
+       else if (!(status & ENP_BIT))
+               pkt_ok = 0;
+       else if (pkt_len < RX_PKT_LEN_MIN)
+               pkt_ok = 0;
+       else if (pkt_len > RX_PKT_LEN_MAX)
+               pkt_ok = 0;
+       else
+               pkt_ok = 1;
+
+       if (pkt_ok) {
+               if (!retrieve)
+                       return 1;
+               nic->packetlen = pkt_len;
+               memcpy(nic->packet, lp->rx_buf[index], nic->packetlen);
+       }
+
+       lp->rx_ring[index].buf_phy_addr = cpu_to_le32(virt_to_bus(lp->rx_buf[index]));
+       lp->rx_ring[index].buf_len = cpu_to_le16(RX_BUF_LEN);
+       wmb();
+       lp->rx_ring[index].rx_flags = cpu_to_le16(OWN_BIT);
+       writel(VAL2 | RDMD0, lp->mmio + CMD0);
+       readl(lp->mmio + CMD0);
+
+       lp->rx_idx = (lp->rx_idx + 1) & RX_SLOTS_MASK;
+       return pkt_ok;
+}
+
+static void amd8111e_disable(struct nic *nic)
+{
+       struct amd8111e_priv *lp = nic->priv_data;
+
+       /* disable interrupt */
+       amd8111e_disable_interrupt(lp);
+
+       /* stop chip */
+       amd8111e_init_hw_default(lp);
+
+       /* unmap mmio */
+       iounmap(lp->mmio);
+
+       /* update status */
+       lp->opened = 0;
+}
+
+static void amd8111e_irq(struct nic *nic, irq_action_t action)
+{
+       struct amd8111e_priv *lp = nic->priv_data;
+               
+       switch (action) {
+       case DISABLE:
+               amd8111e_disable_interrupt(lp);
+               break;
+       case ENABLE:
+               amd8111e_enable_interrupt(lp);
+               break;
+       case FORCE:
+               amd8111e_force_interrupt(lp);
+               break;
+       }
+}
+
+static struct nic_operations amd8111e_operations = {
+       .connect        = dummy_connect,
+       .poll           = amd8111e_poll,
+       .transmit       = amd8111e_transmit,
+       .irq            = amd8111e_irq,
+};
+
+static int amd8111e_probe(struct nic *nic, struct pci_device *pdev)
+{
+       struct amd8111e_priv *lp = &amd8111e;
+       unsigned long mmio_start, mmio_len;
+
+       pci_fill_nic ( nic, pdev );
+       
+       mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+       mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_0);
+
+       memset(lp, 0, sizeof(*lp));
+       lp->pdev = pdev;
+       lp->nic = nic;
+       lp->mmio = ioremap(mmio_start, mmio_len);
+       lp->opened = 1;
+       adjust_pci_device(pdev);
+
+       nic->priv_data = lp;
+
+       amd8111e_restart(lp);
+
+       nic->nic_op     = &amd8111e_operations;
+       return 1;
+}
+
+static struct pci_id amd8111e_nics[] = {
+       PCI_ROM(0x1022, 0x7462, "amd8111e",     "AMD8111E"),
+};
+
+PCI_DRIVER ( amd8111e_driver, amd8111e_nics, PCI_NO_CLASS );
+
+DRIVER ( "AMD8111E", nic_driver, pci_driver, amd8111e_driver,
+        amd8111e_probe, amd8111e_disable );
diff --git a/src/drivers/net/amd8111e.h b/src/drivers/net/amd8111e.h
new file mode 100644 (file)
index 0000000..82b8f7a
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
+ * Copyright (C) 2003 Advanced Micro Devices 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
+ * USA
+
+Module Name:
+
+    amd8111e.h
+
+Abstract:
+       
+        AMD8111 based 10/100 Ethernet Controller driver definitions. 
+
+Environment:
+    
+       Kernel Mode
+
+Revision History:
+       3.0.0
+          Initial Revision.
+       3.0.1
+*/
+
+#ifndef _AMD811E_H
+#define _AMD811E_H
+
+/* Command style register access
+
+Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the  value bit that specifies the value that will be written into the selected bits of register. 
+
+eg., if the value 10011010b is written into the least significant byte of a command style register, bits 1,3 and 4 of the register will be set to 1, and the other bits will not be altered. If the value 00011010b is written into the same byte, bits 1,3 and 4 will be cleared to 0 and the other bits will not be altered.
+
+*/
+
+/*  Offset for Memory Mapped Registers. */
+/* 32 bit registers */
+
+#define  ASF_STAT              0x00    /* ASF status register */
+#define CHIPID                 0x04    /* Chip ID regsiter */
+#define        MIB_DATA                0x10    /* MIB data register */
+#define MIB_ADDR               0x14    /* MIB address register */
+#define STAT0                  0x30    /* Status0 register */
+#define INT0                   0x38    /* Interrupt0 register */
+#define INTEN0                 0x40    /* Interrupt0  enable register*/
+#define CMD0                   0x48    /* Command0 register */
+#define CMD2                   0x50    /* Command2 register */
+#define CMD3                   0x54    /* Command3 resiter */
+#define CMD7                   0x64    /* Command7 register */
+
+#define CTRL1                  0x6C    /* Control1 register */
+#define CTRL2                  0x70    /* Control2 register */
+
+#define XMT_RING_LIMIT         0x7C    /* Transmit ring limit register */
+
+#define AUTOPOLL0              0x88    /* Auto-poll0 register */
+#define AUTOPOLL1              0x8A    /* Auto-poll1 register */
+#define AUTOPOLL2              0x8C    /* Auto-poll2 register */
+#define AUTOPOLL3              0x8E    /* Auto-poll3 register */
+#define AUTOPOLL4              0x90    /* Auto-poll4 register */
+#define        AUTOPOLL5               0x92    /* Auto-poll5 register */
+
+#define AP_VALUE               0x98    /* Auto-poll value register */
+#define DLY_INT_A              0xA8    /* Group A delayed interrupt register */
+#define DLY_INT_B              0xAC    /* Group B delayed interrupt register */
+
+#define FLOW_CONTROL           0xC8    /* Flow control register */
+#define PHY_ACCESS             0xD0    /* PHY access register */
+
+#define STVAL                  0xD8    /* Software timer value register */
+
+#define XMT_RING_BASE_ADDR0    0x100   /* Transmit ring0 base addr register */
+#define XMT_RING_BASE_ADDR1    0x108   /* Transmit ring1 base addr register */
+#define XMT_RING_BASE_ADDR2    0x110   /* Transmit ring2 base addr register */
+#define XMT_RING_BASE_ADDR3    0x118   /* Transmit ring2 base addr register */
+
+#define RCV_RING_BASE_ADDR0    0x120   /* Transmit ring0 base addr register */
+
+#define PMAT0                  0x190   /* OnNow pattern register0 */
+#define PMAT1                  0x194   /* OnNow pattern register1 */
+
+/* 16bit registers */
+
+#define XMT_RING_LEN0          0x140   /* Transmit Ring0 length register */
+#define XMT_RING_LEN1          0x144   /* Transmit Ring1 length register */
+#define XMT_RING_LEN2          0x148   /* Transmit Ring2 length register */
+#define XMT_RING_LEN3          0x14C   /* Transmit Ring3 length register */
+
+#define RCV_RING_LEN0          0x150   /* Receive Ring0 length register */
+
+#define SRAM_SIZE              0x178   /* SRAM size register */
+#define SRAM_BOUNDARY          0x17A   /* SRAM boundary register */
+
+/* 48bit register */
+
+#define PADR                   0x160   /* Physical address register */
+
+#define IFS1                   0x18C   /* Inter-frame spacing Part1 register */
+#define IFS                    0x18D   /* Inter-frame spacing register */
+#define IPG                    0x18E   /* Inter-frame gap register */
+/* 64bit register */
+
+#define LADRF                  0x168   /* Logical address filter register */
+
+
+/* Register Bit Definitions */
+typedef enum {
+
+       ASF_INIT_DONE           = (1 << 1),
+       ASF_INIT_PRESENT        = (1 << 0),
+
+}STAT_ASF_BITS; 
+   
+typedef enum {
+
+       MIB_CMD_ACTIVE          = (1 << 15 ),
+       MIB_RD_CMD              = (1 << 13 ),
+       MIB_CLEAR               = (1 << 12 ),
+       MIB_ADDRESS             = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)|
+                                       (1 << 4) | (1 << 5),
+}MIB_ADDR_BITS;
+
+
+typedef enum {
+       
+       PMAT_DET                = (1 << 12),
+       MP_DET                  = (1 << 11),
+       LC_DET                  = (1 << 10),
+       SPEED_MASK              = (1 << 9)|(1 << 8)|(1 << 7),
+       FULL_DPLX               = (1 << 6),
+       LINK_STATS              = (1 << 5),
+       AUTONEG_COMPLETE        = (1 << 4),
+       MIIPD                   = (1 << 3),
+       RX_SUSPENDED            = (1 << 2),
+       TX_SUSPENDED            = (1 << 1),
+       RUNNING                 = (1 << 0),
+
+}STAT0_BITS;
+
+#define PHY_SPEED_10           0x2
+#define PHY_SPEED_100          0x3
+
+/* INT0                                0x38, 32bit register */
+typedef enum {
+
+       INTR                    = (1 << 31),
+       PCSINT                  = (1 << 28), 
+       LCINT                   = (1 << 27),
+       APINT5                  = (1 << 26),
+       APINT4                  = (1 << 25),
+       APINT3                  = (1 << 24),
+       TINT_SUM                = (1 << 23),
+       APINT2                  = (1 << 22),
+       APINT1                  = (1 << 21),
+       APINT0                  = (1 << 20),
+       MIIPDTINT               = (1 << 19),
+       MCCINT                  = (1 << 17),
+       MREINT                  = (1 << 16),
+       RINT_SUM                = (1 << 15),
+       SPNDINT                 = (1 << 14),
+       MPINT                   = (1 << 13),
+       SINT                    = (1 << 12),
+       TINT3                   = (1 << 11),
+       TINT2                   = (1 << 10),
+       TINT1                   = (1 << 9),
+       TINT0                   = (1 << 8),
+       UINT                    = (1 << 7),
+       STINT                   = (1 << 4),
+       RINT0                   = (1 << 0),
+
+}INT0_BITS;
+
+typedef enum {
+
+       VAL3                    = (1 << 31),   /* VAL bit for byte 3 */
+       VAL2                    = (1 << 23),   /* VAL bit for byte 2 */
+       VAL1                    = (1 << 15),   /* VAL bit for byte 1 */
+       VAL0                    = (1 << 7),    /* VAL bit for byte 0 */
+
+}VAL_BITS;
+
+typedef enum {
+
+       /* VAL3 */
+       LCINTEN                 = (1 << 27),
+       APINT5EN                = (1 << 26),
+       APINT4EN                = (1 << 25),
+       APINT3EN                = (1 << 24),
+       /* VAL2 */
+       APINT2EN                = (1 << 22),
+       APINT1EN                = (1 << 21),
+       APINT0EN                = (1 << 20),
+       MIIPDTINTEN             = (1 << 19),
+       MCCIINTEN               = (1 << 18),
+       MCCINTEN                = (1 << 17),
+       MREINTEN                = (1 << 16),
+       /* VAL1 */
+       SPNDINTEN               = (1 << 14),
+       MPINTEN                 = (1 << 13),
+       TINTEN3                 = (1 << 11),
+       SINTEN                  = (1 << 12),
+       TINTEN2                 = (1 << 10),
+       TINTEN1                 = (1 << 9),
+       TINTEN0                 = (1 << 8),
+       /* VAL0 */
+       STINTEN                 = (1 << 4),
+       RINTEN0                 = (1 << 0),
+
+       INTEN0_CLEAR            = 0x1F7F7F1F, /* Command style register */
+
+}INTEN0_BITS;          
+
+typedef enum {
+       /* VAL2 */
+       RDMD0                   = (1 << 16),
+       /* VAL1 */
+       TDMD3                   = (1 << 11),
+       TDMD2                   = (1 << 10),
+       TDMD1                   = (1 << 9),
+       TDMD0                   = (1 << 8),
+       /* VAL0 */
+       UINTCMD                 = (1 << 6),
+       RX_FAST_SPND            = (1 << 5),
+       TX_FAST_SPND            = (1 << 4),
+       RX_SPND                 = (1 << 3),
+       TX_SPND                 = (1 << 2),
+       INTREN                  = (1 << 1),
+       RUN                     = (1 << 0),
+
+       CMD0_CLEAR              = 0x000F0F7F,   /* Command style register */    
+
+}CMD0_BITS;
+
+typedef enum {
+
+       /* VAL3 */
+       CONDUIT_MODE            = (1 << 29),
+       /* VAL2 */
+       RPA                     = (1 << 19),
+       DRCVPA                  = (1 << 18),
+       DRCVBC                  = (1 << 17),
+       PROM                    = (1 << 16),
+       /* VAL1 */
+       ASTRP_RCV               = (1 << 13),
+       RCV_DROP0               = (1 << 12),
+       EMBA                    = (1 << 11),
+       DXMT2PD                 = (1 << 10),
+       LTINTEN                 = (1 << 9),
+       DXMTFCS                 = (1 << 8),
+       /* VAL0 */
+       APAD_XMT                = (1 << 6),
+       DRTY                    = (1 << 5),
+       INLOOP                  = (1 << 4),
+       EXLOOP                  = (1 << 3),
+       REX_RTRY                = (1 << 2),
+       REX_UFLO                = (1 << 1),
+       REX_LCOL                = (1 << 0),
+
+       CMD2_CLEAR              = 0x3F7F3F7F,   /* Command style register */
+
+}CMD2_BITS;
+
+typedef enum {
+
+       /* VAL3 */
+       ASF_INIT_DONE_ALIAS     = (1 << 29),
+       /* VAL2 */
+       JUMBO                   = (1 << 21),
+       VSIZE                   = (1 << 20),    
+       VLONLY                  = (1 << 19),
+       VL_TAG_DEL              = (1 << 18),    
+       /* VAL1 */
+       EN_PMGR                 = (1 << 14),                    
+       INTLEVEL                = (1 << 13),
+       FORCE_FULL_DUPLEX       = (1 << 12),    
+       FORCE_LINK_STATUS       = (1 << 11),    
+       APEP                    = (1 << 10),    
+       MPPLBA                  = (1 << 9),     
+       /* VAL0 */
+       RESET_PHY_PULSE         = (1 << 2),     
+       RESET_PHY               = (1 << 1),     
+       PHY_RST_POL             = (1 << 0),     
+
+}CMD3_BITS;
+
+
+typedef enum {
+
+       /* VAL0 */
+       PMAT_SAVE_MATCH         = (1 << 4),
+       PMAT_MODE               = (1 << 3),
+       MPEN_SW                 = (1 << 1),
+       LCMODE_SW               = (1 << 0),
+
+       CMD7_CLEAR              = 0x0000001B    /* Command style register */
+
+}CMD7_BITS;
+
+
+typedef enum {
+
+       RESET_PHY_WIDTH         = (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */
+       XMTSP_MASK              = (1 << 9) | (1 << 8),  /* 9:8 */
+       XMTSP_128               = (1 << 9),     /* 9 */ 
+       XMTSP_64                = (1 << 8),
+       CACHE_ALIGN             = (1 << 4),
+       BURST_LIMIT_MASK        = (0xF << 0 ),
+       CTRL1_DEFAULT           = 0x00010111,
+
+}CTRL1_BITS;
+
+typedef enum {
+
+       FMDC_MASK               = (1 << 9)|(1 << 8),    /* 9:8 */
+       XPHYRST                 = (1 << 7),
+       XPHYANE                 = (1 << 6),
+       XPHYFD                  = (1 << 5),
+       XPHYSP                  = (1 << 4) | (1 << 3),  /* 4:3 */
+       APDW_MASK               = (1 << 2) | (1 << 1) | (1 << 0), /* 2:0 */
+
+}CTRL2_BITS;
+
+/* XMT_RING_LIMIT              0x7C, 32bit register */
+typedef enum {
+
+       XMT_RING2_LIMIT         = (0xFF << 16), /* 23:16 */
+       XMT_RING1_LIMIT         = (0xFF << 8),  /* 15:8 */
+       XMT_RING0_LIMIT         = (0xFF << 0),  /* 7:0 */
+
+}XMT_RING_LIMIT_BITS;
+
+typedef enum {
+
+       AP_REG0_EN              = (1 << 15),
+       AP_REG0_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
+       AP_PHY0_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL0_BITS;
+
+/* AUTOPOLL1                   0x8A, 16bit register */
+typedef enum {
+
+       AP_REG1_EN              = (1 << 15),
+       AP_REG1_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
+       AP_PRE_SUP1             = (1 << 6),
+       AP_PHY1_DFLT            = (1 << 5),
+       AP_PHY1_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL1_BITS;
+
+
+typedef enum {
+
+       AP_REG2_EN              = (1 << 15),
+       AP_REG2_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
+       AP_PRE_SUP2             = (1 << 6),
+       AP_PHY2_DFLT            = (1 << 5),
+       AP_PHY2_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL2_BITS;
+
+typedef enum {
+
+       AP_REG3_EN              = (1 << 15),
+       AP_REG3_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
+       AP_PRE_SUP3             = (1 << 6),
+       AP_PHY3_DFLT            = (1 << 5),
+       AP_PHY3_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL3_BITS;
+
+
+typedef enum {
+
+       AP_REG4_EN              = (1 << 15),
+       AP_REG4_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
+       AP_PRE_SUP4             = (1 << 6),
+       AP_PHY4_DFLT            = (1 << 5),
+       AP_PHY4_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL4_BITS;
+
+
+typedef enum {
+
+       AP_REG5_EN              = (1 << 15),
+       AP_REG5_ADDR_MASK       = (0xF << 8) |(1 << 12),/* 12:8 */
+       AP_PRE_SUP5             = (1 << 6),
+       AP_PHY5_DFLT            = (1 << 5),
+       AP_PHY5_ADDR_MASK       = (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL5_BITS;
+
+
+
+
+/* AP_VALUE                    0x98, 32bit ragister */
+typedef enum {
+
+       AP_VAL_ACTIVE           = (1 << 31),
+       AP_VAL_RD_CMD           = ( 1 << 29),
+       AP_ADDR                 = (1 << 18)|(1 << 17)|(1 << 16), /* 18:16 */
+       AP_VAL                  = (0xF << 0) | (0xF << 4) |( 0xF << 8) |
+                                 (0xF << 12),  /* 15:0 */
+
+}AP_VALUE_BITS;
+
+typedef enum {
+
+       DLY_INT_A_R3            = (1 << 31),
+       DLY_INT_A_R2            = (1 << 30),
+       DLY_INT_A_R1            = (1 << 29),
+       DLY_INT_A_R0            = (1 << 28),
+       DLY_INT_A_T3            = (1 << 27),
+       DLY_INT_A_T2            = (1 << 26),
+       DLY_INT_A_T1            = (1 << 25),
+       DLY_INT_A_T0            = ( 1 << 24),
+       EVENT_COUNT_A           = (0xF << 16) | (0x1 << 20),/* 20:16 */
+       MAX_DELAY_TIME_A        = (0xF << 0) | (0xF << 4) | (1 << 8)|
+                                 (1 << 9) | (1 << 10), /* 10:0 */
+
+}DLY_INT_A_BITS;
+
+typedef enum {
+
+       DLY_INT_B_R3            = (1 << 31),
+       DLY_INT_B_R2            = (1 << 30),
+       DLY_INT_B_R1            = (1 << 29),
+       DLY_INT_B_R0            = (1 << 28),
+       DLY_INT_B_T3            = (1 << 27),
+       DLY_INT_B_T2            = (1 << 26),
+       DLY_INT_B_T1            = (1 << 25),
+       DLY_INT_B_T0            = ( 1 << 24),
+       EVENT_COUNT_B           = (0xF << 16) | (0x1 << 20),/* 20:16 */
+       MAX_DELAY_TIME_B        = (0xF << 0) | (0xF << 4) | (1 << 8)| 
+                                 (1 << 9) | (1 << 10), /* 10:0 */
+}DLY_INT_B_BITS;
+
+
+/* FLOW_CONTROL                0xC8, 32bit register */
+typedef enum {
+
+       PAUSE_LEN_CHG           = (1 << 30),
+       FTPE                    = (1 << 22),
+       FRPE                    = (1 << 21),
+       NAPA                    = (1 << 20),
+       NPA                     = (1 << 19),
+       FIXP                    = ( 1 << 18),
+       FCCMD                   = ( 1 << 16),
+       PAUSE_LEN               = (0xF << 0) | (0xF << 4) |( 0xF << 8) |                                          (0xF << 12),  /* 15:0 */
+
+}FLOW_CONTROL_BITS;
+
+/* PHY_ ACCESS                 0xD0, 32bit register */
+typedef enum {
+
+       PHY_CMD_ACTIVE          = (1 << 31),
+       PHY_WR_CMD              = (1 << 30),
+       PHY_RD_CMD              = (1 << 29),
+       PHY_RD_ERR              = (1 << 28),
+       PHY_PRE_SUP             = (1 << 27),
+       PHY_ADDR                = (1 << 21) | (1 << 22) | (1 << 23)|
+                                       (1 << 24) |(1 << 25),/* 25:21 */
+       PHY_REG_ADDR            = (1 << 16) | (1 << 17) | (1 << 18)|                                                    (1 << 19) | (1 << 20),/* 20:16 */
+       PHY_DATA                = (0xF << 0)|(0xF << 4) |(0xF << 8)|
+                                       (0xF << 12),/* 15:0 */
+
+}PHY_ACCESS_BITS;
+
+
+/* PMAT0                       0x190,   32bit register */
+typedef enum {
+       PMR_ACTIVE              = (1 << 31),
+       PMR_WR_CMD              = (1 << 30),
+       PMR_RD_CMD              = (1 << 29),
+       PMR_BANK                = (1 <<28),
+       PMR_ADDR                = (0xF << 16)|(1 << 20)|(1 << 21)|
+                                       (1 << 22),/* 22:16 */
+       PMR_B4                  = (0xF << 0) | (0xF << 4),/* 15:0 */
+}PMAT0_BITS;
+
+
+/* PMAT1                       0x194,   32bit register */
+typedef enum {
+       PMR_B3                  = (0xF << 24) | (0xF <<28),/* 31:24 */
+       PMR_B2                  = (0xF << 16) |(0xF << 20),/* 23:16 */
+       PMR_B1                  = (0xF << 8) | (0xF <<12), /* 15:8 */
+       PMR_B0                  = (0xF << 0)|(0xF << 4),/* 7:0 */
+}PMAT1_BITS;
+
+/************************************************************************/
+/*                                                                      */
+/*                      MIB counter definitions                         */
+/*                                                                      */
+/************************************************************************/
+
+#define rcv_miss_pkts                          0x00
+#define rcv_octets                             0x01
+#define rcv_broadcast_pkts                     0x02
+#define rcv_multicast_pkts                     0x03
+#define rcv_undersize_pkts                     0x04
+#define rcv_oversize_pkts                      0x05
+#define rcv_fragments                          0x06
+#define rcv_jabbers                            0x07
+#define rcv_unicast_pkts                       0x08
+#define rcv_alignment_errors                   0x09
+#define rcv_fcs_errors                         0x0A
+#define rcv_good_octets                                0x0B
+#define rcv_mac_ctrl                           0x0C
+#define rcv_flow_ctrl                          0x0D
+#define rcv_pkts_64_octets                     0x0E
+#define rcv_pkts_65to127_octets                        0x0F
+#define rcv_pkts_128to255_octets               0x10
+#define rcv_pkts_256to511_octets               0x11
+#define rcv_pkts_512to1023_octets              0x12
+#define rcv_pkts_1024to1518_octets             0x13
+#define rcv_unsupported_opcode                 0x14
+#define rcv_symbol_errors                      0x15
+#define rcv_drop_pkts_ring1                    0x16
+#define rcv_drop_pkts_ring2                    0x17
+#define rcv_drop_pkts_ring3                    0x18
+#define rcv_drop_pkts_ring4                    0x19
+#define rcv_jumbo_pkts                         0x1A
+
+#define xmt_underrun_pkts                      0x20
+#define xmt_octets                             0x21
+#define xmt_packets                            0x22
+#define xmt_broadcast_pkts                     0x23
+#define xmt_multicast_pkts                     0x24
+#define xmt_collisions                         0x25
+#define xmt_unicast_pkts                       0x26
+#define xmt_one_collision                      0x27
+#define xmt_multiple_collision                 0x28
+#define xmt_deferred_transmit                  0x29
+#define xmt_late_collision                     0x2A
+#define xmt_excessive_defer                    0x2B
+#define xmt_loss_carrier                       0x2C
+#define xmt_excessive_collision                        0x2D
+#define xmt_back_pressure                      0x2E
+#define xmt_flow_ctrl                          0x2F
+#define xmt_pkts_64_octets                     0x30
+#define xmt_pkts_65to127_octets                        0x31
+#define xmt_pkts_128to255_octets               0x32
+#define xmt_pkts_256to511_octets               0x33
+#define xmt_pkts_512to1023_octets              0x34
+#define xmt_pkts_1024to1518_octet              0x35
+#define xmt_oversize_pkts                      0x36
+#define xmt_jumbo_pkts                         0x37
+
+/* ipg parameters */
+#define DEFAULT_IPG                    0x60
+#define IFS1_DELTA                     36
+#define        IPG_CONVERGE_JIFFIES (HZ/2)
+#define        IPG_STABLE_TIME 5
+#define        MIN_IPG 96
+#define        MAX_IPG 255
+#define IPG_STEP       16
+#define CSTATE  1 
+#define SSTATE  2 
+
+/* amd8111e decriptor flag definitions */
+typedef enum {
+
+       OWN_BIT         =       (1 << 15),
+       ADD_FCS_BIT     =       (1 << 13),
+       LTINT_BIT       =       (1 << 12),
+       STP_BIT         =       (1 << 9),
+       ENP_BIT         =       (1 << 8),
+       KILL_BIT        =       (1 << 6),
+       TCC_VLAN_INSERT =       (1 << 1),
+       TCC_VLAN_REPLACE =      (1 << 1) |( 1<< 0),
+
+}TX_FLAG_BITS;
+
+typedef enum {
+       ERR_BIT         =       (1 << 14),
+       FRAM_BIT        =       (1 << 13),
+       OFLO_BIT        =       (1 << 12),
+       CRC_BIT         =       (1 << 11),
+       PAM_BIT         =       (1 << 6),
+       LAFM_BIT        =       (1 << 5),
+       BAM_BIT         =       (1 << 4),
+       TT_VLAN_TAGGED  =       (1 << 3) |(1 << 2),/* 0x000 */
+       TT_PRTY_TAGGED  =       (1 << 3),/* 0x0008 */
+
+}RX_FLAG_BITS;
+
+#define RESET_RX_FLAGS         0x0000
+#define TT_MASK                        0x000c
+#define TCC_MASK               0x0003
+
+/* driver ioctl parameters */
+#define AMD8111E_REG_DUMP_LEN   13*sizeof(u32) 
+
+/* crc generator constants */
+#define CRC32 0xedb88320
+#define INITCRC 0xFFFFFFFF
+
+/* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register.
+BUG? */
+#define  amd8111e_writeq(_UlData,_memMap)   \
+               writel(*(u32*)(&_UlData), _memMap);     \
+               writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)   
+
+/* maps the external speed options to internal value */
+typedef enum {
+       SPEED_AUTONEG,
+       SPEED10_HALF,
+       SPEED10_FULL,
+       SPEED100_HALF,
+       SPEED100_FULL,
+}EXT_PHY_OPTION;
+
+
+#endif /* _AMD8111E_H */
+
index fdbf983..d087e29 100644 (file)
 
 #define TX_TIME_OUT       2*TICKS_PER_SEC
 
-typedef unsigned char  u8;
-typedef   signed char  s8;
-typedef unsigned short u16;
-typedef   signed short s16;
-typedef unsigned int   u32;
-typedef   signed int   s32;
-
 /* Register offsets for davicom device */
 enum davicom_offsets {
    CSR0=0,     CSR1=0x08,  CSR2=0x10,  CSR3=0x18,  CSR4=0x20,  CSR5=0x28,
index 3707da6..cc904c7 100644 (file)
@@ -413,13 +413,6 @@ static char *adapter_name[] = {
 #define ALIGN8      ((u32)8 - 1)       /* 2 longword (quadword) align */
 #define ALIGN         ALIGN8              /* Keep the LANCE happy... */
 
-typedef        long            s32;
-typedef        unsigned long   u32;
-typedef        short           s16;
-typedef        unsigned short  u16;
-typedef        char            s8;
-typedef        unsigned char   u8;
-
 /*
 ** The DEPCA Rx and Tx ring descriptors. 
 */
index 4061ebf..e1ff44e 100644 (file)
 #define dprintf(x)
 #endif
 
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
 /* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
index d5de2cc..2eb6b33 100644 (file)
@@ -72,6 +72,9 @@ typedef enum {
  * and the corresponding inplace checks inserted instead.
  * Pieces such as LED handling that we definitely don't need are deleted.
  *
+ * Please keep the function ordering so that it is easy to produce diffs
+ * against the linux driver.
+ *
  * The following defines should not be needed normally,
  * but may be helpful for debugging purposes. */
 
@@ -120,7 +123,9 @@ static int e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr, uint16
 static void e1000_phy_hw_reset(struct e1000_hw *hw);
 static int e1000_phy_reset(struct e1000_hw *hw);
 static int e1000_detect_gig_phy(struct e1000_hw *hw);
-static void e1000_irq(struct nic *nic, irq_action_t action);
+static int e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+static void e1000_init_rx_addrs(struct e1000_hw *hw);
+static void e1000_clear_vfta(struct e1000_hw *hw);
 
 /* Printing macros... */
 
@@ -174,11 +179,18 @@ static void e1000_irq(struct nic *nic, irq_action_t action);
 
 #define E1000_WRITE_FLUSH(a) {uint32_t x; x = E1000_READ_REG(a, STATUS);}
 
+
+/******************************************************************************
+ * Inline functions from e1000_main.c of the linux driver
+ ******************************************************************************/
+
+#if 0
 static inline uint32_t
 e1000_io_read(struct e1000_hw *hw __unused, uint32_t port)
 {
         return inl(port);
 }
+#endif
 
 static inline void
 e1000_io_write(struct e1000_hw *hw __unused, uint32_t port, uint32_t value)
@@ -197,1092 +209,578 @@ static inline void e1000_pci_clear_mwi(struct e1000_hw *hw)
                              hw->pci_cmd_word & ~PCI_COMMAND_INVALIDATE);
 }
 
+
 /******************************************************************************
- * Raises the EEPROM's clock input.
- *
- * hw - Struct containing variables accessed by shared code
- * eecd - EECD's current value
- *****************************************************************************/
-static void
-e1000_raise_ee_clk(struct e1000_hw *hw,
-                   uint32_t *eecd)
-{
-       /* Raise the clock input to the EEPROM (by setting the SK bit), and then
-        * wait <delay> microseconds.
-        */
-       *eecd = *eecd | E1000_EECD_SK;
-       E1000_WRITE_REG(hw, EECD, *eecd);
-       E1000_WRITE_FLUSH(hw);
-       udelay(hw->eeprom.delay_usec);
-}
+ * Inline functions from e1000_hw.c of the linux driver
+ ******************************************************************************/
 
 /******************************************************************************
- * Lowers the EEPROM's clock input.
- *
- * hw - Struct containing variables accessed by shared code 
- * eecd - EECD's current value
- *****************************************************************************/
-static void
-e1000_lower_ee_clk(struct e1000_hw *hw,
-                   uint32_t *eecd)
-{
-       /* Lower the clock input to the EEPROM (by clearing the SK bit), and then 
-        * wait 50 microseconds. 
-        */
-       *eecd = *eecd & ~E1000_EECD_SK;
-       E1000_WRITE_REG(hw, EECD, *eecd);
-       E1000_WRITE_FLUSH(hw);
-       udelay(hw->eeprom.delay_usec);
+* Writes a value to one of the devices registers using port I/O (as opposed to
+* memory mapped I/O). Only 82544 and newer devices support port I/O. *
+* hw - Struct containing variables accessed by shared code
+* offset - offset to write to * value - value to write
+*****************************************************************************/
+static inline void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset,
+                                     uint32_t value){
+       e1000_io_write(hw, hw->io_base, offset);
+       e1000_io_write(hw, hw->io_base + 4, value);
 }
 
-/******************************************************************************
- * Shift data bits out to the EEPROM.
- *
- * hw - Struct containing variables accessed by shared code
- * data - data to send to the EEPROM
- * count - number of bits to shift out
- *****************************************************************************/
-static void
-e1000_shift_out_ee_bits(struct e1000_hw *hw,
-                        uint16_t data,
-                        uint16_t count)
-{
-       struct e1000_eeprom_info *eeprom = &hw->eeprom;
-       uint32_t eecd;
-       uint32_t mask;
-       
-       /* We need to shift "count" bits out to the EEPROM. So, value in the
-        * "data" parameter will be shifted out to the EEPROM one bit at a time.
-        * In order to do this, "data" must be broken down into bits. 
-        */
-       mask = 0x01 << (count - 1);
-       eecd = E1000_READ_REG(hw, EECD);
-       if (eeprom->type == e1000_eeprom_microwire) {
-               eecd &= ~E1000_EECD_DO;
-       } else if (eeprom->type == e1000_eeprom_spi) {
-               eecd |= E1000_EECD_DO;
-       }
-       do {
-               /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
-                * and then raising and then lowering the clock (the SK bit controls
-                * the clock input to the EEPROM).  A "0" is shifted out to the EEPROM
-                * by setting "DI" to "0" and then raising and then lowering the clock.
-                */
-               eecd &= ~E1000_EECD_DI;
-               
-               if(data & mask)
-                       eecd |= E1000_EECD_DI;
-               
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               
-               udelay(eeprom->delay_usec);
-               
-               e1000_raise_ee_clk(hw, &eecd);
-               e1000_lower_ee_clk(hw, &eecd);
-               
-               mask = mask >> 1;
-               
-       } while(mask);
 
-       /* We leave the "DI" bit set to "0" when we leave this routine. */
-       eecd &= ~E1000_EECD_DI;
-       E1000_WRITE_REG(hw, EECD, eecd);
-}
+/******************************************************************************
+ * Functions from e1000_hw.c of the linux driver
+ ******************************************************************************/
 
 /******************************************************************************
- * Shift data bits in from the EEPROM
+ * Set the phy type member in the hw struct.
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
-static uint16_t
-e1000_shift_in_ee_bits(struct e1000_hw *hw,
-                       uint16_t count)
+static int32_t
+e1000_set_phy_type(struct e1000_hw *hw)
 {
-       uint32_t eecd;
-       uint32_t i;
-       uint16_t data;
-       
-       /* In order to read a register from the EEPROM, we need to shift 'count' 
-        * bits in from the EEPROM. Bits are "shifted in" by raising the clock
-        * input to the EEPROM (setting the SK bit), and then reading the value of
-        * the "DO" bit.  During this "shifting in" process the "DI" bit should
-        * always be clear.
-        */
-       
-       eecd = E1000_READ_REG(hw, EECD);
-       
-       eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
-       data = 0;
-       
-       for(i = 0; i < count; i++) {
-               data = data << 1;
-               e1000_raise_ee_clk(hw, &eecd);
-               
-               eecd = E1000_READ_REG(hw, EECD);
-               
-               eecd &= ~(E1000_EECD_DI);
-               if(eecd & E1000_EECD_DO)
-                       data |= 1;
-               
-               e1000_lower_ee_clk(hw, &eecd);
+       DEBUGFUNC("e1000_set_phy_type");
+
+       switch(hw->phy_id) {
+       case M88E1000_E_PHY_ID:
+       case M88E1000_I_PHY_ID:
+       case M88E1011_I_PHY_ID:
+               hw->phy_type = e1000_phy_m88;
+               break;
+       case IGP01E1000_I_PHY_ID:
+               hw->phy_type = e1000_phy_igp;
+               break;
+       default:
+               /* Should never have loaded on this device */
+               hw->phy_type = e1000_phy_undefined;
+               return -E1000_ERR_PHY_TYPE;
        }
-       
-       return data;
+
+       return E1000_SUCCESS;
 }
 
 /******************************************************************************
- * Prepares EEPROM for access
+ * IGP phy init script - initializes the GbE PHY
  *
  * hw - Struct containing variables accessed by shared code
- *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This 
- * function should be called before issuing a command to the EEPROM.
  *****************************************************************************/
-static int32_t
-e1000_acquire_eeprom(struct e1000_hw *hw)
+static void
+e1000_phy_init_script(struct e1000_hw *hw)
 {
-       struct e1000_eeprom_info *eeprom = &hw->eeprom;
-       uint32_t eecd, i=0;
+       DEBUGFUNC("e1000_phy_init_script");
 
-       eecd = E1000_READ_REG(hw, EECD);
+#if 0
+       /* See e1000_sw_init() of the Linux driver */
+       if(hw->phy_init_script) {
+#else
+       if((hw->mac_type == e1000_82541) ||
+          (hw->mac_type == e1000_82547) ||
+          (hw->mac_type == e1000_82541_rev_2) ||
+          (hw->mac_type == e1000_82547_rev_2)) {
+#endif
+               mdelay(20);
 
-       /* Request EEPROM Access */
-       if(hw->mac_type > e1000_82544) {
-               eecd |= E1000_EECD_REQ;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               eecd = E1000_READ_REG(hw, EECD);
-               while((!(eecd & E1000_EECD_GNT)) &&
-                     (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
-                       i++;
-                       udelay(5);
-                       eecd = E1000_READ_REG(hw, EECD);
-               }
-               if(!(eecd & E1000_EECD_GNT)) {
-                       eecd &= ~E1000_EECD_REQ;
-                       E1000_WRITE_REG(hw, EECD, eecd);
-                       DEBUGOUT("Could not acquire EEPROM grant\n");
-                       return -E1000_ERR_EEPROM;
-               }
-       }
+               e1000_write_phy_reg(hw,0x0000,0x0140);
 
-       /* Setup EEPROM for Read/Write */
+               mdelay(5);
 
-       if (eeprom->type == e1000_eeprom_microwire) {
-               /* Clear SK and DI */
-               eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
-               E1000_WRITE_REG(hw, EECD, eecd);
+               if(hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547) {
+                       e1000_write_phy_reg(hw, 0x1F95, 0x0001);
 
-               /* Set CS */
-               eecd |= E1000_EECD_CS;
-               E1000_WRITE_REG(hw, EECD, eecd);
-       } else if (eeprom->type == e1000_eeprom_spi) {
-               /* Clear SK and CS */
-               eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-               E1000_WRITE_REG(hw, EECD, eecd);
-               udelay(1);
-       }
+                       e1000_write_phy_reg(hw, 0x1F71, 0xBD21);
 
-       return E1000_SUCCESS;
-}
+                       e1000_write_phy_reg(hw, 0x1F79, 0x0018);
 
-/******************************************************************************
- * Returns EEPROM to a "standby" state
- * 
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-static void
-e1000_standby_eeprom(struct e1000_hw *hw)
-{
-       struct e1000_eeprom_info *eeprom = &hw->eeprom;
-       uint32_t eecd;
-       
-       eecd = E1000_READ_REG(hw, EECD);
+                       e1000_write_phy_reg(hw, 0x1F30, 0x1600);
 
-       if(eeprom->type == e1000_eeprom_microwire) {
+                       e1000_write_phy_reg(hw, 0x1F31, 0x0014);
 
-               /* Deselect EEPROM */
-               eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               udelay(eeprom->delay_usec);
-       
-               /* Clock high */
-               eecd |= E1000_EECD_SK;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               udelay(eeprom->delay_usec);
-       
-               /* Select EEPROM */
-               eecd |= E1000_EECD_CS;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               udelay(eeprom->delay_usec);
+                       e1000_write_phy_reg(hw, 0x1F32, 0x161C);
 
-               /* Clock low */
-               eecd &= ~E1000_EECD_SK;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               udelay(eeprom->delay_usec);
-       } else if(eeprom->type == e1000_eeprom_spi) {
-               /* Toggle CS to flush commands */
-               eecd |= E1000_EECD_CS;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               udelay(eeprom->delay_usec);
-               eecd &= ~E1000_EECD_CS;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               udelay(eeprom->delay_usec);
-       }
-}
+                       e1000_write_phy_reg(hw, 0x1F94, 0x0003);
 
-/******************************************************************************
- * Terminates a command by inverting the EEPROM's chip select pin
- *
- * hw - Struct containing variables accessed by shared code
- *****************************************************************************/
-static void
-e1000_release_eeprom(struct e1000_hw *hw)
-{
-       uint32_t eecd;
+                       e1000_write_phy_reg(hw, 0x1F96, 0x003F);
 
-       eecd = E1000_READ_REG(hw, EECD);
+                       e1000_write_phy_reg(hw, 0x2010, 0x0008);
+               } else {
+                       e1000_write_phy_reg(hw, 0x1F73, 0x0099);
+               }
 
-       if (hw->eeprom.type == e1000_eeprom_spi) {
-               eecd |= E1000_EECD_CS;  /* Pull CS high */
-               eecd &= ~E1000_EECD_SK; /* Lower SCK */
+               e1000_write_phy_reg(hw, 0x0000, 0x3300);
 
-               E1000_WRITE_REG(hw, EECD, eecd);
 
-               udelay(hw->eeprom.delay_usec);
-       } else if(hw->eeprom.type == e1000_eeprom_microwire) {
-               /* cleanup eeprom */
+               if(hw->mac_type == e1000_82547) {
+                       uint16_t fused, fine, coarse;
 
-               /* CS on Microwire is active-high */
-               eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+                       /* Move to analog registers page */
+                       e1000_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
 
-               E1000_WRITE_REG(hw, EECD, eecd);
+                       if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
+                               e1000_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused);
 
-               /* Rising edge of clock */
-               eecd |= E1000_EECD_SK;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               udelay(hw->eeprom.delay_usec);
+                               fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
+                               coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
 
-               /* Falling edge of clock */
-               eecd &= ~E1000_EECD_SK;
-               E1000_WRITE_REG(hw, EECD, eecd);
-               E1000_WRITE_FLUSH(hw);
-               udelay(hw->eeprom.delay_usec);
-       }
+                               if(coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
+                                       coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
+                                       fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
+                               } else if(coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
+                                       fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
 
-       /* Stop requesting EEPROM access */
-       if(hw->mac_type > e1000_82544) {
-               eecd &= ~E1000_EECD_REQ;
-               E1000_WRITE_REG(hw, EECD, eecd);
+                               fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
+                                       (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
+                                       (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
+
+                               e1000_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_CONTROL, fused);
+                               e1000_write_phy_reg(hw, IGP01E1000_ANALOG_FUSE_BYPASS,
+                                               IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
+              &n