Redo standalone driver for WD8013 / SMC Ultra boards.

(The old one was buggy.)
Frontend / backend splitup and most code taken from sys/dev/ic/dp8390.c
and sys/dev/isa/if_we.c.
This commit is contained in:
drochner 1998-02-16 11:21:59 +00:00
parent 642cbc64e2
commit b8cdacb8d5
4 changed files with 656 additions and 581 deletions

View File

@ -1,4 +1,4 @@
## $NetBSD: Makefile.inc,v 1.1.1.1 1997/03/14 02:40:33 perry Exp $
## $NetBSD: Makefile.inc,v 1.2 1998/02/16 11:21:59 drochner Exp $
SRCS += netif_small.c
.if (${USE_NETIF} == "3c509")
@ -8,7 +8,7 @@ SRCS += 3c509.c elink3.c
SRCS += 3c590.c elink3.c
.endif
.if (${USE_NETIF} == "wd80x3")
SRCS += wd80x3.c
SRCS += wd80x3.c dp8390.c
.endif
.if (${USE_NETIF} == "pcnet_pci")
SRCS += pcnet_pci.c am7990.c

View File

@ -0,0 +1,349 @@
/* $NetBSD: dp8390.c,v 1.1 1998/02/16 11:22:00 drochner Exp $ */
/*
* Polling driver for National Semiconductor DS8390/WD83C690 based
* ethernet adapters.
*
* Copyright (c) 1998 Matthias Drochner. All rights reserved.
*
* Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
*
* Copyright (C) 1993, David Greenman. 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 is
* the author responsible for the proper functioning of this software, nor does
* the author assume any responsibility for damages incurred with its use.
*/
#include <sys/types.h>
#include <machine/pio.h>
#include <lib/libsa/stand.h>
#include <libi386.h>
#include <dev/ic/dp8390reg.h>
#include "dp8390.h"
#include "etherdrv.h"
int dp8390_iobase, dp8390_membase, dp8390_memsize;
#if defined(SUPPORT_WD80X3) && defined(SUPPORT_SMC_ULTRA)
int dp8390_is790;
#endif
u_int8_t dp8390_cr_proto;
u_int8_t dp8390_dcr_reg;
#define WE_IOBASE dp8390_iobase
static u_short rec_page_start;
static u_short rec_page_stop;
static u_short next_packet;
extern u_char eth_myaddr[6];
#ifndef _STANDALONE
static caddr_t vmembase;
extern caddr_t mapmem __P((int, int));
extern void unmapmem __P((caddr_t, int));
extern int mapio __P((void));
static void bbcopy(src, dst, len)
caddr_t src, dst;
int len;
{
char *s = (char *)src, *d = (char *)dst;
while(len--)
*d++ = *s++;
}
#endif
static void dp8390_read __P((int, char *, u_short));
#define NIC_GET(reg) inb(WE_IOBASE + reg)
#define NIC_PUT(reg, val) outb(WE_IOBASE + reg, val)
static void
dp8390_init()
{
int i;
/*
* Initialize the NIC in the exact order outlined in the NS manual.
* This init procedure is "mandatory"...don't change what or when
* things happen.
*/
/* Set interface for page 0, remote DMA complete, stopped. */
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
if (dp8390_dcr_reg & ED_DCR_LS) {
NIC_PUT(ED_P0_DCR, dp8390_dcr_reg);
} else {
/*
* Set FIFO threshold to 8, No auto-init Remote DMA, byte
* order=80x86, byte-wide DMA xfers,
*/
NIC_PUT(ED_P0_DCR, ED_DCR_FT1 | ED_DCR_LS);
}
/* Clear remote byte count registers. */
NIC_PUT(ED_P0_RBCR0, 0);
NIC_PUT(ED_P0_RBCR1, 0);
/* Tell RCR to do nothing for now. */
NIC_PUT(ED_P0_RCR, ED_RCR_MON);
/* Place NIC in internal loopback mode. */
NIC_PUT(ED_P0_TCR, ED_TCR_LB0);
/* Set lower bits of byte addressable framing to 0. */
if (dp8390_is790)
NIC_PUT(0x09, 0);
/* Initialize receive buffer ring. */
NIC_PUT(ED_P0_BNRY, rec_page_start);
NIC_PUT(ED_P0_PSTART, rec_page_start);
NIC_PUT(ED_P0_PSTOP, rec_page_stop);
/*
* Clear all interrupts. A '1' in each bit position clears the
* corresponding flag.
*/
NIC_PUT(ED_P0_ISR, 0xff);
/*
* Disable all interrupts.
*/
NIC_PUT(ED_P0_IMR, 0);
/* Program command register for page 1. */
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STP);
/* Copy out our station address. */
for (i = 0; i < 6; ++i)
NIC_PUT(ED_P1_PAR0 + i, eth_myaddr[i]);
/*
* Set current page pointer to one page after the boundary pointer, as
* recommended in the National manual.
*/
next_packet = rec_page_start + 1;
NIC_PUT(ED_P1_CURR, next_packet);
/* Program command register for page 0. */
NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
/* directed and broadcast */
NIC_PUT(ED_P0_RCR, ED_RCR_AB);
/* Take interface out of loopback. */
NIC_PUT(ED_P0_TCR, 0);
/* Fire up the interface. */
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
}
int
dp8390_config()
{
#ifndef _STANDALONE
if (mapio()) {
printf("no IO access\n");
return(-1);
}
vmembase = mapmem(dp8390_membase, dp8390_memsize);
if (!vmembase) {
printf("no memory access\n");
return(-1);
}
#endif
rec_page_start = ED_TXBUF_SIZE;
rec_page_stop = dp8390_memsize >> ED_PAGE_SHIFT;
dp8390_init();
return(0);
}
void
dp8390_stop()
{
int n = 5000;
/* Stop everything on the interface, and select page 0 registers. */
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STP);
/*
* Wait for interface to enter stopped state, but limit # of checks to
* 'n' (about 5ms). It shouldn't even take 5us on modern DS8390's, but
* just in case it's an old one.
*/
while (((NIC_GET(ED_P0_ISR) & ED_ISR_RST) == 0) && --n);
#ifndef _STANDALONE
unmapmem(vmembase, dp8390_memsize);
#endif
}
int
EtherSend(pkt, len)
char *pkt;
int len;
{
#ifdef _STANDALONE
vpbcopy(pkt, dp8390_membase, len);
#else
bbcopy(pkt, vmembase, len);
#endif
/* Set TX buffer start page. */
NIC_PUT(ED_P0_TPSR, 0);
/* Set TX length. */
NIC_PUT(ED_P0_TBCR0, len < 60 ? 60 : len);
NIC_PUT(ED_P0_TBCR1, len >> 8);
/* Set page 0, remote DMA complete, transmit packet, and *start*. */
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_TXP | ED_CR_STA);
return(len);
}
static void
dp8390_read(buf, dest, len)
int buf;
char *dest;
u_short len;
{
u_short tmp_amount;
/* Does copy wrap to lower addr in ring buffer? */
if (buf + len > dp8390_membase + dp8390_memsize) {
tmp_amount = dp8390_membase + dp8390_memsize - buf;
/* Copy amount up to end of NIC memory. */
#ifdef _STANDALONE
pvbcopy(buf, dest, tmp_amount);
#else
bbcopy(vmembase + buf - dp8390_membase, dest, tmp_amount);
#endif
len -= tmp_amount;
buf = dp8390_membase + (rec_page_start << ED_PAGE_SHIFT);
dest += tmp_amount;
}
#ifdef _STANDALONE
pvbcopy(buf, dest, len);
#else
bbcopy(vmembase + buf - dp8390_membase, dest, len);
#endif
}
int
EtherReceive(pkt, maxlen)
char *pkt;
int maxlen;
{
struct dp8390_ring packet_hdr;
int packet_ptr;
u_short len;
u_char boundary, current;
#ifdef DP8390_OLDCHIPS
u_char nlen;
#endif
if (!(NIC_GET(ED_P0_RSR) & ED_RSR_PRX))
return(0); /* XXX error handling */
/* Set NIC to page 1 registers to get 'current' pointer. */
NIC_PUT(ED_P0_CR, dp8390_cr_proto | ED_CR_PAGE_1 | ED_CR_STA);
/*
* 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
* it points to where new data has been buffered. The 'CURR' (current)
* register points to the logical end of the ring-buffer - i.e. it
* points to where additional new data will be added. We loop here
* until the logical beginning equals the logical end (or in other
* words, until the ring-buffer is empty).
*/
current = NIC_GET(ED_P1_CURR);
/* Set NIC to page 0 registers to update boundary register. */
NIC_PUT(ED_P1_CR, dp8390_cr_proto | ED_CR_PAGE_0 | ED_CR_STA);
if (next_packet == current)
return(0);
/* Get pointer to this buffer's header structure. */
packet_ptr = dp8390_membase + (next_packet << ED_PAGE_SHIFT);
/*
* The byte count includes a 4 byte header that was added by
* the NIC.
*/
#ifdef _STANDALONE
pvbcopy(packet_ptr, &packet_hdr, 4);
#else
bbcopy(vmembase + packet_ptr - dp8390_membase, &packet_hdr, 4);
#endif
len = packet_hdr.count;
#ifdef DP8390_OLDCHIPS
/*
* Try do deal with old, buggy chips that sometimes duplicate
* the low byte of the length into the high byte. We do this
* by simply ignoring the high byte of the length and always
* recalculating it.
*
* NOTE: sc->next_packet is pointing at the current packet.
*/
if (packet_hdr.next_packet >= next_packet)
nlen = (packet_hdr.next_packet - next_packet);
else
nlen = ((packet_hdr.next_packet - rec_page_start) +
(rec_page_stop - next_packet));
--nlen;
if ((len & ED_PAGE_MASK) + sizeof(packet_hdr) > ED_PAGE_SIZE)
--nlen;
len = (len & ED_PAGE_MASK) | (nlen << ED_PAGE_SHIFT);
#ifdef DIAGNOSTIC
if (len != packet_hdr.count) {
printf("we: length does not match next packet pointer\n");
printf("we: len %04x nlen %04x start %02x "
"first %02x curr %02x next %02x stop %02x\n",
packet_hdr.count, len,
rec_page_start, next_packet, current,
packet_hdr.next_packet, rec_page_stop);
}
#endif
#endif
if (packet_hdr.next_packet < rec_page_start ||
packet_hdr.next_packet >= rec_page_stop)
panic("we: RAM corrupt");
len -= sizeof(struct dp8390_ring);
if (len < maxlen) {
/* Go get packet. */
dp8390_read(packet_ptr + sizeof(struct dp8390_ring),
pkt, len);
} else
len = 0;
/* Update next packet pointer. */
next_packet = packet_hdr.next_packet;
/*
* Update NIC boundary pointer - being careful to keep it one
* buffer behind (as recommended by NS databook).
*/
boundary = next_packet - 1;
if (boundary < rec_page_start)
boundary = rec_page_stop - 1;
NIC_PUT(ED_P0_BNRY, boundary);
return(len);
}

View File

@ -1,166 +1,19 @@
/* $NetBSD: dp8390.h,v 1.1.1.1 1997/03/14 02:40:33 perry Exp $ */
extern int dp8390_config __P((void));
extern void dp8390_stop __P((void));
/*
* source in this file came from
* the Mach ethernet boot written by Leendert van Doorn.
*
* National Semiconductor DP8390 Network Interface Controller
*/
/* page 0: for reading */
#define DP_CR 0x00 /* read side of command register */
#define DP_CLDA0 0x01 /* current local DMA address 0 */
#define DP_CLDA1 0x02 /* current local DMA address 1 */
#define DP_BNRY 0x03 /* boundary pointer */
#define DP_TSR 0x04 /* transmit status register */
#define DP_NCR 0x05 /* number of collisions register */
#define DP_FIFO 0x06 /* FIFO */
#define DP_ISR 0x07 /* interrupt status register */
#define DP_CRDA0 0x08 /* current remote DMA address 0 */
#define DP_CRDA1 0x09 /* current remote DMA address 1 */
#define DP_RSR 0x0C /* receive status register */
#define DP_CNTR0 0x0D /* tally counter 0 */
#define DP_CNTR1 0x0E /* tally counter 1 */
#define DP_CNTR2 0x0F /* tally counter 2 */
/* page 0: for writing */
#define DP_CR 0x00 /* write side of command register */
#define DP_PSTART 0x01 /* page start register */
#define DP_PSTOP 0x02 /* page stop register */
#define DP_BNRY 0x03 /* boundary pointer */
#define DP_TPSR 0x04 /* transmit page start register */
#define DP_TBCR0 0x05 /* transmit byte count register 0 */
#define DP_TBCR1 0x06 /* transmit byte count register 1 */
#define DP_ISR 0x07 /* interrupt status register */
#define DP_RSAR0 0x08 /* remote start address register 0 */
#define DP_RSAR1 0x09 /* remote start address register 1 */
#define DP_RBCR0 0x0A /* remote byte count register 0 */
#define DP_RBCR1 0x0B /* remote byte count register 1 */
#define DP_RCR 0x0C /* receive configuration register */
#define DP_TCR 0x0D /* transmit configuration register */
#define DP_DCR 0x0E /* data configuration register */
#define DP_IMR 0x0F /* interrupt mask register */
/* page 1: read/write */
#define DP_CR 0x00 /* command register */
#define DP_PAR0 0x01 /* physical address register 0 */
#define DP_PAR1 0x02 /* physical address register 1 */
#define DP_PAR2 0x03 /* physical address register 2 */
#define DP_PAR3 0x04 /* physical address register 3 */
#define DP_PAR4 0x05 /* physical address register 4 */
#define DP_PAR5 0x06 /* physical address register 5 */
#define DP_CURR 0x07 /* current page register */
#define DP_MAR0 0x08 /* multicast address register 0 */
#define DP_MAR1 0x09 /* multicast address register 1 */
#define DP_MAR2 0x0A /* multicast address register 2 */
#define DP_MAR3 0x0B /* multicast address register 3 */
#define DP_MAR4 0x0C /* multicast address register 4 */
#define DP_MAR5 0x0D /* multicast address register 5 */
#define DP_MAR6 0x0E /* multicast address register 6 */
#define DP_MAR7 0x0F /* multicast address register 7 */
/* bits in command register */
#define CR_STP 0x01 /* stop: software reset */
#define CR_STA 0x02 /* start: activate NIC */
#define CR_TXP 0x04 /* transmit packet */
#define CR_DMA 0x38 /* mask for DMA control */
# define CR_DM_NOP 0x00 /* DMA: no operation */
# define CR_DM_RR 0x08 /* DMA: remote read */
# define CR_DM_RW 0x10 /* DMA: remote write */
# define CR_DM_SP 0x18 /* DMA: send packet */
# define CR_DM_ABORT 0x20 /* DMA: abort remote DMA operation */
#define CR_PS 0xC0 /* mask for page select */
# define CR_PS_P0 0x00 /* register page 0 */
# define CR_PS_P1 0x40 /* register page 1 */
# define CR_PS_T0 0x80 /* test mode register map */
# define CR_SP_T1 0xC0 /* test mode register map */
/* bits in interrupt status register */
#define ISR_PRX 0x01 /* packet received with no errors */
#define ISR_PTX 0x02 /* packet transmitted with no errors */
#define ISR_RXE 0x04 /* receive error */
#define ISR_TXE 0x08 /* transmit error */
#define ISR_OVW 0x10 /* overwrite warning */
#define ISR_CNT 0x20 /* counter overflow */
#define ISR_RDC 0x40 /* remote DMA complete */
#define ISR_RST 0x80 /* reset status */
/* bits in interrupt mask register */
#define IMR_PRXE 0x01 /* packet received ienable */
#define IMR_PTXE 0x02 /* packet transmitted ienable */
#define IMR_RXEE 0x04 /* receive error ienable */
#define IMR_TXEE 0x08 /* transmit error ienable */
#define IMR_OVWE 0x10 /* overwrite warning ienable */
#define IMR_CNTE 0x20 /* counter overflow ienable */
#define IMR_RDCE 0x40 /* DMA complete ienable */
/* bits in data control register */
#define DCR_WTS 0x01 /* word transfer select */
# define DCR_BYTEWIDE 0x00 /* WTS: byte wide transfers */
# define DCR_WORDWIDE 0x01 /* WTS: word wide transfers */
#define DCR_BOS 0x02 /* byte order select */
# define DCR_LTLENDIAN 0x00 /* BOS: little endian */
# define DCR_BIGENDIAN 0x02 /* BOS: big endian */
#define DCR_LAS 0x04 /* long address select */
#define DCR_BMS 0x08 /* burst mode select */
#define DCR_AR 0x10 /* autoinitialize remote */
#define DCR_FTS 0x60 /* FIFO threshold select */
# define DCR_2BYTES 0x00 /* 2 bytes */
# define DCR_4BYTES 0x40 /* 4 bytes */
# define DCR_8BYTES 0x20 /* 8 bytes */
# define DCR_12BYTES 0x60 /* 12 bytes */
/* bits in transmit configuration register */
#define TCR_CRC 0x01 /* inhibit CRC */
#define TCR_ELC 0x06 /* encoded loopback control */
# define TCR_NORMAL 0x00 /* ELC: normal operation */
# define TCR_INTERNAL 0x02 /* ELC: internal loopback */
# define TCR_0EXTERNAL 0x04 /* ELC: external loopback LPBK=0 */
# define TCR_1EXTERNAL 0x06 /* ELC: external loopback LPBK=1 */
#define TCR_ATD 0x08 /* auto transmit */
#define TCR_OFST 0x10 /* collision offset enable (be nice) */
/* bits in transmit status register */
#define TSR_PTX 0x01 /* packet transmitted (without error)*/
#define TSR_DFR 0x02 /* transmit deferred */
#define TSR_COL 0x04 /* transmit collided */
#define TSR_ABT 0x08 /* transmit aborted */
#define TSR_CRS 0x10 /* carrier sense lost */
#define TSR_FU 0x20 /* fifo underrun */
#define TSR_CDH 0x40 /* CD heartbeat */
#define TSR_OWC 0x80 /* out of window collision */
/* bits in receive configuration register */
#define RCR_SEP 0x01 /* save errored packets */
#define RCR_AR 0x02 /* accept runt packets */
#define RCR_AB 0x04 /* accept broadcast */
#define RCR_AM 0x08 /* accept multicast */
#define RCR_PRO 0x10 /* physical promiscuous */
#define RCR_MON 0x20 /* monitor mode */
/* bits in receive status register */
#define RSR_PRX 0x01 /* packet received intact */
#define RSR_CRC 0x02 /* CRC error */
#define RSR_FAE 0x04 /* frame alignment error */
#define RSR_FO 0x08 /* FIFO overrun */
#define RSR_MPA 0x10 /* missed packet */
#define RSR_PHY 0x20 /* multicast address match !! */
#define RSR_DIS 0x40 /* receiver disabled */
/* dp8390 configuration information */
typedef struct {
u_short dc_reg; /* dp8390 base address */
u_long dc_mem; /* base memory */
u_char dc_tpsr; /* transmit start page */
u_char dc_pstart; /* receive start page */
u_char dc_pstop; /* receive end page */
} dpconf_t;
/* dp8390 receive header */
typedef struct {
u_char dh_status; /* copy of rsr */
u_char dh_next; /* pointer to next packet */
u_char dh_rbcl; /* receive byte count low */
u_char dh_rbch; /* receive byte count high */
} dphdr_t;
extern int dp8390_iobase;
extern int dp8390_membase;
extern int dp8390_memsize;
#ifdef SUPPORT_WD80X3
#ifdef SUPPORT_SMC_ULTRA
extern int dp8390_is790;
#else
#define dp8390_is790 0
#endif
#else
#ifdef SUPPORT_SMC_ULTRA
#define dp8390_is790 1
#endif
#endif
extern u_int8_t dp8390_cr_proto; /* values always set in CR */
extern u_int8_t dp8390_dcr_reg; /* override DCR if LS is set */

View File

@ -1,266 +1,322 @@
/* $NetBSD: wd80x3.c,v 1.4 1997/09/20 12:13:06 drochner Exp $ */
/* $NetBSD: wd80x3.c,v 1.5 1998/02/16 11:22:00 drochner Exp $ */
/* stripped down from netbsd:sys/arch/i386/netboot/wd8x13.c */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* source in this file came from
* the Mach ethernet boot written by Leendert van Doorn.
* Device driver for National Semiconductor DS8390/WD83C690 based ethernet
* adapters.
*
* A very simple network driver for WD80x3 boards that polls.
* Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
*
* Copyright (c) 1992 by Leendert van Doorn
* Copyright (C) 1993, David Greenman. 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 is
* the author responsible for the proper functioning of this software, nor does
* the author assume any responsibility for damages incurred with its use.
*/
/*
* Device driver for the Western Digital/SMC 8003 and 8013 series,
* and the SMC Elite Ultra (8216).
*/
#include <sys/types.h>
#include <machine/pio.h>
#include <lib/libsa/stand.h>
#include <lib/libkern/libkern.h>
#include <libi386.h>
#ifdef _STANDALONE
#include <lib/libkern/libkern.h>
#include <bootinfo.h>
#endif
#include "etherdrv.h"
#include <dev/ic/dp8390reg.h>
#include "dp8390.h"
#include <dev/isa/if_wereg.h>
#ifndef BASEREG
#define BASEREG 0x240
#define BASEMEM 0xd0000
#endif
static int ourbasereg, ourbasemem;
#define WD_BASEREG BASEREG
#define WD_BASEMEM BASEMEM
/* configurable parameters */
#define WD_BASEREG ourbasereg /* base register */
/* the base address doesn't have to be particularly accurate - the
board seems to pick up on addresses in the range a0000..effff.
*/
#define WD_BASEMEM ourbasemem /* base ram */
/* bit definitions for board features */
#define INTERFACE_CHIP 01 /* has an WD83C583 interface chip */
#define BOARD_16BIT 02 /* 16 bit board */
#define SLOT_16BIT 04 /* 16 bit slot */
/* register offset definitions */
#define WD_MSR 0x00 /* control (w) and status (r) */
#define WD_REG0 0x00 /* generic register definitions */
#define WD_REG1 0x01
#define WD_REG2 0x02
#define WD_REG3 0x03
#define WD_REG4 0x04
#define WD_REG5 0x05
#define WD_REG6 0x06
#define WD_REG7 0x07
#define WD_EA0 0x08 /* most significant addr byte */
#define WD_EA1 0x09
#define WD_EA2 0x0A
#define WD_EA3 0x0B
#define WD_EA4 0x0C
#define WD_EA5 0x0D /* least significant addr byte */
#define WD_LTB 0x0E /* LAN type byte */
#define WD_CHKSUM 0x0F /* sum from WD_EA0 upto here is 0xFF */
#define WD_DP8390 0x10 /* natsemi chip */
/* bits in control register */
#define WD_MSR_MEMMASK 0x3F /* memory enable bits mask */
#define WD_MSR_MENABLE 0x40 /* memory enable */
#define WD_MSR_RESET 0x80 /* software reset */
/* bits in bus size register */
#define WD_BSR_16BIT 0x01 /* 16 bit bus */
/* bits in LA address register */
#define WD_LAAR_A19 0x01 /* address lines for above 1Mb ram */
#define WD_LAAR_LAN16E 0x40 /* enables 16bit shrd RAM for LAN */
#define WD_LAAR_MEM16E 0x80 /* enables 16bit shrd RAM for host */
static u_char eth_myaddr[6];
static int boardid;
static dpconf_t dpc;
static struct btinfo_netif bi_netif;
/*
* Determine whether wd8003 hardware performs register aliasing
* (i.e. whether it is an old WD8003E board).
*/
static int
Aliasing(void) {
if (inb(WD_BASEREG + WD_REG1) != inb(WD_BASEREG + WD_EA1))
return 0;
if (inb(WD_BASEREG + WD_REG2) != inb(WD_BASEREG + WD_EA2))
return 0;
if (inb(WD_BASEREG + WD_REG3) != inb(WD_BASEREG + WD_EA3))
return 0;
if (inb(WD_BASEREG + WD_REG4) != inb(WD_BASEREG + WD_EA4))
return 0;
if (inb(WD_BASEREG + WD_REG7) != inb(WD_BASEREG + WD_CHKSUM))
return 0;
return 1;
}
/*
* Determine whether this board has 16-bit capabilities
*/
static int
BoardIs16Bit(void) {
u_char bsreg = inb(WD_BASEREG + WD_REG1);
outb(WD_BASEREG + WD_REG1, bsreg ^ WD_BSR_16BIT);
delay(2000);
if (inb(WD_BASEREG + WD_REG1) == bsreg) {
/*
* Pure magic: LTB is 0x05 indicates that this is a WD8013EB board,
* 0x27 indicates that this is an WD8013 Elite board, and 0x29
* indicates an SMC Elite 16 board.
*/
u_char tlb = inb(WD_BASEREG + WD_LTB);
return tlb == 0x05 || tlb == 0x27 || tlb == 0x29
#ifdef SUPPORT_SMC_ULTRA
|| tlb == 0x2b
#ifndef _STANDALONE
extern int mapio __P((void));
#endif
;
}
outb(WD_BASEREG + WD_REG1, bsreg);
return 1;
u_char eth_myaddr[6];
static u_int8_t we_type;
static int we_is16bit;
#ifdef _STANDALONE
static struct btinfo_netif bi_netif;
#endif
const char *
we_params()
{
const char *typestr;
dp8390_memsize = 8192;
we_type = inb(WD_BASEREG + WE_CARD_ID);
switch (we_type) {
#ifdef SUPPORT_WD80X3
case WE_TYPE_WD8003S:
typestr = "WD8003S";
break;
case WE_TYPE_WD8003E:
typestr = "WD8003E";
break;
case WE_TYPE_WD8003EB:
typestr = "WD8003EB";
break;
case WE_TYPE_WD8003W:
typestr = "WD8003W";
break;
case WE_TYPE_WD8013EBT:
typestr = "WD8013EBT";
dp8390_memsize = 16384;
we_is16bit = 1;
break;
case WE_TYPE_WD8013W:
typestr = "WD8013W";
dp8390_memsize = 16384;
we_is16bit = 1;
break;
case WE_TYPE_WD8013EP: /* also WD8003EP */
if (inb(WD_BASEREG + WE_ICR) & WE_ICR_16BIT) {
we_is16bit = 1;
dp8390_memsize = 16384;
typestr = "WD8013EP";
} else
typestr = "WD8003EP";
break;
case WE_TYPE_WD8013WC:
typestr = "WD8013WC";
dp8390_memsize = 16384;
we_is16bit = 1;
break;
case WE_TYPE_WD8013EBP:
typestr = "WD8013EBP";
dp8390_memsize = 16384;
we_is16bit = 1;
break;
case WE_TYPE_WD8013EPC:
typestr = "WD8013EPC";
dp8390_memsize = 16384;
we_is16bit = 1;
break;
#endif
#ifdef SUPPORT_SMC_ULTRA
case WE_TYPE_SMC8216C:
case WE_TYPE_SMC8216T:
{
u_int8_t hwr;
typestr = (we_type == WE_TYPE_SMC8216C) ?
"SMC8216/SMC8216C" : "SMC8216T";
hwr = inb(WD_BASEREG + WE790_HWR);
outb(WD_BASEREG + WE790_HWR, hwr | WE790_HWR_SWH);
switch (inb(WD_BASEREG + WE790_RAR) & WE790_RAR_SZ64) {
case WE790_RAR_SZ64:
dp8390_memsize = 65536;
break;
case WE790_RAR_SZ32:
dp8390_memsize = 32768;
break;
case WE790_RAR_SZ16:
dp8390_memsize = 16384;
break;
case WE790_RAR_SZ8:
/* 8216 has 16K shared mem -- 8416 has 8K */
typestr = (we_type == WE_TYPE_SMC8216C) ?
"SMC8416C/SMC8416BT" : "SMC8416T";
dp8390_memsize = 8192;
break;
}
outb(WD_BASEREG + WE790_HWR, hwr);
we_is16bit = 1;
#ifdef SUPPORT_WD80X3
dp8390_is790 = 1;
#endif
break;
}
#endif
default:
/* Not one we recognize. */
return (NULL);
}
/*
* Make some adjustments to initial values depending on what is
* found in the ICR.
*/
if (we_is16bit && (we_type != WE_TYPE_WD8013EBT) &&
(inb(WD_BASEREG + WE_ICR) & WE_ICR_16BIT) == 0) {
we_is16bit = 0;
dp8390_memsize = 8192;
}
#ifdef WE_DEBUG
{
int i;
printf("we_params: type = 0x%x, typestr = %s, is16bit = %d, "
"memsize = %d\n", we_type, typestr, we_is16bit, dp8390_memsize);
for (i = 0; i < 8; i++)
printf(" %d -> 0x%x\n", i,
inb(WD_BASEREG + i));
}
#endif
return (typestr);
}
/*
* Determine whether the 16 bit capable board is plugged
* into a 16 bit slot.
*/
static int
SlotIs16Bit(void) {
return inb(WD_BASEREG + WD_REG1) & WD_BSR_16BIT;
}
/*
* Reset ethernet board after a timeout
*/
static void
edreset() {
int dpreg = dpc.dc_reg;
/* initialize the board */
outb(WD_BASEREG + WD_MSR,
WD_MSR_MENABLE | (((u_long)WD_BASEMEM >> 13) & WD_MSR_MEMMASK));
/* reset dp8390 ethernet chip */
outb(dpreg + DP_CR, CR_STP|CR_DM_ABORT);
/* initialize first register set */
outb(dpreg + DP_IMR, 0);
outb(dpreg + DP_CR, CR_PS_P0|CR_STP|CR_DM_ABORT);
outb(dpreg + DP_TPSR, dpc.dc_tpsr);
outb(dpreg + DP_PSTART, dpc.dc_pstart);
outb(dpreg + DP_PSTOP, dpc.dc_pstop);
outb(dpreg + DP_BNRY, dpc.dc_pstart);
outb(dpreg + DP_RCR, RCR_MON);
outb(dpreg + DP_TCR, TCR_NORMAL|TCR_OFST);
if (boardid & SLOT_16BIT)
outb(dpreg + DP_DCR, DCR_WORDWIDE|DCR_8BYTES);
else
outb(dpreg + DP_DCR, DCR_BYTEWIDE|DCR_8BYTES);
outb(dpreg + DP_RBCR0, 0);
outb(dpreg + DP_RBCR1, 0);
outb(dpreg + DP_ISR, 0xFF);
/* initialize second register set */
outb(dpreg + DP_CR, CR_PS_P1|CR_DM_ABORT);
outb(dpreg + DP_PAR0, eth_myaddr[0]);
outb(dpreg + DP_PAR1, eth_myaddr[1]);
outb(dpreg + DP_PAR2, eth_myaddr[2]);
outb(dpreg + DP_PAR3, eth_myaddr[3]);
outb(dpreg + DP_PAR4, eth_myaddr[4]);
outb(dpreg + DP_PAR5, eth_myaddr[5]);
outb(dpreg + DP_CURR, dpc.dc_pstart+1);
/* and back to first register set */
outb(dpreg + DP_CR, CR_PS_P0|CR_DM_ABORT);
outb(dpreg + DP_RCR, RCR_AB);
/* flush counters */
(void) inb(dpreg + DP_CNTR0);
(void) inb(dpreg + DP_CNTR1);
(void) inb(dpreg + DP_CNTR2);
/* and go ... */
outb(dpreg + DP_CR, CR_STA|CR_DM_ABORT);
}
/*
* Initialize the WD80X3 board
*/
int
EtherInit(myadr)
char *myadr;
{
unsigned sum;
int memsize;
int i;
const char *typestr;
u_int8_t x;
int i;
u_int8_t laar_proto;
u_int8_t msr_proto;
ourbasereg = BASEREG;
ourbasemem = BASEMEM;
dp8390_iobase = WD_BASEREG + WE_NIC_OFFSET;
dp8390_membase = WD_BASEMEM;
/* reset the ethernet card */
outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
delay(2000);
outb(WD_BASEREG + WD_MSR, 0);
/* determine whether the controller is there */
sum = inb(WD_BASEREG + WD_EA0) + inb(WD_BASEREG + WD_EA1) +
inb(WD_BASEREG + WD_EA2) + inb(WD_BASEREG + WD_EA3) +
inb(WD_BASEREG + WD_EA4) + inb(WD_BASEREG + WD_EA5) +
inb(WD_BASEREG + WD_LTB) + inb(WD_BASEREG + WD_CHKSUM);
if ((sum & 0xFF) != 0xFF)
return 0;
/*
* Determine the type of board
*/
boardid = 0;
if (!Aliasing()) {
if (BoardIs16Bit()) {
boardid |= BOARD_16BIT;
if (SlotIs16Bit())
boardid |= SLOT_16BIT;
}
}
memsize = (boardid & BOARD_16BIT) ? 0x4000 : 0x2000; /* 16 or 8 Kb */
/* special setup needed for WD8013 boards */
if (boardid & SLOT_16BIT)
outb(WD_BASEREG + WD_REG5, WD_LAAR_A19|WD_LAAR_LAN16E);
/* get ethernet address */
for(i = 0; i < 6; i++)
eth_myaddr[i] = myadr[i]= inb(WD_BASEREG + WD_EA0 + i);
/* save settings for future use */
dpc.dc_reg = WD_BASEREG + WD_DP8390;
dpc.dc_mem = WD_BASEMEM;
dpc.dc_tpsr = 0;
dpc.dc_pstart = 6;
dpc.dc_pstop = (memsize >> 8) & 0xFF;
printf("Using wd80x3 board, port 0x%x, iomem 0x%x, iosiz %d\n", WD_BASEREG, WD_BASEMEM, memsize);
edreset();
#ifdef SUPPORT_SMC_ULTRA
outb(WD_BASEREG + 0, 0x40);
outb(WD_BASEREG + 5, 0x80);
outb(WD_BASEREG + 6, 0x1);
#ifndef _STANDALONE
if (mapio()) {
printf("no IO access\n");
return(0);
}
#endif
strncpy(bi_netif.ifname, "ed", sizeof(bi_netif.ifname));
bi_netif.bus = BI_BUS_ISA;
bi_netif.addr.iobase = WD_BASEREG;
for (x = 0, i = 0; i < 8; i++)
x += inb(WD_BASEREG + WE_PROM + i);
BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
if (x != WE_ROM_CHECKSUM_TOTAL)
return(0);
return 1;
/* reset the ethernet card */
outb(WD_BASEREG + WE_MSR, WE_MSR_RST);
delay(100);
outb(WD_BASEREG + WE_MSR, inb(WD_BASEREG + WE_MSR) & ~WE_MSR_RST);
delay(5000);
typestr = we_params();
if (!typestr)
return(0);
printf("Using %s board, port 0x%x, iomem 0x%x, iosiz %d\n",
typestr, WD_BASEREG, WD_BASEMEM, dp8390_memsize);
/* get ethernet address */
for(i = 0; i < 6; i++)
eth_myaddr[i] = myadr[i]= inb(WD_BASEREG + WE_PROM + i);
/*
* Set upper address bits and 8/16 bit access to shared memory.
*/
if (dp8390_is790) {
laar_proto = inb(WD_BASEREG + WE_LAAR) & ~WE_LAAR_M16EN;
outb(WD_BASEREG + WE_LAAR, laar_proto |
(we_is16bit ? WE_LAAR_M16EN : 0));
} else if ((we_type & WE_SOFTCONFIG) ||
(we_type == WE_TYPE_WD8013EBT)) {
laar_proto = (WD_BASEMEM >> 19) & WE_LAAR_ADDRHI;
if (we_is16bit)
laar_proto |= WE_LAAR_L16EN;
outb(WD_BASEREG + WE_LAAR, laar_proto |
(we_is16bit ? WE_LAAR_M16EN : 0));
}
/*
* Set address and enable interface shared memory.
*/
if (dp8390_is790) {
/* XXX MAGIC CONSTANTS XXX */
x = inb(WD_BASEREG + 0x04);
outb(WD_BASEREG + 0x04, x | 0x80);
outb(WD_BASEREG + 0x0b,
((WD_BASEMEM >> 13) & 0x0f) |
((WD_BASEMEM >> 11) & 0x40) |
(inb(WD_BASEREG + 0x0b) & 0xb0));
outb(WD_BASEREG + 0x04, x);
msr_proto = 0x00;
dp8390_cr_proto = 0x00;
} else {
msr_proto = (WD_BASEMEM >> 13) & WE_MSR_ADDR;
dp8390_cr_proto = ED_CR_RD2;
}
outb(WD_BASEREG + WE_MSR, msr_proto | WE_MSR_MENB);
delay(2);
/*
* DCR gets:
*
* FIFO threshold to 8, No auto-init Remote DMA,
* byte order=80x86.
*
* 16-bit cards also get word-wide DMA transfers.
*/
dp8390_dcr_reg = ED_DCR_FT1 | ED_DCR_LS | (we_is16bit ? ED_DCR_WTS : 0);
if (dp8390_config())
return(0);
#ifdef _STANDALONE
strncpy(bi_netif.ifname, "we", sizeof(bi_netif.ifname));
bi_netif.bus = BI_BUS_ISA;
bi_netif.addr.iobase = WD_BASEREG;
BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
#endif
return(1);
}
/*
@ -268,191 +324,8 @@ char *myadr;
*/
void
EtherStop(void) {
/* stop dp8390, followed by a board reset */
outb(dpc.dc_reg + DP_CR, CR_STP|CR_DM_ABORT);
outb(WD_BASEREG + WD_MSR, WD_MSR_RESET);
outb(WD_BASEREG + WD_MSR, 0);
/* stop dp8390, followed by a board reset */
dp8390_stop();
outb(WD_BASEREG + WE_MSR, WE_MSR_RST);
outb(WD_BASEREG + WE_MSR, 0);
}
/* TBD - all users must take care to use the current "data seg" value
when moving data from/to the controller */
static void
WdCopyIn(u_long src, void *dst, u_long count) {
#if TRACE > 0
printf("WdCopy from %x to %x for %d\n", src, dst, count);
#endif
/* assert(count <= 1514); */
if (boardid & SLOT_16BIT)
outb(WD_BASEREG + WD_REG5,
WD_LAAR_MEM16E|WD_LAAR_LAN16E|WD_LAAR_A19);
pvbcopy(src, dst, count);
if (boardid & SLOT_16BIT)
outb(WD_BASEREG + WD_REG5, WD_LAAR_LAN16E|WD_LAAR_A19);
}
static void
WdCopyOut(void *src, u_long dst, u_long count) {
#if TRACE > 0
printf("WdCopy from %x to %x for %d\n", src, dst, count);
#endif
/* assert(count <= 1514); */
if (boardid & SLOT_16BIT)
outb(WD_BASEREG + WD_REG5,
WD_LAAR_MEM16E|WD_LAAR_LAN16E|WD_LAAR_A19);
vpbcopy(src, dst, count);
if (boardid & SLOT_16BIT)
outb(WD_BASEREG + WD_REG5, WD_LAAR_LAN16E|WD_LAAR_A19);
}
/*
* Send an ethernet packet to destination 'dest'
*/
int
EtherSend(pkt, len)
char *pkt;
int len;
{
int newlen=len;
if (newlen < 60)
newlen = 60;
#if TRACE > 0
{
int i;
DUMP_STRUCT("EtherSend: pkt", pkt, len);
#if 0
for(i=0; i<(len<MDUMP?len:MDUMP); i++) printe("%x ", *((u_char*)(pkt+i)));
printe("\n");
#endif
}
#endif
#if 0
printe("EtherSend: WdCopy from %x to %x for %d\n", LA(pkt), dpc.dc_mem + (dpc.dc_tpsr << 8), len);
#endif
WdCopyOut(pkt,
dpc.dc_mem + (dpc.dc_tpsr << 8), newlen);
outb(dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
outb(dpc.dc_reg + DP_TBCR0, (newlen & 0xFF));
outb(dpc.dc_reg + DP_TBCR1, (newlen >> 8) & 0xFF);
outb(dpc.dc_reg + DP_CR, CR_TXP);
#if 0
printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TPSR, dpc.dc_tpsr);
printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR0, (len & 0xFF));
printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_TBCR1, (len >> 8) & 0xFF);
printe("Ethersend: outb(%x, %x)\n", dpc.dc_reg + DP_CR, CR_TXP);
#endif
return len;
}
/*
* Copy dp8390 packet header for observation
*/
static void
GetHeader(u_long haddr, dphdr_t *dph) {
#if TRACE > 0
printe("GetHeader: WdCopy from %x to %x for %d\n", haddr, LA(dph), sizeof(dphdr_t));
#endif
WdCopyIn(haddr, dph, sizeof(dphdr_t));
#if 0
DUMP_STRUCT("GetHeader: dphdr_t", dph, sizeof(dphdr_t));
#endif
}
/*
* Poll the dp8390 just see if there's an Ethernet packet
* available. If there is, its contents is returned in a
* pkt structure, otherwise a nil pointer is returned.
*/
int
EtherReceive(pkt, maxlen)
char *pkt;
int maxlen;
{
u_char pageno, curpage, nextpage;
int dpreg = dpc.dc_reg;
dphdr_t dph;
u_long addr;
if (inb(dpreg + DP_RSR) & RSR_PRX) {
int len;
/* get current page numbers */
pageno = inb(dpreg + DP_BNRY) + 1;
if (pageno == dpc.dc_pstop)
pageno = dpc.dc_pstart;
outb(dpreg + DP_CR, CR_PS_P1);
curpage = inb(dpreg + DP_CURR);
outb(dpreg + DP_CR, CR_PS_P0);
if (pageno == curpage)
return 0;
/* get packet header */
addr = dpc.dc_mem + (pageno << 8);
GetHeader(addr, &dph);
nextpage = dph.dh_next;
len = ((dph.dh_rbch & 0xFF) << 8) | (dph.dh_rbcl & 0xFF);
len -= sizeof(dphdr_t);
if (len > 1514) /* bug in dp8390 */
len = 1514;
if(len>maxlen){
/* release occupied pages */
if (nextpage == dpc.dc_pstart)
nextpage = dpc.dc_pstop;
outb(dpreg + DP_BNRY, nextpage - 1);
return(0);
}
#if TRACE > 0
{
int i;
printe("EtherReceive %d bytes: ", len);
printe("\n");
}
#endif
/*
* The dp8390 maintains a circular buffer of pages (256 bytes)
* in which incomming ethernet packets are stored. The following
* if detects wrap arounds, and copies the ethernet packet to
* our local buffer in two chunks if necesarry.
*/
/* assert(len <= (6 << 8));*/
if (nextpage < pageno && nextpage > dpc.dc_pstart) {
u_long nbytes = ((dpc.dc_pstop - pageno) << 8) - sizeof(dphdr_t);
if(nbytes>len)printf("ep0: fatal size error\n");
/* assert(nbytes <= (6 << 8));*/
#if TRACE > 0
printe("EtherReceive1: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt), nbytes);
#endif
WdCopyIn(addr + sizeof(dphdr_t),
pkt, nbytes);
if ((len - nbytes) > 0)
/* TBD - this OK? */
#if TRACE > 0
printe("EtherReceive2: WdCopy from %x to %x for %x\n",dpc.dc_mem + (dpc.dc_pstart << 8), LA(pkt) + nbytes, len - nbytes);
#endif
WdCopyIn(dpc.dc_mem + (dpc.dc_pstart << 8),
pkt + nbytes,
len - nbytes);
} else {
#if TRACE > 0
printe("EtherReceive3: WdCopy from %x to %x for %x\n", addr + sizeof(dphdr_t), LA(pkt), len);
#endif
WdCopyIn(addr + sizeof(dphdr_t),
pkt, len);
}
/* release occupied pages */
if (nextpage == dpc.dc_pstart)
nextpage = dpc.dc_pstop;
outb(dpreg + DP_BNRY, nextpage - 1);
return len;
}
return 0;
}