diff options
Diffstat (limited to 'chips/lance.c')
-rw-r--r-- | chips/lance.c | 1570 |
1 files changed, 0 insertions, 1570 deletions
diff --git a/chips/lance.c b/chips/lance.c deleted file mode 100644 index 750d4c57..00000000 --- a/chips/lance.c +++ /dev/null @@ -1,1570 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1993-1989 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ -/* - * File: lance.c - * Author: Robert V. Baron & Alessandro Forin - * Date: 5/90 - * - * Driver for the DEC LANCE Ethernet Controller. - */ - -/* - - Byte ordering issues. - - The lance sees data naturally as half word (16 bit) quantitites. - Bit 2 (BSWP) in control register 3 (CSR3) controls byte swapping. - To quote the spec: - - 02 BSWP BYTE SWAP allows the chip to - operate in systems that consdier bits (15:08) of data pointers - by an even addressa and bits (7:0) to be pointed by an - odd address. - - When BSWP=1, the chip will swap the high and low bytes on DMA - data transfers between the silo and bus memory. Only data from - silo transfers is swapped; the Initialization Block data and - the Descriptor Ring entries are NOT swapped. (emphasis theirs) - - - So on systems with BYTE_MSF=1, the BSWP bit should be set. Note, - however, that all shorts in the descriptor ring and initialization - block need to be swapped. The BITFIELD macros in lance.h handle this - magic. - -*/ - -#include <ln.h> -#if NLN > 0 -#include <platforms.h> - -/* - * AMD Am7990 LANCE (Ethernet Interface) - */ -#include <sys/ioctl.h> -#include <vm/vm_kern.h> - -#include <machine/machspl.h> /* spl definitions */ -#include <kern/time_out.h> -#include <sys/syslog.h> -#include <ipc/ipc_port.h> -#include <ipc/ipc_kmsg.h> - -#include <device/device_types.h> -#include <device/errno.h> -#include <device/io_req.h> -#include <device/if_hdr.h> -#include <device/if_ether.h> -#include <device/net_status.h> -#include <device/net_io.h> - -#ifdef FLAMINGO -#define se_reg_type unsigned int -#endif - -#include <chips/lance.h> -#include <chips/busses.h> - -#define private static -#define public - -typedef struct se_softc *se_softc_t; /* move above prototypes */ - -void se_write_reg(); /* forwards */ -void se_read(); -void se_rint(); -void se_tint(); - -private vm_offset_t se_Hmem_nogap(), se_Hmem_gap16(); -private vm_offset_t se_malloc(); - - -/* This config section should go into a separate file */ - -#ifdef LUNA88K -# include <luna88k/board.h> -# define MAPPED 1 - #undef bcopy - extern void bcopy(), bzero(); - -#define wbflush() -#define Hmem(lna) (vm_offset_t)((lna) + sc->lnbuf) -#define Lmem(lna) (vm_offset_t)((lna) + sc->lnoffset) - -#define SPACE (TRI_PORT_RAM_SPACE>>1) -private struct se_switch se_switch[] = { - { LANCE_ADDR - TRI_PORT_RAM, /* pointer */ - SPACE /* host side */, - SPACE /* lance side */, - - TRI_PORT_RAM, - 0, /* romstride */ - 0, /* ramstride */ - SPACE, - /* desc_copyin */ bcopy, - /* desc_copyout */ bcopy, - /* data_copyin */ bcopy, - /* data_copyout */ bcopy, - /* bzero */ bzero, - /* mapaddr */ se_Hmem_nogap, - /* mapoffs */ se_Hmem_nogap - }, -}; - -#endif - -#ifdef DECSTATION -#include <mips/mips_cpu.h> -#include <mips/PMAX/pmad_aa.h> - -#define MAPPED 1 - -/* - * The LANCE buffer memory as seen from the Pmax cpu is funny. - * It is viewed as short words (16bits), spaced at word (32bits) - * intervals. The same applies to the registers. From the LANCE - * point of view memory is instead contiguous. - * The ROM that contains the station address is in the space belonging - * to the clock/battery backup memory. This space is again 16 bits - * in a 32bit envelope. And the ether address is stored in the "high" - * byte of 6 consecutive quantities. - * - * But Pmaxen and 3maxen (and..) map lance space differently. - * This requires dynamic adaptation of the driver, which - * is done via the following switches. - * For convenience, the switch holds information about - * the location of the lance control registers as well. - * This could be either absolute (pmax) or relative to - * some register base (3max, turbochannel) - */ -void copyin_gap16(), copyout_gap16(), bzero_gap16(); -extern void bcopy(), bzero(); -void copyin_gap32(), copyout_gap32(); - -private struct se_switch se_switch[] = { -/* pmax */ - { 0x00000000, 0x01000000, 0x0, 0x05000000, 8, 16, 64*1024, - copyin_gap16, copyout_gap16, copyin_gap16, copyout_gap16, - bzero_gap16, se_Hmem_gap16, se_Hmem_gap16}, -/* 3max */ - { PMAD_OFFSET_LANCE, PMAD_OFFSET_RAM, PMAD_OFFSET_RAM, PMAD_OFFSET_ROM, - 16, 0, PMAD_RAM_SIZE, - bcopy, bcopy, bcopy, bcopy, bzero, se_Hmem_nogap, se_Hmem_nogap}, -/* 3min */ -/* XXX re-use other 64k */ - { 0/*later*/, 0/*later*/, 0x0, 0/*later*/, 0, 128, 64*1024, - copyin_gap16, copyout_gap16, copyin_gap32, copyout_gap32, - bzero_gap16, se_Hmem_gap16, se_Hmem_nogap}, -}; - -/* - * "lna" is what se_malloc hands back. They are offsets using - * the sizing that the Lance would use. The Lance space is - * mapped somewhere in the I/O space, as indicated by the softc. - * Hence we have these two macros: - */ -/* H & L are not hi and lo but - H = HOST == addresses for host to reference board memory - L = LOCAL == addresses on board - */ -#define Hmem(lna) (vm_offset_t)((se_sw->mapaddr)(lna) + sc->lnbuf) -#define Lmem(lna) (vm_offset_t)((vm_offset_t)lna + sc->lnoffset) -#endif /*DECSTATION*/ - - -#ifdef VAXSTATION -#include <vax/ka3100.h> - -#define wbflush() - -void xzero(x, l) vm_offset_t x; int l; { blkclr(x, l); } -void xcopy(f, t, l) vm_offset_t f, t; int l; { bcopy(f, t, l); } - -private struct se_switch se_switch[] = { - /* pvax sees contiguous bits in lower 16Meg of memory */ - { 0, 0, 0, 0, 0, 0, 64*1024, - xcopy, xcopy, xcopy, xcopy, xzero, se_Hmem_nogap, se_Hmem_nogap}, -}; - -/* - * "lna" is what se_malloc hands back. They are offsets using - * the sizing that the Lance would use. The Lance space is - * mapped somewhere in the I/O space, as indicated by the softc. - * Hence we have these two macros: - */ -/* H & L are not hi and lo but - H = HOST == addresses for host to reference board memory - L = LOCAL == addresses on board - */ - /* - * This does not deal with > 16 Meg physical memory, where - * Hmem != Lmem - */ -#define Hmem(lna) (vm_offset_t)((lna) + sc->lnbuf) -#define Lmem(lna) (vm_offset_t)((lna) + sc->lnoffset) - -#endif /*VAXSTATION*/ - - -#ifdef FLAMINGO -#include <alpha/alpha_cpu.h> - -/* XXX might be wrong, mostly stolen from kmin */ -extern void copyin_gap16(), copyout_gap16(), bzero_gap16(); -extern void copyin_gap32(), copyout_gap32(); -extern void bcopy(), bzero(); - -private struct se_switch se_switch[] = { -/* XXX re-use other 64k */ - { 0/*later*/, 0/*later*/, 0x0, 0/*later*/, 0, 128, 64*1024, - copyin_gap16, copyout_gap16, copyin_gap32, copyout_gap32, - bzero_gap16, se_Hmem_gap16, se_Hmem_nogap}, -}; - -/* - * "lna" is what se_malloc hands back. They are offsets using - * the sizing that the Lance would use. The Lance space is - * mapped somewhere in the I/O space, as indicated by the softc. - * Hence we have these two macros: - */ -/* H & L are not hi and lo but - H = HOST == addresses for host to reference board memory - L = LOCAL == addresses on board - */ -#define Hmem(lna) (vm_offset_t)((se_sw->mapaddr)(lna) + sc->lnbuf) -#define Lmem(lna) (vm_offset_t)((vm_offset_t)lna + sc->lnoffset) -#endif /*FLAMINGO*/ - - -/* - * Map a lance-space offset into an host-space one - */ -private vm_offset_t se_Hmem_nogap( vm_offset_t lna) { return lna;} -private vm_offset_t se_Hmem_gap16( vm_offset_t lna) { return lna << 1;} - -/* - * Memory addresses for LANCE are 24 bits wide. - */ -#define Addr_lo(y) ((unsigned short)((vm_offset_t)(y) & 0xffff)) -#define Addr_hi(y) ((unsigned short)(((vm_offset_t)(y)>>16) & 0xff)) - -#define LN_MEMORY_SIZE (se_sw->ramsize) - -/* XXX to accomodate heterogeneity this should be made per-drive */ -/* XXX and then some more */ - -struct se_switch *se_sw = se_switch; - -void set_se_switch(n) -int n; -{ - se_sw = &se_switch[n]; -} - -#ifndef LUNA88K -void setse_switch(n, r, b, l, o) - vm_offset_t r, b, l, o; - int n; -{ - se_switch[n].regspace = r; - se_switch[n].bufspace = b; - se_switch[n].ln_bufspace = l; - se_switch[n].romspace = o; - - /* make sure longword aligned */ - if (se_switch[n].bufspace & 0x7) { - se_switch[n].bufspace = (se_switch[n].bufspace+0x7) & ~0x7; - } - - set_se_switch(n); -} -#endif - -/* - * Autoconf info - */ - -private vm_offset_t se_std[NLN] = { 0 }; -private struct bus_device *se_info[NLN]; -private int se_probe(); -private void se_attach(); - -struct bus_driver se_driver = - { se_probe, 0, se_attach, 0, se_std, "se", se_info, }; - -/* - * Externally visible functions - */ -char *se_unprobed_addr = 0; -void se_intr(); /* kernel */ - -int se_open(), se_output(), se_get_status(), /* user */ - se_set_status(), se_setinput(), se_restart(); - -/* - * - * Internal functions & definitions - * - */ - -private int se_probe(); -private void se_init(); -private void init_lance_space(); -private void se_desc_set_status(); -private volatile long *se_desc_alloc(); /* must be aligned! */ -void se_start(); -private void copy_from_lance(); -private int copy_to_lance(); - -int se_verbose = 0; /* debug flag */ - -#define RLOG 4 /* 2**4 = 16 receive descriptors */ -#define TLOG 4 /* 2**4 = 16 transmit descriptors */ -#define NRCV (1<<RLOG) /* Receive descriptors */ -#define NXMT (1<<TLOG) /* Transmit descriptors */ - -#define LN_BUFFER_SIZE (0x800-0x80) - -/* - * Ethernet software status per interface. - * - * Each interface is referenced by a network interface structure, - * is_if, which contains the output queue for the interface, its address, ... - */ -int se_loopback_hack = 1; - -struct se_softc { - struct ifnet is_if; /* generic interface header */ - unsigned char is_addr[6]; /* ethernet hardware address */ - unsigned short pad; - se_reg_t lnregs; /* Lance registers */ - vm_offset_t lnbuf; /* Lance memory, Host offset */ - vm_offset_t lnoffset; /* Lance memory, Lance offset */ - vm_offset_t lnrom; - vm_offset_t lnsbrk; /* Lance memory allocator */ - vm_offset_t lninit_block; /* Init block address */ - se_desc_t lnrring[NRCV]; /* Receive ring desc. */ - volatile long *lnrbuf[NRCV]; /* Receive buffers */ - se_desc_t lntring[NXMT]; /* Transmit ring desc. */ - volatile long *lntbuf[NXMT]; /* Transmit buffers */ - - int rcv_last; /* Rcv buffer last read */ - - io_req_t tpkt[NXMT+1]; /* Xmt pkt queue */ - int xmt_count; /* Xmt queue size */ - int xmt_last; /* Xmt queue head (insert) */ - int xmt_complete; /* Xmt queue tail (remove) */ - - int se_flags; /* Flags for SIOCSIFFLAGS */ - int counters[4]; /* error counters */ -#define bablcnt counters[0] -#define misscnt counters[1] -#define merrcnt counters[2] -#define rstrtcnt counters[3] -} se_softc_data[NLN]; - -se_softc_t se_softc[NLN]; /* quick access */ - -/* - * Probe the Lance to see if it's there - */ -private int se_open_state = 0; - -private int se_probe( - vm_offset_t reg, - register struct bus_device *ui) -{ - register se_softc_t sc; - se_reg_t rdp, rap; - int unit = ui->unit; - - /* - * See if the interface is there by reading the lance CSR. On pmaxen - * and 3maxen this is superfluous, but.. - */ - rdp = (se_reg_t) (reg + se_sw->regspace); -#ifdef DECSTATION - if (check_memory(rdp, 0)) - return 0; -#endif /*DECSTATION*/ -#ifdef MAPPED - SE_probe(reg,ui); -#endif /*MAPPED*/ - rap = rdp + 2; /* XXX might not be true in the future XXX */ - /* rdp and rap are "shorts" on consecutive - "long" word boundaries */ - - /* - * Bind this interface to the softc. - */ - sc = &se_softc_data[unit]; - se_softc[unit] = sc; - sc->lnregs = (se_reg_t) (reg + se_sw->regspace); - sc->lnbuf = (vm_offset_t) (reg + se_sw->bufspace); - sc->lnoffset = (vm_offset_t) (se_sw->ln_bufspace); - sc->lnrom = (vm_offset_t) (reg + se_sw->romspace); - - /* - * Reset the interface, and make sure we really do it! (the 3max - * seems quite stubborn about these registers) - */ - se_write_reg(rap, CSR0_SELECT, CSR0_SELECT, "RAP"); - se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); - - /* - * Allocate lance RAM buffer memory - */ - init_lance_space(sc); - - /* - * Initialize the chip - * - * NOTE: From now on we will only touch csr0 - */ - if (se_ship_init_block(sc, unit)) - return 0; - - /* - * Tell the world we are alive and well - */ - se_open_state++; - return 1; -} - -int se_ship_init_block( - register se_softc_t sc, - int unit) -{ - se_reg_t rdp = sc->lnregs; - se_reg_t rap; - register int i = 0; - - rap = rdp + 2; /* XXX might not be true in the future XXX */ - - /* - * Load LANCE control block. - */ - -#ifdef LUNA88K - /* turn on byte swap bit in csr3, set bcon bit - as in 2.5 */ - se_write_reg(rap, CSR3_SELECT, CSR3_SELECT, "RAP"); - se_write_reg(rdp, LN_CSR3_BSWP|LN_CSR3_BCON, - LN_CSR3_BSWP|LN_CSR3_BCON, "csr3"); -#endif - - se_write_reg(rap, CSR1_SELECT, CSR1_SELECT, "RAP"); - se_write_reg(rdp, Addr_lo(Lmem(sc->lninit_block)), - Addr_lo(Lmem(sc->lninit_block)), "csr1"); - - se_write_reg(rap, CSR2_SELECT, CSR2_SELECT, "RAP"); - se_write_reg(rdp, Addr_hi(Lmem(sc->lninit_block)), - Addr_hi(Lmem(sc->lninit_block)), "csr2"); - - /* - * Start the INIT sequence now - */ - se_write_reg(rap, CSR0_SELECT, CSR0_SELECT, "RAP"); - *rdp = (LN_CSR0_IDON | LN_CSR0_INIT); - wbflush(); - - /* give it plenty of time to settle */ - while (i++ < 10000) { - delay(100); - if ((*rdp & LN_CSR0_IDON) != 0) - break; - } - /* make sure got out okay */ - if ((*rdp & LN_CSR0_IDON) == 0) { - printf("se%d: cannot initialize\n", unit); - if (*rdp & LN_CSR0_ERR) - printf("se%d: initialization error, csr = %04x\n", - unit, (*rdp & 0xffff)); - return 1; - } - /* - * Do not enable interrupts just yet. - */ - /* se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); */ - - return 0; -} - -void -se_write_reg( - register se_reg_t regptr, - register int val, - register int result, - char *regname) -{ - register int i = 0; - - while ((unsigned short)(*regptr) != (unsigned short)result) { - *regptr = (se_reg_type)val; - wbflush(); - if (++i > 10000) { - printf("se: %s did not settle (to x%x): x%x\n", - regname, result, (unsigned short)(*regptr)); - return; - } - delay(100); - } -} - -unsigned short -se_read_reg( - register se_reg_t regptr) -{ - return (unsigned short) (*regptr); -} - -private void -init_lance_space( - register se_softc_t sc) -{ - register int lptr; /* Generic lance pointer */ - se_desc_t ringaddr; - long *rom_eaddress = (long *) sc->lnrom; - int i; - struct se_init_block init_block; - - /* - * Allocate local RAM buffer memory for the init block, - * fill in our local copy then copyout. - */ - - sc->lninit_block = se_malloc(sc, sizeof (struct se_init_block)); - - /* - * Set values on stack, then copyout en-masse - */ - bzero(&init_block, sizeof(init_block)); - init_block.mode = 0; - - /* byte swapping between host and lance */ - - init_block.phys_addr_low = ((rom_eaddress[0]>>se_sw->romstride)&0xff) | - (((rom_eaddress[1]>>se_sw->romstride)&0xff) << 8); - init_block.phys_addr_med = ((rom_eaddress[2]>>se_sw->romstride)&0xff) | - (((rom_eaddress[3]>>se_sw->romstride)&0xff) << 8); - init_block.phys_addr_high = ((rom_eaddress[4]>>se_sw->romstride)&0xff) | - (((rom_eaddress[5]>>se_sw->romstride)&0xff) << 8); - - /* - * Allocate both descriptor rings at once. - * Note that the quadword alignment requirement is - * inherent in the way we perform allocation, - * but it does depend on the size of the init block. - */ - lptr = se_malloc(sc, sizeof (struct se_desc) * (NXMT + NRCV)); - - /* - * Initialize the buffer descriptors - */ - init_block.recv_ring_pointer_lo = Addr_lo(Lmem(lptr)); - init_block.recv_ring_pointer_hi = Addr_hi(Lmem(lptr)); - init_block.recv_ring_len = RLOG; - - for ( i = 0; i < NRCV ; i++, lptr += sizeof(struct se_desc)) { - ringaddr = (se_desc_t)Hmem(lptr); - sc->lnrring[i] = ringaddr; - sc->lnrbuf[i] = se_desc_alloc (sc, ringaddr); - } - - init_block.xmit_ring_pointer_lo = Addr_lo(Lmem(lptr)); - init_block.xmit_ring_pointer_hi = Addr_hi(Lmem(lptr)); - init_block.xmit_ring_len = TLOG; - - for ( i = 0 ; i < NXMT ; i++, lptr += sizeof(struct se_desc)) { - ringaddr = (se_desc_t)Hmem(lptr); - sc->lntring[i] = ringaddr; - sc->lntbuf[i] = se_desc_alloc (sc, ringaddr); - } - - /* - * No logical address filtering - */ - init_block.logical_addr_filter0 = 0; - init_block.logical_addr_filter1 = 0; - init_block.logical_addr_filter2 = 0; - init_block.logical_addr_filter3 = 0; - - /* - * Move init block into lance space - */ - (se_sw->desc_copyout)((vm_offset_t)&init_block, Hmem(sc->lninit_block), sizeof(init_block)); - wbflush(); -} - -/* - * Interface exists: make available by filling in network interface - * record. System will initialize the interface when it is ready - * to accept packets. - */ -private void -se_attach( - register struct bus_device *ui) -{ - unsigned char *enaddr; - struct ifnet *ifp; - long *rom_eaddress; - int unit = ui->unit; - se_softc_t sc = se_softc[unit]; - - rom_eaddress = (long *) sc->lnrom; - - /* - * Read the address from the prom and save it. - */ - enaddr = sc->is_addr; - enaddr[0] = (unsigned char) ((rom_eaddress[0] >> se_sw->romstride) & 0xff); - enaddr[1] = (unsigned char) ((rom_eaddress[1] >> se_sw->romstride) & 0xff); - enaddr[2] = (unsigned char) ((rom_eaddress[2] >> se_sw->romstride) & 0xff); - enaddr[3] = (unsigned char) ((rom_eaddress[3] >> se_sw->romstride) & 0xff); - enaddr[4] = (unsigned char) ((rom_eaddress[4] >> se_sw->romstride) & 0xff); - enaddr[5] = (unsigned char) ((rom_eaddress[5] >> se_sw->romstride) & 0xff); - - printf(": %x-%x-%x-%x-%x-%x", - (rom_eaddress[0] >> se_sw->romstride) & 0xff, - (rom_eaddress[1] >> se_sw->romstride) & 0xff, - (rom_eaddress[2] >> se_sw->romstride) & 0xff, - (rom_eaddress[3] >> se_sw->romstride) & 0xff, - (rom_eaddress[4] >> se_sw->romstride) & 0xff, - (rom_eaddress[5] >> se_sw->romstride) & 0xff); - - /* - * Initialize the standard interface descriptor - */ - ifp = &sc->is_if; - ifp->if_unit = unit; - ifp->if_header_size = sizeof(struct ether_header); - ifp->if_header_format = HDR_ETHERNET; - ifp->if_address_size = 6; - ifp->if_mtu = ETHERMTU; - ifp->if_flags |= IFF_BROADCAST; - - ifp->if_address = (char *) enaddr; - - if_init_queues(ifp); -#ifdef MAPPED - SE_attach(ui); -#endif /*MAPPED*/ - -} - -/* - * Use a different hardware address for interface - */ -void -se_setaddr( - unsigned char eaddr[6], - int unit) -{ - register se_softc_t sc = se_softc[unit]; - struct se_init_block init_block; - - /* - * Modify initialization block accordingly - */ - (se_sw->desc_copyin) (Hmem(sc->lninit_block), (vm_offset_t)&init_block, sizeof(init_block)); - bcopy(eaddr, &init_block.phys_addr_low, sizeof(*eaddr)); - (se_sw->desc_copyout)((vm_offset_t)&init_block, Hmem(sc->lninit_block), sizeof(init_block)); - /* - * Make a note of it - */ - bcopy(eaddr, sc->is_addr, sizeof(*eaddr)); - - /* - * Restart the interface - */ - se_restart(&sc->is_if); - se_init(unit); -} - -/* - * Restart interface - * - * We use this internally on those errors that hang the chip, - * not sure yet what use the MI code will make of it. - * - * After stopping the chip and effectively turning off the interface - * we release all pending buffers and cause the chip to init - * itself. We do not enable interrupts here. - */ -int -se_restart( register struct ifnet *ifp ) -{ - register se_softc_t sc = se_softc[ifp->if_unit]; - se_reg_t rdp; - register int i; - - rdp = sc->lnregs; - - /* - * stop the chip - */ - se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); - - /* - * stop network activity - */ - if (ifp->if_flags & IFF_RUNNING) { - ifp->if_flags &= ~(IFF_UP | IFF_RUNNING); - sc->se_flags &= ~(IFF_UP | IFF_RUNNING); - } - sc->rstrtcnt++; - - if (se_verbose) - printf("se%d: %d restarts\n", ifp->if_unit, sc->rstrtcnt); - - /* - * free up any buffers currently in use - */ - for (i = 0; i < NXMT; i++) - if (sc->tpkt[i]) { - iodone(sc->tpkt[i]); - sc->tpkt[i] = (io_req_t) 0; - } - /* - * INIT the chip again, no need to reload init block address. - */ - se_ship_init_block(sc, ifp->if_unit); - - return (0); -} - -/* - * Initialize the interface. - */ -private void -se_init( int unit ) -{ - register se_softc_t sc = se_softc[unit]; - register se_desc_t *rp; - register struct ifnet *ifp = &sc->is_if; - se_reg_t rdp; - short mode; - spl_t s; - int i; - - if (ifp->if_flags & IFF_RUNNING) - return; - - rdp = sc->lnregs; - - /* - * Init the buffer descriptors and indexes for each of the rings. - */ - for (i = 0, rp = sc->lnrring; i < NRCV; i++, rp++) - se_desc_set_status(*rp, LN_RSTATE_OWN); - - for (i = 0, rp = sc->lntring; i < NXMT; i++, rp++) - se_desc_set_status(*rp, 0); - - sc->xmt_count = sc->xmt_complete = sc->xmt_last = sc->rcv_last = 0; - - /* - * Deal with loopback mode operation - */ - s = splimp(); - - (se_sw->desc_copyin) (Hmem(sc->lninit_block), (vm_offset_t)&mode, sizeof(mode)); - - if (ifp->if_flags & IFF_LOOPBACK - && ((mode & LN_MODE_LOOP) == 0)) { - /* if not already in loopback mode, do external loopback */ - mode &= ~LN_MODE_INTL; - mode |= LN_MODE_LOOP; - (se_sw->desc_copyout) ((vm_offset_t)&mode, Hmem(sc->lninit_block), sizeof(mode)); - se_restart(ifp); - se_init(ifp->if_unit); - splx(s); - return; - } - - ifp->if_flags |= (IFF_UP | IFF_RUNNING); - sc->se_flags |= (IFF_UP | IFF_RUNNING); - - /* - * Start the Lance and enable interrupts - */ - *rdp = (LN_CSR0_STRT | LN_CSR0_INEA); - wbflush(); - - /* - * See if anything is already queued - */ - se_start(unit); - splx(s); -} - - -/* - * Shut off the lance - */ -void -se_stop(int unit) -{ - se_reg_t rdp = se_softc[unit]->lnregs; - - se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); -} - - -/* - * Open the device, declaring the interface up - * and enabling lance interrupts. - */ -/*ARGSUSED*/ -int -se_open( - int unit, - int flag) -{ - register se_softc_t sc = se_softc[unit]; - - if (unit >= NLN) - return EINVAL; - if (!se_open_state) - return ENXIO; - - sc->is_if.if_flags |= IFF_UP; - se_open_state++; - se_init(unit); - return (0); -} - -#ifdef MAPPED -int se_use_mapped_interface[NLN]; -#endif /*MAPPED*/ - -void -se_normal(int unit) -{ -#ifdef MAPPED - se_use_mapped_interface[unit] = 0; -#endif /*MAPPED*/ - if (se_softc[unit]) { - se_restart((struct ifnet *)se_softc[unit]); - se_init(unit); - } -} - -/* - * Ethernet interface interrupt routine - */ -void -se_intr( - int unit, - spl_t spllevel) -{ - register se_softc_t sc = se_softc[unit]; - se_reg_t rdp; - register struct ifnet *ifp = &sc->is_if; - register unsigned short csr; - -#ifdef MAPPED - if (se_use_mapped_interface[unit]) - { - SE_intr(unit,spllevel); - return; - } -#endif /*MAPPED*/ - - if (se_open_state < 2) { /* Stray, or not open for business */ - rdp = (sc ? sc->lnregs : (se_reg_t)se_unprobed_addr); - *rdp |= LN_CSR0_STOP; - wbflush(); - return; - } - rdp = sc->lnregs; - - /* - * Read the CSR and process any error condition. - * Later on, restart the lance by writing back - * the CSR (for set-to-clear bits). - */ - csr = *rdp; /* pick up the csr */ - - /* drop spurious interrupts */ - if ((csr & LN_CSR0_INTR) == 0) - return; - -#ifdef DECSTATION - splx(spllevel); /* drop priority now */ -#endif /*DECSTATION*/ -again: - /* - * Check for errors first - */ - if ( csr & LN_CSR0_ERR ) { - if (csr & LN_CSR0_MISS) { - /* - * Stop the chip to prevent a corrupt packet from - * being transmitted. There is a known problem with - * missed packet errors causing corrupted data to - * be transmitted to the same host as was just - * transmitted, with a valid crc appended to the - * packet. The only solution is to stop the chip, - * which will clear the Lance silo, thus preventing - * the corrupt data from being sent. - */ - se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); - - sc->misscnt++; - if (se_verbose) { - int me = 0, lance = 0, index; - struct se_desc r; - for (index = 0; index < NRCV; index++) { - (se_sw->desc_copyin)( - (vm_offset_t)sc->lnrring[index], - (vm_offset_t)&r, - sizeof(r)); - if (r.status & LN_RSTATE_OWN) - lance++; - else - me++; - } - printf("se%d: missed packet (%d) csr = %x, Lance %x, me %x\n", - unit, sc->misscnt, csr, lance, me); - } - se_restart(ifp); - se_init(unit); - return; - } - if (csr & LN_CSR0_BABL) { - sc->bablcnt++; - if (se_verbose) - printf("se%d: xmt timeout (%d)\n", - unit, sc->bablcnt); - } - if (csr & LN_CSR0_MERR) { - sc->merrcnt++; - printf("se%d: memory error (%d)\n", - unit, sc->merrcnt); - - if (((csr & LN_CSR0_RXON) == 0) - || ((csr & LN_CSR0_TXON) == 0)) { - se_restart(ifp); - se_init(unit); - return; - } - } - } - - *rdp = LN_CSR0_INEA | (csr & LN_CSR0_WTC); - wbflush(); - - if ( csr & LN_CSR0_RINT ) - se_rint( unit ); - - if ( csr & LN_CSR0_TINT ) - se_tint( unit ); - - if ((csr = *rdp) & (LN_CSR0_RINT | LN_CSR0_TINT)) - goto again; -} - -/* - * Handle a transmitter complete interrupt. - */ -void -se_tint(int unit) -{ - register se_softc_t sc = se_softc[unit]; - register index; - register status; - io_req_t request; - struct se_desc r; - - /* - * Free up descriptors for all packets in queue for which - * transmission is complete. Start from queue tail, stop at first - * descriptor we do not OWN, or which is in an inconsistent state - * (lance still working). - */ - - while ((sc->xmt_complete != sc->xmt_last) && (sc->xmt_count > 0)) { - - index = sc->xmt_complete; - (se_sw->desc_copyin) ((vm_offset_t)sc->lntring[index], - (vm_offset_t)&r, sizeof(r)); - status = r.status; - - /* - * Does lance still own it ? - */ - if (status & LN_TSTATE_OWN) - break; - - /* - * Packet sent allright, release queue slot. - */ - request = sc->tpkt[index]; - sc->tpkt[index] = (io_req_t) 0; - sc->xmt_complete = ++index & (NXMT - 1); - --sc->xmt_count; - - sc->is_if.if_opackets++; - if (status & (LN_TSTATE_DEF|LN_TSTATE_ONE|LN_TSTATE_MORE)) - sc->is_if.if_collisions++; - - /* - * Check for transmission errors. - */ - if (!se_loopback_hack && status & LN_TSTATE_ERR) { - sc->is_if.if_oerrors++; - if (se_verbose) - printf("se%d: xmt error (x%x)\n", unit, r.status2); - - if (r.status2 & (LN_TSTATE2_RTRY|LN_TSTATE2_LCOL)) - sc->is_if.if_collisions++; - - /* - * Restart chip on errors that disable the - * transmitter. - */ - iodone(request); - if (r.status2 & LN_TSTATE2_DISABLE) { - register struct ifnet *ifp = &sc->is_if; - se_restart(ifp); - se_init(ifp->if_unit); - return; - } - } else if (request) { - /* - * If this was a broadcast packet loop it back. - * Signal successful transmission of the packet. - */ - register struct ether_header *eh; - register int i; - - eh = (struct ether_header *) request->io_data; - /* ether broadcast address is in the spec */ - for (i = 0; (i < 6) && (eh->ether_dhost[i] == 0xff); i++) - ; /* nop */ - /* sending to ourselves makes sense sometimes */ - if (i != 6 && se_loopback_hack) - for (i = 0; - (i < 6) && (eh->ether_dhost[i] == sc->is_addr[i]); - i++) - ; /* nop */ - if (i == 6) - se_read(sc, 0, request->io_count, request); - iodone(request); - } - } - /* - * Dequeue next transmit request, if any. - */ - if (sc->xmt_count <= 0) - se_start(unit); -} - -/* - * Handle a receiver complete interrupt. - */ -void -se_rint(int unit) -{ - register se_softc_t sc = se_softc[unit]; - register index, first, len; - unsigned char status, status1; - int ring_cnt; - struct se_desc r; - - /* - * Starting from where we left off, look around the receive ring and - * pass on all complete packets. - */ - - for (;; sc->rcv_last = ++index & (NRCV - 1)) { - - /* - * Read in current descriptor - */ -read_descriptor: - (se_sw->desc_copyin) ((vm_offset_t)sc->lnrring[sc->rcv_last], - (vm_offset_t)&r, sizeof(r)); - status = r.status; - if (status & LN_RSTATE_OWN) - break; - first = index = sc->rcv_last; - - /* - * If not the start of a packet, error - */ - if (!(status & LN_RSTATE_STP)) { - if (se_verbose) - printf("se%d: Rring #%d, status=%x !STP\n", - unit, index, status); - break; - } - /* - * See if packet is chained (should not) by looking at - * the last descriptor (OWN clear and ENP set). - * Remember the status info in this last descriptor. - */ - ring_cnt = 1, status1 = status; - while (((status1 & (LN_RSTATE_ERR | LN_RSTATE_OWN | LN_RSTATE_ENP)) == 0) && - (ring_cnt++ <= NRCV)) { - struct se_desc r1; - index = (index + 1) & (NRCV - 1); - (se_sw->desc_copyin) ((vm_offset_t)sc->lnrring[index], - (vm_offset_t)&r1, sizeof(r1)); - status1 = r1.status; - } - - /* - * Chained packet (--> illegally sized!); re-init the - * descriptors involved and ignore this bogus packet. I - * donno how, but it really happens that we get these - * monsters. - */ - if (ring_cnt > 1) { - /* - * Return all descriptors to lance - */ - se_desc_set_status(sc->lnrring[first], LN_RSTATE_OWN); - while (first != index) { - first = (first + 1) & (NRCV - 1); - se_desc_set_status(sc->lnrring[first], LN_RSTATE_OWN); - } - if ((status1 & LN_RSTATE_ERR) && se_verbose) - printf("se%d: rcv error %x (chained)\n", unit, status1); - continue; - } - - /* - * Good packets must be owned by us and have the end of - * packet flag. And nothing else. - */ - if ((status & ~LN_RSTATE_STP) == LN_RSTATE_ENP) { - sc->is_if.if_ipackets++; - - if ((len = r.message_size) == 0) - /* race seen on pmaxen: the lance - * has not updated the size yet ?? - */ - goto read_descriptor; - /* - * Drop trailing CRC bytes from len and ship packet - * up - */ - se_read(sc, (volatile char*)sc->lnrbuf[first], len-4,0); - - /* - * Return descriptor to lance, and move on to next - * packet - */ - r.status = LN_RSTATE_OWN; - (se_sw->desc_copyout)((vm_offset_t)&r, - (vm_offset_t)sc->lnrring[first], - sizeof(r)); - continue; - } - /* - * Not a good packet, see what is wrong - */ - if (status & LN_RSTATE_ERR) { - sc->is_if.if_ierrors++; - - if (se_verbose) - printf("se%d: rcv error (x%x)\n", unit, status); - - /* - * Return descriptor to lance - */ - se_desc_set_status(sc->lnrring[first], LN_RSTATE_OWN); - } else { - /* - * Race condition viz lance, Wait for the next - * interrupt. - */ - return; - } - } -} - -/* - * Output routine. - * Call common function for wiring memory, - * come back later (to se_start) to get - * things going. - */ -io_return_t -se_output( - int dev, - io_req_t ior) -{ - return net_write(&se_softc[dev]->is_if, (int(*)())se_start, ior); -} - -/* - * Start output on interface. - * - */ -void -se_start(int unit) -{ - register se_softc_t sc = se_softc[unit]; - io_req_t request; - struct se_desc r; - int tlen; - spl_t s; - register int index; - - s = splimp(); - - for (index = sc->xmt_last; - sc->xmt_count < (NXMT - 1); - sc->xmt_last = index = (index + 1) & (NXMT - 1)) { - /* - * Dequeue the next transmit request, if any. - */ - IF_DEQUEUE(&sc->is_if.if_snd, request); - if (request == 0) { - /* - * Tell the lance to send the packet now - * instead of waiting until the next 1.6 ms - * poll interval expires. - */ - *sc->lnregs = LN_CSR0_TDMD | LN_CSR0_INEA; - splx(s); - return; /* Nothing on the queue */ - } - - /* - * Keep request around until transmission complete - */ - sc->tpkt[index] = request; - tlen = copy_to_lance(request, sc->lntbuf[index]); - - /* - * Give away buffer. Must copyin/out, set len, - * and set the OWN flag. We do not do chaining. - */ - (se_sw->desc_copyin)((vm_offset_t)sc->lntring[index], - (vm_offset_t)&r, sizeof(r)); - r.buffer_size = -(tlen) | 0xf000; - r.status = (LN_TSTATE_OWN | LN_TSTATE_STP | LN_TSTATE_ENP); - (se_sw->desc_copyout)((vm_offset_t)&r, - (vm_offset_t)sc->lntring[index], - sizeof(r)); - wbflush(); - - sc->xmt_count++; - } - /* - * Since we actually have queued new packets, tell - * the chip to rescan the descriptors _now_. - * It is quite unlikely that the ring be filled, - * but if it is .. the more reason to do it! - */ - *sc->lnregs = LN_CSR0_TDMD | LN_CSR0_INEA; - splx(s); -} - - -/* - * Pull a packet off the interface and - * hand it up to the higher levels. - * - * Simulate broadcast packets in software. - */ -void -se_read( - register se_softc_t sc, - volatile char *lnrbuf, - int len, - io_req_t loop_back) -{ - register struct ifnet *ifp = &sc->is_if; - register ipc_kmsg_t new_kmsg; - char *hdr, *pkt; - - if (len <= sizeof(struct ether_header)) - return; /* sanity */ - - /* - * Get a new kmsg to put data into. - */ - new_kmsg = net_kmsg_get(); - if (new_kmsg == IKM_NULL) { - /* - * No room, drop the packet - */ - ifp->if_rcvdrops++; - return; - } - - hdr = net_kmsg(new_kmsg)->header; - pkt = net_kmsg(new_kmsg)->packet; - -#define OFF0 (sizeof(struct ether_header) - sizeof(struct packet_header)) -#define OFF1 (OFF0 & ~3) - if (loop_back) { - bcopy(loop_back->io_data, hdr, sizeof(struct ether_header)); - bcopy(loop_back->io_data + OFF0, - pkt, len - OFF0); - } else - copy_from_lance(lnrbuf, len, (struct ether_header*)hdr, - (struct packet_header*)pkt); - - /* - * Set up the 'fake' header with length. Type has been left - * in the correct place. - */ - len = len - OFF0; - ((struct packet_header *)pkt)->length = len; - - /* - * Hand the packet to the network module. - */ - net_packet(ifp, new_kmsg, len, ethernet_priority(new_kmsg)); -} - - -/* - * Get a packet out of Lance memory and into main memory. - */ -private void -copy_from_lance( - register volatile unsigned char *rbuf, - register unsigned int nbytes, - struct ether_header *hdr, - struct packet_header *pkt) -{ - /* - * Read in ethernet header - */ - (se_sw->data_copyin) ((vm_offset_t)rbuf, (vm_offset_t)hdr, sizeof(struct ether_header)); - - nbytes -= sizeof(struct ether_header); - rbuf += (se_sw->mapoffs) (sizeof(struct ether_header)); - - pkt->type = (unsigned short) hdr->ether_type; - - (se_sw->data_copyin) ((vm_offset_t)rbuf, (vm_offset_t)(pkt + 1), nbytes); -} - - -/* - * Move a packet into Lance space - */ -private int -copy_to_lance( - register io_req_t request, - volatile char *sbuf) -{ - register unsigned short *dp; - register int len; - - dp = (unsigned short *) request->io_data; - len = request->io_count; - - if (len > (int)(ETHERMTU + sizeof(struct ether_header))) { - printf("se: truncating HUGE packet\n"); - len = ETHERMTU + sizeof(struct ether_header); - } - - (se_sw->data_copyout) ((vm_offset_t)dp, (vm_offset_t)sbuf, len); - - if (len < LN_MINBUF_NOCH) - /* - * The lance needs at least this much data in a packet. Who - * cares if I send some garbage that was left in the lance - * buffer ? If one can spoof packets then one can spoof - * packets! - */ - len = LN_MINBUF_NOCH; - return len; -} - -/* - * Reset a descriptor's flags. - * Optionally give the descriptor to the lance - */ -private void -se_desc_set_status ( - register se_desc_t lndesc, - int val) -{ - struct se_desc desc; - - (se_sw->desc_copyin) ((vm_offset_t)lndesc, (vm_offset_t)&desc, sizeof(desc)); - desc.desc4.bits = 0; - desc.status = val; - (se_sw->desc_copyout) ((vm_offset_t)&desc, (vm_offset_t)lndesc, sizeof(desc)); - wbflush(); -} - -/* - * Set/Get status functions - */ -int -se_get_status( - int dev, - dev_flavor_t flavor, - dev_status_t status, /* pointer to OUT array */ - natural_t *status_count) /* out */ -{ - return (net_getstat(&se_softc[dev]->is_if, - flavor, status, status_count)); -} - -int -se_set_status( - int unit, - dev_flavor_t flavor, - dev_status_t status, - natural_t status_count) -{ - register se_softc_t sc; - - sc = se_softc[unit]; - - - switch (flavor) { - - case NET_STATUS: - break; - - case NET_ADDRESS: { - - register union ether_cvt { - unsigned char addr[6]; - int lwd[2]; - } *ec = (union ether_cvt *) status; - - if (status_count < sizeof(*ec) / sizeof(int)) - return (D_INVALID_SIZE); - - ec->lwd[0] = ntohl(ec->lwd[0]); - ec->lwd[1] = ntohl(ec->lwd[1]); - - se_setaddr(ec->addr, unit); - - break; - } - - default: - return (D_INVALID_OPERATION); - } - - return (D_SUCCESS); -} - - -/* - * Install new filter. - * Nothing special needs to be done here. - */ -io_return_t -se_setinput( - int dev, - ipc_port_t receive_port, - int priority, - filter_t *filter, - natural_t filter_count) -{ - return (net_set_filter(&se_softc[dev]->is_if, - receive_port, priority, - filter, filter_count)); -} - -/* - * Allocate and initialize a ring descriptor. - * Allocates a buffer from the lance memory and writes a descriptor - * for that buffer to the host virtual address LNDESC. - */ -private volatile long -*se_desc_alloc ( - register se_softc_t sc, - register se_desc_t lndesc) -{ - register vm_offset_t dp; /* data pointer */ - struct se_desc desc; - - /* - * Allocate buffer in lance space - */ - dp = se_malloc(sc, LN_BUFFER_SIZE); - - /* - * Build a descriptor pointing to it - */ - desc.addr_low = Addr_lo(Lmem(dp)); - desc.addr_hi = Addr_hi(Lmem(dp)); - desc.status = 0; - desc.buffer_size = -LN_BUFFER_SIZE; - desc.desc4.bits = 0; - - /* - * Copy the descriptor to lance space - */ - (se_sw->desc_copyout) ((vm_offset_t)&desc, (vm_offset_t)lndesc, sizeof(desc)); - wbflush(); - - return (volatile long *) Hmem(dp); -} - -/* - * Allocate a chunk of lance RAM buffer. Since we never - * give lance RAM buffer memory back, we'll just step up the - * byte-count on a per-unit basis. - * - * The return value is an index into the lance memory, which can be - * passed with Hmem() and Lmem() to get the host and chip virtual addresses. - */ -private vm_offset_t -se_malloc( - se_softc_t sc, - int size) -{ - register vm_offset_t ret; - - /* - * On first call, zero lance memory - */ - if (sc->lnsbrk == 0) - (se_sw->bzero) (Hmem(0), LN_MEMORY_SIZE); - - /* - * Start out on the first double longword boundary - * (this accomodates some machines, with minimal loss) - */ - if (sc->lnsbrk & 0xf) - sc->lnsbrk = (sc->lnsbrk + 0x10) & ~0xf; - - ret = sc->lnsbrk; - sc->lnsbrk += size; - - if (sc->lnsbrk > LN_MEMORY_SIZE) - panic("se_malloc"); - - return ret; -} - -#endif NLN > 0 |