-5.4.0 2005-04-01
+5.5.0 2005-05-17
/*
* $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....
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.
SYMCHECK ?= $(PERL) ./util/symcheck.pl
SORTOBJDUMP ?= $(PERL) ./util/sortobjdump.pl
NRV2B ?= ./util/nrv2b
+DOXYGEN ?= doxygen
# Location to place generated files
#
#
SRCDIRS += core
SRCDIRS += proto
-SRCDIRS += image
+#SRCDIRS += image
SRCDIRS += drivers/bus
SRCDIRS += drivers/net
#SRCDIRS += drivers/disk
# 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)
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 :
# 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'"
{
/* 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;
}
/*
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;
}
/*
/**************************************************************************
-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
#include "isa.h"
#include "hardware.h"
-#include "lxt971a.h"
+#include "mii.h"
#include "timer.h"
#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);
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.
}
+
/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
+ * TRANSMIT - Transmit a frame
+ **************************************************************************/
+
/* Function: p2001_eth_transmit
*
* Description: transmits a packet and waits for completion or timeout.
// 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 */
/* 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);
}
+
/**************************************************************************
-IRQ - Enable, Disable or Force Interrupts
-***************************************************************************/
+ * IRQ - Enable, Disable or Force Interrupts
+ **************************************************************************/
+
/* Function: p2001_eth_irq
*
* Description: Enable, Disable, or Force, interrupts
}
+
/**************************************************************************
-INIT - Initialize device
-***************************************************************************/
+ * INIT - Initialize device
+ **************************************************************************/
+
/* Function: p2001_init
*
* Description: resets the ethernet controller chip and various
{
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 */
// 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;
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 */
}
+
/**************************************************************************
-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 */
}
+
/**************************************************************************
-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");
}
+
+/**************************************************************************
+ * 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);
/* Report the ISA pnp id of the board */
dev->devid.vendor_id = htons(GENERIC_ISAPNP_VENDOR);
- dev->devid.vendor_id = htons(0x1234);
return 1;
}
}
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
} 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
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
+++ /dev/null
-/*
- * 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 */
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 */
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 */
# 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
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);
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);
/* 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... */
#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 */
#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 */
#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" );
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 ) {
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 ) {
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,
if ( sh.length == 0 ) {
/* Avoid infinite loop? */
DBG ( "NBI invalid segheader length 0\n" );
+ errno = EBADIMG;
return 0;
}
- 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 */
sh_off += NBI_LENGTH ( sh.length );
if ( sh_off >= NBI_HEADER_LENGTH ) {
DBG ( "NBI header overflow\n" );
+ errno = EBADIMG;
return 0;
}
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 );
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;
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;
imgheader->execaddr.linear );
/* no gateA20_unset for PM call */
+ errno = ENOERR;
rc = xstart32 ( imgheader->execaddr.linear,
virt_to_phys ( &loaderinfo ),
( ( imgheader->location.segment << 4 ) +
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;
}
}
+/** Declaration of the NBI image format */
static struct image nbi_image __image = {
.name = "NBI",
.probe = nbi_probe,
#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.
*
*/
#else /* ASSEMBLY */
-/* Breakpoint for when debugging under bochs */
+/** Breakpoint for when debugging under bochs */
static inline void bochsbp ( void ) {
__asm__ __volatile__ ( "xchgw %bx, %bx" );
}
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 */
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 );
}
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 */
#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
-/*
- * Routines for filling a buffer with data received piecemeal, where
- * the size of the data is not necessarily known in advance.
+/** @file
+ *
+ * Buffers for loading files.
+ *
+ * This file provides routines for filling a buffer with data received
+ * piecemeal, where the size of the data is not necessarily known in
+ * advance.
*
* Some protocols do not provide a mechanism for us to know the size
* of the file before we happen to receive a particular block
* which assemble a file into a single contiguous block. The whole
* block is then passed to the image loader.
*
+ * Example usage:
+ *
+ * @code
+ *
+ * struct buffer my_buffer;
+ * void *data;
+ * off_t offset;
+ * size_t len;
+ *
+ * // We have an area of memory [buf_start,buf_end) into which we want
+ * // to load a file, where buf_start and buf_end are physical addresses.
+ * buffer->start = buf_start;
+ * buffer->end = buf_end;
+ * init_buffer ( &buffer );
+ * ...
+ * while ( get_file_block ( ... ) ) {
+ * // Downloaded block is stored in [data,data+len), and represents
+ * // the portion of the file at offsets [offset,offset+len)
+ * if ( ! fill_buffer ( &buffer, data, offset, len ) ) {
+ * // An error occurred
+ * return 0;
+ * }
+ * ...
+ * }
+ * ...
+ * // The whole file is now present at [buf_start,buf_start+filesize),
+ * // where buf_start is a physical address. The struct buffer can simply
+ * // be discarded; there is no done_buffer() call.
+ *
+ * @endcode
+ *
+ * For a description of the internal operation, see \ref buffer_int.
+ *
+ */
+
+/** @page buffer_int Buffer internals
+ *
+ * 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.
+ *
+ * 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 ) {
DBG ( "BUFFER [%x,%x) initialised\n", buffer->start, buffer->end );
}
-/*
- * Split a free block
+/**
+ * Split a free block.
+ *
+ * @v desc A descriptor for the free block
+ * @v block Start address of the block
+ * @v split Address at which to split the block
+ * @ret None
+ * @err None
+ *
+ * Split a free block into two separate free blocks. If the split
+ * point lies outside the block, no action is taken; this is not an
+ * error.
+ *
+ * @b NOTE: It is the reponsibility of the caller to ensure that there
+ * is enough room in each of the two portions for a free block
+ * descriptor (a @c struct @c buffer_free_block, except in the case of
+ * a tail block which requires only a one byte descriptor). If the
+ * caller fails to do this, data corruption will occur.
+ *
+ * In practice, this means that the granularity at which blocks are
+ * split must be at least @c sizeof(struct @c buffer_free_block).
*
*/
static void split_free_block ( struct buffer_free_block *desc,
copy_to_phys ( block, desc, sizeof ( *desc ) );
}
-/*
- * Mark a free block as used
+/**
+ * Mark a free block as used.
+ *
+ * @v buffer The buffer containing the block
+ * @v desc A descriptor for the free block
+ * @v prev_block Address of the previous block
+ * @ret None
+ * @err None
+ *
+ * Marks a free block as used, i.e. removes it from the free list.
*
*/
static inline void unfree_block ( struct buffer *buffer,
copy_to_phys ( prev_block, &prev_desc, sizeof ( prev_desc ) );
}
-/*
- * 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).
+ *
+ * @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. (See split_free_block() for details.)
*
- * 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.
+ * 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 ) {
if ( data_end > buffer->end ) {
DBG ( "BUFFER [%x,%x) too small for data!\n",
buffer->start, buffer->end );
+ errno = ENOMEM;
return 0;
}
#ifdef DOWNLOAD_PROTO_TFTP
"TFTP "
#endif
+#ifdef DOWNLOAD_PROTO_FSP
+ "FSP "
+#endif
#ifdef DOWNLOAD_PROTO_NFS
"NFS "
#endif
--- /dev/null
+#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;
+}
#include <lib.h>
#endif
+/* Linker symbols */
+extern char _bss[], _ebss[];
+
jmp_buf restart_etherboot;
int url_port;
/* Probe boot device */
if ( ! probe ( &dev ) ) {
/* Device found on bus, but probe failed */
- printf ( "...probe failed\n" );
+ printf ( "...probe failed: %m\n" );
continue;
}
/* 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;
}
/* Boot the image */
if ( ! image->boot ( image_context ) ) {
/* Boot failed */
- printf ( "...boot failed\n" );
+ printf ( "...boot failed: %m\n" );
continue;
}
--- /dev/null
+#include "errno.h"
+
+/*
+ * This table was generated from the relevant section of errno.h using
+ *
+ * perl -ne 'if ( /(PXENV_STATUS_(\S+))/ ) {
+ * $code = $1; $msg = $2;
+ * $msg =~ s/_/ /g; $msg = ucfirst lc $msg;
+ * $msg =~ s/(tftp|udp|arp|undi|bis|binl|pxenv|pxe|dhcp)/uc $1/ieg;
+ * print "\t{ $code, \"$msg\" },\n";
+ * }'
+ *
+ * followed by a little manual tweaking.
+ *
+ */
+static struct errortab pxe_errortab[] __errortab = {
+ { PXENV_STATUS_SUCCESS, "Success" },
+ { PXENV_STATUS_FAILURE, "Failure" },
+ { PXENV_STATUS_BAD_FUNC, "Bad function" },
+ { PXENV_STATUS_UNSUPPORTED, "Unsupported function" },
+ { PXENV_STATUS_KEEP_UNDI, "Keep UNDI" },
+ { PXENV_STATUS_KEEP_ALL, "Keep all" },
+ { PXENV_STATUS_OUT_OF_RESOURCES, "Out of resources" },
+ { PXENV_STATUS_ARP_TIMEOUT, "ARP timeout" },
+ { PXENV_STATUS_UDP_CLOSED, "UDP closed" },
+ { PXENV_STATUS_UDP_OPEN, "UDP open" },
+ { PXENV_STATUS_TFTP_CLOSED, "TFTP closed" },
+ { PXENV_STATUS_TFTP_OPEN, "TFTP open" },
+ { PXENV_STATUS_MCOPY_PROBLEM, "Memory copy problem" },
+ { PXENV_STATUS_BIS_INTEGRITY_FAILURE, "BIS integrity failure" },
+ { PXENV_STATUS_BIS_VALIDATE_FAILURE, "BIS validation failure" },
+ { PXENV_STATUS_BIS_INIT_FAILURE, "BIS init failure" },
+ { PXENV_STATUS_BIS_SHUTDOWN_FAILURE, "BIS shutdown failure" },
+ { PXENV_STATUS_BIS_GBOA_FAILURE, "BIS GBOA failure" },
+ { PXENV_STATUS_BIS_FREE_FAILURE, "BIS free failure" },
+ { PXENV_STATUS_BIS_GSI_FAILURE, "BIS GSI failure" },
+ { PXENV_STATUS_BIS_BAD_CKSUM, "BIS bad checksum" },
+ { PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS, "TFTP cannot ARP address" },
+ { PXENV_STATUS_TFTP_OPEN_TIMEOUT, "TFTP open timeout" },
+ { PXENV_STATUS_TFTP_UNKNOWN_OPCODE, "TFTP unknown opcode" },
+ { PXENV_STATUS_TFTP_READ_TIMEOUT, "TFTP read timeout" },
+ { PXENV_STATUS_TFTP_ERROR_OPCODE, "TFTP error opcode" },
+ { PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION,
+ "TFTP cannot open connection" },
+ { PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION,
+ "TFTP cannot read from connection" },
+ { PXENV_STATUS_TFTP_TOO_MANY_PACKAGES, "TFTP too many packages" },
+ { PXENV_STATUS_TFTP_FILE_NOT_FOUND, "TFTP file not found" },
+ { PXENV_STATUS_TFTP_ACCESS_VIOLATION, "TFTP access violation" },
+ { PXENV_STATUS_TFTP_NO_MCAST_ADDRESS, "TFTP no mcast address" },
+ { PXENV_STATUS_TFTP_NO_FILESIZE, "TFTP no filesize" },
+ { PXENV_STATUS_TFTP_INVALID_PACKET_SIZE, "TFTP invalid packet size" },
+ { PXENV_STATUS_DHCP_TIMEOUT, "DHCP timeout" },
+ { PXENV_STATUS_DHCP_NO_IP_ADDRESS, "DHCP no ip address" },
+ { PXENV_STATUS_DHCP_NO_BOOTFILE_NAME, "DHCP no bootfile name" },
+ { PXENV_STATUS_DHCP_BAD_IP_ADDRESS, "DHCP bad ip address" },
+ { PXENV_STATUS_UNDI_INVALID_FUNCTION, "UNDI invalid function" },
+ { PXENV_STATUS_UNDI_MEDIATEST_FAILED, "UNDI mediatest failed" },
+ { PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST,
+ "UNDI cannot initialise NIC for multicast" },
+ { PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC,
+ "UNDI cannot initialise NIC" },
+ { PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY,
+ "UNDI cannot initialise PHY" },
+ { PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA,
+ "UNDI cannot read config data" },
+ { PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA,
+ "UNDI cannot read init data" },
+ { PXENV_STATUS_UNDI_BAD_MAC_ADDRESS, "UNDI bad MAC address" },
+ { PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM, "UNDI bad EEPROM checksum" },
+ { PXENV_STATUS_UNDI_ERROR_SETTING_ISR, "UNDI error setting ISR" },
+ { PXENV_STATUS_UNDI_INVALID_STATE, "UNDI invalid state" },
+ { PXENV_STATUS_UNDI_TRANSMIT_ERROR, "UNDI transmit error" },
+ { PXENV_STATUS_UNDI_INVALID_PARAMETER, "UNDI invalid parameter" },
+ { PXENV_STATUS_BSTRAP_PROMPT_MENU, "Bootstrap prompt menu" },
+ { PXENV_STATUS_BSTRAP_MCAST_ADDR, "Bootstrap mcast addr" },
+ { PXENV_STATUS_BSTRAP_MISSING_LIST, "Bootstrap missing list" },
+ { PXENV_STATUS_BSTRAP_NO_RESPONSE, "Bootstrap no response" },
+ { PXENV_STATUS_BSTRAP_FILE_TOO_BIG, "Bootstrap file too big" },
+ { PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE,
+ "BINL canceled by keystroke" },
+ { PXENV_STATUS_BINL_NO_PXE_SERVER, "BINL no PXE server" },
+ { PXENV_STATUS_NOT_AVAILABLE_IN_PMODE,
+ "Not available in protected mode" },
+ { PXENV_STATUS_NOT_AVAILABLE_IN_RMODE, "Not available in real mode" },
+ { PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED,
+ "BUSD device not supported" },
+ { PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY,
+ "Loader no free base memory" },
+ { PXENV_STATUS_LOADER_NO_BC_ROMID, "Loader no Base Code ROM ID" },
+ { PXENV_STATUS_LOADER_BAD_BC_ROMID, "Loader bad Base Code ROM ID" },
+ { PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE,
+ "Loader bad Base Code runtime image" },
+ { PXENV_STATUS_LOADER_NO_UNDI_ROMID, "Loader no UNDI ROM ID" },
+ { PXENV_STATUS_LOADER_BAD_UNDI_ROMID, "Loader bad UNDI ROM ID" },
+ { PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE,
+ "Loader bad UNDI driver image" },
+ { PXENV_STATUS_LOADER_NO_PXE_STRUCT, "Loader no !PXE struct" },
+ { PXENV_STATUS_LOADER_NO_PXENV_STRUCT, "Loader no PXENV+ struct" },
+ { PXENV_STATUS_LOADER_UNDI_START, "Loader UNDI start" },
+ { PXENV_STATUS_LOADER_BC_START, "Loader Base Code start" },
+};
#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
+ *
+ * printf and friends.
+ *
+ * Etherboot's printf() functions understand the following format
+ * specifiers:
+ *
+ * - Hexadecimal integers
+ * - @c %[#]x - 4 bytes int (8 hex digits, lower case)
+ * - @c %[#]X - 4 bytes int (8 hex digits, upper case)
+ * - @c %[#]lx - 8 bytes long (16 hex digits, lower case)
+ * - @c %[#]lX - 8 bytes long (16 hex digits, upper case)
+ * - @c %[#]hx - 2 bytes int (4 hex digits, lower case)
+ * - @c %[#]hX - 2 bytes int (4 hex digits, upper case)
+ * - @c %[#]hhx - 1 byte int (2 hex digits, lower case)
+ * - @c %[#]hhX - 1 byte int (2 hex digits, upper case)
+ * .
+ * If the optional # prefix is specified, the output will
+ * be prefixed with 0x (or 0X).
+ *
+ * - Other integers
+ * - @c %d - decimal int
+ * .
+ * Note that any width specification (e.g. the @c 02 in @c %02x)
+ * will be accepted but ignored.
+ *
+ * - Strings and characters
+ * - @c %c - char
+ * - @c %s - string
+ * - @c %m - error message text (i.e. strerror(errno))
+ *
+ * - Etherboot-specific specifiers
+ * - @c %@ - IP in ddd.ddd.ddd.ddd notation
+ * - @c %! - MAC address in xx:xx:xx:xx:xx:xx notation
+ *
+ */
- 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 @c 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 != '%') {
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;
*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);
*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 == '@') {
--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);
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 @c buf==NULL, then the string will be written to the console
+ * directly using putchar().
+ *
+ */
int sprintf(char *buf, const char *fmt, ...)
{
va_list args;
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;
--- /dev/null
+# 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 = YES
+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
+FILE_PATTERNS =
+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 =
+MAKEINDEX_CMD_NAME =
+COMPACT_LATEX = YES
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+#---------------------------------------------------------------------------
+# 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 =
*
***************************************************************************/
-#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 @c
+ * 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
+ 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 );
}
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 );
}
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 ) {
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 ) {
}
}
-/*
- * 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 ) {
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 @c buf is NULL,
+ * the data is discarded.
*
*/
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 @c buf is large enough to contain a tag of the
+ * requested size.
*
*/
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.
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 ) {
}
}
-/*
- * 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 @c bus_loc structure to the next possible ISAPnP
+ * location.
+ *
+ * @v bus_loc Bus location
+ * @ret True @c 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 @c bus_loc structure will
+ * be zeroed.
*
*/
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,
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 ) {
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 ) {
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 ) {
.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,
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 ) {
/* 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 */
--- /dev/null
+/* 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, ®_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, ®_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, ®_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, ®_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, ®_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_BMSR, ®_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_ADVERTISE, ®_val);
+ amd8111e_read_phy(lp, lp->ext_phy_addr, MII_LPA, ®_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 );
--- /dev/null
+/*
+ * 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 */
+
#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,
#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.
*/
#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))
has 34 pins, the top row of 2 are not used.
***************************************************************************/
+/*
+
+ timlegge 2005-05-18 remove the relocation changes cards that
+ write directly to the hardware don't need it
+*/
+
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
#define eeprom_delay() { udelay(40); }
#define EE_READ_CMD (6 << 6)
-/* do a full reset */
-#define eepro_full_reset(ioaddr) outb(RESET_CMD, ioaddr); udelay(40);
+/* do a full reset; data sheet asks for 250us delay */
+#define eepro_full_reset(ioaddr) outb(RESET_CMD, ioaddr); udelay(255);
/* do a nice reset */
#define eepro_sel_reset(ioaddr) { \
eepro_sw2bank0(nic->ioaddr); /* Switch back to bank 0 */
eepro_clear_int(nic->ioaddr);
/* Initialise RCV */
- rx_start = (unsigned int)bus_to_virt(RCV_LOWER_LIMIT << 8);
- outw(RCV_LOWER_LIMIT << 8, nic->ioaddr + RCV_BAR);
+ outw(rx_start = (RCV_LOWER_LIMIT << 8), nic->ioaddr + RCV_BAR);
outw(((RCV_UPPER_LIMIT << 8) | 0xFE), nic->ioaddr + RCV_STOP);
+ /* Make sure 1st poll won't find a valid packet header */
+ outw((RCV_LOWER_LIMIT << 8), nic->ioaddr + HOST_ADDRESS_REG);
+ outw(0, nic->ioaddr + IO_PORT);
/* Intialise XMT */
outw((XMT_LOWER_LIMIT << 8), nic->ioaddr + xmt_bar);
eepro_sel_reset(nic->ioaddr);
- tx_start = tx_end = (unsigned int)bus_to_virt(XMT_LOWER_LIMIT << 8);
+ tx_start = tx_end = (XMT_LOWER_LIMIT << 8);
tx_last = 0;
eepro_en_rx(nic->ioaddr);
}
***************************************************************************/
static int eepro_poll(struct nic *nic, int retrieve)
{
- unsigned int rcv_car = virt_to_bus((void *)rx_start);
+ unsigned int rcv_car = rx_start;
unsigned int rcv_event, rcv_status, rcv_next_frame, rcv_size;
/* return true if there's an ethernet packet ready to read */
}
#endif
nic->packetlen = rcv_size;
- rcv_car = virt_to_bus((void *) (rx_start + RCV_HEADER + rcv_size));
- rx_start = (unsigned int)bus_to_virt(rcv_next_frame << 8);
+ rcv_car = (rx_start + RCV_HEADER + rcv_size);
+ rx_start = rcv_next_frame;
+/*
+ hex_dump(rcv_car, nic->packetlen);
+*/
+
if (rcv_car == 0)
rcv_car = ((RCV_UPPER_LIMIT << 8) | 0xff);
outw(rcv_car - 1, nic->ioaddr + RCV_STOP);
eepro_sw2bank0(nic->ioaddr); /* Switch to bank 0 */
/* Flush the Tx and disable Rx */
outb(STOP_RCV_CMD, nic->ioaddr);
- tx_start = tx_end = (unsigned int) (bus_to_virt(XMT_LOWER_LIMIT << 8));
+ tx_start = tx_end = (XMT_LOWER_LIMIT << 8);
tx_last = 0;
/* Reset the 82595 */
eepro_full_reset(nic->ioaddr);
static int ioaddr;
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
enum speedo_offsets {
SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */
SCBPointer = 4, /* General purpose pointer. */
* (C) 2003 Manfred Spraul
* See Linux Driver for full information
*
-* Linux Driver Version 0.22, 19 Jan 2004
+* Linux Driver Version 0.30, 25 Sep 2004
+* Linux Kernel 2.6.10
*
*
* REVISION HISTORY:
* ================
* v1.0 01-31-2004 timlegge Initial port of Linux driver
* v1.1 02-03-2004 timlegge Large Clean up, first release
-*
+* v1.2 05-14-2005 timlegge Add Linux 0.22 to .030 features
+*
* Indent Options: indent -kr -i8
***************************************************************************/
#include "pci.h"
/* Include timer support functions */
#include "timer.h"
+#include "mii.h"
-#define drv_version "v1.1"
-#define drv_date "02-03-2004"
+#define drv_version "v1.2"
+#define drv_date "05-14-2005"
//#define TFTM_DEBUG
#ifdef TFTM_DEBUG
#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;
+#define ETH_DATA_LEN 1500
/* Condensed operations for readability. */
#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
static unsigned long BASE;
/* NIC specific static variables go here */
+#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3
+#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066
+#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086
+#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c
+#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6
+#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df
+#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6
+#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056
+#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057
+#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037
+#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038
/*
* Hardware access:
*/
-#define DEV_NEED_LASTPACKET1 0x0001
-#define DEV_IRQMASK_1 0x0002
-#define DEV_IRQMASK_2 0x0004
-#define DEV_NEED_TIMERIRQ 0x0008
+#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */
+#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */
+#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */
+#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */
+#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */
enum {
NvRegIrqStatus = 0x000,
#define NVREG_IRQSTAT_MIIEVENT 0040
#define NVREG_IRQSTAT_MASK 0x1ff
NvRegIrqMask = 0x004,
+#define NVREG_IRQ_RX_ERROR 0x0001
#define NVREG_IRQ_RX 0x0002
#define NVREG_IRQ_RX_NOBUF 0x0004
#define NVREG_IRQ_TX_ERR 0x0008
#define NVREG_IRQ_TX1 0x0100
#define NVREG_IRQMASK_WANTED_1 0x005f
#define NVREG_IRQMASK_WANTED_2 0x0147
-#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
+#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1))
NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL 3
NvRegOffloadConfig = 0x90,
#define NVREG_OFFLOAD_HOMEPHY 0x601
-#define NVREG_OFFLOAD_NORMAL 0x5ee
+#define NVREG_OFFLOAD_NORMAL RX_NIC_BUFSIZE
NvRegReceiverControl = 0x094,
#define NVREG_RCVCTL_START 0x01
NvRegReceiverStatus = 0x98,
NvRegRandomSeed = 0x9c,
#define NVREG_RNDSEED_MASK 0x00ff
#define NVREG_RNDSEED_FORCE 0x7f00
+#define NVREG_RNDSEED_FORCE2 0x2d00
+#define NVREG_RNDSEED_FORCE3 0x7400
NvRegUnknownSetupReg1 = 0xA0,
#define NVREG_UNKSETUP1_VAL 0x16070f
NvRegMulticastMaskA = 0xB8,
NvRegMulticastMaskB = 0xBC,
+ NvRegPhyInterface = 0xC0,
+#define PHY_RGMII 0x10000000
+
NvRegTxRingPhysAddr = 0x100,
NvRegRxRingPhysAddr = 0x104,
NvRegRingSizes = 0x108,
NvRegUnknownTransmitterReg = 0x10c,
NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
-#define NVREG_LINKSPEED_10 10
+#define NVREG_LINKSPEED_10 1000
#define NVREG_LINKSPEED_100 100
-#define NVREG_LINKSPEED_1000 1000
+#define NVREG_LINKSPEED_1000 50
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
- NvRegUnknownSetupReg3 = 0x134,
+ NvRegUnknownSetupReg3 = 0x13c,
#define NVREG_UNKSETUP3_VAL1 0x200010
NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK 0x0001
#define NVREG_TXRXCTL_BIT2 0x0004
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
+#define NVREG_TXRXCTL_RXCHECK 0x0400
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
NvRegAdapterControl = 0x188,
#define NVREG_ADAPTCTL_START 0x02
#define NVREG_ADAPTCTL_LINKUP 0x04
-#define NVREG_ADAPTCTL_PHYVALID 0x4000
+#define NVREG_ADAPTCTL_PHYVALID 0x40000
#define NVREG_ADAPTCTL_RUNNING 0x100000
#define NVREG_ADAPTCTL_PHYSHIFT 24
NvRegMIISpeed = 0x18c,
#define NVREG_MIISPEED_BIT8 (1<<8)
#define NVREG_MIIDELAY 5
NvRegMIIControl = 0x190,
-#define NVREG_MIICTL_INUSE 0x10000
-#define NVREG_MIICTL_WRITE 0x08000
+#define NVREG_MIICTL_INUSE 0x08000
+#define NVREG_MIICTL_WRITE 0x00400
#define NVREG_MIICTL_ADDRSHIFT 5
NvRegMIIData = 0x194,
NvRegWakeUpFlags = 0x200,
#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01
#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
+#define NVREG_WAKEUPFLAGS_ENABLE 0x1111
NvRegPatternCRC = 0x204,
NvRegPatternMask = 0x208,
#define NVREG_POWERSTATE_D3 0x0003
};
-
-
-#define NV_TX_LASTPACKET (1<<0)
-#define NV_TX_RETRYERROR (1<<3)
-#define NV_TX_LASTPACKET1 (1<<8)
-#define NV_TX_DEFERRED (1<<10)
-#define NV_TX_CARRIERLOST (1<<11)
-#define NV_TX_LATECOLLISION (1<<12)
-#define NV_TX_UNDERFLOW (1<<13)
-#define NV_TX_ERROR (1<<14)
-#define NV_TX_VALID (1<<15)
-
-#define NV_RX_DESCRIPTORVALID (1<<0)
-#define NV_RX_MISSEDFRAME (1<<1)
-#define NV_RX_SUBSTRACT1 (1<<3)
-#define NV_RX_ERROR1 (1<<7)
-#define NV_RX_ERROR2 (1<<8)
-#define NV_RX_ERROR3 (1<<9)
-#define NV_RX_ERROR4 (1<<10)
-#define NV_RX_CRCERR (1<<11)
-#define NV_RX_OVERFLOW (1<<12)
-#define NV_RX_FRAMINGERR (1<<13)
-#define NV_RX_ERROR (1<<14)
-#define NV_RX_AVAIL (1<<15)
+#define FLAG_MASK_V1 0xffff0000
+#define FLAG_MASK_V2 0xffffc000
+#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
+#define LEN_MASK_V2 (0xffffffff ^ FLAG_MASK_V2)
+
+#define NV_TX_LASTPACKET (1<<16)
+#define NV_TX_RETRYERROR (1<<19)
+#define NV_TX_LASTPACKET1 (1<<24)
+#define NV_TX_DEFERRED (1<<26)
+#define NV_TX_CARRIERLOST (1<<27)
+#define NV_TX_LATECOLLISION (1<<28)
+#define NV_TX_UNDERFLOW (1<<29)
+#define NV_TX_ERROR (1<<30)
+#define NV_TX_VALID (1<<31)
+
+#define NV_TX2_LASTPACKET (1<<29)
+#define NV_TX2_RETRYERROR (1<<18)
+#define NV_TX2_LASTPACKET1 (1<<23)
+#define NV_TX2_DEFERRED (1<<25)
+#define NV_TX2_CARRIERLOST (1<<26)
+#define NV_TX2_LATECOLLISION (1<<27)
+#define NV_TX2_UNDERFLOW (1<<28)
+/* error and valid are the same for both */
+#define NV_TX2_ERROR (1<<30)
+#define NV_TX2_VALID (1<<31)
+
+#define NV_RX_DESCRIPTORVALID (1<<16)
+#define NV_RX_MISSEDFRAME (1<<17)
+#define NV_RX_SUBSTRACT1 (1<<18)
+#define NV_RX_ERROR1 (1<<23)
+#define NV_RX_ERROR2 (1<<24)
+#define NV_RX_ERROR3 (1<<25)
+#define NV_RX_ERROR4 (1<<26)
+#define NV_RX_CRCERR (1<<27)
+#define NV_RX_OVERFLOW (1<<28)
+#define NV_RX_FRAMINGERR (1<<29)
+#define NV_RX_ERROR (1<<30)
+#define NV_RX_AVAIL (1<<31)
+
+#define NV_RX2_CHECKSUMMASK (0x1C000000)
+#define NV_RX2_CHECKSUMOK1 (0x10000000)
+#define NV_RX2_CHECKSUMOK2 (0x14000000)
+#define NV_RX2_CHECKSUMOK3 (0x18000000)
+#define NV_RX2_DESCRIPTORVALID (1<<29)
+#define NV_RX2_SUBSTRACT1 (1<<25)
+#define NV_RX2_ERROR1 (1<<18)
+#define NV_RX2_ERROR2 (1<<19)
+#define NV_RX2_ERROR3 (1<<20)
+#define NV_RX2_ERROR4 (1<<21)
+#define NV_RX2_CRCERR (1<<22)
+#define NV_RX2_OVERFLOW (1<<23)
+#define NV_RX2_FRAMINGERR (1<<24)
+/* error and avail are the same for both */
+#define NV_RX2_ERROR (1<<30)
+#define NV_RX2_AVAIL (1<<31)
/* Miscelaneous hardware related defines: */
#define NV_PCI_REGSZ 0x270
#define NV_WAKEUPMASKENTRIES 4
/* General driver defaults */
-#define NV_WATCHDOG_TIMEO (2*HZ)
-#define DEFAULT_MTU 1500 /* also maximum supported, at least for now */
+#define NV_WATCHDOG_TIMEO (5*HZ)
#define RX_RING 4
#define TX_RING 2
-/* limited to 1 packet until we understand NV_TX_LASTPACKET */
-#define TX_LIMIT_STOP 10
-#define TX_LIMIT_START 5
+
+/*
+ * If your nic mysteriously hangs then try to reduce the limits
+ * to 1/0: It might be required to set NV_TX_LASTPACKET in the
+ * last valid ring entry. But this would be impossible to
+ * implement - probably a disassembly error.
+ */
+#define TX_LIMIT_STOP 63
+#define TX_LIMIT_START 62
/* rx/tx mac addr + type + vlan + align + slack*/
-#define RX_NIC_BUFSIZE (DEFAULT_MTU + 64)
+#define RX_NIC_BUFSIZE (ETH_DATA_LEN + 64)
/* even more slack */
-#define RX_ALLOC_BUFSIZE (DEFAULT_MTU + 128)
+#define RX_ALLOC_BUFSIZE (ETH_DATA_LEN + 128)
#define OOM_REFILL (1+HZ/20)
#define POLL_WAIT (1+HZ/100)
-
+#define LINK_TIMEOUT (3*HZ)
+
+/*
+ * desc_ver values:
+ * This field has two purposes:
+ * - Newer nics uses a different ring layout. The layout is selected by
+ * comparing np->desc_ver with DESC_VER_xy.
+ * - It contains bits that are forced on when writing to NvRegTxRxControl.
+ */
+#define DESC_VER_1 0x0
+#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
+
+/* PHY defines */
+#define PHY_OUI_MARVELL 0x5043
+#define PHY_OUI_CICADA 0x03f1
+#define PHYID1_OUI_MASK 0x03ff
+#define PHYID1_OUI_SHFT 6
+#define PHYID2_OUI_MASK 0xfc00
+#define PHYID2_OUI_SHFT 10
+#define PHY_INIT1 0x0f000
+#define PHY_INIT2 0x0e00
+#define PHY_INIT3 0x01000
+#define PHY_INIT4 0x0200
+#define PHY_INIT5 0x0004
+#define PHY_INIT6 0x02000
+#define PHY_GIGABIT 0x0100
+
+#define PHY_TIMEOUT 0x1
+#define PHY_ERROR 0x2
+
+#define PHY_100 0x1
+#define PHY_1000 0x2
+#define PHY_HALF 0x100
+
+/* FIXME: MII defines that should be added to <linux/mii.h> */
+#define MII_1000BT_CR 0x09
+#define MII_1000BT_SR 0x0a
+#define ADVERTISE_1000FULL 0x0200
+#define ADVERTISE_1000HALF 0x0100
+#define LPA_1000FULL 0x0800
+#define LPA_1000HALF 0x0400
+
+/* Big endian: should work, but is untested */
struct ring_desc {
u32 PacketBuffer;
- u16 Length;
- u16 Flags;
+ u32 FlagLen;
};
u32 linkspeed;
int duplex;
int phyaddr;
+ int wolenabled;
+ unsigned int phy_oui;
+ u16 gigabit;
/* General data: RO fields */
u8 *ring_addr;
u32 orig_mac[2];
u32 irqmask;
+ u32 desc_ver;
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
unsigned int cur_rx, refill_rx;
- unsigned int rx_buf_sz;
/*
* tx specific fields.
*/
unsigned int next_tx, nic_tx;
- u16 tx_flags;
+ u32 tx_flags;
} npx;
static struct forcedeth_private *np;
/* force out pending posted writes */
readl(base);
}
+
+static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
+{
+ return le32_to_cpu(prd->FlagLen)
+ & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
+}
+
static int reg_delay(int offset, u32 mask,
u32 target, int delay, int delaymax, const char *msg)
{
int value)
{
u8 *base = (u8 *) BASE;
- int was_running;
u32 reg;
int retval;
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
- was_running = 0;
- reg = readl(base + NvRegAdapterControl);
- if (reg & NVREG_ADAPTCTL_RUNNING) {
- was_running = 1;
- writel(reg & ~NVREG_ADAPTCTL_RUNNING,
- base + NvRegAdapterControl);
- }
+
reg = readl(base + NvRegMIIControl);
if (reg & NVREG_MIICTL_INUSE) {
writel(NVREG_MIICTL_INUSE, base + NvRegMIIControl);
}
reg =
- NVREG_MIICTL_INUSE | (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
+ (addr << NVREG_MIICTL_ADDRSHIFT) | miireg;
if (value != MII_READ) {
writel(value, base + NvRegMIIData);
reg |= NVREG_MIICTL_WRITE;
miireg, addr));
retval = -1;
} else {
- /* FIXME: why is that required? */
- udelay(50);
retval = readl(base + NvRegMIIData);
dprintf(("mii_rw read from reg %d at PHY %d: 0x%x.\n",
miireg, addr, retval));
}
- if (was_running) {
- reg = readl(base + NvRegAdapterControl);
- writel(reg | NVREG_ADAPTCTL_RUNNING,
- base + NvRegAdapterControl);
- }
return retval;
}
+static int phy_reset(struct nic *nic)
+{
+
+ u32 miicontrol;
+ unsigned int tries = 0;
+
+ miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
+ miicontrol |= BMCR_RESET;
+ if (mii_rw(nic, np->phyaddr, MII_BMCR, miicontrol)) {
+ return -1;
+ }
+
+ /* wait for 500ms */
+ mdelay(500);
+
+ /* must wait till reset is deasserted */
+ while (miicontrol & BMCR_RESET) {
+ mdelay(10);
+ miicontrol = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
+ /* FIXME: 100 tries seem excessive */
+ if (tries++ > 100)
+ return -1;
+ }
+ return 0;
+}
+
+static int phy_init(struct nic *nic)
+{
+ u8 *base = (u8 *) BASE;
+ u32 phyinterface, phy_reserved, mii_status, mii_control,
+ mii_control_1000, reg;
+
+ /* set advertise register */
+ reg = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ);
+ reg |=
+ (ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF |
+ ADVERTISE_100FULL | 0x800 | 0x400);
+ if (mii_rw(nic, np->phyaddr, MII_ADVERTISE, reg)) {
+ printf("phy write to advertise failed.\n");
+ return PHY_ERROR;
+ }
+
+ /* get phy interface type */
+ phyinterface = readl(base + NvRegPhyInterface);
+
+ /* see if gigabit phy */
+ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
+
+ if (mii_status & PHY_GIGABIT) {
+ np->gigabit = PHY_GIGABIT;
+ mii_control_1000 =
+ mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ);
+ mii_control_1000 &= ~ADVERTISE_1000HALF;
+ if (phyinterface & PHY_RGMII)
+ mii_control_1000 |= ADVERTISE_1000FULL;
+ else
+ mii_control_1000 &= ~ADVERTISE_1000FULL;
+
+ if (mii_rw
+ (nic, np->phyaddr, MII_1000BT_CR, mii_control_1000)) {
+ printf("phy init failed.\n");
+ return PHY_ERROR;
+ }
+ } else
+ np->gigabit = 0;
+
+ /* reset the phy */
+ if (phy_reset(nic)) {
+ printf("phy reset failed\n");
+ return PHY_ERROR;
+ }
+
+ /* phy vendor specific configuration */
+ if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII)) {
+ phy_reserved =
+ mii_rw(nic, np->phyaddr, MII_RESV1, MII_READ);
+ phy_reserved &= ~(PHY_INIT1 | PHY_INIT2);
+ phy_reserved |= (PHY_INIT3 | PHY_INIT4);
+ if (mii_rw(nic, np->phyaddr, MII_RESV1, phy_reserved)) {
+ printf("phy init failed.\n");
+ return PHY_ERROR;
+ }
+ phy_reserved =
+ mii_rw(nic, np->phyaddr, MII_NCONFIG, MII_READ);
+ phy_reserved |= PHY_INIT5;
+ if (mii_rw(nic, np->phyaddr, MII_NCONFIG, phy_reserved)) {
+ printf("phy init failed.\n");
+ return PHY_ERROR;
+ }
+ }
+ if (np->phy_oui == PHY_OUI_CICADA) {
+ phy_reserved =
+ mii_rw(nic, np->phyaddr, MII_SREVISION, MII_READ);
+ phy_reserved |= PHY_INIT6;
+ if (mii_rw(nic, np->phyaddr, MII_SREVISION, phy_reserved)) {
+ printf("phy init failed.\n");
+ return PHY_ERROR;
+ }
+ }
+
+ /* restart auto negotiation */
+ mii_control = mii_rw(nic, np->phyaddr, MII_BMCR, MII_READ);
+ mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
+ if (mii_rw(nic, np->phyaddr, MII_BMCR, mii_control)) {
+ return PHY_ERROR;
+ }
+
+ return 0;
+}
+
static void start_rx(struct nic *nic __unused)
{
u8 *base = (u8 *) BASE;
u8 *base = (u8 *) BASE;
dprintf(("txrx_reset\n"));
- writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET,
+ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver,
base + NvRegTxRxControl);
+
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
- writel(NVREG_TXRXCTL_BIT2, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
}
//int nr = refill_rx % RX_RING;
rx_ring[i].PacketBuffer =
virt_to_le32desc(&rxb[i * RX_NIC_BUFSIZE]);
- rx_ring[i].Length = cpu_to_le16(RX_NIC_BUFSIZE);
wmb();
- rx_ring[i].Flags = cpu_to_le16(NV_RX_AVAIL);
+ rx_ring[i].FlagLen =
+ cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL);
/* printf("alloc_rx: Packet %d marked as Available\n",
refill_rx); */
refill_rx++;
static int update_linkspeed(struct nic *nic)
{
- int adv, lpa, newdup;
+ int adv, lpa;
u32 newls;
+ int newdup = np->duplex;
+ u32 mii_status;
+ int retval = 0;
+ u32 control_1000, status_1000, phyreg;
+ u8 *base = (u8 *) BASE;
+ int i;
+
+ /* BMSR_LSTATUS is latched, read it twice:
+ * we want the current value.
+ */
+ mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
+ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
+
+#if 1
+ //yhlu
+ for(i=0;i<30;i++) {
+ mii_status = mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ);
+ if((mii_status & BMSR_LSTATUS) && (mii_status & BMSR_ANEGCOMPLETE)) break;
+ mdelay(100);
+ }
+#endif
+
+ if (!(mii_status & BMSR_LSTATUS)) {
+ printf
+ ("no link detected by phy - falling back to 10HD.\n");
+ newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+ newdup = 0;
+ retval = 0;
+ goto set_speed;
+ }
+
+ /* check auto negotiation is complete */
+ if (!(mii_status & BMSR_ANEGCOMPLETE)) {
+ /* still in autonegotiation - configure nic for 10 MBit HD and wait. */
+ newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
+ newdup = 0;
+ retval = 0;
+ printf("autoneg not completed - falling back to 10HD.\n");
+ goto set_speed;
+ }
+
+ retval = 1;
+ if (np->gigabit == PHY_GIGABIT) {
+ control_1000 =
+ mii_rw(nic, np->phyaddr, MII_1000BT_CR, MII_READ);
+ status_1000 =
+ mii_rw(nic, np->phyaddr, MII_1000BT_SR, MII_READ);
+
+ if ((control_1000 & ADVERTISE_1000FULL) &&
+ (status_1000 & LPA_1000FULL)) {
+ printf
+ ("update_linkspeed: GBit ethernet detected.\n");
+ newls =
+ NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_1000;
+ newdup = 1;
+ goto set_speed;
+ }
+ }
+
adv = mii_rw(nic, np->phyaddr, MII_ADVERTISE, MII_READ);
lpa = mii_rw(nic, np->phyaddr, MII_LPA, MII_READ);
dprintf(("update_linkspeed: PHY advertises 0x%hX, lpa 0x%hX.\n",
newls = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
newdup = 0;
}
- if (np->duplex != newdup || np->linkspeed != newls) {
- np->duplex = newdup;
- np->linkspeed = newls;
- return 1;
+
+ set_speed:
+ if (np->duplex == newdup && np->linkspeed == newls)
+ return retval;
+
+ dprintf(("changing link setting from %d/%s to %d/%s.\n",
+ np->linkspeed, np->duplex ? "Full-Duplex": "Half-Duplex", newls, newdup ? "Full-Duplex": "Half-Duplex"));
+
+ np->duplex = newdup;
+ np->linkspeed = newls;
+
+ if (np->gigabit == PHY_GIGABIT) {
+ phyreg = readl(base + NvRegRandomSeed);
+ phyreg &= ~(0x3FF00);
+ if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10)
+ phyreg |= NVREG_RNDSEED_FORCE3;
+ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
+ phyreg |= NVREG_RNDSEED_FORCE2;
+ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
+ phyreg |= NVREG_RNDSEED_FORCE;
+ writel(phyreg, base + NvRegRandomSeed);
}
- return 0;
-}
+ phyreg = readl(base + NvRegPhyInterface);
+ phyreg &= ~(PHY_HALF | PHY_100 | PHY_1000);
+ if (np->duplex == 0)
+ phyreg |= PHY_HALF;
+ if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
+ phyreg |= PHY_100;
+ else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
+ phyreg |= PHY_1000;
+ writel(phyreg, base + NvRegPhyInterface);
+ writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
+ base + NvRegMisc1);
+ pci_push(base);
+ writel(np->linkspeed, base + NvRegLinkSpeed);
+ pci_push(base);
+
+ return retval;
+}
+
+#if 0 /* Not used */
+static void nv_linkchange(struct nic *nic)
+{
+ if (update_linkspeed(nic)) {
+// if (netif_carrier_ok(nic)) {
+ stop_rx();
+//= } else {
+ // netif_carrier_on(dev);
+ // printk(KERN_INFO "%s: link up.\n", dev->name);
+ // }
+ start_rx(nic);
+ } else {
+ // if (netif_carrier_ok(dev)) {
+ // netif_carrier_off(dev);
+ // printk(KERN_INFO "%s: link down.\n", dev->name);
+ stop_rx();
+ // }
+ }
+}
+#endif
static int init_ring(struct nic *nic)
{
int i;
np->next_tx = np->nic_tx = 0;
- for (i = 0; i < TX_RING; i++) {
- tx_ring[i].Flags = 0;
- }
+ for (i = 0; i < TX_RING; i++)
+ tx_ring[i].FlagLen = 0;
np->cur_rx = 0;
np->refill_rx = 0;
- for (i = 0; i < RX_RING; i++) {
- rx_ring[i].Flags = 0;
- }
+ for (i = 0; i < RX_RING; i++)
+ rx_ring[i].FlagLen = 0;
return alloc_rx(nic);
}
writel(0, base + NvRegMulticastMaskA);
writel(0, base + NvRegMulticastMaskB);
writel(0, base + NvRegPacketFilterFlags);
+
+ writel(0, base + NvRegTransmitterControl);
+ writel(0, base + NvRegReceiverControl);
+
writel(0, base + NvRegAdapterControl);
+
+ /* 2) initialize descriptor rings */
+ oom = init_ring(nic);
+
writel(0, base + NvRegLinkSpeed);
writel(0, base + NvRegUnknownTransmitterReg);
txrx_reset(nic);
writel(0, base + NvRegUnknownSetupReg6);
- /* 2) initialize descriptor rings */
np->in_shutdown = 0;
- oom = init_ring(nic);
/* 3) set mac address */
{
writel(mac[1], base + NvRegMacAddrB);
}
- /* 4) continue setup */
+ /* 4) give hw rings */
+ writel((u32) virt_to_le32desc(&rx_ring[0]),
+ base + NvRegRxRingPhysAddr);
+ writel((u32) virt_to_le32desc(&tx_ring[0]),
+ base + NvRegTxRingPhysAddr);
+
+ writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) +
+ ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT),
+ base + NvRegRingSizes);
+
+ /* 5) continue setup */
np->linkspeed = NVREG_LINKSPEED_FORCE | NVREG_LINKSPEED_10;
np->duplex = 0;
+ writel(np->linkspeed, base + NvRegLinkSpeed);
writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
- writel(0, base + NvRegTxRxControl);
+ writel(np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
- writel(NVREG_TXRXCTL_BIT1, base + NvRegTxRxControl);
-
+ writel(NVREG_TXRXCTL_BIT1 | np->desc_ver, base + NvRegTxRxControl);
reg_delay(NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31,
NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY,
NV_SETUP5_DELAYMAX,
"open: SetupReg5, Bit 31 remained off\n");
- writel(0, base + NvRegUnknownSetupReg4);
-
- /* 5) Find a suitable PHY */
- writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed);
- for (i = 1; i < 32; i++) {
- int id1, id2;
-
- id1 = mii_rw(nic, i, MII_PHYSID1, MII_READ);
- if (id1 < 0)
- continue;
- id2 = mii_rw(nic, i, MII_PHYSID2, MII_READ);
- if (id2 < 0)
- continue;
- dprintf(("open: Found PHY %04x:%04x at address %d.\n",
- id1, id2, i));
- np->phyaddr = i;
-
- update_linkspeed(nic);
-
- break;
- }
- if (i == 32) {
- printf("open: failing due to lack of suitable PHY.\n");
- ret = -1;
- goto out_drain;
- }
+ writel(0, base + NvRegUnknownSetupReg4);
+// writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
+#if 0
printf("%d-Mbs Link, %s-Duplex\n",
np->linkspeed & NVREG_LINKSPEED_10 ? 10 : 100,
np->duplex ? "Full" : "Half");
+#endif
+
/* 6) continue setup */
- writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
- base + NvRegMisc1);
+ writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
writel(readl(base + NvRegTransmitterStatus),
base + NvRegTransmitterStatus);
writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
writel(readl(base + NvRegReceiverStatus),
base + NvRegReceiverStatus);
- /* FIXME: I cheated and used the calculator to get a random number */
- i = 75963081;
+ /* Get a random number */
+ i = random();
writel(NVREG_RNDSEED_FORCE | (i & NVREG_RNDSEED_MASK),
base + NvRegRandomSeed);
writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6);
writel((np->
phyaddr << NVREG_ADAPTCTL_PHYSHIFT) |
- NVREG_ADAPTCTL_PHYVALID, base + NvRegAdapterControl);
+ NVREG_ADAPTCTL_PHYVALID | NVREG_ADAPTCTL_RUNNING,
+ base + NvRegAdapterControl);
+ writel(NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY, base + NvRegMIISpeed);
writel(NVREG_UNKSETUP4_VAL, base + NvRegUnknownSetupReg4);
writel(NVREG_WAKEUPFLAGS_VAL, base + NvRegWakeUpFlags);
- /* 7) start packet processing */
- writel((u32) virt_to_le32desc(&rx_ring[0]),
- base + NvRegRxRingPhysAddr);
- writel((u32) virt_to_le32desc(&tx_ring[0]),
- base + NvRegTxRingPhysAddr);
-
-
- writel(((RX_RING - 1) << NVREG_RINGSZ_RXSHIFT) +
- ((TX_RING - 1) << NVREG_RINGSZ_TXSHIFT),
- base + NvRegRingSizes);
-
i = readl(base + NvRegPowerState);
- if ((i & NVREG_POWERSTATE_POWEREDUP) == 0) {
+ if ((i & NVREG_POWERSTATE_POWEREDUP) == 0)
writel(NVREG_POWERSTATE_POWEREDUP | i,
base + NvRegPowerState);
- }
+
pci_push(base);
udelay(10);
writel(readl(base + NvRegPowerState) | NVREG_POWERSTATE_VALID,
base + NvRegPowerState);
- writel(NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl);
writel(0, base + NvRegIrqMask);
pci_push(base);
- writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
- pci_push(base);
writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
pci_push(base);
base + NvRegPacketFilterFlags);
set_multicast(nic);
+ /* One manual link speed update: Interrupts are enabled, future link
+ * speed changes cause interrupts and are handled by nv_link_irq().
+ */
+ {
+ u32 miistat;
+ miistat = readl(base + NvRegMIIStatus);
+ writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
+ dprintf(("startup: got 0x%hX.\n", miistat));
+ }
+ ret = update_linkspeed(nic);
+
//start_rx(nic);
start_tx(nic);
- if (!
- (mii_rw(nic, np->phyaddr, MII_BMSR, MII_READ) &
- BMSR_ANEGCOMPLETE)) {
+ if (ret) {
+ //Start Connection netif_carrier_on(dev);
+ } else {
printf("no link during initialization.\n");
}
- udelay(10000);
- out_drain:
return ret;
}
-//extern void hex_dump(const char *data, const unsigned int len);
-
+/*
+ * extern void hex_dump(const char *data, const unsigned int len);
+*/
/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
/* nic->packet should contain data on return */
/* nic->packetlen should contain length of data */
- struct ring_desc *prd;
int len;
int i;
+ u32 Flags;
i = np->cur_rx % RX_RING;
- prd = &rx_ring[i];
- if ( ! (prd->Flags & cpu_to_le16(NV_RX_DESCRIPTORVALID)) ) {
- return 0;
+ Flags = le32_to_cpu(rx_ring[i].FlagLen);
+ len = nv_descr_getlength(&rx_ring[i], np->desc_ver);
+
+ if (Flags & NV_RX_AVAIL)
+ return 0; /* still owned by hardware, */
+
+ if (np->desc_ver == DESC_VER_1) {
+ if (!(Flags & NV_RX_DESCRIPTORVALID))
+ return 0;
+ } else {
+ if (!(Flags & NV_RX2_DESCRIPTORVALID))
+ return 0;
}
- if ( ! retrieve ) return 1;
+ if (!retrieve)
+ return 1;
/* got a valid packet - forward it to the network core */
- len = cpu_to_le16(prd->Length);
nic->packetlen = len;
- //hex_dump(rxb + (i * RX_NIC_BUFSIZE), len);
- memcpy(nic->packet, rxb +
- (i * RX_NIC_BUFSIZE), nic->packetlen);
-
+ memcpy(nic->packet, rxb + (i * RX_NIC_BUFSIZE), nic->packetlen);
+/*
+ * hex_dump(rxb + (i * RX_NIC_BUFSIZE), len);
+*/
wmb();
np->cur_rx++;
alloc_rx(nic);
/* send the packet to destination */
u8 *ptxb;
u16 nstype;
- //u16 status;
u8 *base = (u8 *) BASE;
int nr = np->next_tx % TX_RING;
ptxb[s++] = '\0';
tx_ring[nr].PacketBuffer = (u32) virt_to_le32desc(ptxb);
- tx_ring[nr].Length = cpu_to_le16(s - 1);
wmb();
- tx_ring[nr].Flags = np->tx_flags;
+ tx_ring[nr].FlagLen = cpu_to_le32((s - 1) | np->tx_flags);
- writel(NVREG_TXRXCTL_KICK, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_KICK | np->desc_ver, base + NvRegTxRxControl);
pci_push(base);
- tx_ring[nr].Flags = np->tx_flags;
np->next_tx++;
}
/**************************************************************************
IRQ - Enable, Disable, or Force interrupts
***************************************************************************/
-static void forcedeth_irq(struct nic *nic __unused, irq_action_t action __unused)
+static void forcedeth_irq(struct nic *nic __unused,
+ irq_action_t action __unused)
{
- switch ( action ) {
- case DISABLE :
- break;
- case ENABLE :
- break;
- case FORCE :
- break;
- }
+ switch (action) {
+ case DISABLE:
+ break;
+ case ENABLE:
+ break;
+ case FORCE:
+ break;
+ }
}
static struct nic_operations forcedeth_operations = {
};
-static struct pci_id forcedeth_nics[] = {
- PCI_ROM(0x10de, 0x01C3, "nforce", "nForce Ethernet Controller"),
- PCI_ROM(0x10de, 0x0066, "nforce2", "nForce2 Ethernet Controller"),
- PCI_ROM(0x10de, 0x00D6, "nforce3", "nForce3 Ethernet Controller"),
-};
-
-PCI_DRIVER ( forcedeth_driver, forcedeth_nics, PCI_NO_CLASS );
-
/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
unsigned long addr;
int sz;
u8 *base;
+ int i;
if (pci->ioaddr == 0)
return 0;
BASE = (unsigned long) ioremap(addr, sz);
if (!BASE)
return 0;
+
+ /* handle different descriptor versions */
+ if (pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
+ pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
+ pci->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_3)
+ np->desc_ver = DESC_VER_1;
+ else
+ np->desc_ver = DESC_VER_2;
+
//rx_ring[0] = rx_ring;
//tx_ring[0] = tx_ring;
#endif
printf("%s: MAC Address %!, ", pci->name, nic->node_addr);
- np->tx_flags =
- cpu_to_le16(NV_TX_LASTPACKET | NV_TX_LASTPACKET1 |
- NV_TX_VALID);
- switch (pci->device_id) {
- case 0x01C3: // nforce
- np->irqmask = NVREG_IRQMASK_WANTED_2;
- np->irqmask |= NVREG_IRQ_TIMER;
- break;
- case 0x0066: // nforce2
- np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
- np->irqmask = NVREG_IRQMASK_WANTED_2;
- np->irqmask |= NVREG_IRQ_TIMER;
- break;
- case 0x00D6: // nforce3
- np->tx_flags |= cpu_to_le16(NV_TX_LASTPACKET1);
- np->irqmask = NVREG_IRQMASK_WANTED_2;
- np->irqmask |= NVREG_IRQ_TIMER;
-
- }
+ /* disable WOL */
+ writel(0, base + NvRegWakeUpFlags);
+ np->wolenabled = 0;
+
+ if (np->desc_ver == DESC_VER_1) {
+ np->tx_flags = NV_TX_LASTPACKET | NV_TX_VALID;
+ } else {
+ np->tx_flags = NV_TX2_LASTPACKET | NV_TX2_VALID;
+ }
+
+ switch (pci->device_id) {
+ case 0x01C3: // nforce
+ // DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ np->irqmask = NVREG_IRQMASK_WANTED_2 | NVREG_IRQ_TIMER;
+ // np->need_linktimer = 1;
+ // np->link_timeout = jiffies + LINK_TIMEOUT;
+ break;
+ case 0x0066:
+ /* Fall Through */
+ case 0x00D6:
+ // DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER
+ np->irqmask = NVREG_IRQMASK_WANTED_2;
+ np->irqmask |= NVREG_IRQ_TIMER;
+ // np->need_linktimer = 1;
+ // np->link_timeout = jiffies + LINK_TIMEOUT;
+ if (np->desc_ver == DESC_VER_1)
+ np->tx_flags |= NV_TX_LASTPACKET1;
+ else
+ np->tx_flags |= NV_TX2_LASTPACKET1;
+ break;
+ case 0x0086:
+ /* Fall Through */
+ case 0x008c:
+ /* Fall Through */
+ case 0x00e6:
+ /* Fall Through */
+ case 0x00df:
+ /* Fall Through */
+ case 0x0056:
+ /* Fall Through */
+ case 0x0057:
+ /* Fall Through */
+ case 0x0037:
+ /* Fall Through */
+ case 0x0038:
+ //DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ
+ np->irqmask = NVREG_IRQMASK_WANTED_2;
+ np->irqmask |= NVREG_IRQ_TIMER;
+ // np->need_linktimer = 1;
+ // np->link_timeout = jiffies + LINK_TIMEOUT;
+ if (np->desc_ver == DESC_VER_1)
+ np->tx_flags |= NV_TX_LASTPACKET1;
+ else
+ np->tx_flags |= NV_TX2_LASTPACKET1;
+ break;
+ default:
+ printf
+ ("Your card was undefined in this driver. Review driver_data in Linux driver and send a patch\n");
+ }
+
+ /* find a suitable phy */
+ for (i = 1; i < 32; i++) {
+ int id1, id2;
+ id1 = mii_rw(nic, i, MII_PHYSID1, MII_READ);
+ if (id1 < 0 || id1 == 0xffff)
+ continue;
+ id2 = mii_rw(nic, i, MII_PHYSID2, MII_READ);
+ if (id2 < 0 || id2 == 0xffff)
+ continue;
+ id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
+ id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
+ dprintf
+ (("%s: open: Found PHY %hX:%hX at address %d.\n",
+ pci->name, id1, id2, i));
+ np->phyaddr = i;
+ np->phy_oui = id1 | id2;
+ break;
+ }
+ if (i == 32) {
+ /* PHY in isolate mode? No phy attached and user wants to
+ * test loopback? Very odd, but can be correct.
+ */
+ printf
+ ("%s: open: Could not find a valid PHY.\n", pci->name);
+ }
+
+ if (i != 32) {
+ /* reset it */
+ phy_init(nic);
+ }
+
dprintf(("%s: forcedeth.c: subsystem: %hX:%hX bound to %s\n",
pci->name, pci->vendor, pci->dev_id, pci->name));
+ if(!forcedeth_reset(nic)) return 0; // no valid link
- forcedeth_reset(nic);
-// if (board_found && valid_link)
/* point to NIC specific routines */
nic->nic_op = &forcedeth_operations;
return 1;
-// }
- /* else */
}
+static struct pci_id forcedeth_nics[] = {
+PCI_ROM(0x10de, 0x01C3, "nforce", "nForce NVENET_1 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0066, "nforce2", "nForce NVENET_2 Ethernet Controller"),
+PCI_ROM(0x10de, 0x00D6, "nforce3", "nForce NVENET_3 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0086, "nforce4", "nForce NVENET_4 Ethernet Controller"),
+PCI_ROM(0x10de, 0x008c, "nforce5", "nForce NVENET_5 Ethernet Controller"),
+PCI_ROM(0x10de, 0x00e6, "nforce6", "nForce NVENET_6 Ethernet Controller"),
+PCI_ROM(0x10de, 0x00df, "nforce7", "nForce NVENET_7 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0056, "nforce8", "nForce NVENET_8 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0057, "nforce9", "nForce NVENET_9 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0037, "nforce10", "nForce NVENET_10 Ethernet Controller"),
+PCI_ROM(0x10de, 0x0038, "nforce11", "nForce NVENET_11 Ethernet Controller"),
+};
+
+PCI_DRIVER ( forcedeth_driver, forcedeth_nics, PCI_NO_CLASS );
+
DRIVER ( "forcedeth", nic_driver, pci_driver, forcedeth_driver,
forcedeth_probe, forcedeth_disable );
/* to get the PCI support functions, if this is a PCI NIC */
#include "pci.h"
-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))
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
-typedef uint8_t u8;
-typedef int8_t s8;
-typedef uint16_t u16;
-typedef int16_t s16;
-typedef uint32_t u32;
-typedef int32_t s32;
-
/* helpful macroes if on a big_endian machine for changing byte order.
not strictly needed on Intel */
#define get_unaligned(ptr) (*(ptr))
#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;
-
#define HZ 100
/* Condensed operations for readability. */
#define drv_version "v1.3"
#define drv_date "03-29-2004"
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
static u32 ioaddr; /* Globally used for the card's io address */
static struct nic_operations pcnet32_operations;
static struct pci_driver pcnet32_driver;
#define drv_version "v1.6"
#define drv_date "03-27-2004"
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
#define HZ 1000
static u32 ioaddr;
#define NUM_RX_DESC 4 /* Number of Rx descriptor registers. */
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
/* Time in ticks before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*TICKS_PER_SEC)
#define drv_version "v1.12"
#define drv_date "2004-03-21"
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
#define HZ 100
/* Condensed operations for readability. */
/* 11-13-2003 timlegge Fix Issue with NetGear GA302T
* 11-18-2003 ebiederm Generalize NetGear Fix to what the code was supposed to be.
* 01-06-2005 Alf (Frederic Olivie) Add Dell bcm 5751 (0x1677) support
+ * 04-15-2005 Martin Vogt Add Fujitsu Siemens Computer (FSC) 0x1734 bcm 5751 0x105d support
*/
#include "etherboot.h"
{ PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
{ PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
{ PCI_VENDOR_ID_DELL, 0x0179, PHY_ID_BCM5751 }, /* EtherXpress */
+
+ /* Fujitsu Siemens Computer */
+ { PCI_VENDOR_ID_FSC, 0x105d, PHY_ID_BCM5751 }, /* Futro C200 */
/* Compaq boards. */
{ PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
(X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
(X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
- (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5751 || \
+ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || (X) == PHY_ID_BCM5751 || \
(X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
unsigned long regs;
* Indent Style: indent -kr -i8
***************************************************************************/
-/*
-#include <asm/io.h>
-#include <asm/types.h>
-#include <linux/netdevice.h>
-*/
-
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
- /*****************************************************************
- * TLan Definitions
- *
- ****************************************************************/
+/*****************************************************************
+* TLan Definitions
+*
+****************************************************************/
#define FALSE 0
#define TRUE 1
/*********************************************************************/
/*
+ 08 Feb 2005 Ramesh Chander chhabaramesh at yahoo.co.in added table entries
+ for SGThomson STE10/100A
07 Sep 2003 timlegge Multicast Support Added
11 Apr 2001 mdc [patch to etherboot 4.7.24]
Major rewrite to include Linux tulip driver media detection
#define TX_TIME_OUT 2*TICKS_PER_SEC
-typedef uint8_t u8;
-typedef int8_t s8;
-typedef uint16_t u16;
-typedef int16_t s16;
-typedef uint32_t u32;
-typedef int32_t s32;
-
/* helpful macros if on a big_endian machine for changing byte order.
not strictly needed on Intel */
#define get_unaligned(ptr) (*(ptr))
enum tulip_chips {
DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
LC82C168, MX98713, MX98715, MX98725, AX88141, AX88140, PNIC2, COMET,
- COMPEX9881, I21145, XIRCOM
+ COMPEX9881, I21145, XIRCOM, SGThomson, /*Ramesh Chander*/
};
enum pci_id_flags_bits {
TULIP_IOTYPE, 256, MX98715 },
{ "3Com 3cSOHO100B-TX (ADMtek Centuar)", { 0x930010b7, 0xffffffff, 0, 0, 0, 0 },
TULIP_IOTYPE, TULIP_SIZE, COMET },
+ { "SG Thomson STE10/100A", { 0x2774104a, 0xffffffff, 0, 0, 0, 0 },
+ TULIP_IOTYPE, 256, COMET }, /*Ramesh Chander*/
{ 0, { 0, 0, 0, 0, 0, 0 }, 0, 0, 0 },
};
| HAS_PWRDWN | HAS_NWAY },
{ "Xircom tulip work-alike", HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII
| HAS_PWRDWN | HAS_NWAY },
+ { "SGThomson STE10/100A", HAS_MII | MC_HASH_ONLY }, /*Ramesh Chander*/
{ 0, 0 },
};
PCI_ROM(0x11f6, 0x9881, "rl100tx", "Compex RL100-TX"),
PCI_ROM(0x115d, 0x0003, "xircomtulip", "Xircom Tulip"),
PCI_ROM(0x104a, 0x0981, "tulip-0981", "Tulip 0x104a 0x0981"),
-PCI_ROM(0x104a, 0x2774, "tulip-2774", "Tulip 0x104a 0x2774"),
+PCI_ROM(0x104a, 0x2774, "SGThomson-STE10100A", "Tulip 0x104a 0x2774"), /*Modified by Ramesh Chander*/
PCI_ROM(0x1113, 0x9511, "tulip-9511", "Tulip 0x1113 0x9511"),
PCI_ROM(0x1186, 0x1561, "tulip-1561", "Tulip 0x1186 0x1561"),
PCI_ROM(0x1259, 0xa120, "tulip-a120", "Tulip 0x1259 0xa120"),
static const char *w89c840_version = "driver Version 0.94 - December 12, 2003";
-typedef unsigned char u8;
-typedef signed char s8;
-typedef unsigned short u16;
-typedef signed short s16;
-typedef unsigned int u32;
-typedef signed int s32;
-
/* Linux support functions */
#define virt_to_le32desc(addr) virt_to_bus(addr)
#define le32desc_to_virt(addr) bus_to_virt(addr)
#include "stdint.h"
-/*
- * "start" and "end" denote the real boundaries of the buffer. "fill"
- * denotes the offset to the first free block in the buffer. (If the
- * buffer is full, "fill" will equal ( end - start ) ).
+/* @file */
+
+/**
+ * A buffer
+ *
+ * @c start and @c end denote the real boundaries of the buffer, and
+ * are physical addresses. @c fill denotes the offset to the first
+ * free block in the buffer. (If the buffer is full, @c fill will
+ * equal @c end-start.)
*
*/
struct buffer {
- physaddr_t start;
- physaddr_t end;
- off_t fill;
+ physaddr_t start; /**< Start of buffer in memory */
+ physaddr_t end; /**< End of buffer in memory */
+ off_t fill; /**< Offset to first gap in buffer */
};
-/*
- * Free blocks in the buffer start with a "tail byte". If non-zero,
- * this byte 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 the remainder of
- * the descriptor (the struct buffer_free_block) follows the tail
- * byte.
+/**
+ * A free block descriptor.
*
- * This scheme is necessary because we may end up with a tail that is
- * smaller than a struct buffer_free_block.
+ * See \ref buffer_int for a full description of the fields.
*
*/
struct buffer_free_block {
- char tail;
- physaddr_t next_free;
- physaddr_t end;
+ char tail; /**< Tail byte marker */
+ physaddr_t next_free; /**< Address of next free block */
+ physaddr_t end; /**< End of this block */
} __attribute__ (( packed ));
-/* This must be provided by the architecture-dependent load_buffer.c */
-extern struct buffer load_buffer;
-
/* Functions in buffer.c */
extern void init_buffer ( struct buffer *buffer );
#ifndef COMPILER_H
#define COMPILER_H
-/* We export the symbol obj_OBJECT (OBJECT is defined on command-line)
+/*
+ * Doxygen can't cope with some of the more esoteric areas of C, so we
+ * make its life simpler.
+ *
+ */
+#ifdef DOXYGEN
+#define __attribute__(x)
+#endif
+
+/*
+ * We export the symbol obj_OBJECT (OBJECT is defined on command-line)
* as a global symbol, so that the linker can drag in selected object
* files from the library using -u obj_OBJECT.
*
--- /dev/null
+#ifndef ERRNO_H
+#define ERRNO_H
+
+/** @file
+ *
+ * Error codes
+ *
+ */
+
+/* PXE error codes are determined by the PXE specification */
+
+/* Generic errors */
+#define PXENV_STATUS_SUCCESS 0x00
+#define PXENV_STATUS_FAILURE 0x01
+#define PXENV_STATUS_BAD_FUNC 0x02
+#define PXENV_STATUS_UNSUPPORTED 0x03
+#define PXENV_STATUS_KEEP_UNDI 0x04
+#define PXENV_STATUS_KEEP_ALL 0x05
+#define PXENV_STATUS_OUT_OF_RESOURCES 0x06
+
+/* ARP errors (0x10 to 0x1f) */
+#define PXENV_STATUS_ARP_TIMEOUT 0x11
+
+/* Base-Code state errors */
+#define PXENV_STATUS_UDP_CLOSED 0x18
+#define PXENV_STATUS_UDP_OPEN 0x19
+#define PXENV_STATUS_TFTP_CLOSED 0x1a
+#define PXENV_STATUS_TFTP_OPEN 0x1b
+
+/* BIOS/system errors (0x20 to 0x2f) */
+#define PXENV_STATUS_MCOPY_PROBLEM 0x20
+#define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21
+#define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22
+#define PXENV_STATUS_BIS_INIT_FAILURE 0x23
+#define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24
+#define PXENV_STATUS_BIS_GBOA_FAILURE 0x25
+#define PXENV_STATUS_BIS_FREE_FAILURE 0x26
+#define PXENV_STATUS_BIS_GSI_FAILURE 0x27
+#define PXENV_STATUS_BIS_BAD_CKSUM 0x28
+
+/* TFTP/MTFTP errors (0x30 to 0x3f) */
+#define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30
+#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32
+#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33
+#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35
+#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36
+#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38
+#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39
+#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3a
+#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3b
+#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3c
+#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3d
+#define PXENV_STATUS_TFTP_NO_FILESIZE 0x3e
+#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3f
+
+/* Reserved errors 0x40 to 0x4f) */
+
+/* DHCP/BOOTP errors (0x50 to 0x5f) */
+#define PXENV_STATUS_DHCP_TIMEOUT 0x51
+#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52
+#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53
+#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54
+
+/* Driver errors (0x60 to 0x6f) */
+#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
+#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
+#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
+#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
+#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
+#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67
+#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68
+#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
+#define PXENV_STATUS_UNDI_INVALID_STATE 0x6a
+#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6b
+#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6c
+
+/* ROM and NBP bootstrap errors (0x70 to 0x7f) */
+#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74
+#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76
+#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77
+#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78
+#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79
+
+/* Environment NBP errors (0x80 to 0x8f) */
+
+/* Reserved errors (0x90 to 0x9f) */
+
+/* Miscellaneous errors (0xa0 to 0xaf) */
+#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xa0
+#define PXENV_STATUS_BINL_NO_PXE_SERVER 0xa1
+#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xa2
+#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xa3
+
+/* BUSD errors (0xb0 to 0xbf) */
+#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xb0
+
+/* Loader errors (0xc0 to 0xcf) */
+#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xc0
+#define PXENV_STATUS_LOADER_NO_BC_ROMID 0xc1
+#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xc2
+#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xc3
+#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xc4
+#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xc5
+#define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xc6
+#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xc8
+#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xc9
+#define PXENV_STATUS_LOADER_UNDI_START 0xca
+#define PXENV_STATUS_LOADER_BC_START 0xcb
+
+/*
+ * The range 0xd0 to 0xff is defined as "Vendor errors" by the PXE
+ * spec. We place all our Etherboot-specific errors in this range.
+ * We also define some generic errors as aliases to the PXE errors.
+ *
+ */
+
+#define ENOERR 0x00
+#define ENOMEM PXENV_STATUS_OUT_OF_RESOURCES
+#define EBADIMG 0xd0
+#define EIMGRET 0xd1
+#define ETIMEDOUT 0xd2
+#define EINVAL 0xd3
+
+/* Data structures and declarations */
+
+#include "tables.h"
+
+extern int errno;
+
+extern const char * strerror ( int errno );
+
+struct errortab {
+ int errno;
+ const char *text;
+};
+
+#define __errortab __table(errortab,01)
+
+#endif /* ERRNO_H */
#ifndef ETHERBOOT_H
#define ETHERBOOT_H
+/*
+ * Standard includes that we always want
+ *
+ */
+
+#include "compiler.h"
+#include "stddef.h"
+#include "stdint.h"
+
+
+/*
+ * IMPORTANT!!!!!!!!!!!!!!
+ *
+ * Everything below this point is cruft left over from older versions
+ * of Etherboot. Do not add *anything* below this point. Things are
+ * gradually being moved to individual header files.
+ *
+ */
+
+
#include <stdarg.h>
#include "osdep.h"
extern long rfc1112_sleep_interval P((long base, int exp));
extern void cleanup P((void));
-/* config.c */
-extern void print_config(void);
-
/* osloader.c */
/* Be careful with sector_t it is an unsigned long long on x86 */
typedef uint64_t sector_t;
extern unsigned long currticks P((void));
extern void exit P((int status));
-/* serial.c */
-extern int serial_getc P((void));
-extern void serial_putc P((int));
-extern int serial_ischar P((void));
-extern int serial_init P((void));
-extern void serial_fini P((void));
-
-/* floppy.c */
-extern int bootdisk P((int dev,int part));
/***************************************************************************
External variables
extern char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE];
#endif
-/* bootmenu.c */
-
-/* osloader.c */
-
-/* created by linker */
-extern char _virt_start[], _text[], _etext[], _text16[], _etext16[];
-extern char _data[], _edata[], _bss[], _ebss[], _end[];
-
/*
* Local variables:
#define PCI_VENDOR_ID_MORETON 0x15aa
#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
#define PCI_VENDOR_ID_PDC 0x15e9
+#define PCI_VENDOR_ID_FSC 0x1734
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
#define PCI_VENDOR_ID_TEKRAM 0x1de1
#define PCI_VENDOR_ID_3DLABS 0x3d3d
#include <pxe_types.h>
#endif
+#include "errno.h"
+
/* Defaults in case pxe_types.h did not define a type. These are
* placeholder structures just to make the code compile.
*/
-/*
- **************************************************************************
- *
- * Status codes returned in the status word of the PXENV API parameter
- * structure. Some of these codes are also used to return status
- * information from a boot image loader back to the bootrom.
- */
-
-/* Generic API errors that are reported by the loader */
-#define PXENV_STATUS_SUCCESS 0x00
-#define PXENV_STATUS_FAILURE 0x01 /* general failure */
-#define PXENV_STATUS_BAD_FUNC 0x02 /* invalid function number */
-#define PXENV_STATUS_UNSUPPORTED 0x03 /* not yet supported */
-#define PXENV_STATUS_KEEP_UNDI 0x04 /* keep UNDI in memory */
-#define PXENV_STATUS_KEEP_ALL 0x05 /* keep everything in memory */
-#define PXENV_STATUS_OUT_OF_RESOURCES 0x06 /* also keep everything */
-
-/* ARP/UDP errors (0x10 to 0x1F) */
-#define PXENV_STATUS_ARP_CANCELED 0x10 /* ARP canceled by keystroke */
-#define PXENV_STATUS_ARP_TIMEOUT 0x11 /* ARP timeout */
-#define PXENV_STATUS_UDP_CLOSED 0x18 /* UDP closed */
-#define PXENV_STATUS_UDP_OPEN 0x19 /* UDP already open */
-#define PXENV_STATUS_TFTP_CLOSED 0x1A /* TFTP closed */
-#define PXENV_STATUS_TFTP_OPEN 0x1B /* TFTP already opened */
-
-/* BIOS/system errors (0x20 to 0x2F) */
-#define PXENV_STATUS_MCOPY_PROBLEM 0x20 /* can't copy into memory */
-
-/* TFP errors (0x30 to 0x3F) */
-#define PXENV_STATUS_TFTP_CANNOT_ARP 0x30 /* TFTP ARP problem */
-#define PXENV_STATUS_TFTP_OPEN_CANCELED 0x31 /* TFTP open canceled by key */
-#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32 /* timeout during TFTP open */
-#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33 /* unknown TFTP opcode */
-#define PXENV_STATUS_TFTP_READ_CANCELED 0x34 /* TFTP read canceled by key */
-#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35 /* timeout during TFTP read */
-#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36 /* bad TFTP opcode */
-#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION \
- 0x38 /* error during TFTP open */
-#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION \
- 0x39 /* error during TFTP read */
-#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES \
- 0x3A /* too many packages */
-#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3B /* file not found */
-#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3C /* access violation */
-#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3D /* no multicast address */
-#define PXENV_STATUS_TFTP_NO_FILESIZE 0x3E /* unable to get file size */
-#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE \
- 0x3F /* invalid packet size */
-
-/* BOOTP errors (0x40 to 0x4F) */
-#define PXENV_STATUS_BOOTP_CANCELED 0x40 /* BOOTP canceled by key */
-#define PXENV_STATUS_BOOTP_TIMEOUT 0x41 /* timeout during BOOTP */
-#define PXENV_STATUS_BOOTP_NO_FILE 0x42 /* missing bootfile name */
-
-/* DHCP errors (0x50 to 0x5F) */
-#define PXENV_STATUS_DHCP_CANCELED 0x50 /* DHCP canceled by key */
-#define PXENV_STATUS_DHCP_TIMEOUT 0x51 /* timeout during DHCP */
-#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52 /* missing IP address */
-#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53 /* missing bootfile name */
-#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54 /* invalid IP address */
-
-/* Driver errors (0x60 to 0x6F) */
-#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60 /* invalid UNDI function */
-#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61 /* media test failed */
-#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST \
- 0x62 /* cannot init for multicast */
-#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC \
- 0x63 /* cannot init NIC */
-#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY \
- 0x64 /* cannot init hardware */
-#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA \
- 0x65 /* cannot read config data */
-#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA \
- 0x66 /* cannot read init data */
-#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67 /* invalid hardware address */
-#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM \
- 0x68 /* invalid EEPROM checksum */
-#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
-#define PXENV_STATUS_UNDI_INVALID_STATE 0x6a /* invalid UNDI state */
-#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6b /* transmit error */
-#define PXENV_STATUS_UNDI_INVALID_PARAMETER \
- 0x6c /* almost anything */
-
-/* Bootstrap (.1) errors (0x70 to 0x7F) */
-#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74 /* invalid bootstrap menu */
-#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76 /* missing multicast address */
-#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77 /* missing file list */
-#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78 /* no response from server */
-#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79 /* next file too big */
-
-/* Environment (.2) errors (0x80 to 0x8F) */
-
-/* MTFTP errors (0x90 to 0x9F) */
-#define PXENV_STATUS_MTFTP_OPEN_CANCEL 0x91 /* MTFTP open canceled by key */
-#define PXENV_STATUS_MTFTP_OPEN_TIMEOUT 0x92 /* timeout during MTFTP open */
-#define PXENV_STATUS_MTFTP_UNKNOWN_OP 0x93 /* unknown TFTP opcode */
-#define PXENV_STATUS_MTFTP_READ_CANCEL 0x94 /* MTFTP read canceled by key */
-#define PXENV_STATUS_MTFTP_READ_TIMEOUT 0x95 /* timeout during MTFTP read */
-#define PXENV_STATUS_MTFTP_ERROR_OP 0x96 /* bad TFTP opcode */
-#define PXENV_STATUS_MTFTP_CANNOT_OPEN 0x98 /* error during MTFTP open */
-#define PXENV_STATUS_MTFTP_CANNOT_READ 0x99 /* error during MTFTP read */
-#define PXENV_STATUS_MTFTP_TOO_MANY 0x9A /* too many packages */
-#define PXENV_STATUS_MTFTP_PACK_SIZE 0x9B /* invalid package size */
-
-/* Misc. errors (0xA0 to 0xAF) */
-#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE \
- 0xA0 /* BINL canceled by key */
-#define PXENV_STATUS_BINL_NO_PXE_SERVER 0xA1 /* no BINL server found */
-#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE \
- 0xA2 /* not avail. in prot mode */
-#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE \
- 0xA3 /* not avail. in real mode */
-
-/* BUSD errors (0xB0 to 0xBF) */
-#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED \
- 0xB0 /* BUSD services not enabled */
-#define PXENV_STATUS_BUSD_DEV_ENABLE 0xB1 /* BUSD device not enabled */
-
-/* Loader errors (0xC0 to 0xCF) */
-#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY \
- 0xC0 /* no free base memory */
-#define PXENV_STATUS_LOADER_NO_BC_ROMID 0xC1 /* no base code rom ID */
-#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xC2 /* bad base code rom ID */
-#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE \
- 0xC3 /* bad base code image */
-#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xC4 /* no UNDI rom ID */
-#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xC5 /* bad UNDI rom ID */
-#define PXENV_STATUS_LOADER_UNDI_DRIVER_IMAGE \
- 0xC6 /* bad UNDI runtime image */
-#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xC8 /* missing !PXE struct */
-#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT \
- 0xC9 /* missing PXENV+ struct */
-#define PXENV_STATUS_LOADER_UNDI_START 0xCA /* UNDI not started */
-#define PXENV_STATUS_LOADER_BC_START 0xCB /* base code not started */
-
-/* Reserved errors (0xD0 to 0xFF) */
-#define PXENV_STATUS_IMAGE_INVALID 0xD0 /* invalid boot image */
-#define PXENV_STATUS_STOP_BASE 0xD1 /* error stopping base code */
-#define PXENV_STATUS_UNLOAD_BASE 0xD2 /* error unloading base code */
-#define PXENV_STATUS_STOP_UNDI 0xD3 /* error stopping UNDI */
-#define PXENV_STATUS_CLEANUP_UNDI 0xD4 /* error cleaning up UNDI */
-
-
/*****************************************************************************
* The remainder of this file is original to Etherboot.
*****************************************************************************
#ifndef TABLES_H
#define TABLES_H
-/*
- * Macros for dealing with linker-generated tables of fixed-size
- * symbols. We make fairly extensive use of these in order to avoid
- * ifdef spaghetti and/or linker symbol pollution. For example,
- * instead of having code such as
+/** @page ifdef_harmful #ifdef considered harmful
+ *
+ * Overuse of @c #ifdef has long been a problem in Etherboot.
+ * Etherboot provides a rich array of features, but all these features
+ * take up valuable space in a ROM image. The traditional solution to
+ * this problem has been for each feature to have its own @c #ifdef
+ * option, allowing the feature to be compiled in only if desired.
+ *
+ * The problem with this is that it becomes impossible to compile, let
+ * alone test, all possible versions of Etherboot. Code that is not
+ * typically used tends to suffer from bit-rot over time. It becomes
+ * extremely difficult to predict which combinations of compile-time
+ * options will result in code that can even compile and link
+ * correctly.
+ *
+ * To solve this problem, we have adopted a new approach from
+ * Etherboot 5.5 onwards. @c #ifdef is now "considered harmful", and
+ * its use should be minimised. Separate features should be
+ * implemented in separate @c .c files, and should \b always be
+ * compiled (i.e. they should \b not be guarded with a @c #ifdef @c
+ * MY_PET_FEATURE statement). By making (almost) all code always
+ * compile, we avoid the problem of bit-rot in rarely-used code.
+ *
+ * The file config.h, in combination with the @c make command line,
+ * specifies the objects that will be included in any particular build
+ * of Etherboot. For example, suppose that config.h includes the line
+ *
+ * @code
+ *
+ * #define CONSOLE_SERIAL
+ * #define DOWNLOAD_PROTO_TFTP
+ *
+ * @endcode
+ *
+ * When a particular Etherboot image (e.g. @c bin/rtl8139.zdsk) is
+ * built, the options specified in config.h are used to drag in the
+ * relevant objects at link-time. For the above example, serial.o and
+ * tftp.o would be linked in.
+ *
+ * There remains one problem to solve: how do these objects get used?
+ * Traditionally, we had code such as
+ *
+ * @code
+ *
+ * #ifdef CONSOLE_SERIAL
+ * serial_init();
+ * #endif
+ *
+ * @endcode
+ *
+ * in main.c, but this reintroduces @c #ifdef and so is a Bad Idea.
+ * We cannot simply remove the @c #ifdef and make it
+ *
+ * @code
*
- * #ifdef CONSOLE_SERIAL
* serial_init();
- * #endif
+ *
+ * @endcode
+ *
+ * because then serial.o would end up always being linked in.
+ *
+ * The solution is to use @link tables.h linker tables @endlink.
+ *
+ */
+
+/** @file
+ *
+ * Linker tables
+ *
+ * Read @ref ifdef_harmful first for some background on the motivation
+ * for using linker tables.
+ *
+ * This file provides macros for dealing with linker-generated tables
+ * of fixed-size symbols. We make fairly extensive use of these in
+ * order to avoid @c #ifdef spaghetti and/or linker symbol pollution.
+ * For example, instead of having code such as
+ *
+ * @code
+ *
+ * #ifdef CONSOLE_SERIAL
+ * serial_init();
+ * #endif
+ *
+ * @endcode
*
* we make serial.c generate an entry in the initialisation function
* table, and then have a function call_init_fns() that simply calls
* all functions present in this table. If and only if serial.o gets
* linked in, then its initialisation function will be called. We
* avoid linker symbol pollution (i.e. always dragging in serial.o
- * just because of a call to serial_init()) and we also avoid ifdef
- * spaghetti (having to conditionalise every reference to functions in
- * serial.c).
+ * just because of a call to serial_init()) and we also avoid @c
+ * #ifdef spaghetti (having to conditionalise every reference to
+ * functions in serial.c).
*
* The linker script takes care of assembling the tables for us. All
- * our table sections have names of the format ".tbl.NAME.NN" where
- * NAME designates the data structure stored in the table
- * (e.g. "init_fn") and NN is a two-digit decimal number used to
- * impose an ordering upon the tables if required. NN=00 is reserved
- * for the symbol indicating "table start", and NN=99 is reserved for
- * the symbol indicating "table end".
+ * our table sections have names of the format @c .tbl.NAME.NN where
+ * @c NAME designates the data structure stored in the table (e.g. @c
+ * init_fn) and @c NN is a two-digit decimal number used to impose an
+ * ordering upon the tables if required. @c NN=00 is reserved for the
+ * symbol indicating "table start", and @c NN=99 is reserved for the
+ * symbol indicating "table end".
+ *
+ * As an example, suppose that we want to create a "frobnicator"
+ * feature framework, and allow for several independent modules to
+ * provide frobnicating services. Then we would create a frob.h
+ * header file containing e.g.
+ *
+ * @code
+ *
+ * struct frobnicator {
+ * const char *name; // Name of the frobnicator
+ * void ( *frob ) ( void ); // The frobnicating function itself
+ * };
+ *
+ * #define __frobnicator __table ( frobnicators, 01 )
+ *
+ * @endcode
*
- * To define an entry in the "xxx" table:
+ * Any module providing frobnicating services would look something
+ * like
*
- * static struct xxx my_xxx __table(xxx,01) = { ... };
+ * @code
*
- * To access start and end markers for the "xxx" table:
+ * #include "frob.h"
*
- * static struct xxx xxx_start[0] __table_start(xxx);
- * static struct xxx xxx_end[0] __table_end(xxx);
+ * static void my_frob ( void ) {
+ * // Do my frobnicating
+ * ...
+ * }
*
- * See init.h and init.c for an example of how these macros are used
- * in practice.
+ * static struct frob my_frobnicator __frobnicator = {
+ * .name = "my_frob",
+ * .frob = my_frob,
+ * };
+ *
+ * @endcode
+ *
+ * The central frobnicator code (frob.c) would use the frobnicating
+ * modules as follows
+ *
+ * @code
+ *
+ * #include "frob.h"
+ *
+ * static struct frob frob_start[0] __table_start ( frobnicators );
+ * static struct frob frob_end[0] __table_end ( frobnicators );
+ *
+ * // Call all linked-in frobnicators
+ * void frob_all ( void ) {
+ * struct frob *frob;
+ *
+ * for ( frob = frob_start ; frob < frob_end ; frob++ ) {
+ * printf ( "Calling frobnicator \"%s\"\n", frob->name );
+ * frob->frob ();
+ * }
+ * }
+ *
+ * @endcode
+ *
+ * See init.h and init.c for a real-life example.
*
*/
#define __table_section_start(table) __table_section(table,00)
#define __table_section_end(table) __table_section(table,99)
+
+/**
+ * Linker table entry.
+ *
+ * Declares a data structure to be part of a linker table. Use as
+ * e.g.
+ *
+ * @code
+ *
+ * static struct my_foo __table ( foo, 01 ) = {
+ * ...
+ * };
+ *
+ * @endcode
+ *
+ */
#define __table(table,idx) \
__attribute__ (( unused, __table_section(table,idx) ))
+
+/**
+ * Linker table start marker.
+ *
+ * Declares a data structure (usually an empty data structure) to be
+ * the start of a linker table. Use as e.g.
+ *
+ * @code
+ *
+ * static struct foo_start[0] __table_start ( foo );
+ *
+ * @endcode
+ *
+ */
#define __table_start(table) \
__attribute__ (( unused, __table_section_start(table) ))
+
+/**
+ * Linker table end marker.
+ *
+ * Declares a data structure (usually an empty data structure) to be
+ * the end of a linker table. Use as e.g.
+ *
+ * @code
+ *
+ * static struct foo_end[0] __table_end ( foo );
+ *
+ * @endcode
+ *
+ */
#define __table_end(table) \
__attribute__ (( unused, __table_section_end(table) ))
--- /dev/null
+ /*********************************************************************\
+ * Copyright (c) 2005 by Radim Kolar (hsn-sendmail.cz) *
+ * *
+ * You may copy or modify this file in any manner you wish, provided *
+ * that this notice is always included, and that you hold the author *
+ * harmless for any loss or damage resulting from the installation or *
+ * use of this software. *
+ * *
+ * This file provides support for FSP v2 protocol written from scratch *
+ * by Radim Kolar, FSP project leader. *
+ * *
+ * ABOUT FSP *
+ * FSP is a lightweight file transfer protocol and is being used for *
+ * booting, Internet firmware updates, embedded devices and in *
+ * wireless applications. FSP is very easy to implement; contact Radim *
+ * Kolar if you need hand optimized assembler FSP stacks for various *
+ * microcontrollers, CPUs or consultations. *
+ * http://fsp.sourceforge.net/ *
+ * *
+ * REVISION HISTORY *
+ * 1.0 2005-03-17 rkolar Initial coding *
+ * 1.1 2005-03-24 rkolar We really need to send CC_BYE to the server *
+ * at end of transfer, because next stage boot *
+ * loader is unable to contact FSP server *
+ * until session timeouts. *
+ * 1.2 2005-03-26 rkolar We need to query filesize in advance, *
+ * because NBI loader do not reads file until *
+ * eof is reached.
+ * REMARKS *
+ * there is no support for selecting port number of fsp server, maybe *
+ * we should parse fsp:// URLs in boot image filename. *
+ * this implementation has filename limit 255 chars. *
+ \*********************************************************************/
+
+#ifdef DOWNLOAD_PROTO_FSP
+#include "etherboot.h"
+#include "nic.h"
+
+#define FSP_PORT 21
+
+/* FSP commands */
+#define CC_GET_FILE 0x42
+#define CC_BYE 0x4A
+#define CC_ERR 0x40
+#define CC_STAT 0x4D
+
+/* etherboot limits */
+#define FSP_MAXFILENAME 255
+
+struct fsp_info {
+ in_addr server_ip;
+ uint16_t server_port;
+ uint16_t local_port;
+ const char *filename;
+ int (*fnc)(unsigned char *, unsigned int, unsigned int, int);
+};
+
+struct fsp_header {
+ uint8_t cmd;
+ uint8_t sum;
+ uint16_t key;
+ uint16_t seq;
+ uint16_t len;
+ uint32_t pos;
+} PACKED;
+
+#define FSP_MAXPAYLOAD (ETH_MAX_MTU - \
+ (sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct fsp_header)))
+
+static struct fsp_request {
+ struct iphdr ip;
+ struct udphdr udp;
+ struct fsp_header fsp;
+ unsigned char data[FSP_MAXFILENAME + 1 + 2];
+} request;
+
+struct fsp_reply {
+ struct iphdr ip;
+ struct udphdr udp;
+ struct fsp_header fsp;
+ unsigned char data[FSP_MAXPAYLOAD];
+} PACKED;
+
+
+static int await_fsp(int ival, void *ptr, unsigned short ptype __unused,
+ struct iphdr *ip, struct udphdr *udp)
+{
+ if(!udp)
+ return 0;
+ if (ip->dest.s_addr != arptable[ARP_CLIENT].ipaddr.s_addr)
+ return 0;
+ if (ntohs(udp->dest) != ival)
+ return 0;
+ if (ntohs(udp->len) < 12+sizeof(struct udphdr))
+ return 0;
+ return 1;
+}
+
+static int proto_fsp(struct fsp_info *info)
+{
+ uint32_t filepos;
+ uint32_t filelength=0;
+ int i,retry;
+ uint16_t reqlen;
+ struct fsp_reply *reply;
+ int block=1;
+
+ /* prepare FSP request packet */
+ filepos=0;
+ i=strlen(info->filename);
+ if(i>FSP_MAXFILENAME)
+ {
+ printf("Boot filename is too long.\n");
+ return 0;
+ }
+ strcpy(request.data,info->filename);
+ *(uint16_t *)(request.data+i+1)=htons(FSP_MAXPAYLOAD);
+ request.fsp.len=htons(i+1);
+ reqlen=i+3+12;
+
+ rx_qdrain();
+ retry=0;
+
+ /* main loop */
+ for(;;) {
+ int sum;
+ long timeout;
+
+ /* query filelength if not known */
+ if(filelength == 0)
+ request.fsp.cmd=CC_STAT;
+
+ /* prepare request packet */
+ request.fsp.pos=htonl(filepos);
+ request.fsp.seq=random();
+ request.fsp.sum=0;
+ for(i=0,sum=reqlen;i<reqlen;i++)
+ {
+ sum += ((uint8_t *)&request.fsp)[i];
+ }
+ request.fsp.sum= sum + (sum >> 8);
+ /* send request */
+ if (!udp_transmit(info->server_ip.s_addr, info->local_port,
+ info->server_port, sizeof(request.ip) +
+ sizeof(request.udp) + reqlen, &request))
+ return (0);
+ /* wait for retry */
+#ifdef CONGESTED
+ timeout =
+ rfc2131_sleep_interval(filepos ? TFTP_REXMT : TIMEOUT, retry);
+#else
+ timeout = rfc2131_sleep_interval(TIMEOUT, retry);
+#endif
+ retry++;
+ if (!await_reply(await_fsp, info->local_port, NULL, timeout))
+ continue;
+ reply=(struct fsp_reply *) &nic.packet[ETH_HLEN];
+ /* check received packet */
+ if (reply->fsp.seq != request.fsp.seq)
+ continue;
+ reply->udp.len=ntohs(reply->udp.len)-sizeof(struct udphdr);
+ if(reply->udp.len < ntohs(reply->fsp.len) + 12 )
+ continue;
+ sum=-reply->fsp.sum;
+ for(i=0;i<reply->udp.len;i++)
+ {
+ sum += ((uint8_t *)&(reply->fsp))[i];
+ }
+ sum = (sum + (sum >> 8)) & 0xff;
+ if(sum != reply->fsp.sum)
+ {
+ printf("FSP checksum failed. computed %d, but packet has %d.\n",sum,reply->fsp.sum);
+ continue;
+ }
+ if(reply->fsp.cmd == CC_ERR)
+ {
+ printf("\nFSP error: %s",info->filename);
+ if(reply->fsp.len)
+ printf(" [%s]",reply->data);
+ printf("\n");
+ return 0;
+ }
+ if(reply->fsp.cmd == CC_BYE && filelength == 1)
+ {
+ info->fnc(request.data,block,1,1);
+ return 1;
+ }
+ if(reply->fsp.cmd == CC_STAT)
+ {
+ if(reply->data[8] == 0)
+ {
+ /* file not found, etc. */
+ filelength=0xffffffff;
+ } else
+ {
+ filelength= ntohl(*((uint32_t *)&reply->data[4]));
+ }
+ request.fsp.cmd = CC_GET_FILE;
+ request.fsp.key = reply->fsp.key;
+ retry=0;
+ continue;
+ }
+
+ if(reply->fsp.cmd == CC_GET_FILE)
+ {
+ if(ntohl(reply->fsp.pos) != filepos)
+ continue;
+ request.fsp.key = reply->fsp.key;
+ retry=0;
+ i=ntohs(reply->fsp.len);
+ if(i == 1)
+ {
+ request.fsp.cmd=CC_BYE;
+ request.data[0]=reply->data[0];
+ continue;
+ }
+ /* let last byte alone */
+ if(i >= filelength)
+ i = filelength - 1;
+ if(!info->fnc(reply->data,block++,i,0))
+ return 0;
+ filepos += i;
+ filelength -= i;
+ }
+ }
+
+ return 0;
+}
+
+int url_fsp(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
+{
+ struct fsp_info info;
+ /* Set the defaults */
+ info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr;
+ info.server_port = FSP_PORT;
+ info.local_port = 1024 + random() & 0xfbff;
+ info.fnc = fnc;
+
+ /* Now parse the url */
+ /* printf("fsp-URI: [%s]\n", name); */
+ /* quick hack for now */
+ info.filename=name;
+ return proto_fsp(&info);
+}
+#endif
# If PXE image, just fill the length field and write it out
if ($opts{'x'}) {
substr($rom, 2, 1) = chr((length($rom) + 511) / 512);
- &writerom($ARGV[0], \$rom);
+ writerom($ARGV[0], \$rom);
return;
}
# Size specified with -s overrides value in 3rd byte in image
$romsize = ($filesize + 511) & ~511
}
} else {
- $romsize = &getromsize(\$rom);
+ $romsize = getromsize(\$rom);
# 0 put there by *loader.S means makerom should pick the size
if ($romsize == 0) {
# Shrink romsize down to the smallest power of two that will do
}
substr($rom, 2, 1) = chr(($romsize / 512) % 256);
print "ROM size is $romsize\n" if $opts{'v'};
- my $identoffset = &addident(\$rom);
- &pcipnpheaders(\$rom, $identoffset);
- &undiheaders(\$rom);
+ # set the product string only if we don't have one yet
+ my $pnp_hdr_offset = unpack('v', substr($rom, PNP_PTR_LOC, 2));
+ my $identoffset = substr($rom, $pnp_hdr_offset+PNP_DEVICE_OFF, 2) eq "\0\0" ? addident(\$rom) : undef;
+ pcipnpheaders(\$rom, $identoffset);
+ undiheaders(\$rom);
# 3c503 requires last two bytes to be 0x80
substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
if ($opts{'3'} and $romsize == MINROMSIZE);
- &checksum(\$rom);
- &writerom($ARGV[0], \$rom);
+ checksum(\$rom);
+ writerom($ARGV[0], \$rom);
}
sub modrom () {
close(R);
defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n";
print "$filesize bytes read\n" if $opts{'v'};
- &pcipnpheaders(\$rom);
- &undiheaders(\$rom);
- &checksum(\$rom);
- &writerom($ARGV[0], \$rom);
+ pcipnpheaders(\$rom, undef);
+ undiheaders(\$rom);
+ checksum(\$rom);
+ writerom($ARGV[0], \$rom);
}
# Main routine. See how we were called and behave accordingly
if ($0 =~ m:modrom(\.pl)?$:) {
- &modrom();
+ modrom();
} else {
- &makerom();
+ makerom();
}
exit(0);