Patchwork [RFC] Network console for coreboot

login
register
about
Submitter Rudolf Marek
Date 2010-06-01 22:39:52
Message ID <4C058C38.7060607@assembler.cz>
Download mbox | patch
Permalink /patch/1440/
State Superseded
Headers show

Comments

Rudolf Marek - 2010-06-01 22:39:52
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi all,

I clean up the patch bit more. Looks way better. Question is if the ne2k.c
belongs to drivers or /lib (and where to put header file)

Otherwise it is nearly ready. I made Kconfig for that which is able to translate
the IP strings to the binary data via new funcs.

Signed-off-by: Rudolf Marek <r.marek@assembler.cz>

I think I need to kill some warnings and add some header prototypes...

Thanks,
Rudolf
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkwFjDgACgkQ3J9wPJqZRNV3NACfScfUXCIVmspTLABf01PzSKIv
TU4An0K6d3d7jQLyi75cRVZiH9JwU7Qc
=+26L
-----END PGP SIGNATURE-----
ron minnich - 2010-06-02 02:42:11
That is amazingly great.

BTW: http://supplier.sandia.gov/opportunities/expanded.aspx?ID=768



coreboot is mandatory. Rudolf's kind of work shows why. Sandia is
putting some money on coreboot.

ron
Peter Stuge - 2010-06-02 03:21:58
Rudolf Marek wrote:
> I clean up the patch bit more. Looks way better. Question is if the
> ne2k.c belongs to drivers or /lib (and where to put header file)

It's not a driver for initialization, it's console code, so I think
it belongs in lib, similar to usbdebug code.


> Otherwise it is nearly ready. I made Kconfig for that which is able
> to translate the IP strings to the binary data via new funcs.

It's starting to look pretty awesome! I would like some small
clarifications for the Kconfig prompts but I can send a patch or do
them myself later.

I just had a thought. Would it make sense to use syslog format for
the packets that are sent out?


> +++ src/console/Kconfig	(working copy)
> @@ -1,5 +1,31 @@
>  menu "Console options"
>  
> +config CONSOLE_NE2K
> +	bool "Ethernet console over NE2K"

Is it only for PCI clones? coreboot supports many boards with ISA
slots. Can the code work there as well if the jumper/jumperless
configured IO base is specified?


> +config CONSOLE_NE2K_DST_MAC
> +	depends on CONSOLE_NE2K
> +	string "DST unicast MAC"

We may need to create some new terminology for the network console.
(What terms are Linux using?)

The destination might be called the "console server" so here it would
say "Console server MAC address" and the help can explain further why
it's neccessary to supply it.


> +config CONSOLE_NE2K_DST_IP
> +	depends on CONSOLE_NE2K
> +	string "DST unicast IP"

Same here, "Console server IP address"


> +config CONSOLE_NE2K_SRC_IP
> +	depends on CONSOLE_NE2K
> +	string "SRC unicast IP"

Hmm, "Source IP address" maybe?


> +config CONSOLE_NE2K_IO_PORT
> +	depends on CONSOLE_NE2K
> +	hex "NE2K adapter fixed IO port"
> +	default 0xe00

If an ISA device is also allowed then it may be more difficult to add
a fixed IO resource to the device tree..


> +++ src/lib/ns8390.h	(revision 0)

This file has a bunch of register defines for various hardware (WDC,
SMC, Digital, 3Com) - are they all relevant?


//Peter
Rudolf Marek - 2010-06-02 07:19:40
Dne 2.6.2010 05:21, Peter Stuge napsal(a):
> Rudolf Marek wrote:
>> I clean up the patch bit more. Looks way better. Question is if the
>> ne2k.c belongs to drivers or /lib (and where to put header file)
>
> It's not a driver for initialization, it's console code, so I think
> it belongs in lib, similar to usbdebug code.

ok.

>> Otherwise it is nearly ready. I made Kconfig for that which is able
>> to translate the IP strings to the binary data via new funcs.
>
> I just had a thought. Would it make sense to use syslog format for
> the packets that are sent out?

Dunno, I just use same port as Linux Netconsole, not sure if I have same format ;)

>> +++ src/console/Kconfig	(working copy)
>> @@ -1,5 +1,31 @@
>>   menu "Console options"
>>
>> +config CONSOLE_NE2K
>> +	bool "Ethernet console over NE2K"
>
> Is it only for PCI clones? coreboot supports many boards with ISA
> slots. Can the code work there as well if the jumper/jumperless
> configured IO base is specified?

Well in theory it should work for ISA cards too (NE2K) Maybe the only problem is 
the address of TX buffer which needs to be adjusted.

>> +config CONSOLE_NE2K_DST_MAC
>> +	depends on CONSOLE_NE2K
>> +	string "DST unicast MAC"
>
> We may need to create some new terminology for the network console.
> (What terms are Linux using?)

Netconsole

>
> The destination might be called the "console server" so here it would
> say "Console server MAC address" and the help can explain further why
> it's neccessary to supply it.
>
>
>> +config CONSOLE_NE2K_DST_IP
>> +	depends on CONSOLE_NE2K
>> +	string "DST unicast IP"
>
> Same here, "Console server IP address"

Yes sure
>
>
>> +config CONSOLE_NE2K_SRC_IP
>> +	depends on CONSOLE_NE2K
>> +	string "SRC unicast IP"
>
> Hmm, "Source IP address" maybe?

Yes... or Coreboot node IP address

>
>
>> +config CONSOLE_NE2K_IO_PORT
>> +	depends on CONSOLE_NE2K
>> +	hex "NE2K adapter fixed IO port"
>> +	default 0xe00
>
> If an ISA device is also allowed then it may be more difficult to add
> a fixed IO resource to the device tree..

Well this is needed because I dont do any IO probing. If we stick with the PCI 
we can just create a function which returns the BAR addr, but at the beginning 
we need some fixed non-conflicting address anyway. I consider console as add-on 
and therefore I did not put that into device tree.

>> +++ src/lib/ns8390.h	(revision 0)
>
> This file has a bunch of register defines for various hardware (WDC,
> SMC, Digital, 3Com) - are they all relevant?

Well those are other PCI clones of NE2K which are not so good compatible. We can 
delete this I think.

I have a question, did someone already test this?

Thanks,

Rudolf

Patch

Index: src/include/ip_checksum.h
===================================================================
--- src/include/ip_checksum.h	(revision 5577)
+++ src/include/ip_checksum.h	(working copy)
@@ -3,5 +3,7 @@ 
 
 unsigned long compute_ip_checksum(void *addr, unsigned long length);
 unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new);
+void str2ip(char *str, unsigned char *ip);
+void str2mac(char *str, unsigned char *mac);
 
 #endif /* IP_CHECKSUM_H */
Index: src/console/Kconfig
===================================================================
--- src/console/Kconfig	(revision 5604)
+++ src/console/Kconfig	(working copy)
@@ -1,5 +1,31 @@ 
 menu "Console options"
 
+config CONSOLE_NE2K
+	bool "Ethernet console over NE2K"
+	default y
+	help
+	  Send coreboot debug output to a Ethernet console.
+
+config CONSOLE_NE2K_DST_MAC
+	depends on CONSOLE_NE2K
+	string "DST unicast MAC"
+	default "00:13:d4:76:a2:ac"
+
+config CONSOLE_NE2K_DST_IP
+	depends on CONSOLE_NE2K
+	string "DST unicast IP"
+	default "10.0.1.27"
+
+config CONSOLE_NE2K_SRC_IP
+	depends on CONSOLE_NE2K
+	string "SRC unicast IP"
+	default "10.0.1.253"
+
+config CONSOLE_NE2K_IO_PORT
+	depends on CONSOLE_NE2K
+	hex "NE2K adapter fixed IO port"
+	default 0xe00
+
 # TODO: Rename to SERIAL_CONSOLE once Kconfig transition is complete.
 config CONSOLE_SERIAL8250
 	bool "Serial port console output"
Index: src/console/ne2k_console.c
===================================================================
--- src/console/ne2k_console.c	(revision 0)
+++ src/console/ne2k_console.c	(revision 0)
@@ -0,0 +1,17 @@ 
+#include <console/console.h>
+
+static void ne2k_tx_byte(unsigned char data)
+{
+	ne2k_append_data(&data, 1, CONFIG_CONSOLE_NE2K_IO_PORT);
+}
+
+static void ne2k_tx_flush(void)
+{
+	ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
+}
+
+static const struct console_driver uart8250_console __console = {
+	.tx_byte = ne2k_tx_byte,
+	.tx_flush = ne2k_tx_flush,
+};
+
Index: src/console/console.c
===================================================================
--- src/console/console.c	(revision 5604)
+++ src/console/console.c	(working copy)
@@ -99,6 +99,10 @@ 
 
 void console_init(void)
 {
+
+#if CONFIG_CONSOLE_NE2K
+	ne2k_init(CONFIG_CONSOLE_NE2K_IO_PORT);
+#endif
 	static const char console_test[] =
 		"\n\ncoreboot-"
 		COREBOOT_VERSION
Index: src/console/Makefile.inc
===================================================================
--- src/console/Makefile.inc	(revision 5604)
+++ src/console/Makefile.inc	(working copy)
@@ -15,6 +15,7 @@ 
 driver-$(CONFIG_CONSOLE_BTEXT) += btext_console.o
 driver-$(CONFIG_CONSOLE_BTEXT) += font-8x16.o
 driver-$(CONFIG_CONSOLE_LOGBUF) += logbuf_console.o
+driver-$(CONFIG_CONSOLE_NE2K) += ne2k_console.o
 
 $(obj)/console/console.o : $(obj)/build.h
 $(obj)/console/console.initobj.o : $(obj)/build.h
Index: src/lib/ne2k.c
===================================================================
--- src/lib/ne2k.c	(revision 0)
+++ src/lib/ne2k.c	(revision 0)
@@ -0,0 +1,312 @@ 
+/*
+ETHERBOOT -  BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+  Date: May/94
+
+ This code is based heavily on David Greenman's if_ed.c driver
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+  This software may be used, modified, copied, distributed, and sold, in
+  both source and binary form provided that the above copyright and these
+  terms are retained. Under no circumstances are the authors responsible for
+  the proper functioning of this software, nor do the authors assume any
+  responsibility for damages incurred with its use.
+
+Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
+Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
+3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
+SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
+3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
+RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
+  parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
+SMC8416 PIO support added by Andrew Bettison (andrewb@zip.com.au) on 4/3/02
+  based on the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
+
+(C) Rudolf Marek <r.marek@assembler.cz> Simplify for RTL8029, Add coreboot glue logic
+
+*/
+
+#define ETH_ALEN		6	/* Size of Ethernet address */
+#define ETH_HLEN		14	/* Size of ethernet header */
+#define	ETH_ZLEN		60	/* Minimum packet */
+#define	ETH_FRAME_LEN		1514	/* Maximum packet */
+#define ETH_DATA_ALIGN		2	/* Amount needed to align the data after an ethernet header */
+#define	ETH_MAX_MTU		(ETH_FRAME_LEN-ETH_HLEN)
+
+#include "ns8390.h"
+#include <ip_checksum.h>
+#include <arch/io.h>
+
+#define MEM_SIZE MEM_32768
+#define TX_START 64
+#define RX_START (64 + D8390_TXBUF_SIZE)
+
+static unsigned int get_count(unsigned int eth_nic_base) {
+	unsigned int ret;
+	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1,
+	     eth_nic_base + D8390_P0_COMMAND);
+
+	ret = inb(eth_nic_base + 8 + 0) | (inb(eth_nic_base + 8 + 1) << 8);
+
+	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0,
+	     eth_nic_base + D8390_P0_COMMAND);
+	return ret;
+}
+
+static void set_count(unsigned int eth_nic_base, unsigned int what) {
+	
+	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1,
+	     eth_nic_base + D8390_P0_COMMAND);
+
+	outb(what & 0xff,eth_nic_base + 8);
+	outb((what >> 8) & 0xff,eth_nic_base + 8 + 1);
+
+	outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0,
+	     eth_nic_base + D8390_P0_COMMAND);
+	
+}
+
+
+static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt,
+				unsigned int eth_nic_base) {
+
+	outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+
+	outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
+
+	outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+
+	outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+
+	outb(dst, eth_nic_base + D8390_P0_RSAR0);
+
+	outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
+
+	outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+
+	while (cnt--) {
+			outb(*(src++), eth_nic_base + NE_ASIC_OFFSET + NE_DATA);
+	}
+
+#warning "Add timeout"
+	/* wait for operation finish */
+	while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) != D8390_ISR_RDC)
+		;
+}
+
+void ne2k_append_data(char *d, int len, unsigned int base) {
+	eth_pio_write(d, (TX_START << 8) + 42 + get_count(base), len, base);
+	set_count(base, get_count(base)+len);
+}
+
+static void ns8390_reset(unsigned int eth_nic_base)
+{
+	int i;
+
+	outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+	     D8390_COMMAND_STP, eth_nic_base + D8390_P0_COMMAND);
+
+	outb(0x48, eth_nic_base + D8390_P0_DCR);
+	outb(0, eth_nic_base + D8390_P0_RBCR0);
+	outb(0, eth_nic_base + D8390_P0_RBCR1);
+	outb(0x20, eth_nic_base + D8390_P0_RCR);
+	outb(2, eth_nic_base + D8390_P0_TCR);
+	outb(TX_START, eth_nic_base + D8390_P0_TPSR);
+	outb(RX_START, eth_nic_base + D8390_P0_PSTART);
+	outb(MEM_SIZE, eth_nic_base + D8390_P0_PSTOP);
+	outb(MEM_SIZE - 1, eth_nic_base + D8390_P0_BOUND);
+	outb(0xFF, eth_nic_base + D8390_P0_ISR);
+	outb(0, eth_nic_base + D8390_P0_IMR);
+
+	outb(D8390_COMMAND_PS1 |
+	     D8390_COMMAND_RD2 | D8390_COMMAND_STP,
+	     eth_nic_base + D8390_P0_COMMAND);
+
+	for (i = 0; i < ETH_ALEN; i++)
+		outb(0x0C, eth_nic_base + D8390_P1_PAR0 + i);
+
+	for (i = 0; i < ETH_ALEN; i++)
+		outb(0xFF, eth_nic_base + D8390_P1_MAR0 + i);
+
+	outb(RX_START, eth_nic_base + D8390_P1_CURR);
+	outb(D8390_COMMAND_PS0 |
+	     D8390_COMMAND_RD2 | D8390_COMMAND_STA,
+	     eth_nic_base + D8390_P0_COMMAND);
+	outb(0xFF, eth_nic_base + D8390_P0_ISR);
+	outb(0, eth_nic_base + D8390_P0_TCR);
+	outb(4, eth_nic_base + D8390_P0_RCR);
+	set_count(eth_nic_base, 0);
+}
+
+static void ns8390_tx_header(unsigned int eth_nic_base, int pktlen) {
+	unsigned short chksum;
+
+	unsigned char hdr[] = { 
+		/*
+		 * ETHERNET HDR
+		 */
+
+		// destination macaddr
+		0x02, 0x00, 0x00, 0x00, 0x00, 0x01,
+		/* source mac */
+		0x02, 0x00, 0x00, 0xC0, 0xFF, 0xEE, 
+		/* ethtype (IP) */
+		0x08, 0x00,
+		/* 
+		 * IP HDR 
+		 */
+		0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 
+		/* TTL, proto (UDP), chksum_hi, chksum_lo, IP0, IP1, IP2, IP3, */
+		0x40, 0x11, 0x0, 0x0, 0x7f, 0x0, 0x0, 0x1,
+		/* IP0, IP1, IP2, IP3  */
+		0xff, 0xff, 0xff, 0xff,
+		/*
+		 * UDP HDR
+		 */
+		/*  SRC PORT DST PORT  (2bytes each), ulen, uchksum (must be zero or correct */
+		0x1a, 0x0b, 0x1a, 0x0a, 0x00, 0x9, 0x00, 0x00, 
+	};
+
+	str2mac(CONFIG_CONSOLE_NE2K_DST_MAC, &hdr[0]);
+	str2ip(CONFIG_CONSOLE_NE2K_DST_IP, &hdr[30]);
+	str2ip(CONFIG_CONSOLE_NE2K_SRC_IP, &hdr[26]);
+
+	/* zero checksum */
+	hdr[24] = 0;
+	hdr[25] = 0;
+
+	/* update IP packet len */
+	hdr[16] = ((28 + pktlen) >> 8) & 0xff;
+	hdr[17] = (28 + pktlen) & 0xff;
+
+	/* update UDP len */
+	hdr[38] = (8 + pktlen) >> 8;
+	hdr[39] = 8 + pktlen;
+
+	chksum = compute_ip_checksum(&hdr[14], 20);
+
+	hdr[25] = chksum >> 8;
+	hdr[24] = chksum;
+
+	eth_pio_write(hdr, (TX_START << 8), sizeof(hdr), eth_nic_base);
+}
+
+void ne2k_transmit(unsigned int eth_nic_base) {
+	unsigned int pktsize;
+	unsigned int len = get_count(eth_nic_base);
+	int cnt = 10000;
+
+	// so place whole header inside chip buffer
+	ns8390_tx_header(eth_nic_base, len);
+
+	// commit sending now
+	outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+
+	outb(TX_START, eth_nic_base + D8390_P0_TPSR);
+
+	pktsize = 42 + len;
+	if (pktsize < 64) 
+		pktsize = 64;
+
+	outb(pktsize, eth_nic_base + D8390_P0_TBCR0);
+	outb(pktsize >> 8, eth_nic_base + D8390_P0_TBCR1);
+
+	outb(D8390_ISR_PTX, eth_nic_base + D8390_P0_ISR);
+
+	outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+
+	/* wait for operation finish */
+	while ((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_PTX) != D8390_ISR_PTX) {
+			//intk(BIOS_DEBUG, "TX\n"); 
+			if (cnt == 0) {
+				//printk(BIOS_DEBUG, "TX timeout\n"); 
+				break;
+			}
+			cnt --;
+		}
+
+	set_count(eth_nic_base, 0);
+}
+
+#ifdef __PRE_RAM__
+
+#include <arch/romcc_io.h>
+
+int ne2k_init(unsigned int eth_nic_base) {
+
+	device_t dev;
+	unsigned char c;
+
+	/* Power management controller */
+	dev = pci_locate_device(PCI_ID(0x10ec,
+				       0x8029), 0);
+
+	if (dev == PCI_DEV_INVALID)
+		return ;
+
+	pci_write_config32(dev, 0x10, eth_nic_base | 1 );
+	pci_write_config8(dev, 0x4, 0x1);
+
+
+	c = inb(eth_nic_base + NE_ASIC_OFFSET + NE_RESET);
+	outb(c, eth_nic_base + NE_ASIC_OFFSET + NE_RESET);
+
+	(void) inb(0x84);
+
+	outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
+	outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR); 
+
+	outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR); 
+	outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
+	outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
+
+	ns8390_reset(eth_nic_base);
+	return 1;
+}
+
+#else
+
+#include <delay.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arch/io.h>
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+
+static void read_resources(struct device *dev)
+{
+	struct resource *res;
+
+	/* Fix the I/O Resources of the USB2.0 Interface */
+	res = new_resource(dev, PCI_BASE_ADDRESS_0);
+	res->base = CONFIG_CONSOLE_NE2K_IO_PORT;
+	res->size = 32;
+	res->align = 5;
+	res->gran = 5;
+	res->limit = res->base + res->size - 1;
+	res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_STORED |
+		     		IORESOURCE_ASSIGNED;
+	return;
+}
+
+
+static struct device_operations si_sata_ops  = {
+	.read_resources   = read_resources,
+	.set_resources    = pci_dev_set_resources,
+	.enable_resources = pci_dev_enable_resources,
+	.init             = 0,
+	.scan_bus         = 0,
+};
+
+static const struct pci_driver si_sata_driver __pci_driver = {
+        .ops    = &si_sata_ops,
+        .vendor = 0x10ec,
+        .device = 0x8029,
+};
+
+#endif
Index: src/lib/Makefile.inc
===================================================================
--- src/lib/Makefile.inc	(revision 5577)
+++ src/lib/Makefile.inc	(working copy)
@@ -21,10 +21,14 @@ 
 initobj-y += memcmp.o
 initobj-y += cbfs.o
 initobj-y += lzma.o
+initobj-$(CONFIG_CONSOLE_NE2K) += ne2k.o
+initobj-$(CONFIG_CONSOLE_NE2K) += compute_ip_checksum.o
+
 #initobj-y += lzmadecode.o
 
 obj-$(CONFIG_USBDEBUG_DIRECT) += usbdebug_direct.o
 obj-$(CONFIG_COMPRESSED_PAYLOAD_LZMA) += lzma.o
+driver-$(CONFIG_CONSOLE_NE2K) += ne2k.o
 
 obj-$(CONFIG_BOOTSPLASH) += jpeg.o
 
Index: src/lib/ns8390.h
===================================================================
--- src/lib/ns8390.h	(revision 0)
+++ src/lib/ns8390.h	(revision 0)
@@ -0,0 +1,240 @@ 
+/**************************************************************************
+ETHERBOOT -  BOOTP/TFTP Bootstrap Program
+
+Author: Martin Renters
+  Date: Jun/94
+
+**************************************************************************/
+
+//FILE_LICENCE ( BSD2 );
+
+#define VENDOR_NONE	0
+#define VENDOR_WD	1
+#define VENDOR_NOVELL	2
+#define VENDOR_3COM	3
+
+#define FLAG_PIO	0x01
+#define FLAG_16BIT	0x02
+#define FLAG_790	0x04
+
+#define MEM_8192	32
+#define MEM_16384	64
+#define MEM_32768	128
+
+#define	ISA_MAX_ADDR	0x400
+
+/**************************************************************************
+Western Digital/SMC Board Definitions
+**************************************************************************/
+#define WD_LOW_BASE	0x200
+#define WD_HIGH_BASE	0x3e0
+#ifndef	WD_DEFAULT_MEM
+#define WD_DEFAULT_MEM	0xD0000
+#endif
+#define WD_NIC_ADDR	0x10
+
+/**************************************************************************
+Western Digital/SMC ASIC Addresses
+**************************************************************************/
+#define WD_MSR		0x00
+#define WD_ICR		0x01
+#define WD_IAR		0x02
+#define WD_BIO		0x03
+#define WD_IRR		0x04
+#define WD_LAAR		0x05
+#define WD_IJR		0x06
+#define WD_GP2		0x07
+#define WD_LAR		0x08
+#define WD_BID		0x0E
+
+#define WD_ICR_16BIT	0x01
+
+#define WD_MSR_MENB	0x40
+
+#define WD_LAAR_L16EN	0x40
+#define WD_LAAR_M16EN	0x80
+
+#define WD_SOFTCONFIG	0x20
+
+/**************************************************************************
+Western Digital/SMC Board Types
+**************************************************************************/
+#define TYPE_WD8003S	0x02
+#define TYPE_WD8003E	0x03
+#define TYPE_WD8013EBT	0x05
+#define TYPE_WD8003W	0x24
+#define TYPE_WD8003EB	0x25
+#define TYPE_WD8013W	0x26
+#define TYPE_WD8013EP	0x27
+#define TYPE_WD8013WC	0x28
+#define TYPE_WD8013EPC	0x29
+#define TYPE_SMC8216T	0x2a
+#define TYPE_SMC8216C	0x2b
+#define TYPE_SMC8416T	0x00	/* Bogus entries: the 8416 generates the */
+#define TYPE_SMC8416C	0x00	/* the same codes as the 8216. */
+#define TYPE_SMC8013EBP	0x2c
+
+/**************************************************************************
+3com 3c503 definitions
+**************************************************************************/
+
+#ifndef	_3COM_BASE
+#define _3COM_BASE 0x300
+#endif
+
+#define _3COM_TX_PAGE_OFFSET_8BIT     0x20
+#define _3COM_TX_PAGE_OFFSET_16BIT    0x0
+#define _3COM_RX_PAGE_OFFSET_16BIT    0x20
+
+#define _3COM_ASIC_OFFSET 0x400
+#define _3COM_NIC_OFFSET 0x0
+
+#define _3COM_PSTR            0
+#define _3COM_PSPR            1
+
+#define _3COM_BCFR            3
+#define _3COM_BCFR_2E0        0x01
+#define _3COM_BCFR_2A0        0x02
+#define _3COM_BCFR_280        0x04
+#define _3COM_BCFR_250        0x08
+#define _3COM_BCFR_350        0x10
+#define _3COM_BCFR_330        0x20
+#define _3COM_BCFR_310        0x40
+#define _3COM_BCFR_300        0x80
+#define _3COM_PCFR            4
+#define _3COM_PCFR_PIO        0
+#define _3COM_PCFR_C8000      0x10
+#define _3COM_PCFR_CC000      0x20
+#define _3COM_PCFR_D8000      0x40
+#define _3COM_PCFR_DC000      0x80
+#define _3COM_CR              6
+#define _3COM_CR_RST          0x01    /* Reset GA and NIC */
+#define _3COM_CR_XSEL         0x02    /* Transceiver select. BNC=1(def) AUI=0 */
+#define _3COM_CR_EALO         0x04    /* window EA PROM 0-15 to I/O base */
+#define _3COM_CR_EAHI         0x08    /* window EA PROM 16-31 to I/O base */
+#define _3COM_CR_SHARE        0x10    /* select interrupt sharing option */
+#define _3COM_CR_DBSEL        0x20    /* Double buffer select */
+#define _3COM_CR_DDIR         0x40    /* DMA direction select */
+#define _3COM_CR_START        0x80    /* Start DMA controller */
+#define _3COM_GACFR           5
+#define _3COM_GACFR_MBS0      0x01
+#define _3COM_GACFR_MBS1      0x02
+#define _3COM_GACFR_MBS2      0x04
+#define _3COM_GACFR_RSEL      0x08    /* enable shared memory */
+#define _3COM_GACFR_TEST      0x10    /* for GA testing */
+#define _3COM_GACFR_OWS       0x20    /* select 0WS access to GA */
+#define _3COM_GACFR_TCM       0x40    /* Mask DMA interrupts */
+#define _3COM_GACFR_NIM       0x80    /* Mask NIC interrupts */
+#define _3COM_STREG           7
+#define _3COM_STREG_REV       0x07    /* GA revision */
+#define _3COM_STREG_DIP       0x08    /* DMA in progress */
+#define _3COM_STREG_DTC       0x10    /* DMA terminal count */
+#define _3COM_STREG_OFLW      0x20    /* Overflow */
+#define _3COM_STREG_UFLW      0x40    /* Underflow */
+#define _3COM_STREG_DPRDY     0x80    /* Data port ready */
+#define _3COM_IDCFR           8
+#define _3COM_IDCFR_DRQ0      0x01    /* DMA request 1 select */
+#define _3COM_IDCFR_DRQ1      0x02    /* DMA request 2 select */
+#define _3COM_IDCFR_DRQ2      0x04    /* DMA request 3 select */
+#define _3COM_IDCFR_UNUSED    0x08    /* not used */
+#define _3COM_IDCFR_IRQ2      0x10    /* Interrupt request 2 select */
+#define _3COM_IDCFR_IRQ3      0x20    /* Interrupt request 3 select */
+#define _3COM_IDCFR_IRQ4      0x40    /* Interrupt request 4 select */
+#define _3COM_IDCFR_IRQ5      0x80    /* Interrupt request 5 select */
+#define _3COM_IRQ2      2
+#define _3COM_IRQ3      3
+#define _3COM_IRQ4      4
+#define _3COM_IRQ5      5
+#define _3COM_DAMSB           9
+#define _3COM_DALSB           0x0a
+#define _3COM_VPTR2           0x0b
+#define _3COM_VPTR1           0x0c
+#define _3COM_VPTR0           0x0d
+#define _3COM_RFMSB           0x0e
+#define _3COM_RFLSB           0x0f
+
+/**************************************************************************
+NE1000/2000 definitions
+**************************************************************************/
+#define NE_ASIC_OFFSET	0x10
+#define NE_RESET	0x0F		/* Used to reset card */
+#define NE_DATA		0x00		/* Used to read/write NIC mem */
+
+#define COMPEX_RL2000_TRIES	200
+
+/**************************************************************************
+8390 Register Definitions
+**************************************************************************/
+#define D8390_P0_COMMAND	0x00
+#define D8390_P0_PSTART		0x01
+#define D8390_P0_PSTOP		0x02
+#define D8390_P0_BOUND		0x03
+#define D8390_P0_TSR		0x04
+#define	D8390_P0_TPSR		0x04
+#define D8390_P0_TBCR0		0x05
+#define D8390_P0_TBCR1		0x06
+#define D8390_P0_ISR		0x07
+#define D8390_P0_RSAR0		0x08
+#define D8390_P0_RSAR1		0x09
+#define D8390_P0_RBCR0		0x0A
+#define D8390_P0_RBCR1		0x0B
+#define D8390_P0_RSR		0x0C
+#define D8390_P0_RCR		0x0C
+#define D8390_P0_TCR		0x0D
+#define D8390_P0_DCR		0x0E
+#define D8390_P0_IMR		0x0F
+#define D8390_P1_COMMAND	0x00
+#define D8390_P1_PAR0		0x01
+#define D8390_P1_PAR1		0x02
+#define D8390_P1_PAR2		0x03
+#define D8390_P1_PAR3		0x04
+#define D8390_P1_PAR4		0x05
+#define D8390_P1_PAR5		0x06
+#define D8390_P1_CURR		0x07
+#define D8390_P1_MAR0		0x08
+
+#define D8390_COMMAND_PS0	0x0		/* Page 0 select */
+#define D8390_COMMAND_PS1	0x40		/* Page 1 select */
+#define D8390_COMMAND_PS2	0x80		/* Page 2 select */
+#define	D8390_COMMAND_RD2	0x20		/* Remote DMA control */
+#define D8390_COMMAND_RD1	0x10
+#define D8390_COMMAND_RD0	0x08
+#define D8390_COMMAND_TXP	0x04		/* transmit packet */
+#define D8390_COMMAND_STA	0x02		/* start */
+#define D8390_COMMAND_STP	0x01		/* stop */
+
+#define D8390_RCR_MON		0x20		/* monitor mode */
+
+#define D8390_DCR_FT1		0x40
+#define D8390_DCR_LS		0x08		/* Loopback select */
+#define D8390_DCR_WTS		0x01		/* Word transfer select */
+
+#define D8390_ISR_PRX		0x01		/* successful recv */
+#define D8390_ISR_PTX		0x02		/* successful xmit */
+#define D8390_ISR_RXE		0x04		/* receive error */
+#define D8390_ISR_TXE		0x08		/* transmit error */
+#define D8390_ISR_OVW		0x10		/* Overflow */
+#define D8390_ISR_CNT		0x20		/* Counter overflow */
+#define D8390_ISR_RDC		0x40		/* Remote DMA complete */
+#define D8390_ISR_RST		0x80		/* reset */
+
+#define D8390_RSTAT_PRX		0x01		/* successful recv */
+#define D8390_RSTAT_CRC		0x02		/* CRC error */
+#define D8390_RSTAT_FAE		0x04		/* Frame alignment error */
+#define D8390_RSTAT_OVER	0x08		/* FIFO overrun */
+
+#define D8390_TXBUF_SIZE	6
+#define D8390_RXBUF_END		32
+#define D8390_PAGE_SIZE         256
+
+struct ringbuffer {
+	unsigned char status;
+	unsigned char next;
+	unsigned short len;
+};
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
+
Index: src/lib/compute_ip_checksum.c
===================================================================
--- src/lib/compute_ip_checksum.c	(revision 5577)
+++ src/lib/compute_ip_checksum.c	(working copy)
@@ -51,3 +51,42 @@ 
 	}
 	return (~checksum) & 0xFFFF;
 }
+
+void str2ip(char *str, unsigned char *ip)
+{
+	unsigned char c, i = 0;
+	unsigned char acc = 0;
+
+	do {
+		c = str[i];
+		if ((c >= '0') && (c <= '9')) {
+			acc *= 10;
+			acc += (c - '0');
+		} else {
+			*ip++ = acc;
+			acc = 0;
+		}
+		i++;
+	} while (c != '\0');
+}
+
+void str2mac(char *str, unsigned char *mac)
+{
+	unsigned char c, i = 0;
+	unsigned char acc = 0;
+
+	do {
+		c = str[i];
+		if ((c >= '0') && (c <= '9')) {
+			acc *= 16;
+			acc += (c - '0');
+		} else if ((c >= 'a') && (c <= 'f')) {
+			acc *= 16;
+			acc += ((c - 'a') + 10) ;
+		} else {
+			*mac++ = acc;
+			acc = 0;
+		}
+		i++;
+	} while (c != '\0');
+}
Index: src/arch/i386/lib/printk_init.c
===================================================================
--- src/arch/i386/lib/printk_init.c	(revision 5577)
+++ src/arch/i386/lib/printk_init.c	(working copy)
@@ -23,6 +23,13 @@ 
 
 static void console_tx_byte(unsigned char byte)
 {
+unsigned char d = byte;
+
+#if CONFIG_CONSOLE_NE2K
+#ifdef __PRE_RAM__
+	ne2k_append_data(&d, 1, CONFIG_CONSOLE_NE2K_IO_PORT);
+#endif
+#endif
 	if (byte == '\n')
 		uart8250_tx_byte(CONFIG_TTYS0_BASE, '\r');
 
@@ -41,6 +48,8 @@ 
 	va_start(args, fmt);
 	i = vtxprintf(console_tx_byte, fmt, args);
 	va_end(args);
-
+#if CONFIG_CONSOLE_NE2K
+	ne2k_transmit(CONFIG_CONSOLE_NE2K_IO_PORT);
+#endif
 	return i;
 }