diff options
Diffstat (limited to 'sys/i386/isa/if_ex.c')
-rw-r--r-- | sys/i386/isa/if_ex.c | 1133 |
1 files changed, 0 insertions, 1133 deletions
diff --git a/sys/i386/isa/if_ex.c b/sys/i386/isa/if_ex.c deleted file mode 100644 index 6a09445..0000000 --- a/sys/i386/isa/if_ex.c +++ /dev/null @@ -1,1133 +0,0 @@ -/* - * Copyright (c) 1996, Javier Martín Rueda (jmrueda@diatel.upm.es) - * 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 unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - * MAINTAINER: Matthew N. Dodd <winter@jurai.net> - * <mdodd@FreeBSD.org> - */ - -/* - * Intel EtherExpress Pro/10, Pro/10+ Ethernet driver - * - * Revision history: - * - * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast. - */ - -#include "ex.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/conf.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/socket.h> - -#include <sys/module.h> -#include <sys/bus.h> - -#include <machine/bus.h> -#include <machine/resource.h> -#include <sys/rman.h> - -#include <net/ethernet.h> -#include <net/if.h> - -#include <netinet/in.h> -#include <netinet/if_ether.h> - -#include <net/bpf.h> - -#include <machine/clock.h> - -#include <isa/isavar.h> -#include <isa/pnpvar.h> - -#include <i386/isa/if_exreg.h> - -#ifdef EXDEBUG -# define Start_End 1 -# define Rcvd_Pkts 2 -# define Sent_Pkts 4 -# define Status 8 -static int debug_mask = 0; -static int exintr_count = 0; -# define DODEBUG(level, action) if (level & debug_mask) action -#else -# define DODEBUG(level, action) -#endif - -#define Conn_BNC 1 -#define Conn_TPE 2 -#define Conn_AUI 3 - -#define CARD_TYPE_EX_10 1 -#define CARD_TYPE_EX_10_PLUS 2 - -struct ex_softc { - struct arpcom arpcom; /* Ethernet common data */ - - device_t dev; - struct resource *ioport; - struct resource *irq; - - u_int iobase; /* I/O base address. */ - u_short irq_no; /* IRQ number. */ - - char * irq2ee; /* irq <-> internal */ - u_char * ee2irq; /* representation conversion */ - - u_short connector; /* Connector type. */ - - u_int mem_size; /* Total memory size, in bytes. */ - u_int rx_mem_size; /* Rx memory size (by default, */ - /* first 3/4 of total memory). */ - - u_int rx_lower_limit; /* Lower and upper limits of */ - u_int rx_upper_limit; /* receive buffer. */ - - u_int rx_head; /* Head of receive ring buffer. */ - u_int tx_mem_size; /* Tx memory size (by default, */ - /* last quarter of total memory).*/ - - u_int tx_lower_limit; /* Lower and upper limits of */ - u_int tx_upper_limit; /* transmit buffer. */ - - u_int tx_head; /* Head and tail of */ - u_int tx_tail; /* transmit ring buffer. */ - - u_int tx_last; /* Pointer to beginning of last */ - /* frame in the chain. */ -}; - -static char irq2eemap[] = - { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1, -1, -1 }; -static u_char ee2irqmap[] = - { 9, 3, 5, 10, 11, 0, 0, 0 }; - -static char plus_irq2eemap[] = - { -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, -1, -1, -1 }; -static u_char plus_ee2irqmap[] = - { 3, 4, 5, 7, 9, 10, 11, 12 }; - -/* Bus Front End Functions */ -static void ex_isa_identify __P((driver_t *, device_t)); -static int ex_isa_probe __P((device_t)); -static int ex_isa_attach __P((device_t)); - -/* Network Interface Functions */ -static void ex_init __P((void *)); -static void ex_start __P((struct ifnet *)); -static int ex_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void ex_watchdog __P((struct ifnet *)); - -static void ex_stop __P((struct ex_softc *)); -static void ex_reset __P((struct ex_softc *)); - -static driver_intr_t ex_intr; -static void ex_tx_intr __P((struct ex_softc *)); -static void ex_rx_intr __P((struct ex_softc *)); - -static u_short eeprom_read __P((int, int)); - -static device_method_t ex_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, ex_isa_identify), - DEVMETHOD(device_probe, ex_isa_probe), - DEVMETHOD(device_attach, ex_isa_attach), - - { 0, 0 } -}; - -static driver_t ex_driver = { - "ex", - ex_methods, - sizeof(struct ex_softc), -}; - -static devclass_t ex_devclass; - -DRIVER_MODULE(ex, isa, ex_driver, ex_devclass, 0, 0); - -static struct isa_pnp_id ex_ids[] = { - { 0x3110d425, NULL }, /* INT1031 */ - { 0x3010d425, NULL }, /* INT1030 */ - { 0, NULL }, -}; - -static int -look_for_card (u_int iobase) -{ - int count1, count2; - - /* - * Check for the i82595 signature, and check that the round robin - * counter actually advances. - */ - if (((count1 = inb(iobase + ID_REG)) & Id_Mask) != Id_Sig) - return(0); - count2 = inb(iobase + ID_REG); - count2 = inb(iobase + ID_REG); - count2 = inb(iobase + ID_REG); - - return((count2 & Counter_bits) == ((count1 + 0xc0) & Counter_bits)); -} - -static int -ex_get_media (u_int32_t iobase) -{ - int tmp; - - outb(iobase + CMD_REG, Bank2_Sel); - tmp = inb(iobase + REG3); - outb(iobase + CMD_REG, Bank0_Sel); - - if (tmp & TPE_bit) - return(Conn_TPE); - if (tmp & BNC_bit) - return(Conn_BNC); - - return (Conn_AUI); -} - -static void -ex_get_address (u_int32_t iobase, u_char *enaddr) -{ - u_int16_t eaddr_tmp; - - eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Lo); - enaddr[5] = eaddr_tmp & 0xff; - enaddr[4] = eaddr_tmp >> 8; - eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Mid); - enaddr[3] = eaddr_tmp & 0xff; - enaddr[2] = eaddr_tmp >> 8; - eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Hi); - enaddr[1] = eaddr_tmp & 0xff; - enaddr[0] = eaddr_tmp >> 8; - - return; -} - -static int -ex_card_type (u_char *enaddr) -{ - if ((enaddr[0] == 0x00) && (enaddr[1] == 0xA0) && (enaddr[2] == 0xC9)) - return (CARD_TYPE_EX_10_PLUS); - - return (CARD_TYPE_EX_10); -} - -/* - * Non-destructive identify. - */ -static void -ex_isa_identify (driver_t *driver, device_t parent) -{ - device_t child; - u_int32_t ioport; - u_char enaddr[6]; - u_int irq; - int tmp; - const char * desc; - - for (ioport = 0x200; ioport < 0x3a0; ioport += 0x10) { - - /* No board found at address */ - if (!look_for_card(ioport)) { - continue; - } - - /* Board in PnP mode */ - if (eeprom_read(ioport, 0) & 0x01) { - continue; - } - - bzero(enaddr, sizeof(enaddr)); - - /* Reset the card. */ - outb(ioport + CMD_REG, Reset_CMD); - DELAY(400); - - ex_get_address(ioport, enaddr); - tmp = eeprom_read(ioport, EE_IRQ_No) & IRQ_No_Mask; - - /* work out which set of irq <-> internal tables to use */ - if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) { - irq = plus_ee2irqmap[tmp]; - desc = "Intel Pro/10+"; - } else { - irq = ee2irqmap[tmp]; - desc = "Intel Pro/10"; - } - - child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ex", -1); - device_set_desc_copy(child, desc); - device_set_driver(child, driver); - bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); - bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, EX_IOSIZE); - } - - return; -} - -static int -ex_isa_probe(device_t dev) -{ - u_int iobase; - u_int irq; - char * irq2ee; - u_char * ee2irq; - u_char enaddr[6]; - int tmp; - int error; - - DODEBUG(Start_End, printf("ex_probe: start\n");); - - /* Check isapnp ids */ - error = ISA_PNP_PROBE(device_get_parent(dev), dev, ex_ids); - - /* If the card had a PnP ID that didn't match any we know about */ - if (error == ENXIO) { - return(error); - } - - /* If we had some other problem. */ - if (!(error == 0 || error == ENOENT)) { - return(error); - } - - iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0); - if (iobase && !look_for_card(iobase)) { - printf("ex: no card found at 0x%03x\n", iobase); - return(ENXIO); - } - - /* - * Reset the card. - */ - outb(iobase + CMD_REG, Reset_CMD); - DELAY(400); - - ex_get_address(iobase, enaddr); - - /* work out which set of irq <-> internal tables to use */ - if (ex_card_type(enaddr) == CARD_TYPE_EX_10_PLUS) { - irq2ee = plus_irq2eemap; - ee2irq = plus_ee2irqmap; - } else { - irq2ee = irq2eemap; - ee2irq = ee2irqmap; - } - - tmp = eeprom_read(iobase, EE_IRQ_No) & IRQ_No_Mask; - irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0); - - if (irq > 0) { - /* This will happen if board is in PnP mode. */ - if (ee2irq[tmp] != irq) { - printf("ex: WARNING: board's EEPROM is configured" - " for IRQ %d, using %d\n", - ee2irq[tmp], irq); - } - } else { - irq = ee2irq[tmp]; - bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); - } - - if (irq == 0) { - printf("ex: invalid IRQ.\n"); - return(ENXIO); - } - - DODEBUG(Start_End, printf("ex_probe: finish\n");); - - return(0); -} - -static int -ex_isa_attach(device_t dev) -{ - struct ex_softc * sc = device_get_softc(dev); - struct ifnet * ifp = &sc->arpcom.ac_if; - int unit = device_get_unit(dev); - int error; - int rid; - void * ih; - - DODEBUG(Start_End, device_printf(dev, "start\n");); - - rid = 0; - sc->ioport = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, - 0, ~0, 1, RF_ACTIVE); - - if (!sc->ioport) { - device_printf(dev, "No I/O space?!\n"); - goto bad; - } - - rid = 0; - sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, - 0, ~0, 1, RF_ACTIVE); - - if (!sc->irq) { - device_printf(dev, "No IRQ?!\n"); - goto bad; - } - - error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET, - ex_intr, (void *)sc, &ih); - - if (error) { - device_printf(dev, "bus_setup_intr() failed!\n"); - goto bad; - } - - /* - * Fill in several fields of the softc structure: - * - I/O base address. - * - Hardware Ethernet address. - * - IRQ number (if not supplied in config file, read it from EEPROM). - * - Connector type. - */ - sc->dev = dev; - sc->iobase = rman_get_start(sc->ioport); - sc->irq_no = rman_get_start(sc->irq); - - ex_get_address(sc->iobase, sc->arpcom.ac_enaddr); - - /* work out which set of irq <-> internal tables to use */ - if (ex_card_type(sc->arpcom.ac_enaddr) == CARD_TYPE_EX_10_PLUS) { - sc->irq2ee = plus_irq2eemap; - sc->ee2irq = plus_ee2irqmap; - } else { - sc->irq2ee = irq2eemap; - sc->ee2irq = ee2irqmap; - } - - sc->connector = ex_get_media(sc->iobase); - sc->mem_size = CARD_RAM_SIZE; /* XXX This should be read from the card itself. */ - - /* - * Initialize the ifnet structure. - */ - ifp->if_softc = sc; - ifp->if_unit = unit; - ifp->if_name = "ex"; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST /* XXX not done yet. | IFF_MULTICAST */; - ifp->if_output = ether_output; - ifp->if_start = ex_start; - ifp->if_ioctl = ex_ioctl; - ifp->if_watchdog = ex_watchdog; - ifp->if_init = ex_init; - ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; - - /* - * Attach the interface. - */ - if_attach(ifp); - ether_ifattach(ifp); - - device_printf(sc->dev, "Ethernet address %6D\n", - sc->arpcom.ac_enaddr, ":"); - - /* - * If BPF is in the kernel, call the attach for it - */ - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); - DODEBUG(Start_End, printf("ex_isa_attach%d: finish\n", unit);); - - return(0); -bad: - - if (sc->ioport) - bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->ioport); - if (sc->irq) - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); - - return (-1); -} - - -static void -ex_init(void *xsc) -{ - struct ex_softc * sc = (struct ex_softc *) xsc; - struct ifnet * ifp = &sc->arpcom.ac_if; - int s; - int i; - register int iobase = sc->iobase; - unsigned short temp_reg; - - DODEBUG(Start_End, printf("ex_init%d: start\n", ifp->if_unit);); - - if (ifp->if_addrhead.tqh_first == NULL) { - return; - } - s = splimp(); - sc->arpcom.ac_if.if_timer = 0; - - /* - * Load the ethernet address into the card. - */ - outb(iobase + CMD_REG, Bank2_Sel); - temp_reg = inb(iobase + EEPROM_REG); - if (temp_reg & Trnoff_Enable) { - outb(iobase + EEPROM_REG, temp_reg & ~Trnoff_Enable); - } - for (i = 0; i < ETHER_ADDR_LEN; i++) { - outb(iobase + I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]); - } - /* - * - Setup transmit chaining and discard bad received frames. - * - Match broadcast. - * - Clear test mode. - * - Set receiving mode. - * - Set IRQ number. - */ - outb(iobase + REG1, inb(iobase + REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr); - outb(iobase + REG2, inb(iobase + REG2) | No_SA_Ins | RX_CRC_InMem); - outb(iobase + REG3, inb(iobase + REG3) & 0x3f /* XXX constants. */ ); - outb(iobase + CMD_REG, Bank1_Sel); - outb(iobase + INT_NO_REG, (inb(iobase + INT_NO_REG) & 0xf8) | sc->irq2ee[sc->irq_no]); - - /* - * Divide the available memory in the card into rcv and xmt buffers. - * By default, I use the first 3/4 of the memory for the rcv buffer, - * and the remaining 1/4 of the memory for the xmt buffer. - */ - sc->rx_mem_size = sc->mem_size * 3 / 4; - sc->tx_mem_size = sc->mem_size - sc->rx_mem_size; - sc->rx_lower_limit = 0x0000; - sc->rx_upper_limit = sc->rx_mem_size - 2; - sc->tx_lower_limit = sc->rx_mem_size; - sc->tx_upper_limit = sc->mem_size - 2; - outb(iobase + RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8); - outb(iobase + RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8); - outb(iobase + XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8); - outb(iobase + XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8); - - /* - * Enable receive and transmit interrupts, and clear any pending int. - */ - outb(iobase + REG1, inb(iobase + REG1) | TriST_INT); - outb(iobase + CMD_REG, Bank0_Sel); - outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); - outb(iobase + STATUS_REG, All_Int); - - /* - * Initialize receive and transmit ring buffers. - */ - outw(iobase + RCV_BAR, sc->rx_lower_limit); - sc->rx_head = sc->rx_lower_limit; - outw(iobase + RCV_STOP_REG, sc->rx_upper_limit | 0xfe); - outw(iobase + XMT_BAR, sc->tx_lower_limit); - sc->tx_head = sc->tx_tail = sc->tx_lower_limit; - - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - DODEBUG(Status, printf("OIDLE init\n");); - - /* - * Final reset of the board, and enable operation. - */ - outb(iobase + CMD_REG, Sel_Reset_CMD); - DELAY(2); - outb(iobase + CMD_REG, Rcv_Enable_CMD); - - ex_start(ifp); - splx(s); - - DODEBUG(Start_End, printf("ex_init%d: finish\n", ifp->if_unit);); -} - - -static void -ex_start(struct ifnet *ifp) -{ - struct ex_softc * sc = ifp->if_softc; - int iobase = sc->iobase; - int i, s, len, data_len, avail, dest, next; - unsigned char tmp16[2]; - struct mbuf * opkt; - struct mbuf * m; - - DODEBUG(Start_End, printf("ex_start%d: start\n", unit);); - - s = splimp(); - - /* - * Main loop: send outgoing packets to network card until there are no - * more packets left, or the card cannot accept any more yet. - */ - while (((opkt = ifp->if_snd.ifq_head) != NULL) && - !(ifp->if_flags & IFF_OACTIVE)) { - - /* - * Ensure there is enough free transmit buffer space for - * this packet, including its header. Note: the header - * cannot wrap around the end of the transmit buffer and - * must be kept together, so we allow space for twice the - * length of the header, just in case. - */ - - for (len = 0, m = opkt; m != NULL; m = m->m_next) { - len += m->m_len; - } - - data_len = len; - - DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len);); - - if (len & 1) { - len += XMT_HEADER_LEN + 1; - } else { - len += XMT_HEADER_LEN; - } - - if ((i = sc->tx_tail - sc->tx_head) >= 0) { - avail = sc->tx_mem_size - i; - } else { - avail = -i; - } - - DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail);); - - if (avail >= len + XMT_HEADER_LEN) { - IF_DEQUEUE(&ifp->if_snd, opkt); - -#ifdef EX_PSA_INTR - /* - * Disable rx and tx interrupts, to avoid corruption - * of the host address register by interrupt service - * routines. - * XXX Is this necessary with splimp() enabled? - */ - outb(iobase + MASK_REG, All_Int); -#endif - - /* - * Compute the start and end addresses of this - * frame in the tx buffer. - */ - dest = sc->tx_tail; - next = dest + len; - - if (next > sc->tx_upper_limit) { - if ((sc->tx_upper_limit + 2 - sc->tx_tail) <= - XMT_HEADER_LEN) { - dest = sc->tx_lower_limit; - next = dest + len; - } else { - next = sc->tx_lower_limit + - next - sc->tx_upper_limit - 2; - } - } - - /* - * Build the packet frame in the card's ring buffer. - */ - DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next);); - - outw(iobase + HOST_ADDR_REG, dest); - outw(iobase + IO_PORT_REG, Transmit_CMD); - outw(iobase + IO_PORT_REG, 0); - outw(iobase + IO_PORT_REG, next); - outw(iobase + IO_PORT_REG, data_len); - - /* - * Output the packet data to the card. Ensure all - * transfers are 16-bit wide, even if individual - * mbufs have odd length. - */ - - for (m = opkt, i = 0; m != NULL; m = m->m_next) { - DODEBUG(Sent_Pkts, printf("[%d]", m->m_len);); - if (i) { - tmp16[1] = *(mtod(m, caddr_t)); - outsw(iobase + IO_PORT_REG, tmp16, 1); - } - outsw(iobase + IO_PORT_REG, - mtod(m, caddr_t) + i, (m->m_len - i) / 2); - - if ((i = (m->m_len - i) & 1) != 0) { - tmp16[0] = *(mtod(m, caddr_t) + - m->m_len - 1); - } - } - if (i) { - outsw(iobase + IO_PORT_REG, tmp16, 1); - } - - /* - * If there were other frames chained, update the - * chain in the last one. - */ - if (sc->tx_head != sc->tx_tail) { - if (sc->tx_tail != dest) { - outw(iobase + HOST_ADDR_REG, - sc->tx_last + XMT_Chain_Point); - outw(iobase + IO_PORT_REG, dest); - } - outw(iobase + HOST_ADDR_REG, - sc->tx_last + XMT_Byte_Count); - i = inw(iobase + IO_PORT_REG); - outw(iobase + HOST_ADDR_REG, - sc->tx_last + XMT_Byte_Count); - outw(iobase + IO_PORT_REG, i | Ch_bit); - } - - /* - * Resume normal operation of the card: - * - Make a dummy read to flush the DRAM write - * pipeline. - * - Enable receive and transmit interrupts. - * - Send Transmit or Resume_XMT command, as - * appropriate. - */ - inw(iobase + IO_PORT_REG); -#ifdef EX_PSA_INTR - outb(iobase + MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); -#endif - if (sc->tx_head == sc->tx_tail) { - outw(iobase + XMT_BAR, dest); - outb(iobase + CMD_REG, Transmit_CMD); - sc->tx_head = dest; - DODEBUG(Sent_Pkts, printf("Transmit\n");); - } else { - outb(iobase + CMD_REG, Resume_XMT_List_CMD); - DODEBUG(Sent_Pkts, printf("Resume\n");); - } - - sc->tx_last = dest; - sc->tx_tail = next; - - if (ifp->if_bpf != NULL) { - bpf_mtap(ifp, opkt); - } - - ifp->if_timer = 2; - ifp->if_opackets++; - m_freem(opkt); - } else { - ifp->if_flags |= IFF_OACTIVE; - DODEBUG(Status, printf("OACTIVE start\n");); - } - } - - splx(s); - - DODEBUG(Start_End, printf("ex_start%d: finish\n", unit);); -} - -static void -ex_stop(struct ex_softc *sc) -{ - int iobase = sc->iobase; - - DODEBUG(Start_End, printf("ex_stop%d: start\n", unit);); - - /* - * Disable card operation: - * - Disable the interrupt line. - * - Flush transmission and disable reception. - * - Mask and clear all interrupts. - * - Reset the 82595. - */ - outb(iobase + CMD_REG, Bank1_Sel); - outb(iobase + REG1, inb(iobase + REG1) & ~TriST_INT); - outb(iobase + CMD_REG, Bank0_Sel); - outb(iobase + CMD_REG, Rcv_Stop); - sc->tx_head = sc->tx_tail = sc->tx_lower_limit; - sc->tx_last = 0; /* XXX I think these two lines are not necessary, because ex_init will always be called again to reinit the interface. */ - outb(iobase + MASK_REG, All_Int); - outb(iobase + STATUS_REG, All_Int); - outb(iobase + CMD_REG, Reset_CMD); - DELAY(200); - - DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit);); - - return; -} - - -static void -ex_intr(void *arg) -{ - struct ex_softc * sc = (struct ex_softc *)arg; - struct ifnet * ifp = &sc->arpcom.ac_if; - int iobase = sc->iobase; - int int_status, send_pkts; - - DODEBUG(Start_End, printf("ex_intr%d: start\n", unit);); - -#ifdef EXDEBUG - if (++exintr_count != 1) - printf("WARNING: nested interrupt (%d). Mail the author.\n", exintr_count); -#endif - - send_pkts = 0; - while ((int_status = inb(iobase + STATUS_REG)) & (Tx_Int | Rx_Int)) { - if (int_status & Rx_Int) { - outb(iobase + STATUS_REG, Rx_Int); - - ex_rx_intr(sc); - } else if (int_status & Tx_Int) { - outb(iobase + STATUS_REG, Tx_Int); - - ex_tx_intr(sc); - send_pkts = 1; - } - } - - /* - * If any packet has been transmitted, and there are queued packets to - * be sent, attempt to send more packets to the network card. - */ - - if (send_pkts && (ifp->if_snd.ifq_head != NULL)) { - ex_start(ifp); - } - -#ifdef EXDEBUG - exintr_count--; -#endif - - DODEBUG(Start_End, printf("ex_intr%d: finish\n", unit);); - - return; -} - -static void -ex_tx_intr(struct ex_softc *sc) -{ - struct ifnet * ifp = &sc->arpcom.ac_if; - int iobase = sc->iobase; - int tx_status; - - DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit);); - - /* - * - Cancel the watchdog. - * For all packets transmitted since last transmit interrupt: - * - Advance chain pointer to next queued packet. - * - Update statistics. - */ - - ifp->if_timer = 0; - - while (sc->tx_head != sc->tx_tail) { - outw(iobase + HOST_ADDR_REG, sc->tx_head); - - if (! inw(iobase + IO_PORT_REG) & Done_bit) - break; - - tx_status = inw(iobase + IO_PORT_REG); - sc->tx_head = inw(iobase + IO_PORT_REG); - - if (tx_status & TX_OK_bit) { - ifp->if_opackets++; - } else { - ifp->if_oerrors++; - } - - ifp->if_collisions += tx_status & No_Collisions_bits; - } - - /* - * The card should be ready to accept more packets now. - */ - - ifp->if_flags &= ~IFF_OACTIVE; - - DODEBUG(Status, printf("OIDLE tx_intr\n");); - DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit);); - - return; -} - -static void -ex_rx_intr(struct ex_softc *sc) -{ - struct ifnet * ifp = &sc->arpcom.ac_if; - int iobase = sc->iobase; - int rx_status; - int pkt_len; - int QQQ; - struct mbuf * m; - struct mbuf * ipkt; - struct ether_header * eh; - - DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit);); - - /* - * For all packets received since last receive interrupt: - * - If packet ok, read it into a new mbuf and queue it to interface, - * updating statistics. - * - If packet bad, just discard it, and update statistics. - * Finally, advance receive stop limit in card's memory to new location. - */ - - outw(iobase + HOST_ADDR_REG, sc->rx_head); - - while (inw(iobase + IO_PORT_REG) == RCV_Done) { - - rx_status = inw(iobase + IO_PORT_REG); - sc->rx_head = inw(iobase + IO_PORT_REG); - QQQ = pkt_len = inw(iobase + IO_PORT_REG); - - if (rx_status & RCV_OK_bit) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - ipkt = m; - if (ipkt == NULL) { - ifp->if_iqdrops++; - } else { - ipkt->m_pkthdr.rcvif = ifp; - ipkt->m_pkthdr.len = pkt_len; - ipkt->m_len = MHLEN; - - while (pkt_len > 0) { - if (pkt_len > MINCLSIZE) { - MCLGET(m, M_DONTWAIT); - if (m->m_flags & M_EXT) { - m->m_len = MCLBYTES; - } else { - m_freem(ipkt); - ifp->if_iqdrops++; - goto rx_another; - } - } - m->m_len = min(m->m_len, pkt_len); - - /* - * NOTE: I'm assuming that all mbufs allocated are of even length, - * except for the last one in an odd-length packet. - */ - - insw(iobase + IO_PORT_REG, - mtod(m, caddr_t), m->m_len / 2); - - if (m->m_len & 1) { - *(mtod(m, caddr_t) + m->m_len - 1) = inb(iobase + IO_PORT_REG); - } - pkt_len -= m->m_len; - - if (pkt_len > 0) { - MGET(m->m_next, M_DONTWAIT, MT_DATA); - if (m->m_next == NULL) { - m_freem(ipkt); - ifp->if_iqdrops++; - goto rx_another; - } - m = m->m_next; - m->m_len = MLEN; - } - } - eh = mtod(ipkt, struct ether_header *); -#ifdef EXDEBUG - if (debug_mask & Rcvd_Pkts) { - if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) { - printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":"); - printf("%6D\n", eh->ether_dhost, ":"); - } /* QQQ */ - } -#endif - if (ifp->if_bpf != NULL) { - bpf_mtap(ifp, ipkt); - - /* - * Note that the interface cannot be in promiscuous mode - * if there are no BPF listeners. And if we are in - * promiscuous mode, we have to check if this packet is - * really ours. - */ - if ((ifp->if_flags & IFF_PROMISC) && - (eh->ether_dhost[0] & 1) == 0 && - bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, sizeof(eh->ether_dhost)) != 0 && - bcmp(eh->ether_dhost, etherbroadcastaddr, sizeof(eh->ether_dhost)) != 0) { - m_freem(ipkt); - goto rx_another; - } - } - m_adj(ipkt, sizeof(struct ether_header)); - ether_input(ifp, eh, ipkt); - ifp->if_ipackets++; - } - } else { - ifp->if_ierrors++; - } - outw(iobase + HOST_ADDR_REG, sc->rx_head); -rx_another: ; - } - - if (sc->rx_head < sc->rx_lower_limit + 2) - outw(iobase + RCV_STOP_REG, sc->rx_upper_limit); - else - outw(iobase + RCV_STOP_REG, sc->rx_head - 2); - - DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit);); - - return; -} - - -static int -ex_ioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) -{ - struct ex_softc * sc = ifp->if_softc; - int s; - int error = 0; - - DODEBUG(Start_End, printf("ex_ioctl%d: start ", ifp->if_unit);); - - s = splimp(); - - switch(cmd) { - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, cmd, data); - break; - - case SIOCSIFFLAGS: - DODEBUG(Start_End, printf("SIOCSIFFLAGS");); - if ((ifp->if_flags & IFF_UP) == 0 && - (ifp->if_flags & IFF_RUNNING)) { - - ifp->if_flags &= ~IFF_RUNNING; - ex_stop(sc); - } else { - ex_init(sc); - } - break; -#ifdef NODEF - case SIOCGHWADDR: - DODEBUG(Start_End, printf("SIOCGHWADDR");); - bcopy((caddr_t)sc->sc_addr, (caddr_t)&ifr->ifr_data, - sizeof(sc->sc_addr)); - break; -#endif - case SIOCADDMULTI: - DODEBUG(Start_End, printf("SIOCADDMULTI");); - case SIOCDELMULTI: - DODEBUG(Start_End, printf("SIOCDELMULTI");); - /* XXX Support not done yet. */ - error = EINVAL; - break; - default: - DODEBUG(Start_End, printf("unknown");); - error = EINVAL; - } - - splx(s); - - DODEBUG(Start_End, printf("\nex_ioctl%d: finish\n", ifp->if_unit);); - - return(error); -} - - -static void -ex_reset(struct ex_softc *sc) -{ - int s; - - DODEBUG(Start_End, printf("ex_reset%d: start\n", unit);); - - s = splimp(); - - ex_stop(sc); - ex_init(sc); - - splx(s); - - DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit);); - - return; -} - - -static void -ex_watchdog(struct ifnet *ifp) -{ - struct ex_softc * sc = ifp->if_softc; - - DODEBUG(Start_End, printf("ex_watchdog%d: start\n", ifp->if_unit);); - - ifp->if_flags &= ~IFF_OACTIVE; - - DODEBUG(Status, printf("OIDLE watchdog\n");); - - ifp->if_oerrors++; - ex_reset(sc); - ex_start(ifp); - - DODEBUG(Start_End, printf("ex_watchdog%d: finish\n", ifp->if_unit);); - - return; -} - - -static u_short -eeprom_read(int iobase, int location) -{ - int i; - u_short data = 0; - int ee_addr; - int read_cmd = location | EE_READ_CMD; - short ctrl_val = EECS; - - ee_addr = iobase + EEPROM_REG; - outb(iobase + CMD_REG, Bank2_Sel); - outb(ee_addr, EECS); - for (i = 8; i >= 0; i--) { - short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val; - outb(ee_addr, outval); - outb(ee_addr, outval | EESK); - DELAY(3); - outb(ee_addr, outval); - DELAY(2); - } - outb(ee_addr, ctrl_val); - - for (i = 16; i > 0; i--) { - outb(ee_addr, ctrl_val | EESK); - DELAY(3); - data = (data << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0); - outb(ee_addr, ctrl_val); - DELAY(2); - } - - ctrl_val &= ~EECS; - outb(ee_addr, ctrl_val | EESK); - DELAY(3); - outb(ee_addr, ctrl_val); - DELAY(2); - outb(iobase + CMD_REG, Bank0_Sel); - return(data); -} |