From 74af7d44ef596cc7d90ea904cc5472cb30cbc7fd Mon Sep 17 00:00:00 2001 From: jkh Date: Fri, 31 Mar 1995 06:51:37 +0000 Subject: 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" --- sys/i386/boot/netboot/509.doc | 21 + sys/i386/boot/netboot/Makefile | 8 +- sys/i386/boot/netboot/ether.c | 1066 +++++++++++++++++++++++++++++--------- sys/i386/boot/netboot/ether.h | 1 + sys/i386/boot/netboot/if_epreg.h | 388 ++++++++++++++ sys/i386/boot/netboot/main.c | 21 +- sys/i386/boot/netboot/netboot.h | 168 ++++++ 7 files changed, 1435 insertions(+), 238 deletions(-) create mode 100644 sys/i386/boot/netboot/509.doc create mode 100644 sys/i386/boot/netboot/if_epreg.h (limited to 'sys/i386/boot/netboot') 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; c1514 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 -- cgit v1.1