diff options
Diffstat (limited to 'sys/dev/ex/if_ex.c')
-rw-r--r-- | sys/dev/ex/if_ex.c | 945 |
1 files changed, 0 insertions, 945 deletions
diff --git a/sys/dev/ex/if_ex.c b/sys/dev/ex/if_ex.c deleted file mode 100644 index 2508bd735e22..000000000000 --- a/sys/dev/ex/if_ex.c +++ /dev/null @@ -1,945 +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. - * - * $Id: if_ex.c,v 1.12 1998/06/07 17:10:30 dfr Exp $ - */ - -/* - * 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" -#if NEX > 0 -#include "bpfilter.h" -#include "opt_inet.h" -#include "opt_ipx.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/socket.h> - -#include <net/if.h> - -#ifdef INET -#include <netinet/in.h> -#include <netinet/if_ether.h> -#endif - -#ifdef IPX -#include <netipx/ipx.h> -#include <netipx/ipx_if.h> -#endif - -#ifdef NS -#include <netns/ns.h> -#include <netns/ns_if.h> -#endif - -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <machine/clock.h> - -#include <i386/isa/isa_device.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 - -struct ex_softc { - struct arpcom arpcom; /* Ethernet common data */ - u_int iobase; /* I/O base address. */ - u_short connector; /* Connector type. */ - u_short irq_no; /* IRQ number. */ - char *irq2ee; /* irq <-> internal representation conversion */ - u_char *ee2irq; - 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, rx_upper_limit; /* Lower and upper limits of 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, tx_upper_limit; /* Lower and upper limits of transmit buffer. */ - u_int tx_head, tx_tail; /* Head and tail of transmit ring buffer. */ - u_int tx_last; /* Pointer to beginning of last frame in the chain. */ -}; - -static struct ex_softc ex_sc[NEX]; /* XXX would it be better to malloc(3) the memory? */ - -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 }; - -static int ex_probe __P((struct isa_device *)); -static int ex_attach __P((struct isa_device *)); -static void ex_init __P((void *)); -static void ex_start __P((struct ifnet *)); -static void ex_stop __P((int)); -static ointhand2_t exintr; -static int ex_ioctl __P((struct ifnet *, u_long, caddr_t)); -static void ex_reset __P((int)); -static void ex_watchdog __P((struct ifnet *)); - -static u_short eeprom_read __P((int, int)); -static int look_for_card __P((u_int)); -static void ex_tx_intr __P((int)); -static void ex_rx_intr __P((int)); - -struct isa_driver exdriver = { - ex_probe, - ex_attach, - "ex", - 0 -}; - -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)); -} - - -int ex_probe(struct isa_device *dev) -{ - int unit = dev->id_unit; - struct ex_softc *sc = &ex_sc[unit]; - u_int iobase; - u_short eaddr_tmp; - int tmp; - - DODEBUG(Start_End, printf("ex_probe%d: start\n", unit);); - - /* - * If an I/O address was supplied in the configuration file, probe only - * that. Otherwise, cycle through the predefined set of possible addresses. - */ - if (dev->id_iobase != -1) { - if (! look_for_card(iobase = dev->id_iobase)) - return(0); - } - else { - for (iobase = 0x200; iobase < 0x3a0; iobase += 0x10) - if (look_for_card(iobase)) - break; - if (iobase >= 0x3a0) - return(0); - else - dev->id_iobase = iobase; - } - - /* - * Reset the card. - */ - outb(iobase + CMD_REG, Reset_CMD); - DELAY(400); - - /* - * 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->iobase = iobase; - eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Lo); - sc->arpcom.ac_enaddr[5] = eaddr_tmp & 0xff; - sc->arpcom.ac_enaddr[4] = eaddr_tmp >> 8; - eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Mid); - sc->arpcom.ac_enaddr[3] = eaddr_tmp & 0xff; - sc->arpcom.ac_enaddr[2] = eaddr_tmp >> 8; - eaddr_tmp = eeprom_read(iobase, EE_Eth_Addr_Hi); - sc->arpcom.ac_enaddr[1] = eaddr_tmp & 0xff; - sc->arpcom.ac_enaddr[0] = eaddr_tmp >> 8; - tmp = eeprom_read(iobase, EE_IRQ_No) & IRQ_No_Mask; - - /* work out which set of irq <-> internal tables to use */ - if (sc->arpcom.ac_enaddr[0] == 0x00 && - sc->arpcom.ac_enaddr[1] == 0xA0 && - sc->arpcom.ac_enaddr[2] == 0xC9) { /* it's a 10+ */ - sc->irq2ee = plus_irq2eemap; - sc->ee2irq = plus_ee2irqmap; - } else { /* it's an ordinary 10 */ - sc->irq2ee = irq2eemap; - sc->ee2irq = ee2irqmap; - } - - if (dev->id_irq > 0) { - if (sc->ee2irq[tmp] != ffs(dev->id_irq) - 1) - printf("ex%d: WARNING: board's EEPROM is configured for IRQ %d, using %d\n", unit, sc->ee2irq[tmp], ffs(dev->id_irq) - 1); - sc->irq_no = ffs(dev->id_irq) - 1; - } - else { - sc->irq_no = sc->ee2irq[tmp]; - dev->id_irq = 1 << sc->irq_no; - } - if (sc->irq_no == 0) { - printf("ex%d: invalid IRQ.\n", unit); - return(0); - } - outb(iobase + CMD_REG, Bank2_Sel); - tmp = inb(iobase + REG3); - if (tmp & TPE_bit) - sc->connector = Conn_TPE; - else if (tmp & BNC_bit) - sc->connector = Conn_BNC; - else - sc->connector = Conn_AUI; - sc->mem_size = CARD_RAM_SIZE; /* XXX This should be read from the card itself. */ - - outb(iobase + CMD_REG, Bank0_Sel); - - DODEBUG(Start_End, printf("ex_probe%d: finish\n", unit);); - return(EX_IOSIZE); -} - - -int ex_attach(struct isa_device *dev) -{ - int unit = dev->id_unit; - struct ex_softc *sc = &ex_sc[unit]; - struct ifnet *ifp = &sc->arpcom.ac_if; - - DODEBUG(Start_End, printf("ex_attach%d: start\n", unit);); - - dev->id_ointr = exintr; - - /* - * Initialize the ifnet structure. - */ - ifp->if_softc = sc; - ifp->if_unit = unit; - ifp->if_name = "ex"; - ifp->if_init = ex_init; - ifp->if_output = ether_output; - ifp->if_start = ex_start; - ifp->if_ioctl = ex_ioctl; - ifp->if_watchdog = ex_watchdog; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST /* XXX not done yet. | IFF_MULTICAST */; - - /* - * Attach the interface. - */ - if_attach(ifp); - ether_ifattach(ifp); - - if (sc->arpcom.ac_enaddr[0] == 0x00 && - sc->arpcom.ac_enaddr[1] == 0xA0 && - sc->arpcom.ac_enaddr[2] == 0xC9) { - printf("ex%d: Intel EtherExpress Pro/10+, address %6D, connector ", dev->id_unit, sc->arpcom.ac_enaddr, ":"); - } else { - printf("ex%d: Intel EtherExpress Pro/10, address %6D, connector ", dev->id_unit, sc->arpcom.ac_enaddr, ":"); - } - switch(sc->connector) { - case Conn_TPE: printf("TPE\n"); break; - case Conn_BNC: printf("BNC\n"); break; - case Conn_AUI: printf("AUI\n"); break; - default: printf("???\n"); - } - - /* - * If BPF is in the kernel, call the attach for it - */ -#if NBPFILTER > 0 - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); -#endif - DODEBUG(Start_End, printf("ex_attach%d: finish\n", unit);); - return(1); -} - - -void ex_init(void *xsc) -{ - register struct ex_softc *sc = (struct ex_softc *) xsc; - struct ifnet *ifp = &sc->arpcom.ac_if; - int s, 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);); -} - - -void ex_start(struct ifnet *ifp) -{ - int unit = ifp->if_unit; - register struct ex_softc *sc = &ex_sc[unit]; - register int iobase = sc->iobase; - int i, s, len, data_len, avail, dest, next; - unsigned char tmp16[2]; - struct mbuf *opkt; - register 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) - 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 NBPFILTER > 0 - if (ifp->if_bpf != NULL) - bpf_mtap(ifp, opkt); -#endif - 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);); -} - - -void ex_stop(int unit) -{ - struct ex_softc *sc = &ex_sc[unit]; - 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);); -} - - -static void exintr(int unit) -{ - struct ex_softc *sc = &ex_sc[unit]; - struct ifnet *ifp = &sc->arpcom.ac_if; - int iobase = sc->iobase; - int int_status, send_pkts; - - DODEBUG(Start_End, printf("exintr%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(unit); - } - else if (int_status & Tx_Int) { - outb(iobase + STATUS_REG, Tx_Int); - ex_tx_intr(unit); - 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("exintr%d: finish\n", unit);); -} - - -void ex_tx_intr(int unit) -{ - register struct ex_softc *sc = &ex_sc[unit]; - register struct ifnet *ifp = &sc->arpcom.ac_if; - register 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);); -} - - -void ex_rx_intr(int unit) -{ - register struct ex_softc *sc = &ex_sc[unit]; - register struct ifnet *ifp = &sc->arpcom.ac_if; - register int iobase = sc->iobase; - int rx_status, pkt_len, QQQ; - register struct mbuf *m, *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 NBPFILTER > 0 - 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; - } - } -#endif - 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);); -} - - -int ex_ioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) -{ - register struct ifaddr *ifa = (struct ifaddr *) data; - struct ex_softc *sc = &ex_sc[ifp->if_unit]; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - DODEBUG(Start_End, printf("ex_ioctl%d: start ", ifp->if_unit);); - - s = splimp(); - - switch(cmd) { - case SIOCSIFADDR: - DODEBUG(Start_End, printf("SIOCSIFADDR");); - ifp->if_flags |= IFF_UP; - - switch(ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: - ex_init(sc); - arp_ifinit((struct arpcom *) ifp, ifa); - break; -#endif -#ifdef IPX_NOTYET - case AF_IPX: - { - register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); - - if (ipx_nullhost(*ina)) - ina->x_host = *(union ipx_host *) (sc->arpcom.ac_enaddr); - else { - ifp->if_flags &= ~IFF_RUNNING; - bcopy((caddr_t) ina->x_host.c_host, (caddr_t) sc->arpcom.ac_enaddr, sizeof(sc->arpcom.ac_enaddr)); - } - ex_init(sc); - break; - } -#endif -#ifdef NS - case AF_NS: - { - register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); - - if (ns_nullhost(*ina)) - ina->x_host = *(union ns_host *) (sc->arpcom.ac_enaddr); - else { - ifp->if_flags &= ~IFF_RUNNING; - bcopy((caddr_t) ina->x_host.c_host, (caddr_t) sc->arpcom.ac_enaddr, sizeof(sc->arpcom.ac_enaddr)); - } - ex_init(sc); - break; - } -#endif - default: - ex_init(sc); - break; - } - break; - case SIOCGIFADDR: - { - struct sockaddr *sa; - - DODEBUG(Start_End, printf("SIOCGIFADDR");); - sa = (struct sockaddr *) &ifr->ifr_data; - bcopy((caddr_t) sc->arpcom.ac_enaddr, (caddr_t) sa->sa_data, ETHER_ADDR_LEN); - } - 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(ifp->if_unit); - } - 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 SIOCSIFMTU: - DODEBUG(Start_End, printf("SIOCSIFMTU");); - if (ifr->ifr_mtu > ETHERMTU) - error = EINVAL; - else - ifp->if_mtu = ifr->ifr_mtu; - break; - 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); -} - - -void ex_reset(int unit) -{ - struct ex_softc *sc = &ex_sc[unit]; - int s; - - DODEBUG(Start_End, printf("ex_reset%d: start\n", unit);); - - s = splimp(); - - ex_stop(unit); - ex_init(sc); - - splx(s); - - DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit);); -} - - -void ex_watchdog(struct ifnet *ifp) -{ - - 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(ifp->if_unit); - ex_start(ifp); - - DODEBUG(Start_End, printf("ex_watchdog%d: finish\n", ifp->if_unit);); -} - - -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); -} - -#endif /* NEX > 0 */ |