summaryrefslogtreecommitdiffstats
path: root/sys/i386/boot/netboot
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1995-03-31 06:51:37 +0000
committerjkh <jkh@FreeBSD.org>1995-03-31 06:51:37 +0000
commit74af7d44ef596cc7d90ea904cc5472cb30cbc7fd (patch)
tree33105a4bd982231d793f7baddf892787695962cf /sys/i386/boot/netboot
parentab22dad2bd3d2a38d0c059f515f9dd9562cdfb20 (diff)
downloadFreeBSD-src-74af7d44ef596cc7d90ea904cc5472cb30cbc7fd.zip
FreeBSD-src-74af7d44ef596cc7d90ea904cc5472cb30cbc7fd.tar.gz
Diskless boot support for 3C509.
I'm not exactly sure why all the inb/outw stuff got added to netboot.h and I'd be happy if someone like Martin or Bruce could take a look at it! Submitted by: "Serge A. Babkin" <babkin@hq.icb.chel.su>
Diffstat (limited to 'sys/i386/boot/netboot')
-rw-r--r--sys/i386/boot/netboot/509.doc21
-rw-r--r--sys/i386/boot/netboot/Makefile8
-rw-r--r--sys/i386/boot/netboot/ether.c1066
-rw-r--r--sys/i386/boot/netboot/ether.h1
-rw-r--r--sys/i386/boot/netboot/if_epreg.h388
-rw-r--r--sys/i386/boot/netboot/main.c21
-rw-r--r--sys/i386/boot/netboot/netboot.h168
7 files changed, 1435 insertions, 238 deletions
diff --git a/sys/i386/boot/netboot/509.doc b/sys/i386/boot/netboot/509.doc
new file mode 100644
index 0000000..1908c64
--- /dev/null
+++ b/sys/i386/boot/netboot/509.doc
@@ -0,0 +1,21 @@
+During adding of 3C509 support I made following changes:
+
+1) File if_epreg.h added - it is slightly different from one in
+/usr/src/sys/i386/isa !
+
+2) Support of 3C509 added to ether.c
+
+3) Flag -DINCLUDE_3C509 added (to ether.h, ether.c, Makefile)
+
+4) Routine eth_fillname() added to ether.c because 3C509 has
+different driver (ep0 instead of ed0). Main.c was changed
+according to this.
+
+I had tested this version with 3C509 only, but I see no reasons
+why it must not work with other cards.
+
+But don't try to link it for both 3C509 and 8390-based cards. In
+this case object file grows behind 16K and everything fails
+to work. I don't know how correct this trouble.
+
+ Serge Babkin (babkin@hq.icb.chel.su)
diff --git a/sys/i386/boot/netboot/Makefile b/sys/i386/boot/netboot/Makefile
index 4038403..fa88647 100644
--- a/sys/i386/boot/netboot/Makefile
+++ b/sys/i386/boot/netboot/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.3 1994/11/17 12:16:01 jkh Exp $
+# Makefile,v 1.4 1994/12/31 17:16:49 jkh Exp
#
# Makefile for NETBOOT
#
@@ -9,7 +9,8 @@
# -DRELOC - Relocation address (usually 0x90000)
# -DINCLUDE_WD - Include Western Digital/SMC support
# -DINCLUDE_NE - Include NE1000/NE2000 support
-# -DINCLUDE_3COM - Include 3c503 support
+# -DINCLUDE_3COM - Include 3c503 support
+# -DINCLUDE_3C509 - Include 3c509 support
# -D_3COM_USE_AUI - Disable transceiver on 3c503 by default
# -DNE_BASE - Base I/O address for NE1000/NE2000
# -D_3COM_BASE - Base I/O address for 3c503
@@ -22,10 +23,11 @@ SRCS= start2.S main.c misc.c ether.c bootmenu.c rpc.c
BINDIR= /usr/mdec
BINMODE= 555
-CFLAGS= -O2 -DNFS -DROMSIZE=${ROMSIZE} -DRELOC=${RELOCADDR}
+CFLAGS= -O2 -DNFS -DROMSIZE=${ROMSIZE} -DRELOC=${RELOCADDR} -DASK_BOOT
CFLAGS+= -DINCLUDE_WD -DWD_DEFAULT_MEM=0xD0000
CFLAGS+= -DINCLUDE_NE -DNE_BASE=0x320
CFLAGS+= -DINCLUDE_3COM -D_3COM_BASE=0x300
+CFLAGS+= -DINCLUDE_3C509
CLEANFILES+= netboot.com.nohdr netboot.com.strip
CLEANFILES+= netboot.rom.nohdr netboot.rom.strip netboot.rom
CLEANFILES+= makerom start2.ro
diff --git a/sys/i386/boot/netboot/ether.c b/sys/i386/boot/netboot/ether.c
index a5cbd2e..1077ab0 100644
--- a/sys/i386/boot/netboot/ether.c
+++ b/sys/i386/boot/netboot/ether.c
@@ -2,12 +2,15 @@
/**************************************************************************
NETBOOT - BOOTP/TFTP Bootstrap Program
-Author: Martin Renters
- Date: May/94
+Author: Martin Renters.
+ Date: Mar 22 1995
- This code is based heavily on David Greenman's if_ed.c driver
+ This code is based heavily on David Greenman's if_ed.c driver and
+ Andres Vega Garcia's if_ep.c driver.
Copyright (C) 1993-1994, David Greenman, Martin Renters.
+ Copyright (C) 1993-1995, Andres Vega Garcia.
+ Copyright (C) 1995, Serge Babkin.
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
@@ -16,15 +19,24 @@ Author: Martin Renters
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
+3c509 support added by Serge Babkin (babkin@hq.icb.chel.su) on 03/22/95
-**************************************************************************/
+***************************************************************************/
+
+/* #define EDEBUG */
#include "netboot.h"
#include "ether.h"
+#ifdef INCLUDE_3C509
+# include "if_epreg.h"
+#endif
+
extern short aui;
+char bnc=0, utp=0; /* for 3C509 */
unsigned short eth_nic_base;
unsigned short eth_asic_base;
+unsigned short eth_base;
unsigned char eth_tx_start;
unsigned char eth_laar;
unsigned char eth_flags;
@@ -34,31 +46,216 @@ unsigned char *eth_bmem;
unsigned char *eth_rmem;
unsigned char *eth_node_addr;
+#ifdef INCLUDE_3C509
+
+static send_ID_sequence();
+static get_eeprom_data();
+static get_e();
+
+#endif
+
/**************************************************************************
The following two variables are used externally
-**************************************************************************/
+***************************************************************************/
char packet[ETH_MAX_PACKET];
int packetlen;
+/*************************************************************************
+ETH_FILLNAME - Fill name of adapter in NFS structure
+**************************************************************************/
+
+eth_fillname(where)
+char *where;
+{
+ switch(eth_vendor) {
+ case VENDOR_3C509:
+ where[0]='e'; where[1]='p'; where[2]='0'; where[3]=0;
+ break;
+ case VENDOR_WD:
+ case VENDOR_NOVELL:
+ case VENDOR_3COM:
+ where[0]='e'; where[1]='d'; where[2]='0'; where[3]=0;
+ break;
+ default:
+ where[0]='?'; where[1]='?'; where[2]='?'; where[3]=0;
+ break;
+ }
+}
+
/**************************************************************************
ETH_PROBE - Look for an adapter
-**************************************************************************/
+***************************************************************************/
eth_probe()
{
+ /* common variables */
int i;
+#ifdef INCLUDE_3C509
+ /* variables for 3C509 */
+ int data, j, io_base, id_port = EP_ID_PORT;
+ int nisa = 0, neisa = 0;
+ u_short k;
+ int ep_current_tag = EP_LAST_TAG + 1;
+ short *p;
+#endif
+#if defined(INCLUDE_3COM) || defined(INCLUDE_WD) || defined(INCLUDE_NE)
+ /* varaibles for 8390 */
struct wd_board *brd;
char *name;
unsigned short chksum;
unsigned char c;
+#endif
eth_vendor = VENDOR_NONE;
+#ifdef INCLUDE_3C509
+
+ /*********************************************************
+ Search for 3Com 509 card
+ ***********************************************************/
+
+ /* Look for the EISA boards, leave them activated */
+ /* search for the first card, ignore all others */
+ for(j = 1; j < 16 && eth_vendor==VENDOR_NONE ; j++) {
+ io_base = (j * EP_EISA_START) | EP_EISA_W0;
+ if (inw(io_base + EP_W0_MFG_ID) != MFG_ID)
+ continue;
+
+ /* we must found 0x1f if the board is EISA configurated */
+ if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f)
+ continue;
+
+ /* Reset and Enable the card */
+ outb(io_base + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER);
+ DELAY(1000); /* we must wait at least 1 ms */
+ outb(io_base + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER);
+
+ /*
+ * Once activated, all the registers are mapped in the range
+ * x000 - x00F, where x is the slot number.
+ */
+ eth_base = j * EP_EISA_START;
+ eth_vendor = VENDOR_3C509;
+ }
+ ep_current_tag--;
+
+ /* Look for the ISA boards. Init and leave them actived */
+ /* search for the first card, ignore all others */
+ outb(id_port, 0xc0); /* Global reset */
+ DELAY(1000);
+ for (i = 0; i < EP_MAX_BOARDS && eth_vendor==VENDOR_NONE; i++) {
+ outb(id_port, 0);
+ outb(id_port, 0);
+ send_ID_sequence(id_port);
+
+ data = get_eeprom_data(id_port, EEPROM_MFG_ID);
+ if (data != MFG_ID)
+ break;
+
+ /* resolve contention using the Ethernet address */
+ for (j = 0; j < 3; j++)
+ data = get_eeprom_data(id_port, j);
+
+ eth_base =
+ (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
+ outb(id_port, ep_current_tag); /* tags board */
+ outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
+ eth_vendor = VENDOR_3C509;
+ ep_current_tag--;
+ }
+
+ if(eth_vendor != VENDOR_3C509)
+ goto no3c509;
+
+ /*
+ * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
+ * 0x9[0-f]50
+ */
+ GO_WINDOW(0);
+ k = get_e(EEPROM_PROD_ID);
+ if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
+ goto no3c509;
+
+ if(eth_base >= EP_EISA_START) {
+ printf("3C5x9 board on EISA at 0x%x - ",eth_base);
+ } else {
+ printf("3C5x9 board on ISA at 0x%x - ",eth_base);
+ }
+
+ /* test for presence of connectors */
+ i = inw(IS_BASE + EP_W0_CONFIG_CTRL);
+ j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14;
+
+ switch(j) {
+ case 0:
+ if(i & IS_UTP) {
+ printf("10baseT\r\n");
+ utp=1;
+ }
+ else {
+ printf("10baseT not present\r\n");
+ eth_vendor=VENDOR_NONE;
+ goto no3c509;
+ }
+
+ break;
+ case 1:
+ if(i & IS_AUI)
+ printf("10base5\r\n");
+ else {
+ printf("10base5 not present\r\n");
+ eth_vendor=VENDOR_NONE;
+ goto no3c509;
+ }
+
+ break;
+ case 3:
+ if(i & IS_BNC) {
+ printf("10base2\r\n");
+ bnc=1;
+ }
+ else {
+ printf("10base2 not present\r\n");
+ eth_vendor=VENDOR_NONE;
+ goto no3c509;
+ }
+
+ break;
+ default:
+ printf("unknown connector\r\n");
+ eth_vendor=VENDOR_NONE;
+ goto no3c509;
+ }
+ /*
+ * Read the station address from the eeprom
+ */
+ p = (u_short *) arptable[ARP_CLIENT].node;
+ for (i = 0; i < 3; i++) {
+ GO_WINDOW(0);
+ p[i] = htons(get_e(i));
+ GO_WINDOW(2);
+ outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i]));
+ }
+
+ printf("Ethernet address: ");
+ for(i=0; i<5; i++) {
+ printf("%b:",arptable[ARP_CLIENT].node[i]);
+ }
+ printf("%b\n",arptable[ARP_CLIENT].node[i]);
+
+ eth_node_addr = arptable[ARP_CLIENT].node;
+ eth_reset();
+ return eth_vendor;
+no3c509:
+ eth_vendor = VENDOR_NONE;
+#endif
+
+#if defined(INCLUDE_3COM) || defined(INCLUDE_WD) || defined(INCLUDE_NE)
#ifdef INCLUDE_WD
/******************************************************************
- Search for WD/SMC cards
- ******************************************************************/
+ Search for WD/SMC cards
+ *******************************************************************/
for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
- eth_asic_base += 0x20) {
+ eth_asic_base += 0x20) {
chksum = 0;
for (i=8; i<16; i++)
chksum += inb(i+eth_asic_base);
@@ -79,13 +276,13 @@ eth_probe()
eth_memsize = brd->memsize;
eth_tx_start = 0;
if ((c == TYPE_WD8013EP) &&
- (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
- eth_flags = FLAG_16BIT;
- eth_memsize = MEM_16384;
+ (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
+ eth_flags = FLAG_16BIT;
+ eth_memsize = MEM_16384;
}
if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
eth_bmem = (char *)(0x80000 |
- ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
+ ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
} else
eth_bmem = (char *)WD_DEFAULT_MEM;
if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
@@ -97,25 +294,25 @@ eth_probe()
}
outb(eth_asic_base + WD_MSR, 0x80); /* Reset */
printf("\r\n%s base 0x%x, memory 0x%X, addr ",
- brd->name, eth_asic_base, eth_bmem);
+ brd->name, eth_asic_base, eth_bmem);
for (i=0; i<6; i++) {
printf("%b",(int)(arptable[ARP_CLIENT].node[i] =
- inb(i+eth_asic_base+WD_LAR)));
- if (i < 5) printf (":");
+ inb(i+eth_asic_base+WD_LAR)));
+ if (i < 5) printf (":");
}
if (eth_flags & FLAG_790) {
outb(eth_asic_base+WD_MSR, WD_MSR_MENB);
outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) |
- 0x80));
+ 0x80));
outb(eth_asic_base+0x0B,
- (((unsigned)eth_bmem >> 13) & 0x0F) |
- (((unsigned)eth_bmem >> 11) & 0x40) |
- (inb(eth_asic_base+0x0B) & 0xB0));
+ (((unsigned)eth_bmem >> 13) & 0x0F) |
+ (((unsigned)eth_bmem >> 11) & 0x40) |
+ (inb(eth_asic_base+0x0B) & 0xB0));
outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) &
- ~0x80));
+ ~0x80));
} else {
outb(eth_asic_base+WD_MSR,
- (((unsigned)eth_bmem >> 13) & 0x3F) | 0x40);
+ (((unsigned)eth_bmem >> 13) & 0x3F) | 0x40);
}
if (eth_flags & FLAG_16BIT) {
if (eth_flags & FLAG_790) {
@@ -124,140 +321,140 @@ eth_probe()
inb(0x84);
} else {
outb(eth_asic_base + WD_LAAR, (eth_laar =
- WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
+ WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
}
}
printf("\r\n");
-
+
}
#endif
#ifdef INCLUDE_3COM
- /******************************************************************
- Search for 3Com 3c503 if no WD/SMC cards
- ******************************************************************/
- if (eth_vendor == VENDOR_NONE) {
- eth_asic_base = _3COM_BASE + _3COM_ASIC_OFFSET;
- eth_nic_base = _3COM_BASE;
- eth_vendor = VENDOR_3COM;
- /*
- * Note that we use the same settings for both 8 and 16 bit cards:
- * both have an 8K bank of memory at page 1 while only the 16 bit
- * cards have a bank at page 0.
- */
- eth_memsize = MEM_16384;
- eth_tx_start = 32;
-
- /* Check our base address */
-
- switch(inb(eth_asic_base + _3COM_BCFR)) {
- case _3COM_BCFR_300:
- if ((int)eth_nic_base != 0x300)
- return(0);
- break;
- case _3COM_BCFR_310:
- if ((int)eth_nic_base != 0x310)
- return(0);
- break;
- case _3COM_BCFR_330:
- if ((int)eth_nic_base != 0x330)
- return(0);
- break;
- case _3COM_BCFR_350:
- if ((int)eth_nic_base != 0x350)
- return(0);
- break;
- case _3COM_BCFR_250:
- if ((int)eth_nic_base != 0x250)
- return(0);
- break;
- case _3COM_BCFR_280:
- if ((int)eth_nic_base != 0x280)
- return(0);
- break;
- case _3COM_BCFR_2A0:
- if ((int)eth_nic_base != 0x2a0)
- return(0);
- break;
- case _3COM_BCFR_2E0:
- if ((int)eth_nic_base != 0x2e0)
- return(0);
- break;
- default:
- return (0);
- }
-
- /* Now get the shared memory address */
-
- switch (inb(eth_asic_base + _3COM_PCFR)) {
- case _3COM_PCFR_DC000:
- eth_bmem = (char *)0xdc000;
- break;
- case _3COM_PCFR_D8000:
- eth_bmem = (char *)0xd8000;
- break;
- case _3COM_PCFR_CC000:
- eth_bmem = (char *)0xcc000;
- break;
- case _3COM_PCFR_C8000:
- eth_bmem = (char *)0xc8000;
- break;
- default:
- return (0);
- }
-
- /* Need this to make eth_poll() happy. */
-
- eth_rmem = eth_bmem - 0x2000;
-
- /* Reset NIC and ASIC */
-
- outb (eth_asic_base + _3COM_CR , _3COM_CR_RST | _3COM_CR_XSEL);
- outb (eth_asic_base + _3COM_CR , _3COM_CR_XSEL);
-
- /* Get our ethernet address */
-
- outb(eth_asic_base + _3COM_CR, _3COM_CR_EALO | _3COM_CR_XSEL);
- printf("\r\n3Com 3c503 base 0x%x, memory 0x%X addr ",
- eth_nic_base, eth_bmem);
- for (i=0; i<6; i++) {
- printf("%b",(int)(arptable[ARP_CLIENT].node[i] =
- inb(eth_nic_base+i)));
- if (i < 5) printf (":");
- }
- outb(eth_asic_base + _3COM_CR, _3COM_CR_XSEL);
- /*
- * Initialize GA configuration register. Set bank and enable shared
- * mem. We always use bank 1.
- */
- outb(eth_asic_base + _3COM_GACFR, _3COM_GACFR_RSEL |
- _3COM_GACFR_MBS0);
-
- outb(eth_asic_base, _3COM_VPTR2, 0xff);
- outb(eth_asic_base, _3COM_VPTR1, 0xff);
- outb(eth_asic_base, _3COM_VPTR0, 0x00);
- /*
- * Clear memory and verify that it worked (we use only 8K)
- */
- bzero(eth_bmem, 0x2000);
- for(i = 0; i < 0x2000; ++i)
- if (*((eth_bmem)+i)) {
- printf ("Failed to clear 3c503 shared mem.\r\n");
- return (0);
- }
- /*
- * Initialize GA page/start/stop registers.
- */
- outb(eth_asic_base + _3COM_PSTR, eth_tx_start);
- outb(eth_asic_base + _3COM_PSPR, eth_memsize);
-
- printf ("\r\n");
-
- }
+ /******************************************************************
+ Search for 3Com 3c503 if no WD/SMC cards
+ *******************************************************************/
+ if (eth_vendor == VENDOR_NONE) {
+ eth_asic_base = _3COM_BASE + _3COM_ASIC_OFFSET;
+ eth_nic_base = _3COM_BASE;
+ eth_vendor = VENDOR_3COM;
+ /*
+ * Note that we use the same settings for both 8 and 16 bit cards:
+ * both have an 8K bank of memory at page 1 while only the 16 bit
+ * cards have a bank at page 0.
+ */
+ eth_memsize = MEM_16384;
+ eth_tx_start = 32;
+
+ /* Check our base address */
+
+ switch(inb(eth_asic_base + _3COM_BCFR)) {
+ case _3COM_BCFR_300:
+ if ((int)eth_nic_base != 0x300)
+ return(0);
+ break;
+ case _3COM_BCFR_310:
+ if ((int)eth_nic_base != 0x310)
+ return(0);
+ break;
+ case _3COM_BCFR_330:
+ if ((int)eth_nic_base != 0x330)
+ return(0);
+ break;
+ case _3COM_BCFR_350:
+ if ((int)eth_nic_base != 0x350)
+ return(0);
+ break;
+ case _3COM_BCFR_250:
+ if ((int)eth_nic_base != 0x250)
+ return(0);
+ break;
+ case _3COM_BCFR_280:
+ if ((int)eth_nic_base != 0x280)
+ return(0);
+ break;
+ case _3COM_BCFR_2A0:
+ if ((int)eth_nic_base != 0x2a0)
+ return(0);
+ break;
+ case _3COM_BCFR_2E0:
+ if ((int)eth_nic_base != 0x2e0)
+ return(0);
+ break;
+ default:
+ return (0);
+ }
+
+ /* Now get the shared memory address */
+
+ switch (inb(eth_asic_base + _3COM_PCFR)) {
+ case _3COM_PCFR_DC000:
+ eth_bmem = (char *)0xdc000;
+ break;
+ case _3COM_PCFR_D8000:
+ eth_bmem = (char *)0xd8000;
+ break;
+ case _3COM_PCFR_CC000:
+ eth_bmem = (char *)0xcc000;
+ break;
+ case _3COM_PCFR_C8000:
+ eth_bmem = (char *)0xc8000;
+ break;
+ default:
+ return (0);
+ }
+
+ /* Need this to make eth_poll() happy. */
+
+ eth_rmem = eth_bmem - 0x2000;
+
+ /* Reset NIC and ASIC */
+
+ outb (eth_asic_base + _3COM_CR , _3COM_CR_RST | _3COM_CR_XSEL);
+ outb (eth_asic_base + _3COM_CR , _3COM_CR_XSEL);
+
+ /* Get our ethernet address */
+
+ outb(eth_asic_base + _3COM_CR, _3COM_CR_EALO | _3COM_CR_XSEL);
+ printf("\r\n3Com 3c503 base 0x%x, memory 0x%X addr ",
+ eth_nic_base, eth_bmem);
+ for (i=0; i<6; i++) {
+ printf("%b",(int)(arptable[ARP_CLIENT].node[i] =
+ inb(eth_nic_base+i)));
+ if (i < 5) printf (":");
+ }
+ outb(eth_asic_base + _3COM_CR, _3COM_CR_XSEL);
+ /*
+ * Initialize GA configuration register. Set bank and enable shared
+ * mem. We always use bank 1.
+ */
+ outb(eth_asic_base + _3COM_GACFR, _3COM_GACFR_RSEL |
+ _3COM_GACFR_MBS0);
+
+ outb(eth_asic_base + _3COM_VPTR2, 0xff);
+ outb(eth_asic_base + _3COM_VPTR1, 0xff);
+ outb(eth_asic_base + _3COM_VPTR0, 0x00);
+ /*
+ * Clear memory and verify that it worked (we use only 8K)
+ */
+ bzero(eth_bmem, 0x2000);
+ for(i = 0; i < 0x2000; ++i)
+ if (*((eth_bmem)+i)) {
+ printf ("Failed to clear 3c503 shared mem.\r\n");
+ return (0);
+ }
+ /*
+ * Initialize GA page/start/stop registers.
+ */
+ outb(eth_asic_base + _3COM_PSTR, eth_tx_start);
+ outb(eth_asic_base + _3COM_PSPR, eth_memsize);
+
+ printf ("\r\n");
+
+ }
#endif
#ifdef INCLUDE_NE
/******************************************************************
- Search for NE1000/2000 if no WD/SMC or 3com cards
- ******************************************************************/
+ Search for NE1000/2000 if no WD/SMC or 3com cards
+ *******************************************************************/
if (eth_vendor == VENDOR_NONE) {
char romdata[16], testbuf[32];
char test[] = "NE1000/2000 memory";
@@ -270,9 +467,9 @@ eth_probe()
eth_tx_start = 32;
c = inb(eth_asic_base + NE_RESET);
outb(eth_asic_base + NE_RESET, c);
- inb(0x84);
+ inb(0x84);
outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_STP |
- D8390_COMMAND_RD2);
+ D8390_COMMAND_RD2);
outb(eth_nic_base + D8390_P0_RCR, D8390_RCR_MON);
outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_FT1 | D8390_DCR_LS);
outb(eth_nic_base + D8390_P0_PSTART, MEM_8192);
@@ -284,7 +481,7 @@ eth_probe()
eth_memsize = MEM_32768;
eth_tx_start = 64;
outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_WTS |
- D8390_DCR_FT1 | D8390_DCR_LS);
+ D8390_DCR_FT1 | D8390_DCR_LS);
outb(eth_nic_base + D8390_P0_PSTART, MEM_16384);
outb(eth_nic_base + D8390_P0_PSTOP, MEM_32768);
eth_pio_write(test, 16384, sizeof(test));
@@ -300,28 +497,132 @@ eth_probe()
}
printf("\r\n");
}
-#endif
- if (eth_vendor == VENDOR_NONE) return(0);
+ if (eth_vendor == VENDOR_NONE)
+ goto no8390;
- if (eth_vendor != VENDOR_3COM) eth_rmem = eth_bmem;
+ if (eth_vendor != VENDOR_3COM) eth_rmem = eth_bmem;
eth_node_addr = arptable[ARP_CLIENT].node;
eth_reset();
return(eth_vendor);
+#endif /* NE */
+no8390:
+#endif /*8390 */
+
+ return VENDOR_NONE;
}
/**************************************************************************
ETH_RESET - Reset adapter
-**************************************************************************/
+***************************************************************************/
eth_reset()
{
- int i;
+ int s, i;
+
+#ifdef INCLUDE_3C509
+
+ /***********************************************************
+ Reset 3Com 509 card
+ *************************************************************/
+
+ if(eth_vendor != VENDOR_3C509)
+ goto no3c509;
+
+ /* stop card */
+ outw(BASE + EP_COMMAND, RX_DISABLE);
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+ outw(BASE + EP_COMMAND, TX_DISABLE);
+ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK);
+ outw(BASE + EP_COMMAND, SET_INTR_MASK);
+ outw(BASE + EP_COMMAND, SET_RX_FILTER);
+
+ /*
+ /* initialize card
+ */
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+
+ GO_WINDOW(0);
+
+ /* Disable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, 0);
+
+ /* Configure IRQ to none */
+ outw(BASE + EP_W0_RESOURCE_CFG, SET_IRQ(0));
+
+ /* Enable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
+
+ GO_WINDOW(2);
+
+ /* Reload the ether_addr. */
+ for (i = 0; i < 6; i++)
+ outb(BASE + EP_W2_ADDR_0 + i, arptable[ARP_CLIENT].node[i]);
+
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+
+ /* Window 1 is operating window */
+ GO_WINDOW(1);
+ for (i = 0; i < 31; i++)
+ inb(BASE + EP_W1_TX_STATUS);
+
+ /* get rid of stray intr's */
+ outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
+
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS);
+
+ outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
+
+ outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
+ FIL_BRDCST);
+
+ /* configure BNC */
+ if(bnc) {
+ outw(BASE + EP_COMMAND, START_TRANSCEIVER);
+ DELAY(1000);
+ }
+ /* configure UTP */
+ if(utp) {
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
+ GO_WINDOW(1);
+ }
+
+ /* start tranciever and receiver */
+ outw(BASE + EP_COMMAND, RX_ENABLE);
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+
+ /* set early threshold for minimal packet length */
+ outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | 64);
+
+ outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16);
+
+ return 1;
+no3c509:
+
+#endif
+
+#if defined(INCLUDE_3COM) || defined(INCLUDE_WD) || defined(INCLUDE_NE)
+
+ /**************************************************************
+ Reset cards based on 8390 chip
+ ****************************************************************/
+
+ if(eth_vendor!=VENDOR_WD && eth_vendor!=VENDOR_NOVELL
+ && eth_vendor!=VENDOR_3COM)
+ goto no8390;
+
if (eth_flags & FLAG_790)
outb(eth_nic_base+D8390_P0_COMMAND,
- D8390_COMMAND_PS0 | D8390_COMMAND_STP);
+ D8390_COMMAND_PS0 | D8390_COMMAND_STP);
else
outb(eth_nic_base+D8390_P0_COMMAND,
- D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
- D8390_COMMAND_STP);
+ D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STP);
if (eth_flags & FLAG_16BIT)
outb(eth_nic_base+D8390_P0_DCR, 0x49);
else
@@ -339,10 +640,10 @@ eth_reset()
outb(eth_nic_base+D8390_P0_IMR, 0);
if (eth_flags & FLAG_790)
outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 |
- D8390_COMMAND_STP);
+ D8390_COMMAND_STP);
else
outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 |
- D8390_COMMAND_RD2 | D8390_COMMAND_STP);
+ D8390_COMMAND_RD2 | D8390_COMMAND_STP);
for (i=0; i<6; i++)
outb(eth_nic_base+D8390_P1_PAR0+i, eth_node_addr[i]);
for (i=0; i<6; i++)
@@ -350,49 +651,122 @@ eth_reset()
outb(eth_nic_base+D8390_P1_CURR, eth_tx_start + D8390_TXBUF_SIZE+1);
if (eth_flags & FLAG_790)
outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
- D8390_COMMAND_STA);
+ D8390_COMMAND_STA);
else
outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
- D8390_COMMAND_RD2 | D8390_COMMAND_STA);
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA);
outb(eth_nic_base+D8390_P0_ISR, 0xFF);
outb(eth_nic_base+D8390_P0_TCR, 0);
#ifdef INCLUDE_3COM
- if (eth_vendor == VENDOR_3COM) {
- /*
- * No way to tell whether or not we're supposed to use
- * the 3Com's transceiver unless the user tells us.
- * 'aui' should have some compile time default value
- * which can be changed from the command menu.
- */
- if (aui)
- outb(eth_asic_base + _3COM_CR, 0);
- else
- outb(eth_asic_base + _3COM_CR, _3COM_CR_XSEL);
- }
+ if (eth_vendor == VENDOR_3COM) {
+ /*
+ * No way to tell whether or not we're supposed to use
+ * the 3Com's transceiver unless the user tells us.
+ * 'aui' should have some compile time default value
+ * which can be changed from the command menu.
+ */
+ if (aui)
+ outb(eth_asic_base + _3COM_CR, 0);
+ else
+ outb(eth_asic_base + _3COM_CR, _3COM_CR_XSEL);
+ }
#endif
return(1);
+no8390:
+#endif /* 8390 */
}
/**************************************************************************
ETH_TRANSMIT - Transmit a frame
-**************************************************************************/
+***************************************************************************/
+static const char padmap[] = {
+ 0, 3, 2, 1};
+
eth_transmit(d,t,s,p)
- char *d; /* Destination */
- unsigned short t; /* Type */
- unsigned short s; /* size */
- char *p; /* Packet */
+char *d; /* Destination */
+unsigned short t; /* Type */
+unsigned short s; /* size */
+char *p; /* Packet */
{
+ register u_int len;
+ int pad;
+ int status;
unsigned char c;
+
+#ifdef INCLUDE_3C509
+
+ if(eth_vendor != VENDOR_3C509)
+ goto no3c509;
+
+#ifdef EDEBUG
+ printf("{l=%d,t=%x}",s+14,t);
+#endif
+
+ /* swap bytes of type */
+ t=(( t&0xFF )<<8) | ((t>>8) & 0xFF);
+
+ len=s+14; /* actual length of packet */
+ pad = padmap[len & 3];
+
+ /*
+ * The 3c509 automatically pads short packets to minimum ethernet length,
+ * but we drop packets that are too large. Perhaps we should truncate
+ * them instead?
+ */
+ if (len + pad > ETHER_MAX_LEN) {
+ return 0;
+ }
+
+ /* drop acknowledgements */
+ while(( status=inb(BASE + EP_W1_TX_STATUS) )& TXS_COMPLETE ) {
+ if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
+ outw(BASE + EP_COMMAND, TX_RESET);
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+ }
+
+ outb(BASE + EP_W1_TX_STATUS, 0x0);
+ }
+
+ while (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
+ /* no room in FIFO */
+ }
+
+ outw(BASE + EP_W1_TX_PIO_WR_1, len);
+ outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */
+
+ /* write packet */
+ outsw(BASE + EP_W1_TX_PIO_WR_1, d, 3);
+ outsw(BASE + EP_W1_TX_PIO_WR_1, eth_node_addr, 3);
+ outw(BASE + EP_W1_TX_PIO_WR_1, t);
+ outsw(BASE + EP_W1_TX_PIO_WR_1, p, s / 2);
+ if (s & 1)
+ outb(BASE + EP_W1_TX_PIO_WR_1, *(p+s - 1));
+
+ while (pad--)
+ outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
+
+ /* timeout after sending */
+ DELAY(1000);
+ return 0;
+no3c509:
+#endif /* 3C509 */
+
+#if defined(INCLUDE_3COM) || defined(INCLUDE_WD) || defined(INCLUDE_NE)
+
+ if(eth_vendor!=VENDOR_WD && eth_vendor!=VENDOR_NOVELL
+ && eth_vendor!=VENDOR_3COM)
+ goto no8390;
+
#ifdef INCLUDE_3COM
- if (eth_vendor == VENDOR_3COM) {
- bcopy(d, eth_bmem, 6); /* dst */
- bcopy(eth_node_addr, eth_bmem+6, ETHER_ADDR_SIZE); /* src */
- *(eth_bmem+12) = t>>8; /* type */
- *(eth_bmem+13) = t;
- bcopy(p, eth_bmem+14, s);
- s += 14;
- while (s < ETH_MIN_PACKET) *(eth_bmem+(s++)) = 0;
- }
+ if (eth_vendor == VENDOR_3COM) {
+ bcopy(d, eth_bmem, 6); /* dst */
+ bcopy(eth_node_addr, eth_bmem+6, ETHER_ADDR_SIZE); /* src */
+ *(eth_bmem+12) = t>>8; /* type */
+ *(eth_bmem+13) = t;
+ bcopy(p, eth_bmem+14, s);
+ s += 14;
+ while (s < ETH_MIN_PACKET) *(eth_bmem+(s++)) = 0;
+ }
#endif
#ifdef INCLUDE_WD
if (eth_vendor == VENDOR_WD) { /* Memory interface */
@@ -437,35 +811,178 @@ eth_transmit(d,t,s,p)
twiddle();
if (eth_flags & FLAG_790)
outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
- D8390_COMMAND_STA);
+ D8390_COMMAND_STA);
else
outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
- D8390_COMMAND_RD2 | D8390_COMMAND_STA);
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA);
outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start);
outb(eth_nic_base+D8390_P0_TBCR0, s);
outb(eth_nic_base+D8390_P0_TBCR1, s>>8);
if (eth_flags & FLAG_790)
outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
- D8390_COMMAND_TXP | D8390_COMMAND_STA);
+ D8390_COMMAND_TXP | D8390_COMMAND_STA);
else
outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 |
- D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
- D8390_COMMAND_STA);
+ D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STA);
return(0);
+
+no8390:
+#endif /* 8390 */
}
/**************************************************************************
ETH_POLL - Wait for a frame
-**************************************************************************/
+***************************************************************************/
eth_poll()
{
- int ret = 0;
+ /* common variables */
unsigned short type = 0;
- unsigned char bound,curr,rstat;
unsigned short len;
+ /* variables for 3C509 */
+#ifdef INCLUDE_3C509
+ struct ether_header *eh;
+ int lenthisone;
+ short rx_fifo2, status, cst;
+ register short rx_fifo;
+#endif
+ /* variables for 8390 */
+#if defined(INCLUDE_3COM) || defined(INCLUDE_WD) || defined(INCLUDE_NE)
+ int ret = 0;
+ unsigned char bound,curr,rstat;
unsigned short pktoff;
unsigned char *p;
struct ringbuffer pkthdr;
+#endif
+
+#ifdef INCLUDE_3C509
+
+ if(eth_vendor!=VENDOR_3C509)
+ goto no3c509;
+
+ cst=inw(BASE + EP_STATUS);
+
+#ifdef EDEBUG
+ if(cst & 0x1FFF)
+ printf("-%x-",cst);
+#endif
+
+ if( (cst & (S_RX_COMPLETE|S_RX_EARLY) )==0 ) {
+ /* acknowledge everything */
+ outw(BASE + EP_COMMAND, ACK_INTR| (cst & S_5_INTS));
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+
+ return 0;
+ }
+
+ status = inw(BASE + EP_W1_RX_STATUS);
+#ifdef EDEBUG
+ printf("*%x*",status);
+#endif
+
+ if (status & ERR_RX) {
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ return 0;
+ }
+
+ rx_fifo = status & RX_BYTES_MASK;
+ if (rx_fifo==0)
+ return 0;
+
+ /* read packet */
+#ifdef EDEBUG
+ printf("[l=%d",rx_fifo);
+#endif
+ insw(BASE + EP_W1_RX_PIO_RD_1, packet, rx_fifo / 2);
+ if(rx_fifo & 1)
+ packet[rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1);
+ packetlen=rx_fifo;
+
+ while(1) {
+ status = inw(BASE + EP_W1_RX_STATUS);
+#ifdef EDEBUG
+ printf("*%x*",status);
+#endif
+ rx_fifo = status & RX_BYTES_MASK;
+
+ if(rx_fifo>0) {
+ insw(BASE + EP_W1_RX_PIO_RD_1, packet+packetlen, rx_fifo / 2);
+ if(rx_fifo & 1)
+ packet[packetlen+rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1);
+ packetlen+=rx_fifo;
+#ifdef EDEBUG
+ printf("+%d",rx_fifo);
+#endif
+ }
+
+ if(( status & RX_INCOMPLETE )==0) {
+#ifdef EDEBUG
+ printf("=%d",packetlen);
+#endif
+ break;
+ }
+
+ DELAY(1000);
+ }
+
+ /* acknowledge reception of packet */
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
+
+ type = (packet[12]<<8) | packet[13];
+
+#ifdef EDEBUG
+ if(packet[0]+packet[1]+packet[2]+packet[3]+packet[4]+
+ packet[5] == 0xFF*6)
+ printf(",t=0x%x,b]",type);
+ else
+ printf(",t=0x%x]",type);
+#endif
+
+
+ if (type == ARP) {
+ struct arprequest *arpreq;
+ unsigned long reqip;
+
+ arpreq = (struct arprequest *)&packet[ETHER_HDR_SIZE];
+
+#ifdef EDEBUG
+ printf("(ARP %I->%I)",ntohl(*(int*)arpreq->sipaddr),
+ ntohl(*(int*)arpreq->tipaddr));
+#endif
+
+ convert_ipaddr(&reqip, arpreq->tipaddr);
+ if ((ntohs(arpreq->opcode) == ARP_REQUEST) &&
+ (reqip == arptable[ARP_CLIENT].ipaddr)) {
+ arpreq->opcode = htons(ARP_REPLY);
+ bcopy(arpreq->sipaddr, arpreq->tipaddr, 4);
+ bcopy(arpreq->shwaddr, arpreq->thwaddr, 6);
+ bcopy(arptable[ARP_CLIENT].node, arpreq->shwaddr, 6);
+ convert_ipaddr(arpreq->sipaddr, &reqip);
+ eth_transmit(arpreq->thwaddr, ARP, sizeof(struct arprequest),
+ arpreq);
+ return(0);
+ }
+ } else if(type==IP) {
+ struct iphdr *iph;
+
+ iph = (struct iphdr *)&packet[ETHER_HDR_SIZE];
+#ifdef EDEBUG
+ printf("(IP %I-%d->%I)",ntohl(*(int*)iph->src),
+ ntohs(iph->protocol),ntohl(*(int*)iph->dest));
+#endif
+ }
+
+ return 1;
+
+no3c509:
+#endif /* 3C509 */
+#if defined(INCLUDE_3COM) || defined(INCLUDE_WD) || defined(INCLUDE_NE)
+
+ if(eth_vendor!=VENDOR_WD && eth_vendor!=VENDOR_NOVELL
+ && eth_vendor!=VENDOR_3COM)
+ goto no8390;
+
rstat = inb(eth_nic_base+D8390_P0_RSR);
if (rstat & D8390_RSTAT_OVER) {
eth_reset();
@@ -527,7 +1044,7 @@ eth_poll()
}
if (eth_flags & FLAG_16BIT) {
outb(eth_asic_base + WD_LAAR, eth_laar &
- ~WD_LAAR_M16EN);
+ ~WD_LAAR_M16EN);
inb(0x84);
}
inb(0x84);
@@ -541,54 +1058,47 @@ eth_poll()
arpreq = (struct arprequest *)&packet[ETHER_HDR_SIZE];
convert_ipaddr(&reqip, arpreq->tipaddr);
if ((ntohs(arpreq->opcode) == ARP_REQUEST) &&
- (reqip == arptable[ARP_CLIENT].ipaddr)) {
- arpreq->opcode = htons(ARP_REPLY);
- bcopy(arpreq->sipaddr, arpreq->tipaddr, 4);
- bcopy(arpreq->shwaddr, arpreq->thwaddr, 6);
- bcopy(arptable[ARP_CLIENT].node, arpreq->shwaddr, 6);
- convert_ipaddr(arpreq->sipaddr, &reqip);
- eth_transmit(arpreq->thwaddr, ARP, sizeof(struct arprequest),
- arpreq);
- return(0);
+ (reqip == arptable[ARP_CLIENT].ipaddr)) {
+ arpreq->opcode = htons(ARP_REPLY);
+ bcopy(arpreq->sipaddr, arpreq->tipaddr, 4);
+ bcopy(arpreq->shwaddr, arpreq->thwaddr, 6);
+ bcopy(arptable[ARP_CLIENT].node, arpreq->shwaddr, 6);
+ convert_ipaddr(arpreq->sipaddr, &reqip);
+ eth_transmit(arpreq->thwaddr, ARP, sizeof(struct arprequest),
+ arpreq);
+ return(0);
}
}
return(ret);
+no8390:
+#endif /* 8390 */
}
#ifdef INCLUDE_NE
/**************************************************************************
NE1000/NE2000 Support Routines
-**************************************************************************/
-static inline unsigned short inw(unsigned short a)
-{
- unsigned short d;
- asm volatile( "inw %1, %0" : "=a" (d) : "d" (a));
- return d;
-}
+***************************************************************************/
-static inline void outw(unsigned short a, unsigned short d)
-{
- asm volatile( "outw %0, %1" : : "a" (d), "d" (a));
-}
+/* inw and outw are not needed more - standard version of them is used */
/**************************************************************************
ETH_PIO_READ - Read a frame via Programmed I/O
-**************************************************************************/
+***************************************************************************/
eth_pio_read(src, dst, cnt, init)
- unsigned short src;
- unsigned char *dst;
- unsigned short cnt;
- int init;
+unsigned short src;
+unsigned char *dst;
+unsigned short cnt;
+int init;
{
if (cnt & 1) cnt++;
outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 |
- D8390_COMMAND_STA);
+ D8390_COMMAND_STA);
outb(eth_nic_base + D8390_P0_RBCR0, cnt);
outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8);
outb(eth_nic_base + D8390_P0_RSAR0, src);
outb(eth_nic_base + D8390_P0_RSAR1, src>>8);
outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD0 |
- D8390_COMMAND_STA);
+ D8390_COMMAND_STA);
if (eth_flags & FLAG_16BIT) {
while (cnt) {
*((unsigned short *)dst) = inw(eth_asic_base + NE_DATA);
@@ -604,22 +1114,22 @@ eth_pio_read(src, dst, cnt, init)
/**************************************************************************
ETH_PIO_WRITE - Write a frame via Programmed I/O
-**************************************************************************/
+***************************************************************************/
eth_pio_write(src, dst, cnt, init)
- unsigned char *src;
- unsigned short dst;
- unsigned short cnt;
- int init;
+unsigned char *src;
+unsigned short dst;
+unsigned short cnt;
+int init;
{
outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 |
- D8390_COMMAND_STA);
+ D8390_COMMAND_STA);
outb(eth_nic_base + D8390_P0_ISR, D8390_ISR_RDC);
outb(eth_nic_base + D8390_P0_RBCR0, cnt);
outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8);
outb(eth_nic_base + D8390_P0_RSAR0, dst);
outb(eth_nic_base + D8390_P0_RSAR1, dst>>8);
outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD1 |
- D8390_COMMAND_STA);
+ D8390_COMMAND_STA);
if (eth_flags & FLAG_16BIT) {
if (cnt & 1) cnt++; /* Round up */
while (cnt) {
@@ -633,11 +1143,101 @@ eth_pio_write(src, dst, cnt, init)
outb(eth_asic_base + NE_DATA, *(src++));
}
while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
- != D8390_ISR_RDC);
+ != D8390_ISR_RDC);
}
#else
/**************************************************************************
ETH_PIO_READ - Dummy routine when NE2000 not compiled in
+***************************************************************************/
+eth_pio_read() {
+}
+#endif
+
+#ifdef INCLUDE_3C509
+/*************************************************************************
+ 3Com 509 - specific routines
**************************************************************************/
-eth_pio_read() {}
+
+static int
+eeprom_rdy()
+{
+ int i;
+
+ for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++);
+ if (i >= MAX_EEPROMBUSY) {
+ printf("3c509: eeprom failed to come ready.\r\n");
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * get_e: gets a 16 bits word from the EEPROM. we must have set the window
+ * before
+ */
+static int
+get_e(offset)
+int offset;
+{
+ if (!eeprom_rdy())
+ return (0xffff);
+ outw(IS_BASE + EP_W0_EEPROM_COMMAND, EEPROM_CMD_RD | offset);
+ if (!eeprom_rdy())
+ return (0xffff);
+ return (inw(IS_BASE + EP_W0_EEPROM_DATA));
+}
+
+static int
+send_ID_sequence(port)
+int port;
+{
+ int cx, al;
+
+ for (al = 0xff, cx = 0; cx < 255; cx++) {
+ outb(port, al);
+ al <<= 1;
+ if (al & 0x100)
+ al ^= 0xcf;
+ }
+ return (1);
+}
+
+
+/*
+ * We get eeprom data from the id_port given an offset into the eeprom.
+ * Basically; after the ID_sequence is sent to all of the cards; they enter
+ * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
+ * the eeprom data. We then read the port 16 times and with every read; the
+ * cards check for contention (ie: if one card writes a 0 bit and another
+ * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
+ * compares the data on the bus; if there is a difference then that card goes
+ * into ID_WAIT state again). In the meantime; one bit of data is returned in
+ * the AX register which is conveniently returned to us by inb(). Hence; we
+ * read 16 times getting one bit of data with each read.
+ */
+static int
+get_eeprom_data(id_port, offset)
+int id_port;
+int offset;
+{
+ int i, data = 0;
+ outb(id_port, 0x80 + offset);
+ DELAY(1000);
+ for (i = 0; i < 16; i++)
+ data = (data << 1) | (inw(id_port) & 1);
+ return (data);
+}
+
+/* a surrogate */
+
+DELAY(val)
+{
+ int c;
+
+ for(c=0; c<val; c+=20) {
+ twiddle();
+ }
+}
+
#endif
+
diff --git a/sys/i386/boot/netboot/ether.h b/sys/i386/boot/netboot/ether.h
index 70a9378..8cd4df4 100644
--- a/sys/i386/boot/netboot/ether.h
+++ b/sys/i386/boot/netboot/ether.h
@@ -16,6 +16,7 @@ Author: Martin Renters
#define VENDOR_WD 1
#define VENDOR_NOVELL 2
#define VENDOR_3COM 3
+#define VENDOR_3C509 4
#define FLAG_PIO 0x01
#define FLAG_16BIT 0x02
diff --git a/sys/i386/boot/netboot/if_epreg.h b/sys/i386/boot/netboot/if_epreg.h
new file mode 100644
index 0000000..049f235
--- /dev/null
+++ b/sys/i386/boot/netboot/if_epreg.h
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2. The name
+ * of the author may not be used to endorse or promote products derived from
+ * this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * if_epreg.h,v 1.4 1994/11/13 10:12:37 gibbs Exp Modified by:
+ *
+ October 2, 1994
+
+ Modified by: Andres Vega Garcia
+
+ INRIA - Sophia Antipolis, France
+ e-mail: avega@sophia.inria.fr
+ finger: avega@pax.inria.fr
+
+ */
+
+/*
+ * Ethernet software status per interface.
+ */
+/*
+ * Some global constants
+ */
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+#define TX_INIT_RATE 16
+#define TX_INIT_MAX_RATE 64
+#define RX_INIT_LATENCY 64
+#define RX_INIT_EARLY_THRESH 64
+#define MIN_RX_EARLY_THRESHF 16 /* not less than ether_header */
+#define MIN_RX_EARLY_THRESHL 4
+
+#define EEPROMSIZE 0x40
+#define MAX_EEPROMBUSY 1000
+#define EP_LAST_TAG 0xd7
+#define EP_MAX_BOARDS 16
+#define EP_ID_PORT 0x100
+
+/*
+ * some macros to acces long named fields
+ */
+#define IS_BASE (eth_base)
+#define BASE (eth_base)
+
+/*
+ * Commands to read/write EEPROM trough EEPROM command register (Window 0,
+ * Offset 0xa)
+ */
+#define EEPROM_CMD_RD 0x0080 /* Read: Address required (5 bits) */
+#define EEPROM_CMD_WR 0x0040 /* Write: Address required (5 bits) */
+#define EEPROM_CMD_ERASE 0x00c0 /* Erase: Address required (5 bits) */
+#define EEPROM_CMD_EWEN 0x0030 /* Erase/Write Enable: No data required */
+
+#define EEPROM_BUSY (1<<15)
+#define EEPROM_TST_MODE (1<<14)
+
+/*
+ * Some short functions, worth to let them be a macro
+ */
+#define is_eeprom_busy(b) (inw((b)+EP_W0_EEPROM_COMMAND)&EEPROM_BUSY)
+#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|(x))
+
+/**************************************************************************
+ * *
+ * These define the EEPROM data structure. They are used in the probe
+ * function to verify the existance of the adapter after having sent
+ * the ID_Sequence.
+ *
+ * There are others but only the ones we use are defined here.
+ *
+ **************************************************************************/
+
+#define EEPROM_NODE_ADDR_0 0x0 /* Word */
+#define EEPROM_NODE_ADDR_1 0x1 /* Word */
+#define EEPROM_NODE_ADDR_2 0x2 /* Word */
+#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */
+#define EEPROM_MFG_ID 0x7 /* 0x6d50 */
+#define EEPROM_ADDR_CFG 0x8 /* Base addr */
+#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */
+
+/**************************************************************************
+ * *
+ * These are the registers for the 3Com 3c509 and their bit patterns when *
+ * applicable. They have been taken out the the "EtherLink III Parallel *
+ * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual *
+ * from 3com. *
+ * *
+ **************************************************************************/
+
+#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a
+ * command reg. */
+#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status
+ * reg. */
+#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window
+ * reg. */
+/*
+ * Window 0 registers. Setup.
+ */
+/* Write */
+#define EP_W0_EEPROM_DATA 0x0c
+#define EP_W0_EEPROM_COMMAND 0x0a
+#define EP_W0_RESOURCE_CFG 0x08
+#define EP_W0_ADDRESS_CFG 0x06
+#define EP_W0_CONFIG_CTRL 0x04
+/* Read */
+#define EP_W0_PRODUCT_ID 0x02
+#define EP_W0_MFG_ID 0x00
+
+/*
+ * Window 1 registers. Operating Set.
+ */
+/* Write */
+#define EP_W1_TX_PIO_WR_2 0x02
+#define EP_W1_TX_PIO_WR_1 0x00
+/* Read */
+#define EP_W1_FREE_TX 0x0c
+#define EP_W1_TX_STATUS 0x0b /* byte */
+#define EP_W1_TIMER 0x0a /* byte */
+#define EP_W1_RX_STATUS 0x08
+#define EP_W1_RX_PIO_RD_2 0x02
+#define EP_W1_RX_PIO_RD_1 0x00
+
+/*
+ * Window 2 registers. Station Address Setup/Read
+ */
+/* Read/Write */
+#define EP_W2_ADDR_5 0x05
+#define EP_W2_ADDR_4 0x04
+#define EP_W2_ADDR_3 0x03
+#define EP_W2_ADDR_2 0x02
+#define EP_W2_ADDR_1 0x01
+#define EP_W2_ADDR_0 0x00
+
+/*
+ * Window 3 registers. FIFO Management.
+ */
+/* Read */
+#define EP_W3_FREE_TX 0x0c
+#define EP_W3_FREE_RX 0x0a
+
+/*
+ * Window 4 registers. Diagnostics.
+ */
+/* Read/Write */
+#define EP_W4_MEDIA_TYPE 0x0a
+#define EP_W4_CTRLR_STATUS 0x08
+#define EP_W4_NET_DIAG 0x06
+#define EP_W4_FIFO_DIAG 0x04
+#define EP_W4_HOST_DIAG 0x02
+#define EP_W4_TX_DIAG 0x00
+
+/*
+ * Window 5 Registers. Results and Internal status.
+ */
+/* Read */
+#define EP_W5_READ_0_MASK 0x0c
+#define EP_W5_INTR_MASK 0x0a
+#define EP_W5_RX_FILTER 0x08
+#define EP_W5_RX_EARLY_THRESH 0x06
+#define EP_W5_TX_AVAIL_THRESH 0x02
+#define EP_W5_TX_START_THRESH 0x00
+
+/*
+ * Window 6 registers. Statistics.
+ */
+/* Read/Write */
+#define TX_TOTAL_OK 0x0c
+#define RX_TOTAL_OK 0x0a
+#define TX_DEFERRALS 0x08
+#define RX_FRAMES_OK 0x07
+#define TX_FRAMES_OK 0x06
+#define RX_OVERRUNS 0x05
+#define TX_COLLISIONS 0x04
+#define TX_AFTER_1_COLLISION 0x03
+#define TX_AFTER_X_COLLISIONS 0x02
+#define TX_NO_SQE 0x01
+#define TX_CD_LOST 0x00
+
+/****************************************
+ *
+ * Register definitions.
+ *
+ ****************************************/
+
+/*
+ * Command register. All windows.
+ *
+ * 16 bit register.
+ * 15-11: 5-bit code for command to be executed.
+ * 10-0: 11-bit arg if any. For commands with no args;
+ * this can be set to anything.
+ */
+#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms
+ * after issuing */
+#define WINDOW_SELECT (u_short) (0x1<<11)
+#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to
+ * determine whether
+ * this is needed. If
+ * so; wait 800 uSec
+ * before using trans-
+ * ceiver. */
+#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on
+ * power-up */
+#define RX_ENABLE (u_short) (0x4<<11)
+#define RX_RESET (u_short) (0x5<<11)
+#define RX_DISCARD_TOP_PACK (u_short) (0x8<<11)
+#define TX_ENABLE (u_short) (0x9<<11)
+#define TX_DISABLE (u_short) (0xa<<11)
+#define TX_RESET (u_short) (0xb<<11)
+#define REQ_INTR (u_short) (0xc<<11)
+#define SET_INTR_MASK (u_short) (0xe<<11)
+#define SET_RD_0_MASK (u_short) (0xf<<11)
+#define SET_RX_FILTER (u_short) (0x10<<11)
+#define FIL_INDIVIDUAL (u_short) (0x1)
+#define FIL_GROUP (u_short) (0x2)
+#define FIL_BRDCST (u_short) (0x4)
+#define FIL_ALL (u_short) (0x8)
+#define SET_RX_EARLY_THRESH (u_short) (0x11<<11)
+#define SET_TX_AVAIL_THRESH (u_short) (0x12<<11)
+#define SET_TX_START_THRESH (u_short) (0x13<<11)
+#define STATS_ENABLE (u_short) (0x15<<11)
+#define STATS_DISABLE (u_short) (0x16<<11)
+#define STOP_TRANSCEIVER (u_short) (0x17<<11)
+/*
+ * The following C_* acknowledge the various interrupts. Some of them don't
+ * do anything. See the manual.
+ */
+#define ACK_INTR (u_short) (0x6800)
+#define C_INTR_LATCH (u_short) (ACK_INTR|0x1)
+#define C_CARD_FAILURE (u_short) (ACK_INTR|0x2)
+#define C_TX_COMPLETE (u_short) (ACK_INTR|0x4)
+#define C_TX_AVAIL (u_short) (ACK_INTR|0x8)
+#define C_RX_COMPLETE (u_short) (ACK_INTR|0x10)
+#define C_RX_EARLY (u_short) (ACK_INTR|0x20)
+#define C_INT_RQD (u_short) (ACK_INTR|0x40)
+#define C_UPD_STATS (u_short) (ACK_INTR|0x80)
+
+/*
+ * Status register. All windows.
+ *
+ * 15-13: Window number(0-7).
+ * 12: Command_in_progress.
+ * 11: reserved.
+ * 10: reserved.
+ * 9: reserved.
+ * 8: reserved.
+ * 7: Update Statistics.
+ * 6: Interrupt Requested.
+ * 5: RX Early.
+ * 4: RX Complete.
+ * 3: TX Available.
+ * 2: TX Complete.
+ * 1: Adapter Failure.
+ * 0: Interrupt Latch.
+ */
+#define S_INTR_LATCH (u_short) (0x1)
+#define S_CARD_FAILURE (u_short) (0x2)
+#define S_TX_COMPLETE (u_short) (0x4)
+#define S_TX_AVAIL (u_short) (0x8)
+#define S_RX_COMPLETE (u_short) (0x10)
+#define S_RX_EARLY (u_short) (0x20)
+#define S_INT_RQD (u_short) (0x40)
+#define S_UPD_STATS (u_short) (0x80)
+#define S_5_INTS (S_CARD_FAILURE|S_TX_COMPLETE|\
+ S_TX_AVAIL|S_RX_COMPLETE|S_RX_EARLY)
+#define S_COMMAND_IN_PROGRESS (u_short) (0x1000)
+
+/*
+ * FIFO Registers.
+ * RX Status. Window 1/Port 08
+ *
+ * 15: Incomplete or FIFO empty.
+ * 14: 1: Error in RX Packet 0: Incomplete or no error.
+ * 13-11: Type of error.
+ * 1000 = Overrun.
+ * 1011 = Run Packet Error.
+ * 1100 = Alignment Error.
+ * 1101 = CRC Error.
+ * 1001 = Oversize Packet Error (>1514 bytes)
+ * 0010 = Dribble Bits.
+ * (all other error codes, no errors.)
+ *
+ * 10-0: RX Bytes (0-1514)
+ */
+#define ERR_RX_INCOMPLETE (u_short) (0x1<<15)
+#define ERR_RX (u_short) (0x1<<14)
+#define ERR_RX_OVERRUN (u_short) (0x8<<11)
+#define ERR_RX_RUN_PKT (u_short) (0xb<<11)
+#define ERR_RX_ALIGN (u_short) (0xc<<11)
+#define ERR_RX_CRC (u_short) (0xd<<11)
+#define ERR_RX_OVERSIZE (u_short) (0x9<<11)
+#define ERR_RX_DRIBBLE (u_short) (0x2<<11)
+
+/*
+ * FIFO Registers.
+ * TX Status. Window 1/Port 0B
+ *
+ * Reports the transmit status of a completed transmission. Writing this
+ * register pops the transmit completion stack.
+ *
+ * Window 1/Port 0x0b.
+ *
+ * 7: Complete
+ * 6: Interrupt on successful transmission requested.
+ * 5: Jabber Error (TP Only, TX Reset required. )
+ * 4: Underrun (TX Reset required. )
+ * 3: Maximum Collisions.
+ * 2: TX Status Overflow.
+ * 1-0: Undefined.
+ *
+ */
+#define TXS_COMPLETE 0x80
+#define TXS_SUCCES_INTR_REQ 0x40
+#define TXS_JABBER 0x20
+#define TXS_UNDERRUN 0x10
+#define TXS_MAX_COLLISION 0x8
+#define TXS_STATUS_OVERFLOW 0x4
+
+/*
+ * Configuration control register.
+ * Window 0/Port 04
+ */
+/* Read */
+#define IS_AUI (1<<13)
+#define IS_BNC (1<<12)
+#define IS_UTP (1<<9)
+/* Write */
+#define ENABLE_DRQ_IRQ 0x0001
+#define W0_P4_CMD_RESET_ADAPTER 0x4
+#define W0_P4_CMD_ENABLE_ADAPTER 0x1
+/*
+ * Media type and status.
+ * Window 4/Port 0A
+ */
+#define ENABLE_UTP 0xc0
+#define DISABLE_UTP 0x0
+
+/*
+ * Resource control register
+ */
+
+#define SET_IRQ(i) ( ((i)<<12) | 0xF00) /* set IRQ i */
+
+/*
+ * Receive status register
+ */
+
+#define RX_BYTES_MASK (u_short) (0x07ff)
+#define RX_ERROR 0x4000
+#define RX_INCOMPLETE 0x8000
+
+
+/*
+ * Misc defines for various things.
+ */
+#define ACTIVATE_ADAPTER_TO_CONFIG 0xff /* to the id_port */
+#define MFG_ID 0x6d50 /* in EEPROM and W0 ADDR_CONFIG */
+#define PROD_ID 0x9150
+
+#define AUI 0x1
+#define BNC 0x2
+#define UTP 0x4
+
+#define ETHER_ADDR_LEN 6
+#define ETHER_MAX 1536
+#define RX_BYTES_MASK (u_short) (0x07ff)
+
+ /* EISA support */
+#define EP_EISA_START 0x1000
+#define EP_EISA_W0 0x0c80
diff --git a/sys/i386/boot/netboot/main.c b/sys/i386/boot/netboot/main.c
index 09b6a17..641ab18 100644
--- a/sys/i386/boot/netboot/main.c
+++ b/sys/i386/boot/netboot/main.c
@@ -6,6 +6,8 @@ Author: Martin Renters
**************************************************************************/
+/* #define MDEBUG */
+
#include "netboot.h"
int jmp_bootmenu[10];
@@ -112,6 +114,10 @@ load()
arptable[ARP_SERVER].ipaddr,
arptable[ARP_GATEWAY].ipaddr);
+#ifdef MDEBUG
+ printf("\n=>>"); getchar();
+#endif
+
/* Now use TFTP to load configuration file */
sprintf(cfg,"cfg.%I",arptable[ARP_CLIENT].ipaddr);
printf("Loading %s...\r\n",cfg);
@@ -123,7 +129,11 @@ load()
longjmp(jmp_bootmenu,1);
}
}
- /* Execute commands in config file */
+
+#ifdef MDEBUG
+ printf("\n=>>"); getchar();
+#endif
+
p = config_buffer;
while(*p) {
q = cmd_line;
@@ -134,6 +144,10 @@ load()
if (*p) p++;
}
+#ifdef MDEBUG
+ printf("\n=>>"); getchar();
+#endif
+
/* Check to make sure we've got a rootfs */
if (!arptable[ARP_ROOTSERVER].ipaddr) {
printf("No ROOT filesystem server!\r\n");
@@ -141,7 +155,10 @@ load()
}
/* Fill in nfsdiskless.myif */
- sprintf(&nfsdiskless.myif.ifra_name,"ed0");
+ /*
+ sprintf(&nfsdiskless.myif.ifra_name,"ep0");
+ */
+ eth_fillname(&nfsdiskless.myif.ifra_name);
nfsdiskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr);
nfsdiskless.myif.ifra_addr.sa_family = AF_INET;
addr = htonl(arptable[ARP_CLIENT].ipaddr);
diff --git a/sys/i386/boot/netboot/netboot.h b/sys/i386/boot/netboot/netboot.h
index cf264cd..7479258 100644
--- a/sys/i386/boot/netboot/netboot.h
+++ b/sys/i386/boot/netboot/netboot.h
@@ -217,6 +217,15 @@ struct rpc_t {
#define TFTP_MIN_PACKET_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr) + 4)
+/*
+static inline unsigned short inw(a)
+ unsigned short a;
+{
+ unsigned char d;
+ asm volatile( "inw %1, %0" : "=a" (d) : "d" (a));
+ return d;
+}
+
static inline unsigned char inb(a)
unsigned short a;
{
@@ -225,12 +234,171 @@ static inline unsigned char inb(a)
return d;
}
+static inline void outw(a,d)
+ unsigned short a;
+ unsigned short d;
+{
+ asm volatile( "outw %0, %1" : : "a" (d), "d" (a));
+}
+
static inline void outb(a,d)
unsigned short a;
unsigned char d;
{
asm volatile( "outb %0, %1" : : "a" (d), "d" (a));
}
+*/
+
+#if __GNUC__ < 2
+
+#define inb(port) inbv(port)
+#define outb(port, data) outbv(port, data)
+
+#else /* __GNUC >= 2 */
+
+/*
+ * Use an expression-statement instead of a conditional expression
+ * because gcc-2.6.0 would promote the operands of the conditional
+ * and produce poor code for "if ((inb(var) & const1) == const2)".
+ */
+#define inb(port) ({ \
+ u_char _data; \
+ if (__builtin_constant_p((int) (port)) && (port) < 256ul) \
+ _data = inbc(port); \
+ else \
+ _data = inbv(port); \
+ _data; })
+
+#define outb(port, data) \
+ (__builtin_constant_p((int) (port)) && (port) < 256ul \
+ ? outbc(port, data) : outbv(port, data))
+
+static __inline u_char
+inbc(u_int port)
+{
+ u_char data;
+
+ __asm __volatile("inb %1,%0" : "=a" (data) : "i" (port));
+ return (data);
+}
+
+static __inline void
+outbc(u_int port, u_char data)
+{
+ __asm __volatile("outb %0,%1" : : "a" (data), "i" (port));
+}
+
+#endif /* __GNUC <= 2 */
+
+static __inline u_char
+inbv(u_int port)
+{
+ u_char data;
+ /*
+ * We use %%dx and not %1 here because i/o is done at %dx and not at
+ * %edx, while gcc generates inferior code (movw instead of movl)
+ * if we tell it to load (u_short) port.
+ */
+ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
+ return (data);
+}
+
+static __inline u_long
+inl(u_int port)
+{
+ u_long data;
+
+ __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
+ return (data);
+}
+
+static __inline void
+insb(u_int port, void *addr, size_t cnt)
+{
+ __asm __volatile("cld; rep; insb"
+ : : "d" (port), "D" (addr), "c" (cnt)
+ : "di", "cx", "memory");
+}
+
+static __inline void
+insw(u_int port, void *addr, size_t cnt)
+{
+ __asm __volatile("cld; rep; insw"
+ : : "d" (port), "D" (addr), "c" (cnt)
+ : "di", "cx", "memory");
+}
+
+static __inline void
+insl(u_int port, void *addr, size_t cnt)
+{
+ __asm __volatile("cld; rep; insl"
+ : : "d" (port), "D" (addr), "c" (cnt)
+ : "di", "cx", "memory");
+}
+
+static __inline u_short
+inw(u_int port)
+{
+ u_short data;
+
+ __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
+ return (data);
+}
+
+static __inline void
+outbv(u_int port, u_char data)
+{
+ u_char al;
+ /*
+ * Use an unnecessary assignment to help gcc's register allocator.
+ * This make a large difference for gcc-1.40 and a tiny difference
+ * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for
+ * best results. gcc-2.6.0 can't handle this.
+ */
+ al = data;
+ __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
+}
+
+static __inline void
+outl(u_int port, u_long data)
+{
+ /*
+ * outl() and outw() aren't used much so we haven't looked at
+ * possible micro-optimizations such as the unnecessary
+ * assignment for them.
+ */
+ __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
+}
+
+static __inline void
+outsb(u_int port, void *addr, size_t cnt)
+{
+ __asm __volatile("cld; rep; outsb"
+ : : "d" (port), "S" (addr), "c" (cnt)
+ : "si", "cx");
+}
+
+static __inline void
+outsw(u_int port, void *addr, size_t cnt)
+{
+ __asm __volatile("cld; rep; outsw"
+ : : "d" (port), "S" (addr), "c" (cnt)
+ : "si", "cx");
+}
+
+static __inline void
+outsl(u_int port, void *addr, size_t cnt)
+{
+ __asm __volatile("cld; rep; outsl"
+ : : "d" (port), "S" (addr), "c" (cnt)
+ : "si", "cx");
+}
+
+static __inline void
+outw(u_int port, u_short data)
+{
+ __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
+}
/***************************************************************************
RPC Functions
OpenPOWER on IntegriCloud