Subject: port-i386/1433: There is no Intel EtherExpress 16 driver
To: None <netbsd-bugs@NetBSD.ORG>
From: Andrew Gillham <gillham@digitron.COM>
List: netbsd-bugs
Date: 09/05/1995 10:50:48
>Number: 1433
>Category: port-i386
>Synopsis: There is no Intel EtherExpress 16 driver
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: gnats-admin (GNATS administrator)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Mon Sep 4 22:35:03 1995
>Last-Modified:
>Originator: Andrew Gillham
>Organization:
Just me.
============================ Real 32bit multi-tasking UN*X System
Andrew Gillham | TCP/IP,NFS,PPP,4.4BSD-lite,multi-user
gillham@andrews.edu | i386,sparc,alpha,mac68k,amiga,others
LAN/WAN/NW/UN*X specialist | ---> http://www.NetBSD.org <---
'Free the daemon in your computer, NetBSD'
>Release: Sept 2, 1995
>Environment:
System: NetBSD badboy 1.0A NetBSD 1.0A (BADBOY) #2: Mon Sep 4 03:51:44 EDT 1995 root@badboy:/usr/src/sys/arch/i386/compile/BADBOY i386
Actual testing done on my brother's system at Intel. (I don't have an EE16)
Here is his dmesg: (note 'ix0')
NetBSD 1.0A (INTEL) #4: Mon Sep 4 11:39:41 PDT 1995
root@ggillhax:/usr/src/sys/arch/i386/compile/INTEL
CPU: i486DX (486-class CPU)
real mem = 7995392
avail mem = 6254592
using 123 buffers containing 503808 bytes of memory
isa0 (root)
com0 at isa0 port 0x3f8-0x3ff irq 4: ns8250 or ns16450, no fifo
com1 at isa0 port 0x2f8-0x2ff irq 3: ns8250 or ns16450, no fifo
lpt0 at isa0 port 0x378-0x37f irq 7
aha0: 1542C/CF detected, unlocking mailbox
aha0 at isa0 port 0x330-0x333 irq 11 drq 7
scsibus0 at aha0
aha0 targ 0 lun 0: <MAXTOR, LXT-213S, 4.57> SCSI1 0/direct fixed
sd0 at scsibus0: 202MB, 1310 cyl, 7 head, 45 sec, 512 bytes/sec
wdc0 at isa0 port 0x1f0-0x1f7 irq 14
wd0 at wdc0 drive 0: 202MB, 683 cyl, 16 head, 38 sec, 512 bytes/sec <Maxtor 7213 AT>
wd0: using 16-sector 16-bit pio transfers, chs addressing
wd1 at wdc0 drive 1: 124MB, 936 cyl, 16 head, 17 sec, 512 bytes/sec <Maxtor 7120 AT>
wd1: using 16-sector 16-bit pio transfers, chs addressing
ix0 at isa0 port 0x300-0x30f iomem 0xd0000-0xd7fff irq 10
ix0: address 00:aa:00:53:9c:32
npx0 at isa0 port 0xf0-0xff: using exception 16
vt0 at isa0 port 0x60-0x6f irq 1: generic, 80 col, color, 8 scr, mf2-kbd, [R3.00]
fdc0 at isa0 port 0x3f0-0x3f7 irq 6 drq 2
fd0 at fdc0 drive 0: 1.44MB 80 cyl, 2 head, 18 sec
root device eisa not configured
root device pci not configured
biomask 4840 netmask 400 ttymask 1a
changing root device to sd0a
>Description:
There is no Intel EtherExpress 16 driver, though it is mentioned
in /sys/dev/isa/files.isa. My brother needed one as the only NICs
used at Intel, are Intel NICs. (imagine that)
>How-To-Repeat:
Install an Intel EtherExpress 16
>Fix:
Included is a port of the FreeBSD "ix" driver by Rod Grimes.
I did nothing more than convert it to the new config format with
cfdata, etc.. I do not claim to be a kernel hacker, so my changes
might not be up to snuff. But... the code does work.
Really this driver should be integrated with if_ie.c, but that was
definitely beyond me!
Included is:
files.isa.diff - uncomment the if_ix.c driver
if_ix.c - add EE16 support
if_ixreg.h - needed for above
*** files.isa.orig Mon Jul 24 08:29:04 1995
--- files.isa Mon Sep 4 14:40:44 1995
***************
*** 148,155 ****
# XXX ???
# XXX NOT IN TREE?
! #device ix at isa: ether, ifnet
! #file dev/isa/if_ix.c ix
# AMD am7990 (Lance) -based boards
# (BICC Isolan, NE2100, DEPCA)
--- 148,155 ----
# XXX ???
# XXX NOT IN TREE?
! device ix at isa: ether, ifnet
! file dev/isa/if_ix.c ix
# AMD am7990 (Lance) -based boards
# (BICC Isolan, NE2100, DEPCA)
-----cut here-----
/*
* Copyright (c) 1993, 1994, 1995
* Rodney W. Grimes, Milwaukie, Oregon 97222. 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 as
* the first lines of this file unmodified.
* 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 Rodney W. Grimes.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY RODNEY W. GRIMES ``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 RODNEY W. GRIMES 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.
*
* $Id: if_ix.c,v 1.7 1995/05/30 08:02:15 rgrimes Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/device.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#endif /* INET */
#ifdef NS /*ZZZ no work done on this, this is just here to remind me*/
#include <netns/ns.h>
#include <netns/ns_if.h>
#endif /* NS */
#ifdef ISO /*ZZZ no work done on this, this is just here to remind me*/
#include <netiso/iso.h>
#include <netiso/iso_var.h>
extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
#endif /* ISO */
/*ZZZ no work done on this, this is just here to remind me*/
#include "bpfilter.h"
#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
#endif /* NBPFILTER > 0 */
#include <machine/cpu.h>
#include <machine/pio.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <i386/isa/isa_machdep.h>
#include <dev/isa/if_ixreg.h>
#define DEBUGNONE 0x0000
#define DEBUGPROBE 0x0001
#define DEBUGATTACH (DEBUGPROBE << 1)
#define DEBUGINIT (DEBUGATTACH << 1)
#define DEBUGINIT_RFA (DEBUGINIT << 1)
#define DEBUGINIT_TFA (DEBUGINIT_RFA << 1)
#define DEBUGINTR (DEBUGINIT_TFA << 1)
#define DEBUGINTR_FR (DEBUGINTR << 1)
#define DEBUGINTR_CX (DEBUGINTR_FR << 1)
#define DEBUGSTART (DEBUGINTR_CX << 1)
#define DEBUGSTOP (DEBUGSTART << 1)
#define DEBUGRESET (DEBUGSTOP << 1)
#define DEBUGDONE (DEBUGRESET << 1)
#define DEBUGIOCTL (DEBUGDONE << 1)
#define DEBUGACK (DEBUGIOCTL << 1)
#define DEBUGCA (DEBUGACK << 1)
#define DEBUGCB_WAIT (DEBUGCA << 1)
#define DEBUGALL 0xFFFFFFFF
/* #define IXDEBUG (DEBUGPROBE | DEBUGINIT | DEBUGSTOP | DEBUGCB_WAIT) */
#ifdef IXDEBUG
int ixdebug=IXDEBUG;
#define DEBUGBEGIN(flag) \
{\
if (ixdebug & flag)\
{
#define DEBUGEND \
}\
}
#define DEBUGDO(x) x
#else /* IXDEBUG */
#define DEBUGBEGIN(flag)
#define DEBUGEND
#define DEBUGDO(x)
#endif /* IXDEBUG */
/*
* Enable the exteneded ixcounters by using #define IXCOUNTERS, note that
* this requires a modification to the ifnet structure to add the counters
* in. Some day a standard extended ifnet structure will be done so that
* additional statistics can be gathered for any board that supports these
* counters.
*/
#ifdef IXCOUNTERS
#define IXCOUNTER(x) x
#else /* IXCOUNTERS */
#define IXCOUNTER(x)
#endif /* IXCOUNTERS */
/*
* Function Prototypes
*/
static inline void ixinterrupt_enable __P((struct ix_softc *));
static inline void ixinterrupt_disable __P((struct ix_softc *));
static inline void ixchannel_attention __P((struct ix_softc *));
u_short ixacknowledge __P((struct ix_softc *));
int ix_cb_wait(cb_t *, char *);
int ix_scb_wait(scb_t *, u_short, char *);
int ixprobe __P((struct device *, void *, void *));
void ixattach __P((struct device *, struct device *, void *));
void ixinit __P((struct ix_softc *));
void ixinit_rfa __P((struct ix_softc *));
void ixinit_tfa __P((struct ix_softc *));
int ixintr __P((void *));
static inline void ixintr_cx __P((struct ix_softc *));
static inline void ixintr_cx_free __P((struct ix_softc *, cb_t *));
static inline void ixintr_fr __P((struct ix_softc *));
static inline void ixintr_fr_copy __P((struct ix_softc *, rfd_t *));
static inline void ixintr_fr_free __P((struct ix_softc *, rfd_t *));
void ixstart __P((struct ifnet *));
int ixstop __P((struct ifnet *));
int ixioctl __P((struct ifnet *, u_long, caddr_t));
void ixreset __P((struct ix_softc *));
void ixwatchdog __P((int));
u_short ixeeprom_read __P((struct ix_softc *, int));
void ixeeprom_outbits __P((struct ix_softc *, int, int));
int ixeeprom_inbits __P((struct ix_softc *));
void ixeeprom_clock __P((struct ix_softc *, int));
/*
RRR */
struct cfdriver ixcd = {
NULL, "ix", ixprobe, ixattach, DV_IFNET, sizeof(struct ix_softc)
};
/*
* Enable the interrupt signal on the board so that it may interrupt
* the host.
*/
static inline void
ixinterrupt_enable(sc)
struct ix_softc *sc;
{
outb(sc->sc_iobase + sel_irq, sc->irq_encoded | IRQ_ENABLE);
}
/*
* Disable the interrupt signal on the board so that it will not interrupt
* the host.
*/
static inline void
ixinterrupt_disable(sc)
struct ix_softc *sc;
{
outb(sc->sc_iobase + sel_irq, sc->irq_encoded);
}
/*
* Send a channel attention to the 82586 chip
*/
static inline void
ixchannel_attention(sc)
struct ix_softc *sc;
{
DEBUGBEGIN(DEBUGCA)
DEBUGDO(printf("ca");)
DEBUGEND
outb(sc->sc_iobase + ca_ctrl, 0);
}
u_short
ixacknowledge(sc)
struct ix_softc *sc;
{
scb_t *scb = (scb_t *)(sc->sc_maddr + SCB_ADDR);
u_short status;
int i;
DEBUGBEGIN(DEBUGACK)
DEBUGDO(printf("ack:");)
DEBUGEND
status = scb->status;
scb->command = status & SCB_ACK_MASK;
if ((status & SCB_ACK_MASK) != 0) {
ixchannel_attention(sc);
for (i = 1000000; scb->command && (i > 0); i--); /*ZZZ timeout*/
if (i == 0) {
printf(".TO=%x:", scb->command);
printf("\nshutting down\n");
ixinterrupt_disable(sc);
sc->flags = IXF_NONE;
status = 0;
} else {
DEBUGBEGIN(DEBUGACK)
DEBUGDO(printf(".ok:");)
DEBUGEND
}
} else {
/* nothing to acknowledge */
DEBUGBEGIN(DEBUGACK)
DEBUGDO(printf("NONE:");)
DEBUGEND
}
DEBUGBEGIN(DEBUGACK)
DEBUGDO(printf("%x ", status);)
DEBUGEND
return(status);
}
int
ix_cb_wait(cb_t *cb, char *message) {
int i;
int status;
for (i=1000000; i>0; i--) {
if (cb->status & CB_COMPLETE) break; /* Wait for done */
}
if (i == 0) {
printf("%s timeout cb->status = %x\n", message, cb->status);
status = 1;
} else {
DEBUGBEGIN(DEBUGCB_WAIT)
DEBUGDO(printf("%s cb ok count = %d\n", message, i);)
DEBUGEND
status = 0;
}
return (status);
}
int
ix_scb_wait(scb_t *scb, u_short expect, char *message) {
int i;
int status;
for (i=1000000; i>0; i--) {
if (scb->status == expect) break; /* Wait for done */
}
if (i == 0) {
printf("%s timeout scb->status = %x\n", message, scb->status);
status = 1;
} else {
DEBUGBEGIN(DEBUGINIT)
DEBUGDO(printf("%s scb ok count = %d\n", message, i);)
DEBUGEND
status = 0;
}
return (status);
}
int
ixprobe(parent, match, aux)
struct device *parent;
void *match, *aux;
{
struct ix_softc *sc = match;
struct isa_attach_args *ia = aux;
int iobase = ia->ia_iobase;
char tempid, idstate;
int i;
int status = 0;
u_short boardid,
checksum,
connector,
eaddrtemp,
irq;
/* ZZZ irq_translate should really be unsigned, but until
* isa_device.h and all uses are fixed we have to live with it */
/* short irq_translate[] = {0, IRQ9, IRQ3, IRQ4, IRQ5, IRQ10, IRQ11, 0}; */
short irq_translate[] = {0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0};
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf ("ixprobe:");)
DEBUGEND
/*
* Since Intel gives us such a nice way to ID this board lets
* see if we really have one at this I/O address
*/
idstate = inb(iobase + autoid) & 0x03;
for (i=0, boardid=0; i < 4; i++) {
tempid = inb(iobase + autoid);
boardid |= ((tempid & 0xF0) >> 4) << ((tempid & 0x03) << 2);
if ((tempid & 0x03) != (++idstate & 0x03)) {
/* out of sequence, destroy boardid and bail out */
boardid = 0;
break;
}
}
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf("boardid = %x\n", boardid);)
DEBUGEND
if (boardid != BOARDID) {
goto ixprobe_exit;
}
/*
* We now know that we have a board, so save the I/O base
* address in the softc and use the softc from here on out
*/
sc->sc_iobase = iobase;
sc->sc_maddr = ISA_HOLE_VADDR(ia->ia_maddr);
sc->sc_msize = ia->ia_msize;
/*
* Reset the Bart ASIC by pulsing the reset bit and waiting
* the required 240 uSecounds. Also place the 82586 in the reset
* mode so that we can access the EEPROM
*/
outb(sc->sc_iobase + ee_ctrl, GA_RESET);
outb(sc->sc_iobase + ee_ctrl, 0);
DELAY(240);
outb(sc->sc_iobase + ee_ctrl, I586_RESET);
/*
* Checksum the EEPROM, should be equal to BOARDID
*/
for (i=0, checksum=0; i<64; i++) {
checksum += ixeeprom_read(sc, i);
}
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf ("checksum = %x\n", checksum);)
DEBUGEND
if (checksum != BOARDID) {
goto ixprobe_exit;
}
/*
* Do the I/O channel ready test
*/
{
u_char lock_bit;
lock_bit = ixeeprom_read(sc, eeprom_lock_address);
if (lock_bit & EEPROM_LOCKED) {
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf ("lockbit set, not doing io channel ready test\n");)
DEBUGEND
} else {
u_char bart_config,
junk;
bart_config = inb(sc->sc_iobase + config);
bart_config |= BART_IOCHRDY_LATE | BART_IO_TEST_EN;
outb(sc->sc_iobase + config, bart_config);
junk = inb(sc->sc_iobase + 0x4000); /*XXX read junk */
bart_config = inb(sc->sc_iobase + config);
outb(sc->sc_iobase + config, bart_config & ~(BART_IO_TEST_EN));
if (bart_config & BART_IO_RESULT) {
printf ("iochannel ready test failed!!\n");
} else {
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf ("iochannel ready test passed\n");)
DEBUGEND
}
}
}
/*
* Size and test the memory on the board. The size of the memory
* can be one of 16k, 32k, 48k or 64k. It can be located in the
* address range 0xC0000 to 0xEFFFF on 16k boundaries. Although
* the board can be configured for 0xEC0000 to 0xEEFFFF,
* or 0xFC0000 to 0xFFFFFF these ranges are not supported by 386bsd.
*
* If the size does not match the passed in memory allocation size
* issue a warning, but continue with the minimum of the two sizes.
*/
{
u_short memory_page;
u_short memory_adjust;
u_short memory_decode;
u_short memory_edecode;
switch (ia->ia_msize) {
case 65536:
case 32768: /* XXX Only support 32k and 64k right now */
{ break; }
case 16384:
case 49512:
default: {
printf("ixprobe mapped memory size out of range\n");
goto ixprobe_exit;
}
}
if ((kvtop(sc->sc_maddr) < 0xC0000) ||
(kvtop(sc->sc_maddr) + sc->sc_msize > 0xF0000)) {
printf("ixprobe mapped memory address out of range\n");
goto ixprobe_exit;
}
memory_page = (kvtop(sc->sc_maddr) & 0x3C000) >> 14;
memory_adjust = MEMCTRL_FMCS16 | (memory_page & 0x3) << 2;
memory_decode = ((1 << (sc->sc_msize / 16384)) - 1) << memory_page;
memory_edecode = ((~memory_decode >> 4) & 0xF0) | (memory_decode >> 8);
/* ZZZ This should be checked against eeprom location 6, low byte */
outb(sc->sc_iobase + memdec, memory_decode & 0xFF);
/* ZZZ This should be checked against eeprom location 1, low byte */
outb(sc->sc_iobase + memctrl, memory_adjust);
/* ZZZ Now if I could find this one I would have it made */
outb(sc->sc_iobase + mempc, (~memory_decode & 0xFF));
/* ZZZ I think this is location 6, high byte */
outb(sc->sc_iobase + memectrl, memory_edecode); /*XXX disable Exxx */
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf("Physical address = %lx\n", kvtop(sc->sc_maddr));)
DEBUGEND
}
/*
* first prime the stupid bart DRAM controller so that it
* works, then zero out all of memory.
*/
bzero(sc->sc_maddr, 32);
bzero(sc->sc_maddr, sc->sc_msize);
/*
* Get the type of connector used, either AUI, BNC or TPE.
*/
connector = ixeeprom_read(sc, eeprom_config1);
if (connector & CONNECT_BNCTPE) {
connector = ixeeprom_read(sc, eeprom_config2);
if (connector & CONNECT_TPE) {
sc->connector = TPE;
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf ("Using TPE connector\n");)
DEBUGEND
} else {
sc->connector = BNC;
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf ("Using BNC connector\n");)
DEBUGEND
}
} else {
sc->connector = AUI;
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf ("Using AUI connector\n");)
DEBUGEND
}
/*
* Get the encoded interrupt number from the EEPROM, check it
* against the passed in IRQ. Issue a warning if they do not
* match. Always use the passed in IRQ, not the one in the EEPROM.
*/
irq = ixeeprom_read(sc, eeprom_config1);
irq = (irq & IRQ) >> IRQ_SHIFT;
sc->irq_encoded = irq;
irq = irq_translate[irq];
if (irq != ia->ia_irq) {
printf("Warning board is configured for IRQ %d\n", irq);
}
/*
* Get the slot width, either 8 bit or 16 bit.
*/
if (inb(sc->sc_iobase + config) & SLOT_WIDTH) {
sc->width = WIDTH_16;
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf("Using 16-bit slot\n");)
DEBUGEND
} else {
sc->width = WIDTH_8;
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf("Using 8-bit slot\n");)
DEBUGEND
}
/*
* Get the hardware ethernet address from the EEPROM and
* save it in the softc for use by the 586 setup code.
*/
eaddrtemp = ixeeprom_read(sc, eeprom_enetaddr_high);
sc->sc_arpcom.ac_enaddr[1] = eaddrtemp & 0xFF;
sc->sc_arpcom.ac_enaddr[0] = eaddrtemp >> 8;
eaddrtemp = ixeeprom_read(sc, eeprom_enetaddr_mid);
sc->sc_arpcom.ac_enaddr[3] = eaddrtemp & 0xFF;
sc->sc_arpcom.ac_enaddr[2] = eaddrtemp >> 8;
eaddrtemp = ixeeprom_read(sc, eeprom_enetaddr_low);
sc->sc_arpcom.ac_enaddr[5] = eaddrtemp & 0xFF;
sc->sc_arpcom.ac_enaddr[4] = eaddrtemp >> 8;
sc->flags = IXF_NONE; /* make sure the flag word is NONE */
ia->ia_iosize = IX_IO_PORTS;
status = 1;
ixprobe_exit:
DEBUGBEGIN(DEBUGPROBE)
DEBUGDO(printf ("ixprobe exited\n");)
DEBUGEND
return(status);
}
void
ixattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct ix_softc *sc = (void *)self;
struct isa_attach_args *ia = aux;
struct cfdata *cf = sc->sc_dev.dv_cfdata;
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct ifaddr *ifa;
struct sockaddr_dl *sdl;
DEBUGBEGIN(DEBUGATTACH)
DEBUGDO(printf("ixattach:");)
DEBUGEND
/*
* Fill in the interface parameters for if_attach
* Note: We could save some code here by first using a
* bzero(ifp, sizeof(ifp)); and then not doing all
* the = 0;'s
* Infact we should bzero this just to make sure
* that something does not get missed.
*/
bzero(ifp, sizeof(ifp));
ifp->if_name = ixcd.cd_name;
ifp->if_unit = sc->sc_dev.dv_unit;;
ifp->if_mtu = ETHERMTU;
ifp->if_flags = IFF_NOTRAILERS | IFF_BROADCAST;
/*
* This is commented out to save memory and cpu time
* ifp->if_timer = 0;
* ifp->if_metric = 0;
* ifp->if_addrlist = 0;
* ifp->if_snd.ifq_head = 0;
* ifp->if_snd.ifq_tail = 0;
* ifp->if_snd.ifq_len = 0;
* ifp->if_snd.ifq_maxlen = 0;
* ifp->if_snd.ifq_drops = 0;
* end of commented out block
*/
ifp->if_output = ether_output;
ifp->if_start = ixstart;
ifp->if_ioctl = ixioctl;
ifp->if_watchdog = ixwatchdog;
/*
* This is commented out to save memory and cpu time
* ifp->if_ipackets = 0;
* ifp->if_ierrors = 0;
* ifp->if_opackets = 0;
* ifp->if_oerrors = 0;
* ifp->if_collisions = 0;
* ifp->if_next = 0;
* end of commented out block
*/
ifp->if_type = IFT_ETHER;
ifp->if_addrlen = ETHER_ADDRESS_LENGTH;
ifp->if_hdrlen = ETHER_HEADER_LENGTH;
/*
* This is commented out to save memory and cpu time
* ifp->if_index = 0;
* ifp->if_lastchange.tv_sec = 0;
* ifp->if_lastchange.tv_usec = 0;
* ifp->if_ibytes = 0;
* ifp->if_obytes = 0;
* ifp->if_imcasts = 0;
* ifp->if_omcasts = 0;
* ifp->if_iqdrops = 0;
* ifp->if_noproto = 0;
* ifp->if_baudrate = 0;
* ifp->if_pcount = 0;
* end of commented out block
*/
#ifdef IXCOUNTERS
/*
* ZZZ more counters added, but bzero gets them
*/
#endif /* IXCOUNTERS */
if_attach(ifp);
printf("\nix%d: address %s\n", ifp->if_unit, ether_sprintf(sc->sc_arpcom.ac_enaddr));
sc->sc_ih = isa_intr_establish(ia->ia_irq, ISA_IST_EDGE, ISA_IPL_NET,
ixintr, sc);
}
void
ixinit(sc)
struct ix_softc *sc;
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
scp_t *scp = (scp_t *)(sc->sc_maddr + SCP_ADDR);
iscp_t *iscp = (iscp_t *)(sc->sc_maddr + ISCP_ADDR);
scb_t *scb = (scb_t *)(sc->sc_maddr + SCB_ADDR);
cb_t *cb;
tbd_t *tbd;
int i;
u_char bart_config; /* bart config byte */
int status = 0;
DEBUGBEGIN(DEBUGINIT)
DEBUGDO(printf("ixinit:");)
DEBUGEND
/* Put bart into loopback until we are done intializing to
* make sure that packets don't hit the wire */
bart_config = inb(sc->sc_iobase + config);
bart_config |= BART_LOOPBACK;
bart_config |= BART_MCS16_TEST; /* inb does not get this bit! */
outb(sc->sc_iobase + config, bart_config);
bart_config = inb(sc->sc_iobase + config);
scp->unused1 = 0; /* Intel says to put zeros in it */
scp->sysbus = sc->width; /* ZZZ need to fix for 596 */
scp->unused2 = 0; /* Intel says to put zeros in it */
scp->unused3 = 0; /* Intel says to put zeros in it */
scp->iscp = ISCP_ADDR;
iscp->busy = ISCP_BUSY;
iscp->scb_offset = SCB_ADDR;
iscp->scb_base = TFA_START;
scb->status = SCB_STAT_NULL;
scb->command = SCB_RESET;
scb->cbl_offset = TFA_START;
scb->rfa_offset = RFA_START;
scb->crc_errors = 0;
scb->aln_errors = 0;
scb->rsc_errors = 0;
scb->ovr_errors = 0;
ixinit_tfa(sc);
ixinit_rfa(sc);
cb = sc->cb_head;
tbd = sc->tbd_head;
/*
* remove the reset signal and start the 586 up, the 586 well read
* the SCP, ISCP and the reset CB. This should put it into a
* known state: RESET!
*/
outb(sc->sc_iobase + ee_ctrl, EENORMAL);
ixchannel_attention(sc);
for (i=100000; iscp->busy && (i>0); i--); /* Wait for done */
if (i == 0) {
printf("iscp->busy time out\n");
status = 1;
} else {
DEBUGBEGIN(DEBUGINIT)
DEBUGDO(printf ("iscp->busy did not timeout = %d\n", i);)
DEBUGEND
}
status |= ix_scb_wait(scb, (u_short)(SCB_STAT_CX | SCB_STAT_CNA),
"Reset");
ixacknowledge(sc);
/* XXX this belongs some place else, run diagnostics on the 586 */
{
cb_diagnose_t *cb_diag = (cb_diagnose_t *)(cb);
cb_diag->common.status = 0;
cb_diag->common.command = CB_CMD_EL | CB_CMD_DIAGNOSE;
scb->command = SCB_CUC_START;
ixchannel_attention(sc);
status |= ix_cb_wait((cb_t *)cb_diag, "Diagnose");
status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "Diagnose");
ixacknowledge(sc);
}
/* XXX end this belongs some place else, run diagnostics on the 586 */
/* XXX this belongs some place else, run configure on the 586 */
{
cb_configure_t *cb_conf = (cb_configure_t *)(cb);
cb_conf->common.status = 0;
cb_conf->common.command = CB_CMD_EL | CB_CMD_CONF;
cb_conf->byte[0] = 12; /* 12 byte configure block */
cb_conf->byte[1] = 8; /* fifo limit at 8 bytes */
cb_conf->byte[2] = 0x40; /* don't save bad frames,
srdy/ardy is srdy */
cb_conf->byte[3] = 0x2E; /* address length is 6 bytes,
address and length are in tb,
preamble length is 8 bytes,
internal loopback off,
external loopback off */
cb_conf->byte[4] = 0; /* linear priority is 0,
ACR (Exponential priorty) is 0,
exponential backoff is 802.3 */
cb_conf->byte[5] = 96; /* interframe spacing in TxC clocks */
cb_conf->byte[6] = 0; /* lower 8 bits of slot time */
cb_conf->byte[7] = 0xf2; /* upper slot time (512 bits),
15 transmision retries */
cb_conf->byte[8] = 0; /* promiscuous mode off,
broadcast enabled,
nrz encodeing,
cease transmission if ^CRS,
insert crc,
end of carrier mode bit stuffing,
no padding */
cb_conf->byte[9] = 0; /* carrier sense filter = 0 bits,
carrier sense source external,
collision detect filter = 0 bits,
collision detect source external */
cb_conf->byte[10] = 60; /* minimum number of bytes is a frame */
cb_conf->byte[11] = 0; /* unused */
scb->command = SCB_CUC_START;
ixchannel_attention(sc);
status |= ix_cb_wait((cb_t *)cb_conf, "Configure");
status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "Configure");
ixacknowledge(sc);
}
/* XXX end this belongs some place else, run configure on the 586 */
/* XXX this belongs some place else, run ias on the 586 */
{
cb_ias_t *cb_ias = (cb_ias_t *)(cb);
cb_ias->common.status = 0;
cb_ias->common.command = CB_CMD_EL | CB_CMD_IAS;
bcopy(sc->sc_arpcom.ac_enaddr, cb_ias->source, ETHER_ADDRESS_LENGTH);
scb->command = SCB_CUC_START;
ixchannel_attention(sc);
status |= ix_cb_wait((cb_t *)cb_ias, "IAS");
status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "IAS");
ixacknowledge(sc);
}
/* XXX end this belongs some place else, run ias on the 586 */
if (status == 0) {
/* Take bart out of loopback as we are done intializing */
bart_config = inb(sc->sc_iobase + config);
bart_config &= ~BART_LOOPBACK;
bart_config |= BART_MCS16_TEST; /* inb does not get this bit! */
outb(sc->sc_iobase + config, bart_config);
/* The above code screwed with the tfa, reinit it! */
ixinit_tfa(sc);
scb->command = SCB_RUC_START; /* start up the receive unit */
ixchannel_attention(sc);
sc->flags |= IXF_INITED; /* we have been initialized */
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
ixinterrupt_enable(sc); /* Let err fly!!! */
}
DEBUGBEGIN(DEBUGINIT)
DEBUGDO(printf("ixinit exited\n");)
DEBUGEND
return;
}
/*
* ixinit_rfa(int unit)
*
* This routine initializes the Receive Frame Area for the 82586
*
* input the unit number to build the RFA for
* access the softc for memory address
* output an initialized RFA, ready for packet receiption
* the following queue pointers in the softc structure are
* also initialize
* sc->rfd_head sc->rfd_tail
* sc->rbd_head sc->rbd_tail
* defines RFA_START the starting offset of the RFA
* RFA_SIZE size of the RFA area
* RB_SIZE size of the receive buffer, this must
* be even and should be greater than the
* minumum packet size and less than the
* maximum packet size
*/
void
ixinit_rfa(sc)
struct ix_softc *sc;
{
rfd_t *rfd;
rbd_t *rbd;
caddr_t rb;
int i,
complete_frame_size,
how_many_frames;
DEBUGBEGIN(DEBUGINIT_RFA)
DEBUGDO(printf("\nix%d: ixinit_rfa\n", sc->sc_dev.dv_unit);)
DEBUGEND
complete_frame_size = sizeof(rfd_t) + sizeof(rbd_t) + RB_SIZE;
how_many_frames = RFA_SIZE / complete_frame_size;
/* build the list of rfd's, rbd's and rb's */
rfd = (rfd_t *)(sc->sc_maddr + RFA_START);
rbd = (rbd_t *)(sc->sc_maddr +
RFA_START +
(how_many_frames * sizeof(rfd_t)));
rb = sc->sc_maddr + RFA_START +
(how_many_frames * (sizeof(rfd_t) + sizeof(rbd_t)));
sc->rfd_head = rfd;
sc->rbd_head = rbd;
for (i = 0; i < how_many_frames; i++, rfd++, rbd++, rb += RB_SIZE) {
rfd->status = 0;
rfd->command = 0;
rfd->next = KVTOBOARD(rfd) + sizeof(rfd_t);
rfd->rbd_offset = INTEL586NULL;
/* ZZZ could bzero this, but just leave a note for now */
/* ZZZ bzero(rfd->destination); */
/* ZZZ bzero(rfd->source); */
rfd->length = 0;
rbd->act_count = 0;
rbd->next = KVTOBOARD(rbd) + sizeof(rbd_t);
rbd->buffer = KVTOBOARD(rb);
rbd->size = RB_SIZE;
/*
* handle the boundary conditions here. for the zeroth
* rfd we must set the rbd_offset to point at the zeroth
* rbd. for the last rfd and rbd we need to close the
* list into a ring and set the end of list bits.
*/
if (i == 0) {
rfd->rbd_offset = KVTOBOARD(rbd);
}
if (i == how_many_frames - 1) {
rfd->command = RFD_CMD_EL | RFD_CMD_SUSP;
rfd->next = KVTOBOARD(sc->rfd_head);
rbd->next = KVTOBOARD(sc->rbd_head);
rbd->size = RBD_SIZE_EL | RB_SIZE;
}
}
sc->rfd_tail = (--rfd);
sc->rbd_tail = (--rbd);
#ifdef IXDEBUG
DEBUGBEGIN(DEBUGINIT_RFA)
rfd = (rfd_t *)(sc->sc_maddr + RFA_START);
rbd = (rbd_t *)(sc->sc_maddr +
RFA_START +
(how_many_frames * sizeof(rfd_t)));
rb = sc->sc_maddr + RFA_START +
(how_many_frames * (sizeof(rfd_t) + sizeof(rbd_t)));
printf(" complete_frame_size = %d\n", complete_frame_size);
printf(" how_many_frames = %d\n", how_many_frames);
printf(" rfd_head = %lx\t\trfd_tail = %lx\n",
kvtop(sc->rfd_head), kvtop(sc->rfd_tail));
printf(" rbd_head = %lx\t\trbd_tail = %lx\n",
kvtop(sc->rbd_head), kvtop(sc->rbd_tail));
for (i = 0; i < how_many_frames; i++, rfd++, rbd++, rb += RB_SIZE) {
printf(" %d:\trfd = %lx\t\trbd = %lx\t\trb = %lx\n",
i, kvtop(rfd), kvtop(rbd), kvtop(rb));
printf("\trfd->command = %x\n", rfd->command);
printf("\trfd->next = %x\trfd->rbd_offset = %x\n",
rfd->next, rfd->rbd_offset);
printf("\trbd->next = %x\trbd->size = %x",
rbd->next, rbd->size);
printf("\trbd->buffer = %lx\n\n",
rbd->buffer);
}
DEBUGEND
#endif /* IXDEBUG */
/*
* ZZZ need to add sanity check to see if last rb runs into
* the stuff after it in memory, this should not be possible
* but if someone screws up with the defines it can happen
*/
DEBUGBEGIN(DEBUGINIT_RFA)
DEBUGDO(printf (" next rb would be at %lx\n", kvtop(rb));)
DEBUGDO(printf("ix%d: ixinit_rfa exit\n", sc->sc_dev.dv_unit);)
DEBUGEND
}
/*
* ixinit_tfa(int unit)
*
* This routine initializes the Transmit Frame Area for the 82586
*
* input the unit number to build the TFA for
* access the softc for memory address
* output an initialized TFA, ready for packet transmission
* the following queue pointers in the softc structure are
* also initialize
* sc->cb_head sc->cb_tail
* sc->tbd_head sc->tbd_tail
* defines TB_COUNT home many transmit buffers to create
* TB_SIZE size of the tranmit buffer, this must
* be even and should be greater than the
* minumum packet size and less than the
* maximum packet size
* TFA_START the starting offset of the TFA
*/
void
ixinit_tfa(sc)
struct ix_softc *sc;
{
cb_transmit_t *cb;
tbd_t *tbd;
caddr_t tb;
int i;
DEBUGBEGIN(DEBUGINIT_TFA)
DEBUGDO(printf("\nix%d: ixinit_tfa\n", sc->sc_dev.dv_unit);)
DEBUGEND
/* build the list of cb's, tbd's and tb's */
cb = (cb_transmit_t *)(sc->sc_maddr + TFA_START);
tbd = (tbd_t *)(sc->sc_maddr +
TFA_START +
(TB_COUNT * sizeof(cb_transmit_t)));
tb = sc->sc_maddr + TFA_START +
(TB_COUNT * (sizeof(cb_transmit_t) + sizeof(tbd_t)));
sc->cb_head = (cb_t *)cb;
sc->tbd_head = tbd;
for (i = 0; i < TB_COUNT; i++, cb++, tbd++, tb += TB_SIZE) {
cb->common.status = 0;
cb->common.command = CB_CMD_NOP;
cb->common.next = KVTOBOARD(cb) + sizeof(cb_transmit_t);
cb->tbd_offset = KVTOBOARD(tbd);
/* ZZZ could bzero this, but just leave a note for now */
/* ZZZ bzero(cb->destination); */
cb->length = 0;
tbd->act_count = 0;
tbd->act_count = TBD_STAT_EOF;
tbd->next = KVTOBOARD(tbd) + sizeof(tbd_t);
tbd->buffer = KVTOBOARD(tb);
/*
* handle the boundary conditions here.
*/
if (i == TB_COUNT - 1) {
cb->common.command = CB_CMD_EL | CB_CMD_NOP;
cb->common.next = INTEL586NULL; /*RRR KVTOBOARD(sc->cb_head);*/
tbd->next = INTEL586NULL; /*RRR KVTOBOARD(sc->tbd_head);*/
}
}
sc->cb_tail = (cb_t *)(--cb);
sc->tbd_tail = (--tbd);
#ifdef IXDEBUG
DEBUGBEGIN(DEBUGINIT_TFA)
cb = (cb_transmit_t *)(sc->sc_maddr + TFA_START);
tbd = (tbd_t *)(sc->sc_maddr +
TFA_START +
(TB_COUNT * sizeof(cb_transmit_t)));
tb = sc->sc_maddr + TFA_START +
(TB_COUNT * (sizeof(cb_transmit_t) + sizeof(tbd_t)));
printf(" TB_COUNT = %d\n", TB_COUNT);
printf(" cb_head = %lx\t\tcb_tail = %lx\n",
kvtop(sc->cb_head), kvtop(sc->cb_tail));
printf(" tbd_head = %lx\t\ttbd_tail = %lx\n",
kvtop(sc->tbd_head), kvtop(sc->tbd_tail));
for (i = 0; i < TB_COUNT; i++, cb++, tbd++, tb += TB_SIZE) {
printf(" %d:\tcb = %lx\t\ttbd = %lx\t\ttb = %lx\n",
i, kvtop(cb), kvtop(tbd), kvtop(tb));
printf("\tcb->common.command = %x\n", cb->common.command);
printf("\tcb->common.next = %x\tcb->tbd_offset = %x\n",
cb->common.next, cb->tbd_offset);
printf("\ttbd->act_count = %x", tbd->act_count);
printf("\ttbd->next = %x", tbd->next);
printf("\ttbd->buffer = %lx\n\n",
tbd->buffer);
}
DEBUGEND
#endif /* IXDEBUG */
/*
* ZZZ need to add sanity check to see if last tb runs into
* the stuff after it in memory, this should not be possible
* but if someone screws up with the defines it can happen
*/
DEBUGBEGIN(DEBUGINIT_TFA)
DEBUGDO(printf (" next tb would be at %lx\n", kvtop(tb));)
DEBUGDO(printf("ix%d: ixinit_tfa exit\n", sc->sc_dev.dv_unit);)
DEBUGEND
}
int
ixintr(arg)
void *arg;
{
struct ix_softc *sc = arg;
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
scb_t *scb = (scb_t *)(sc->sc_maddr + SCB_ADDR);
int check_queue; /* flag to tell us to check the queue */
u_short status;
DEBUGBEGIN(DEBUGINTR)
DEBUGDO(printf("ixintr: ");)
DEBUGEND
if ((sc->flags & IXF_INITED) == 0) {
printf ("\n ixintr without being inited!!\n"); /* ZZZ */
ixinterrupt_disable(sc);
goto ixintr_exit;
}
if (ifp->if_flags & IFF_RUNNING == 0) {
printf("\n ixintr when device not running!!\n"); /* ZZZ */
ixinterrupt_disable(sc);
goto ixintr_exit;
}
/* The sequence, disable ints, status=ack must be done
* as quick as possible to avoid missing things */
ixinterrupt_disable(sc);
status = ixacknowledge(sc);
check_queue = 0;
while ((status & SCB_STAT_MASK) != 0) {
if (status & SCB_STAT_FR) {
ixintr_fr(sc);
}
if (status & SCB_STAT_CX) {
ixintr_cx(sc);
check_queue++;
}
if (status & SCB_STAT_CNA) {
DEBUGBEGIN(DEBUGINTR)
DEBUGDO(printf("cna:");)
DEBUGEND
}
if ((status & SCB_STAT_RNR) ||
((status & SCB_RUS_MASK) == SCB_RUS_NRSC)) {
DEBUGBEGIN(DEBUGINTR)
printf("RNR:"); /* ZZZ this means trouble */
DEBUGEND
IXCOUNTER(ifp->if_rnr++;)
ixinit_rfa(sc);
scb->status = SCB_STAT_NULL;
scb->command = SCB_RUC_START;
scb->rfa_offset = RFA_START;
ixchannel_attention(sc);
}
if (scb->status & SCB_STAT_MASK) {
status = ixacknowledge(sc);
} else {
status = 0;
}
}
ixinterrupt_enable(sc);
if (check_queue && ifp->if_snd.ifq_head != 0) {
ixstart(ifp); /* we have stuff on the queue */
}
ixintr_exit:
DEBUGBEGIN(DEBUGINTR)
DEBUGDO(printf(" ixintr exited\n");)
DEBUGEND
return(0 /* XXX Should be ??? */);
}
static inline void
ixintr_cx(sc)
struct ix_softc *sc;
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
cb_t *cb;
DEBUGBEGIN(DEBUGINTR_CX)
DEBUGDO(printf("cx:");)
DEBUGEND
cb = sc->cb_head;
do {
if (cb->status & CB_BUSY) {
IXCOUNTER(ifp->if_busy++;)
printf("ix.cx.busy"); /* This should never occur */
}
if (cb->status & CB_COMPLETE) {
IXCOUNTER(ifp->if_complete++;)
switch(cb->command & CB_CMD_MASK) {
case CB_CMD_NOP: { break; }
case CB_CMD_IAS: { break; }
case CB_CMD_CONF: { break; }
case CB_CMD_MCAS: { break; }
case CB_CMD_TRANSMIT: {
if (cb->status & CB_OK) {
ifp->if_opackets++;
IXCOUNTER(ifp->if_ok++;)
} else {
if (cb->status & CB_ABORT) {
IXCOUNTER(ifp->if_abort++;)
printf("ix.cx.abort");
}
if (cb->status & CB_LATECOLL) {
IXCOUNTER(ifp->if_latecoll++;)
printf("ix.cx.latecoll");
}
if (cb->status & CB_NOCS) {
IXCOUNTER(ifp->if_nocs++;)
printf("ix.cx.nocs");
}
if (cb->status & CB_NOCTS) {
IXCOUNTER(ifp->if_nocts++;)
printf("ix.cx.nocts");
}
if (cb->status & CB_DMAUNDER) {
IXCOUNTER(ifp->if_dmaunder++;)
printf("ix.cx.dmaunder");
}
if (cb->status & CB_DEFER) {
IXCOUNTER(ifp->if_defer++;)
printf("ix.cx.defer");
}
if (cb->status & CB_HEARTBEAT) {
IXCOUNTER(ifp->if_heartbeat++;)
printf("ix.cx.heartbeat");
}
if (cb->status & CB_EXCESSCOLL) {
IXCOUNTER(ifp->if_excesscoll++;)
printf("ix.cx.excesscoll");
}
ifp->if_oerrors++;
}
ifp->if_collisions += cb->status & CB_COLLISIONS;
ifp->if_timer = 0; /* clear watchdog timeout */
break;
}
case CB_CMD_TDR: { break; }
case CB_CMD_DUMP: { break; }
case CB_CMD_DIAGNOSE: { break; }
default: { break; }
}
ixintr_cx_free(sc, cb);
} else {
}
if (cb->next == INTEL586NULL) {
break;
} else {
cb = (cb_t *)BOARDTOKV(cb->next);
}
}
while (1);
/*
* clear the IFF_OACTIVE flag because the CU should now be
* idle, this only holds true as long as the last CB is the
* only one with the CB_CMD_INT bit set. If the start routine
* violates this rule this code well have to change.
*/
ifp->if_flags &= ~IFF_OACTIVE;
}
static inline void
ixintr_cx_free(sc, cb)
struct ix_softc *sc;
cb_t *cb;
{
DEBUGBEGIN(DEBUGINTR_CX)
DEBUGDO(printf("cb=%x:cb->status=%x:", KVTOBOARD(cb), cb->status);)
DEBUGEND
/*1*/ cb->command = CB_CMD_EL | CB_CMD_NOP;
/*2*/ cb->status = 0;
}
static inline void
ixintr_fr(sc)
struct ix_softc *sc;
{
DEBUGBEGIN(DEBUGINTR_FR)
DEBUGDO(printf("fr:");)
DEBUGEND
/* find each frame in the rfa and copy it up, then free it */
while ((sc->rfd_head->status & (RFD_COMPLETE | RFD_BUSY)) == RFD_COMPLETE) {
ixintr_fr_copy(sc, sc->rfd_head);
ixintr_fr_free(sc, sc->rfd_head);
}
}
static inline void
ixintr_fr_copy(sc, rfd)
struct ix_softc *sc;
rfd_t *rfd;
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
rbd_t *rbd;
caddr_t rb;
struct mbuf *m0, *m;
struct ether_header *eh;
int length,
bytesleft;
rbd = (rbd_t *)(sc->sc_maddr + rfd->rbd_offset);
rb = (caddr_t)(sc->sc_maddr + rbd->buffer);
DEBUGBEGIN(DEBUGINTR_FR)
DEBUGDO(int i;)
DEBUGDO(printf("rfd=%x:", KVTOBOARD(rfd));)
DEBUGDO(printf("rfd->status=%x:", rfd->status);)
DEBUGDO(printf("rbd->act_count=%x:", rbd->act_count);)
DEBUGDO(printf("data=");)
DEBUGDO(for (i = 0; i < 16; i ++) printf ("%02x", rb[i] & 0xFF);)
DEBUGDO(printf(":");)
DEBUGEND
/* trickery here, eh points right at memory on
* the board. eh is only used by ether_input,
* it is not passed to the upper layer */
eh = (struct ether_header *)rb;
/* here we go, lets build an mbuf chain up to hold all this */
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == 0) {
printf ("MGETHDR:"); /* ZZZ need to add drop counters */
return;
}
m0 = m;
length = rbd->act_count & RBD_STAT_SIZE;
bytesleft = length - sizeof(struct ether_header);
rb += sizeof(struct ether_header);
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = bytesleft;
m->m_len = MHLEN;
while (bytesleft > 0) {
if (bytesleft > MINCLSIZE) {
MCLGET(m, M_DONTWAIT);
if (m->m_flags & M_EXT) {
m->m_len = MCLBYTES;
} else {
printf ("MCLGET:");
m_freem(m0); /* ZZZ need to add drop counters */
return;
}
}
m->m_len = min(m->m_len, bytesleft);
bcopy(rb, mtod(m, caddr_t), m->m_len);
rb += m->m_len;
bytesleft -= m->m_len;
if (bytesleft > 0) {
MGET(m->m_next, M_DONTWAIT, MT_DATA);
if (m->m_next == 0) {
printf ("MGET");
m_freem(m0); /* ZZZ need to add drop counters */
return;
}
m = m->m_next;
m->m_len = MLEN;
}
}
ether_input(ifp, eh, m0);
ifp->if_ipackets++;
return;
}
static inline void
ixintr_fr_free(sc, rfd)
struct ix_softc *sc;
rfd_t *rfd;
{
rbd_t *rbd;
rbd = (rbd_t *)(sc->sc_maddr + rfd->rbd_offset);
/* XXX this still needs work, does not handle chained rbd's */
/*1*/ rbd->act_count = 0;
/*2*/ rbd->size = RBD_SIZE_EL | RB_SIZE;
/*3*/ sc->rbd_tail->size = RB_SIZE;
/*4*/ sc->rbd_tail = rbd;
/* Free the rfd buy putting it back on the rfd queue */
/*1*/ rfd->command = RFD_CMD_EL | RFD_CMD_SUSP;
/*2*/ rfd->status = 0;
/*3*/ rfd->rbd_offset = INTEL586NULL;
/*4*/ sc->rfd_head = (rfd_t *)BOARDTOKV(rfd->next);
/*5*/ sc->rfd_tail->command &= ~(RFD_CMD_EL | RFD_CMD_SUSP);
/*6*/ sc->rfd_tail = rfd;
}
/* Psuedo code:
* Do consistency check:
* IFF_UP should be set.
* IFF_RUNNING should be set.
* IFF_OACTIVE should be clear.
* ifp->snd.ifq_head should point to an MBUF
* I82586 CU should be in the idle state.
* All cb's should have CUC = NOP.
* The real work:
* while there are packets to send & free cb's do:
* build a cb, tbd, and tb
* copy the MBUF chain to a tb
* setup the scb for a start CU
* start the CU
* set IFF_OACTIVE
* set ifp->if_timer for watchdog timeout
* Exit:
*/
void
ixstart(struct ifnet *ifp) {
struct ix_softc *sc = ixcd.cd_devs[ifp->if_unit];
scb_t *scb = (scb_t *)BOARDTOKV(SCB_ADDR);
cb_t *cb = sc->cb_head;
tbd_t *tbd;
caddr_t tb;
struct mbuf *m, *m_temp;
u_short length;
IXCOUNTER(int queued;)
DEBUGBEGIN(DEBUGSTART)
DEBUGDO(printf("ixstart:");)
DEBUGEND
/* check that if is up and running */
if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) {
goto ixstart_exit;
}
/* check to see that we are not already active */
if ((ifp->if_flags & IFF_OACTIVE) == IFF_OACTIVE) {
goto ixstart_exit;
}
/* check that there are packets to send */
if (ifp->if_snd.ifq_head == 0) {
goto ixstart_exit;
}
/* check that the command unit is idle */
if ((scb->status & SCB_CUS_MASK) != SCB_CUS_IDLE) {
goto ixstart_exit;
}
/* check that all cb's on the list are free */
#ifdef THISDONTDONOTHING
cb = sc->cb_head;
IXCOUNTER(ifp->if_could_queue = 0;)
do {
/* XXX this does nothing right now! */
DEBUGBEGIN(DEBUGSTART)
DEBUGDO(printf("chk_cb=%x:", KVTOBOARD(cb));)
DEBUGEND
IXCOUNTER(ifp->if_could_queue++;)
if (cb->next == INTEL586NULL) {
break;
} else {
cb = (cb_t *)BOARDTOKV(cb->next);
}
}
while (1);
#endif /* THISDONTDONOTHING */
/* build as many cb's as we can */
IXCOUNTER(queued = 0;)
cb = sc->cb_head;
do {
cb->status = 0;
cb->command = CB_CMD_TRANSMIT;
tbd = (tbd_t *)BOARDTOKV(((cb_transmit_t *)cb)->tbd_offset);
tb = (caddr_t)BOARDTOKV(tbd->buffer);
DEBUGBEGIN(DEBUGSTART)
DEBUGDO(printf("cb=%x:", KVTOBOARD(cb));)
DEBUGDO(printf("tbd=%x:", KVTOBOARD(tbd));)
DEBUGDO(printf("tb=%x:", KVTOBOARD(tb));)
DEBUGEND
IF_DEQUEUE(&ifp->if_snd, m);
length = 0;
for (m_temp = m; m_temp != 0; m_temp = m_temp->m_next) {
bcopy(mtod(m_temp, caddr_t), tb, m_temp->m_len);
tb += m_temp->m_len;
length += m_temp->m_len;
}
m_freem(m);
if (length < ETHER_MIN_LENGTH) length = ETHER_MIN_LENGTH;
#ifdef DIAGNOSTIC
if (length > ETHER_MAX_LENGTH) {
/* XXX
* This should never ever happen, if it does
* we probable screwed up all sorts of board data
* in the above bcopy's and should probably shut
* down, but for now just issue a warning that
* something is real wrong
*/
printf("ix%d: ixstart: Packet length=%d > MTU=%d\n",
ifp->if_unit, length, ETHER_MAX_LENGTH);
}
#endif /* DIAGNOSTIC */
tbd->act_count = TBD_STAT_EOF | length;
IXCOUNTER(queued++;)
/* check to see if we have used the last cb */
if (cb->next == INTEL586NULL) {
IXCOUNTER(ifp->if_filled_queue++;)
break;
} else {
cb = (cb_t *)BOARDTOKV(cb->next);
}
} while (ifp->if_snd.ifq_head != 0);
IXCOUNTER(ifp->if_high_queue = max(ifp->if_high_queue, queued);)
/* set the end of list and interrupt bits in the last cb */
cb->command |= (CB_CMD_EL | CB_CMD_INT);
/* build the scb */
scb->status = SCB_STAT_NULL;
scb->command = SCB_CUC_START;
scb->cbl_offset = KVTOBOARD(sc->cb_head);/* This should not be needed */
/* start the cu */
ixchannel_attention(sc);
/* mark the interface as having output active */
ifp->if_flags |= IFF_OACTIVE;
/*
* set the watchdog timer so that if the board fails to interrupt
* we will go clean up
*/
ifp->if_timer = 2;
ixstart_exit:
DEBUGBEGIN(DEBUGSTART)
DEBUGDO(printf("ixstart exited\n");)
DEBUGEND
return;
}
int
ixstop(struct ifnet *ifp) {
struct ix_softc *sc = ixcd.cd_devs[ifp->if_unit];
DEBUGBEGIN(DEBUGSTOP)
DEBUGDO(printf("ixstop:");)
DEBUGEND
/* XXX Need to find out what spl we are at, and maybe add splx */
ifp->if_flags &= ~IFF_RUNNING;
ixinterrupt_disable(sc);
/* force the 82586 reset pin high */
outb(sc->sc_iobase + ee_ctrl, I586_RESET);
DEBUGBEGIN(DEBUGSTOP)
DEBUGDO(printf("ixstop exiting\n");)
DEBUGEND
return(0);
}
int
ixioctl(struct ifnet *ifp, u_long cmd, caddr_t data) {
struct ix_softc *sc = ixcd.cd_devs[ifp->if_unit];
int status = 0;
DEBUGBEGIN(DEBUGIOCTL)
DEBUGDO(printf("ixioctl:");)
DEBUGEND
switch(cmd) {
case SIOCSIFADDR: {
struct ifaddr *ifa = (struct ifaddr *)data;
if (ifp->if_flags & IFF_RUNNING) ixstop(ifp);
ifp->if_flags |= IFF_UP;
ixinit(sc);
switch(ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET: {
arp_ifinit((struct arpcom *)ifp, ifa);
break;
}
#endif /* INET */
#ifdef NS
case AF_NS: {
/*ZZZ*/printf("Address family NS not supported by ixioctl\n");
break;
}
#endif /* NS */
default: {
DEBUGBEGIN(DEBUGIOCTL)
DEBUGDO(printf("Unknow Address Family in ixioctl\n");)
DEBUGEND
status = EINVAL;
break;
}
}
break;
}
case SIOCSIFFLAGS: {
if (((ifp->if_flags & IFF_UP) == 0) &&
(ifp->if_flags & IFF_RUNNING)) {
ixstop(ifp);
}
else if ((ifp->if_flags & IFF_UP) &&
((ifp->if_flags & IFF_RUNNING) == 0)) {
ixinit(sc);
}
break;
}
default: {
DEBUGBEGIN(DEBUGIOCTL)
DEBUGDO(printf("Unknown cmd in ixioctl\n");)
DEBUGEND
status = EINVAL;
break;
}
}
DEBUGBEGIN(DEBUGIOCTL)
DEBUGDO(printf("ixioctl exit\n");)
DEBUGEND
return(status);
}
void
ixreset(sc)
struct ix_softc *sc;
{
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
int s;
s = splimp();
DEBUGBEGIN(DEBUGRESET)
DEBUGDO(printf("ixreset:");)
DEBUGEND
ixstop(ifp);
ixinit(sc);
DEBUGBEGIN(DEBUGRESET)
DEBUGDO(printf("ixreset exit\n");)
DEBUGEND
(void) splx(s);
return;
}
/*
* The ixwatchdog routine gets called if the transmitter failed to interrupt
* within ifp->if_timer XXXseconds. The interrupt service routine must reset
* ifp->if_timer to 0 after an transmitter interrupt occurs to stop the
* watchdog from happening.
*/
void
ixwatchdog(unit)
int unit;
{
struct ix_softc *sc = ixcd.cd_devs[unit];
log(LOG_ERR, "ix%d: device timeout\n", unit);
sc->sc_arpcom.ac_if.if_oerrors++;
ixreset(sc);
}
u_short
ixeeprom_read(sc, location)
struct ix_softc *sc;
int location;
{
int eeprom_control,
data;
int iobase = sc->sc_iobase;
eeprom_control = inb(iobase + ee_ctrl);
eeprom_control &= 0xB2; /* XXX fix 0xB2 */
eeprom_control |= EECS;
outb(iobase + ee_ctrl, eeprom_control);
ixeeprom_outbits(sc, eeprom_read_op, eeprom_opsize1);
ixeeprom_outbits(sc, location, eeprom_addr_size);
data = ixeeprom_inbits(sc);
eeprom_control = inb(iobase + ee_ctrl);
eeprom_control &= ~(GA_RESET | EEDI | EECS);
outb(iobase + ee_ctrl, eeprom_control);
ixeeprom_clock(sc, 1);
ixeeprom_clock(sc, 0);
return(data);
}
void
ixeeprom_outbits(sc, data, count)
struct ix_softc *sc;
int data, count;
{
int eeprom_control,
i;
int iobase = sc->sc_iobase;
eeprom_control = inb(iobase + ee_ctrl);
eeprom_control &= ~GA_RESET;
for(i=count-1; i>=0; i--) {
eeprom_control &= ~EEDI;
if (data & (1 << i)) {
eeprom_control |= EEDI;
}
outb(iobase + ee_ctrl, eeprom_control);
DELAY(1); /* eeprom data must be setup for 0.4 uSec */
ixeeprom_clock(sc, 1);
ixeeprom_clock(sc, 0);
}
eeprom_control &= ~EEDI;
outb(iobase + ee_ctrl, eeprom_control);
DELAY(1); /* eeprom data must be held for 0.4 uSec */
}
int
ixeeprom_inbits(sc)
struct ix_softc *sc;
{
int eeprom_control,
data,
i;
int iobase = sc->sc_iobase;
eeprom_control = inb(iobase + ee_ctrl);
eeprom_control &= ~GA_RESET;
for(data=0, i=0; i<16; i++) {
data = data << 1;
ixeeprom_clock(sc, 1);
eeprom_control = inb(iobase + ee_ctrl);
if (eeprom_control & EEDO) {
data |= 1;
}
ixeeprom_clock(sc, 0);
}
return(data);
}
void
ixeeprom_clock(sc, state)
struct ix_softc *sc;
int state;
{
int eeprom_control;
int iobase = sc->sc_iobase;
eeprom_control = inb(iobase + ee_ctrl);
eeprom_control &= ~(GA_RESET | EESK);
if (state) {
eeprom_control = eeprom_control | EESK;
}
outb(iobase + ee_ctrl, eeprom_control);
DELAY(9); /* EESK must be stable for 8.38 uSec */
}
-----cut here-----
/*
* Copyright (c) 1993, 1994, 1995
* Rodney W. Grimes, Milwaukie, Oregon 97222. 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 as
* the first lines of this file unmodified.
* 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 Rodney W. Grimes.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY RODNEY W. GRIMES ``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 RODNEY W. GRIMES 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.
*
* $Id: if_ixreg.h,v 1.6 1995/05/30 08:02:17 rgrimes Exp $
*/
/*
* These really belong some place else, but I can't find them right
* now. I'll look again latter
*/
#define ETHER_ADDRESS_LENGTH 6 /* Length of an ethernet address */
#define ETHER_HEADER_LENGTH 14 /* Length of an ethernet header */
#define ETHER_DATA_LENGTH ETHERMTU
#define ETHER_CRC_LENGTH 4
#define ETHER_MIN_LENGTH 64 /* Minimum length of an ethernet packet */
#define ETHER_MAX_LENGTH (ETHER_HEADER_LENGTH + \
ETHERMTU + \
ETHER_CRC_LENGTH)
#define IX_IO_PORTS 16 /* Number of I/O ports used, note
* this is not true, due to shadow
* ports at 400X,800X and C00X
*/
#define dxreg 0x00 /* Data transfer register Word R/W */
#define wrptr 0x02 /* Write address pointer Word R/W */
#define rdptr 0x04 /* Read address pointer Word R/W */
#define ca_ctrl 0x06 /* Channel attention control Byte R/W */
#define sel_irq 0x07 /* IRQ select Byte R/W */
#define IRQ_ENABLE 0x08 /* Enable board interrupts */
#define smb_ptr 0x08 /* Shadow memory bank pointer Word R/W */
#define memdec 0x0A /* Memory address decode Byte W */
#define memctrl 0x0B /* Memory mapped control Byte R/W */
#define MEMCTRL_UNUSED 0x83 /* Unused bits */
#define MEMCTRL_MEMMEG 0x60 /* Which megabyte of memory, 0, E or F */
#define MEMCTRL_FMCS16 0x10 /* MEMCS16- for F000 */
#define MEMCTRL_MEMADJ 0xC0 /* memory adjust value */
#define mempc 0x0C /* MEMCS16- page control Byte R/W */
#define config 0x0D /* Configuration, test Byte R/W */
#define BART_LINK 0x01 /* link integrity active, TPE */
#define BART_LOOPBACK 0x02 /* Loopback, 0=none, 1=loopback */
#define SLOT_WIDTH 0x04 /* 0 = 8bit, 1 = 16bit */
#define BART_USEWIDTH 0x08 /* use SLOT_WIDTH for bus size */
#define BART_IOCHRDY_LATE 0x10 /* iochrdy late control bit */
#define BART_IO_TEST_EN 0x20 /* enable iochrdy timing test */
#define BART_IO_RESULT 0x40 /* result of the iochrdy test */
#define BART_MCS16_TEST 0x80 /* enable memcs16 select test */
#define ee_ctrl 0x0E /* EEPROM control, reset Byte R/W */
#define EENORMAL 0x00 /* normal state of ee_ctrl */
#define EESK 0x01 /* EEPROM clock bit */
#define EECS 0x02 /* EEPROM chip select */
#define EEDI 0x04 /* EEPROM data in bit (write EEPROM) */
#define EEDO 0x08 /* EEPROM data out bit (read EEPROM) */
#define EEUNUSED 0x30 /* unused bits in ee_ctrl */
#define GA_RESET 0x40 /* BART ASIC chip reset pin */
#define I586_RESET 0x80 /* 82586 chip reset pin */
#define memectrl 0x0F /* Memory control, E000h seg Byte W */
#define autoid 0x0F /* Auto ID register Byte R */
#define BOARDID 0xBABA /* Intel PCED board ID for EtherExpress */
#define eeprom_opsize1 0x03 /* Size of opcodes for r/w/e */
#define eeprom_read_op 0x06 /* EEPROM read op code */
#define eeprom_write_op 0x05 /* EEPROM write op code */
#define eeprom_erase_op 0x07 /* EEPROM erase op code */
#define eeprom_opsize2 0x05 /* Size of opcodes for we/wdr */
#define eeprom_wenable_op 0x13 /* EEPROM write enable op code */
#define eeprom_wdisable_op 0x10 /* EEPROM write disable op code */
#define eeprom_addr_size 0x06 /* Size of EEPROM address */
/* These are the locations in the EEPROM */
#define eeprom_config1 0x00 /* Configuration register 1 */
#define CONNECT_BNCTPE 0x1000 /* 0 = AUI, 1 = BNC/TPE */
#define IRQ 0xE000 /* Encoded IRQ */
#define IRQ_SHIFT 13 /* To shift IRQ to lower bits */
#define eeprom_lock_address 0x01 /* contains the lock bit */
#define EEPROM_LOCKED 0x01 /* means that it is locked */
#define eeprom_enetaddr_low 0x02 /* Ethernet address, low word */
#define eeprom_enetaddr_mid 0x03 /* Ethernet address, middle word */
#define eeprom_enetaddr_high 0x04 /* Ethernet address, high word */
#define eeprom_config2 0x05 /* Configureation register 2 */
#define CONNECT_TPE 0x0001 /* 0 = BNC, 1 = TPE */
/* this converts a kernal virtual address to a board offset */
#define KVTOBOARD(addr) ((int)addr - (int)sc->sc_maddr)
#define BOARDTOKV(addr) ((int)addr + (int)sc->sc_maddr)
/* XXX This belongs is ic/i825x6.h, but is here for editing for now */
#define INTEL586NULL 0xFFFF /* NULL pointer for 82586 */
#define INTEL596NULL 0xFFFFFFFF /* NULL pointer for 82596 */
/*
* Layout of memory for the 825x6 chip:
* Low: Control Blocks
* Transmit Frame Descriptor(s)
* Transmit Frame Buffer(s)
* Receive Frame Descriptors
* Receive Frames
* SCB_ADDR System Control Block
* ISCP_ADDR Intermediate System Configuration Pointer
* High: SCP_ADDR System Configuration Pointer
*/
#define SCP_ADDR (sc->sc_msize - sizeof(scp_t))
#define ISCP_ADDR (SCP_ADDR - sizeof(iscp_t))
#define SCB_ADDR (ISCP_ADDR - sizeof(scb_t))
#define TB_COUNT 3 /* How many transfer buffers in the TFA */
#define TB_SIZE (ETHER_MAX_LENGTH) /* size of transmit buffer */
#define TFA_START 0x0000 /* Start of the TFA */
#define TFA_SIZE (TB_COUNT * \
(sizeof(cb_transmit_t) + sizeof(tbd_t) + TB_SIZE))
#define RFA_START (TFA_SIZE)
#define RFA_SIZE (SCP_ADDR - RFA_START)
#define RB_SIZE (ETHER_MAX_LENGTH) /* size of receive buffer */
typedef struct /* System Configuration Pointer */
{
u_short unused1; /* should be zeros for 82596 compatibility */
u_short sysbus; /* width of the 82586 data bus 0=16, 1=8 */
u_short unused2; /* should be zeros for 82596 compatibility */
u_short unused3; /* should be zeros for 82596 compatibility */
u_long iscp; /* iscp address (24bit 586, 32bit 596) */
} scp_t;
typedef struct /* Intermediate System Configuration Pointer */
{
volatile
u_short busy; /* Set to 1 by host before its first CA,
cleared by 82586 after reading */
#define ISCP_BUSY 0x01 /* 82586 is busy reading the iscp */
u_short scb_offset; /* Address of System Control Block */
u_long scb_base; /* scb base address (24bit 586, 32bit 596) */
} iscp_t;
typedef struct /* System Control Block */
{
volatile
u_short status; /* status bits */
#define SCB_RUS_MASK 0x0070 /* receive unit status mask */
#define SCB_RUS_IDLE 0x0000 /* receive unit status idle */
#define SCB_RUS_SUSP 0x0010 /* receive unit status suspended */
#define SCB_RUS_NRSC 0x0020 /* receive unit status no resources */
#define SCB_RUS_READY 0x0040 /* receive unit status ready */
#define SCB_CUS_MASK 0x0700 /* command unit status mask */
#define SCB_CUS_IDLE 0x0000 /* command unit status idle */
#define SCB_CUS_SUSP 0x0100 /* command unit status suspended */
#define SCB_CUS_ACT 0x0200 /* command unit status active */
#define SCB_STAT_MASK 0xF000 /* command unit status mask */
#define SCB_STAT_RNR 0x1000 /* receive unit left the ready state */
#define SCB_STAT_CNA 0x2000 /* command unit left the active state */
#define SCB_STAT_FR 0x4000 /* the ru finished receiving a frame */
#define SCB_STAT_CX 0x8000 /* the cu finished executing a command
with its I (interrupt) bit set */
#define SCB_STAT_NULL 0x0000 /* used to clear the status work */
u_short command; /* command bits */
#define SCB_RUC_MASK 0x0070 /* receive unit command mask */
#define SCB_RUC_NOP 0x0000 /* receive unit command nop */
#define SCB_RUC_START 0x0010 /* receive unit command start */
#define SCB_RUC_RESUME 0x0020 /* receive unit command resume */
#define SCB_RUC_SUSP 0x0030 /* receive unit command suspend */
#define SCB_RUC_ABORT 0x0040 /* receive unit command abort */
#define SCB_RESET 0x0080 /* reset the chip, same as hardware reset */
#define SCB_CUC_MASK 0x0700 /* command unit command mask */
#define SCB_CUC_NOP 0x0000 /* command unit command nop */
#define SCB_CUC_START 0x0100 /* start execution of the first command */
#define SCB_CUC_RESUME 0x0200 /* resume execution of the next command */
#define SCB_CUC_SUSP 0x0300 /* suspend execution after the current command */
#define SCB_CUC_ABORT 0x0400 /* abort execution of the current command */
#define SCB_ACK_MASK 0xF000 /* command unit acknowledge mask */
#define SCB_ACK_RNR 0x1000 /* ack receive unit left the ready state */
#define SCB_ACK_CNA 0x2000 /* ack command unit left the active state */
#define SCB_ACK_FR 0x4000 /* ack the ru finished receiving a frame */
#define SCB_ACK_CX 0x8000 /* ack the cu finished executing a command
with its I (interrupt) bit set */
u_short cbl_offset; /* first command block on the cbl */
u_short rfa_offset; /* receive frame area */
volatile
u_short crc_errors; /* frame was aligned, but bad crc */
volatile
u_short aln_errors; /* frame was not aligned, and had bad crc */
volatile
u_short rsc_errors; /* did not have resources to receive */
volatile
u_short ovr_errors; /* system bus was not availiable to receive */
} scb_t;
typedef struct /* command block - nop (also the common part of cb's */
{
volatile
u_short status; /* status bits */
#define CB_COLLISIONS 0x000F /* the number of collisions that occured */
#define CB_BIT4 0x0010 /* reserved by intel */
#define CB_EXCESSCOLL 0x0020 /* the number of collisions > MAX allowed */
#define CB_HEARTBEAT 0x0040 /* */
#define CB_DEFER 0x0080 /* had to defer due to trafic */
#define CB_DMAUNDER 0x0100 /* dma underrun */
#define CB_NOCTS 0x0200 /* lost clear to send */
#define CB_NOCS 0x0400 /* lost carrier sense */
#define CB_LATECOLL 0x0800 /* late collision occured (82596 only) */
#define CB_ABORT 0x1000 /* command was aborted by CUC abort command */
#define CB_OK 0x2000 /* command executed without error */
#define CB_BUSY 0x4000 /* command is being executed */
#define CB_COMPLETE 0x8000 /* command completed */
u_short command; /* command bits */
#define CB_CMD_MASK 0x0007 /* command mask */
#define CB_CMD_NOP 0x0000 /* nop command */
#define CB_CMD_IAS 0x0001 /* individual address setup command */
#define CB_CMD_CONF 0x0002 /* configure command */
#define CB_CMD_MCAS 0x0003 /* multicast address setup command */
#define CB_CMD_TRANSMIT 0x0004 /* transmit command */
#define CB_CMD_TDR 0x0005 /* time domain reflectometry command */
#define CB_CMD_DUMP 0x0006 /* dump command */
#define CB_CMD_DIAGNOSE 0x0007 /* diagnose command */
#define CB_CMD_INT 0x2000 /* interrupt when command completed */
#define CB_CMD_SUSP 0x4000 /* suspend CU when command completed */
#define CB_CMD_EL 0x8000 /* end of the command block list */
u_short next; /* pointer to the next cb */
} cb_t;
typedef struct /* command block - individual address setup command */
{
cb_t common; /* common part of all command blocks */
u_char source[ETHER_ADDRESS_LENGTH];
/* ethernet hardware address */
} cb_ias_t;
typedef struct /* command block - configure command */
{
cb_t common; /* common part of all command blocks */
u_char byte[12]; /* ZZZ this is ugly, but it works */
} cb_configure_t;
typedef struct /* command block - multicast address setup command */
{
cb_t common; /* common part of all command blocks */
} cb_mcas_t;
typedef struct /* command block - transmit command */
{
cb_t common; /* common part of all command blocks */
u_short tbd_offset; /* transmit buffer descriptor offset */
u_char destination[ETHER_ADDRESS_LENGTH];
/* ethernet destination address field */
u_short length; /* ethernet length field */
u_char byte[16]; /* XXX stupid fill tell I fix the ixinit
* code for the special cb's */
} cb_transmit_t;
typedef struct /* command block - tdr command */
{
cb_t common; /* common part of all command blocks */
} cb_tdr_t;
typedef struct /* command block - dump command */
{
cb_t common; /* common part of all command blocks */
} cb_dump_t;
typedef struct /* command block - diagnose command */
{
cb_t common; /* common part of all command blocks */
} cb_diagnose_t;
typedef struct /* Transmit Buffer Descriptor */
{
volatile
u_short act_count; /* size of buffer actual count of valid bytes */
#define TBD_STAT_EOF 0x8000 /* end of frame */
u_short next; /* pointer to the next tbd */
u_long buffer; /* transmit buffer address (24bit 586, 32bit 596) */
} tbd_t;
typedef struct /* Receive Frame Descriptor */
{
volatile
u_short status; /* status bits */
#define RFD_BUSY 0x4000 /* frame is being received */
#define RFD_COMPLETE 0x8000 /* this frame is complete */
u_short command; /* command bits */
#define RFD_CMD_SUSP 0x4000 /* suspend the ru after this rfd is used */
#define RFD_CMD_EL 0x8000 /* end of the rfd list */
u_short next; /* pointer to the next rfd */
u_short rbd_offset; /* pointer to the first rbd for this frame */
u_char destination[6]; /* ethernet destination address */
u_char source[6]; /* ethernet source address */
u_short length; /* ethernet length field */
} rfd_t;
typedef struct /* Receive Buffer Descriptor */
{
volatile
u_short act_count; /* Actual Count (size) and status bits */
#define RBD_STAT_SIZE 0x3FFF /* size mask */
#define RBD_STAT_VALID 0x4000 /* act_count field is valid */
#define RBD_STAT_EOF 0x8000 /* end of frame */
u_short next; /* pointer to the next rbd */
u_long buffer; /* receive buffer address */
u_short size; /* size of buffer in bytes, must be even */
#define RBD_SIZE_EL 0x8000 /* end of rbd list */
} rbd_t;
/*
* Ethernet software status per interface.
*
* Each interface is referenced by a network interface structure,
* arpcom.ac_if, which the routing code uses to locate the interface.
* This structure contains the output queue for the interface, its address, ...
*/
struct ix_softc {
struct device sc_dev;
void *sc_ih;
struct arpcom sc_arpcom; /* ethernet common */
int sc_iobase;
caddr_t sc_maddr;
u_int sc_msize;
int flags; /* Software state */
#define IXF_NONE 0x00000000 /* Clear all flags */
#define IXF_INITED 0x00000001 /* Device has been inited */
#define IXF_BPFATTACHED 0x80000000 /* BPF has been attached */
int connector; /* Type of connector used on board */
#define AUI 0x00 /* Using AUI connector */
#define BNC 0x01 /* Using BNC connector */
#define TPE 0x02 /* Using TPE connector */
u_short irq_encoded; /* Encoded interrupt for use on bart */
int width; /* Width of slot the board is in, these
* constants are defined to match what
* the 82586/596 wants in scp->sysbus */
#define WIDTH_8 0x01 /* 8-bit slot */
#define WIDTH_16 0x00 /* 16-bit slot */
cb_t *cb_head; /* head of cb list */
cb_t *cb_tail; /* tail of cb list */
tbd_t *tbd_head; /* head of the tbd list */
tbd_t *tbd_tail; /* tail of the tbd list */
rfd_t *rfd_head; /* head of the rfd list */
rfd_t *rfd_tail; /* tail of the rfd list */
rbd_t *rbd_head; /* head of the rbd list */
rbd_t *rbd_tail; /* tail of the rbd list */
};
-----cut here-----
That's it!
>Audit-Trail:
>Unformatted: