if_vx.c revision 68417
139230Sgibbs/*
239230Sgibbs * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
339230Sgibbs * All rights reserved.
439230Sgibbs *
539230Sgibbs * Redistribution and use in source and binary forms, with or without
639230Sgibbs * modification, are permitted provided that the following conditions
739230Sgibbs * are met:
839230Sgibbs * 1. Redistributions of source code must retain the above copyright
939230Sgibbs *    notice, this list of conditions and the following disclaimer.
1039230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1139230Sgibbs *    notice, this list of conditions and the following disclaimer in the
1239230Sgibbs *    documentation and/or other materials provided with the distribution.
1339230Sgibbs * 3. All advertising materials mentioning features or use of this software
1439230Sgibbs *    must display the following acknowledgement:
1539230Sgibbs *      This product includes software developed by Herb Peyerl.
1639230Sgibbs * 4. The name of Herb Peyerl may not be used to endorse or promote products
1739230Sgibbs *    derived from this software without specific prior written permission.
1839230Sgibbs *
1939230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2039230Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2139230Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2239230Sgibbs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2339230Sgibbs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2439230Sgibbs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2539230Sgibbs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2639230Sgibbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2739230Sgibbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2850477Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2939230Sgibbs *
3039230Sgibbs * $FreeBSD: head/sys/dev/vx/if_vx.c 68417 2000-11-07 00:56:14Z wpaul $
3139230Sgibbs *
3239230Sgibbs */
3339230Sgibbs
3439230Sgibbs/*
3539230Sgibbs * Created from if_ep.c driver by Fred Gray (fgray@rice.edu) to support
3639230Sgibbs * the 3c590 family.
3739230Sgibbs */
3839230Sgibbs
3939230Sgibbs/*
4039230Sgibbs *	Modified from the FreeBSD 1.1.5.1 version by:
4139230Sgibbs *		 	Andres Vega Garcia
4239230Sgibbs *			INRIA - Sophia Antipolis, France
4339230Sgibbs *			avega@sophia.inria.fr
4439230Sgibbs */
4539230Sgibbs
4639230Sgibbs/*
4739230Sgibbs *  Promiscuous mode added and interrupt logic slightly changed
4839230Sgibbs *  to reduce the number of adapter failures. Transceiver select
4939230Sgibbs *  logic changed to use value from EEPROM. Autoconfiguration
5039230Sgibbs *  features added.
5139230Sgibbs *  Done by:
5239230Sgibbs *          Serge Babkin
5339230Sgibbs *          Chelindbank (Chelyabinsk, Russia)
5439230Sgibbs *          babkin@hq.icb.chel.su
5539230Sgibbs */
5639230Sgibbs
5739230Sgibbs
5839230Sgibbs#include <sys/param.h>
5939230Sgibbs#include <sys/systm.h>
6039230Sgibbs#include <sys/sockio.h>
6139230Sgibbs#include <sys/malloc.h>
6239230Sgibbs#include <sys/mbuf.h>
6339230Sgibbs#include <sys/socket.h>
6439230Sgibbs
6539230Sgibbs#include <net/if.h>
6639230Sgibbs
6739230Sgibbs#include <net/ethernet.h>
6839230Sgibbs#include <net/if_arp.h>
6939230Sgibbs
7039230Sgibbs#include <machine/bus_pio.h>
7139230Sgibbs#include <machine/bus.h>
7239230Sgibbs
7340060Sobrien#include <net/bpf.h>
7440060Sobrien
7540060Sobrien
7639230Sgibbs#include <dev/vx/if_vxreg.h>
7739230Sgibbs
7840060Sobrien#define ETHER_MAX_LEN	1518
7939230Sgibbs#define ETHER_ADDR_LEN	6
8039230Sgibbs
8139230Sgibbsstatic struct connector_entry {
8239230Sgibbs  int bit;
8339230Sgibbs  char *name;
8439230Sgibbs} conn_tab[VX_CONNECTORS] = {
8539230Sgibbs#define CONNECTOR_UTP	0
8639230Sgibbs  { 0x08, "utp"},
8739230Sgibbs#define CONNECTOR_AUI	1
8839498Sken  { 0x20, "aui"},
8939498Sken/* dummy */
9039498Sken  { 0, "???"},
9139498Sken#define CONNECTOR_BNC	3
9239230Sgibbs  { 0x10, "bnc"},
9339230Sgibbs#define CONNECTOR_TX	4
9439230Sgibbs  { 0x02, "tx"},
9539230Sgibbs#define CONNECTOR_FX	5
9639230Sgibbs  { 0x04, "fx"},
9739230Sgibbs#define CONNECTOR_MII	6
9839230Sgibbs  { 0x40, "mii"},
9939230Sgibbs  { 0, "???"}
10039230Sgibbs};
10139230Sgibbs
10239230Sgibbs/* int vxattach __P((struct vx_softc *)); */
10339230Sgibbsstatic void vxtxstat __P((struct vx_softc *));
10439230Sgibbsstatic int vxstatus __P((struct vx_softc *));
10539230Sgibbsstatic void vxinit __P((void *));
10639230Sgibbsstatic int vxioctl __P((struct ifnet *, u_long, caddr_t));
10739230Sgibbsstatic void vxstart __P((struct ifnet *ifp));
10839230Sgibbsstatic void vxwatchdog __P((struct ifnet *));
10939230Sgibbsstatic void vxreset __P((struct vx_softc *));
11039230Sgibbs/* void vxstop __P((struct vx_softc *)); */
11139230Sgibbsstatic void vxread __P((struct vx_softc *));
11283131Skenstatic struct mbuf *vxget __P((struct vx_softc *, u_int));
11339230Sgibbsstatic void vxmbuffill __P((void *));
11439230Sgibbsstatic void vxmbufempty __P((struct vx_softc *));
11539230Sgibbsstatic void vxsetfilter __P((struct vx_softc *));
11639230Sgibbsstatic void vxgetlink __P((struct vx_softc *));
11739230Sgibbsstatic void vxsetlink __P((struct vx_softc *));
11839230Sgibbs/* int vxbusyeeprom __P((struct vx_softc *)); */
11939230Sgibbs
12039230Sgibbs
12139230Sgibbsint
12283131Skenvxattach(sc)
12339230Sgibbs    struct vx_softc *sc;
12439230Sgibbs{
12539230Sgibbs    struct ifnet *ifp = &sc->arpcom.ac_if;
12639230Sgibbs    int i;
12739230Sgibbs
12839230Sgibbs    callout_handle_init(&sc->ch);
12939230Sgibbs    GO_WINDOW(0);
13039230Sgibbs    CSR_WRITE_2(sc, VX_COMMAND, GLOBAL_RESET);
13139230Sgibbs    VX_BUSY_WAIT;
13239230Sgibbs
13339230Sgibbs    vxgetlink(sc);
13439230Sgibbs
13583131Sken    /*
13683131Sken     * Read the station address from the eeprom
13783131Sken     */
13839230Sgibbs    GO_WINDOW(0);
13939230Sgibbs    for (i = 0; i < 3; i++) {
14039230Sgibbs        int x;
14139230Sgibbs        if (vxbusyeeprom(sc))
14239230Sgibbs            return 0;
14339230Sgibbs        CSR_WRITE_2(sc,  VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD
14439230Sgibbs	     | (EEPROM_OEM_ADDR_0 + i));
14539230Sgibbs        if (vxbusyeeprom(sc))
14639230Sgibbs            return 0;
14739230Sgibbs        x = CSR_READ_2(sc, VX_W0_EEPROM_DATA);
14839230Sgibbs        sc->arpcom.ac_enaddr[(i << 1)] = x >> 8;
14939230Sgibbs        sc->arpcom.ac_enaddr[(i << 1) + 1] = x;
15039230Sgibbs    }
15139230Sgibbs
15239230Sgibbs    printf(" address %6D\n", sc->arpcom.ac_enaddr, ":");
15339230Sgibbs
15439230Sgibbs    ifp->if_unit = sc->unit;
15539230Sgibbs    ifp->if_name = "vx";
15639230Sgibbs    ifp->if_mtu = ETHERMTU;
15783131Sken    ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
15883131Sken    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
15983131Sken    ifp->if_output = ether_output;
16083131Sken    ifp->if_start = vxstart;
16183131Sken    ifp->if_ioctl = vxioctl;
16283131Sken    ifp->if_init = vxinit;
16383131Sken    ifp->if_watchdog = vxwatchdog;
16483131Sken    ifp->if_softc = sc;
16583131Sken
16639230Sgibbs    ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
16739230Sgibbs
16839230Sgibbs    sc->tx_start_thresh = 20;	/* probably a good starting point. */
16939230Sgibbs
17039230Sgibbs    vxstop(sc);
17139230Sgibbs
17239230Sgibbs    return 1;
17339230Sgibbs}
17439230Sgibbs
17539230Sgibbs
17639230Sgibbs
17739230Sgibbs/*
17839230Sgibbs * The order in here seems important. Otherwise we may not receive
17939230Sgibbs * interrupts. ?!
18039230Sgibbs */
18139230Sgibbsstatic void
18239230Sgibbsvxinit(xsc)
18339230Sgibbs	void *xsc;
18439230Sgibbs{
18539230Sgibbs    struct vx_softc *sc = (struct vx_softc *) xsc;
18639230Sgibbs    struct ifnet *ifp = &sc->arpcom.ac_if;
18739230Sgibbs    int i;
18839230Sgibbs
18939230Sgibbs    VX_BUSY_WAIT;
19039230Sgibbs
19139230Sgibbs    GO_WINDOW(2);
19239230Sgibbs
19339230Sgibbs    for (i = 0; i < 6; i++) /* Reload the ether_addr. */
19439230Sgibbs	CSR_WRITE_1(sc,  VX_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
19539230Sgibbs
19639230Sgibbs    CSR_WRITE_2(sc,  VX_COMMAND, RX_RESET);
19739230Sgibbs    VX_BUSY_WAIT;
19839230Sgibbs    CSR_WRITE_2(sc,  VX_COMMAND, TX_RESET);
19939230Sgibbs    VX_BUSY_WAIT;
20039230Sgibbs
20139230Sgibbs    GO_WINDOW(1);	/* Window 1 is operating window */
20239230Sgibbs    for (i = 0; i < 31; i++)
20339230Sgibbs	CSR_READ_1(sc,  VX_W1_TX_STATUS);
20439230Sgibbs
20539230Sgibbs    CSR_WRITE_2(sc,  VX_COMMAND,SET_RD_0_MASK | S_CARD_FAILURE |
20639230Sgibbs			S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL);
20739230Sgibbs    CSR_WRITE_2(sc,  VX_COMMAND,SET_INTR_MASK | S_CARD_FAILURE |
20839230Sgibbs			S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL);
20939230Sgibbs
21039230Sgibbs    /*
21139230Sgibbs     * Attempt to get rid of any stray interrupts that occured during
21239230Sgibbs     * configuration.  On the i386 this isn't possible because one may
21339230Sgibbs     * already be queued.  However, a single stray interrupt is
21439230Sgibbs     * unimportant.
21539230Sgibbs     */
21639230Sgibbs    CSR_WRITE_2(sc,  VX_COMMAND, ACK_INTR | 0xff);
21739230Sgibbs
21839230Sgibbs    vxsetfilter(sc);
21939230Sgibbs    vxsetlink(sc);
22039230Sgibbs
22139230Sgibbs    CSR_WRITE_2(sc,  VX_COMMAND, RX_ENABLE);
22283131Sken    CSR_WRITE_2(sc,  VX_COMMAND, TX_ENABLE);
22339230Sgibbs
22439230Sgibbs    vxmbuffill((caddr_t) sc);
22539230Sgibbs
22639230Sgibbs    /* Interface is now `running', with no output active. */
22739230Sgibbs    ifp->if_flags |= IFF_RUNNING;
22839230Sgibbs    ifp->if_flags &= ~IFF_OACTIVE;
22939230Sgibbs
23039230Sgibbs    /* Attempt to start output, if any. */
23183131Sken    vxstart(ifp);
23283131Sken}
23383131Sken
23483131Skenstatic void
23539230Sgibbsvxsetfilter(sc)
23639230Sgibbs    struct vx_softc *sc;
23739230Sgibbs{
23839230Sgibbs    register struct ifnet *ifp = &sc->arpcom.ac_if;
23939230Sgibbs
24039230Sgibbs    GO_WINDOW(1);           /* Window 1 is operating window */
24139230Sgibbs    CSR_WRITE_2(sc,  VX_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST |
24239230Sgibbs	 FIL_MULTICAST |
24339230Sgibbs	 ((ifp->if_flags & IFF_PROMISC) ? FIL_PROMISC : 0 ));
24439230Sgibbs}
24539230Sgibbs
24639230Sgibbsstatic void
24739230Sgibbsvxgetlink(sc)
24839230Sgibbs    struct vx_softc *sc;
24939230Sgibbs{
25039230Sgibbs    int n, k;
25139230Sgibbs
25239230Sgibbs    GO_WINDOW(3);
25339230Sgibbs    sc->vx_connectors = CSR_READ_2(sc, VX_W3_RESET_OPT) & 0x7f;
25439230Sgibbs    for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
25539230Sgibbs      if (sc->vx_connectors & conn_tab[k].bit) {
25639230Sgibbs	if (n > 0) {
25739230Sgibbs	  printf("/");
25839230Sgibbs	}
25939230Sgibbs	printf(conn_tab[k].name);
26039230Sgibbs	n++;
26139230Sgibbs      }
26239230Sgibbs    }
26339230Sgibbs    if (sc->vx_connectors == 0) {
26439230Sgibbs	printf("no connectors!");
26539230Sgibbs	return;
26639230Sgibbs    }
26739230Sgibbs    GO_WINDOW(3);
26839230Sgibbs    sc->vx_connector = (CSR_READ_4(sc,  VX_W3_INTERNAL_CFG)
26939230Sgibbs			& INTERNAL_CONNECTOR_MASK)
27039230Sgibbs			>> INTERNAL_CONNECTOR_BITS;
27139230Sgibbs    if (sc->vx_connector & 0x10) {
27239230Sgibbs	sc->vx_connector &= 0x0f;
27339230Sgibbs	printf("[*%s*]", conn_tab[(int)sc->vx_connector].name);
27439230Sgibbs	printf(": disable 'auto select' with DOS util!");
27539230Sgibbs    } else {
27639230Sgibbs	printf("[*%s*]", conn_tab[(int)sc->vx_connector].name);
27739230Sgibbs    }
27839230Sgibbs}
27939230Sgibbs
28039230Sgibbsstatic void
28139230Sgibbsvxsetlink(sc)
28239230Sgibbs    struct vx_softc *sc;
28339230Sgibbs{
28439230Sgibbs    register struct ifnet *ifp = &sc->arpcom.ac_if;
28539230Sgibbs    int i, j, k;
28639230Sgibbs    char *reason, *warning;
28739230Sgibbs    static short prev_flags;
28839230Sgibbs    static char prev_conn = -1;
28939230Sgibbs
29039230Sgibbs    if (prev_conn == -1) {
29139230Sgibbs	prev_conn = sc->vx_connector;
29239230Sgibbs    }
29339230Sgibbs
29439230Sgibbs    /*
29539230Sgibbs     * S.B.
29639230Sgibbs     *
29739230Sgibbs     * Now behavior was slightly changed:
29839230Sgibbs     *
29939230Sgibbs     * if any of flags link[0-2] is used and its connector is
30039230Sgibbs     * physically present the following connectors are used:
30139230Sgibbs     *
30239230Sgibbs     *   link0 - AUI * highest precedence
30339230Sgibbs     *   link1 - BNC
30439230Sgibbs     *   link2 - UTP * lowest precedence
30539230Sgibbs     *
30639230Sgibbs     * If none of them is specified then
30783131Sken     * connector specified in the EEPROM is used
30883131Sken     * (if present on card or UTP if not).
30983131Sken     */
31083131Sken
31183131Sken    i = sc->vx_connector;	/* default in EEPROM */
31239230Sgibbs    reason = "default";
31339230Sgibbs    warning = 0;
31439230Sgibbs
31539230Sgibbs    if (ifp->if_flags & IFF_LINK0) {
31639230Sgibbs	if (sc->vx_connectors & conn_tab[CONNECTOR_AUI].bit) {
31739230Sgibbs	    i = CONNECTOR_AUI;
31839230Sgibbs	    reason = "link0";
319	} else {
320	    warning = "aui not present! (link0)";
321	}
322    } else if (ifp->if_flags & IFF_LINK1) {
323	if (sc->vx_connectors & conn_tab[CONNECTOR_BNC].bit) {
324	    i = CONNECTOR_BNC;
325	    reason = "link1";
326	} else {
327	    warning = "bnc not present! (link1)";
328	}
329    } else if (ifp->if_flags & IFF_LINK2) {
330	if (sc->vx_connectors & conn_tab[CONNECTOR_UTP].bit) {
331	    i = CONNECTOR_UTP;
332	    reason = "link2";
333	} else {
334	    warning = "utp not present! (link2)";
335	}
336    } else if ((sc->vx_connectors & conn_tab[(int)sc->vx_connector].bit) == 0) {
337	warning = "strange connector type in EEPROM.";
338	reason = "forced";
339	i = CONNECTOR_UTP;
340    }
341
342    /* Avoid unnecessary message. */
343    k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2);
344    if ((k != 0) || (prev_conn != i)) {
345	if (warning != 0) {
346	    printf("vx%d: warning: %s\n", sc->unit, warning);
347	}
348	printf("vx%d: selected %s. (%s)\n",
349	       sc->unit, conn_tab[i].name, reason);
350    }
351
352    /* Set the selected connector. */
353    GO_WINDOW(3);
354    j = CSR_READ_4(sc,  VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
355    CSR_WRITE_4(sc,  VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
356
357    /* First, disable all. */
358    CSR_WRITE_2(sc,  VX_COMMAND, STOP_TRANSCEIVER);
359    DELAY(800);
360    GO_WINDOW(4);
361    CSR_WRITE_2(sc,  VX_W4_MEDIA_TYPE, 0);
362
363    /* Second, enable the selected one. */
364    switch(i) {
365      case CONNECTOR_UTP:
366	GO_WINDOW(4);
367	CSR_WRITE_2(sc,  VX_W4_MEDIA_TYPE, ENABLE_UTP);
368	break;
369      case CONNECTOR_BNC:
370	CSR_WRITE_2(sc,  VX_COMMAND, START_TRANSCEIVER);
371	DELAY(800);
372	break;
373      case CONNECTOR_TX:
374      case CONNECTOR_FX:
375	GO_WINDOW(4);
376	CSR_WRITE_2(sc,  VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
377	break;
378      default:	/* AUI and MII fall here */
379	break;
380    }
381    GO_WINDOW(1);
382
383    prev_flags = ifp->if_flags;
384    prev_conn = i;
385}
386
387static void
388vxstart(ifp)
389    struct ifnet *ifp;
390{
391    register struct vx_softc *sc = ifp->if_softc;
392    register struct mbuf *m, *m0;
393    int sh, len, pad;
394
395    /* Don't transmit if interface is busy or not running */
396    if ((sc->arpcom.ac_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
397	return;
398
399startagain:
400    /* Sneak a peek at the next packet */
401    m0 = ifp->if_snd.ifq_head;
402    if (m0 == 0) {
403	return;
404    }
405    /* We need to use m->m_pkthdr.len, so require the header */
406     if ((m0->m_flags & M_PKTHDR) == 0)
407	panic("vxstart: no header mbuf");
408     len = m0->m_pkthdr.len;
409
410     pad = (4 - len) & 3;
411
412    /*
413     * The 3c509 automatically pads short packets to minimum ethernet length,
414     * but we drop packets that are too large. Perhaps we should truncate
415     * them instead?
416     */
417    if (len + pad > ETHER_MAX_LEN) {
418	/* packet is obviously too large: toss it */
419	++ifp->if_oerrors;
420	IF_DEQUEUE(&ifp->if_snd, m0);
421	m_freem(m0);
422	goto readcheck;
423    }
424    VX_BUSY_WAIT;
425    if (CSR_READ_2(sc, VX_W1_FREE_TX) < len + pad + 4) {
426	CSR_WRITE_2(sc,  VX_COMMAND, SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2));
427	/* not enough room in FIFO */
428	if (CSR_READ_2(sc, VX_W1_FREE_TX) < len + pad + 4) { /* make sure */
429	    ifp->if_flags |= IFF_OACTIVE;
430	    ifp->if_timer = 1;
431	    return;
432	}
433    }
434    CSR_WRITE_2(sc,  VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2));
435    IF_DEQUEUE(&ifp->if_snd, m0);
436    if (m0 == 0) {		/* not really needed */
437	return;
438    }
439
440    VX_BUSY_WAIT;
441    CSR_WRITE_2(sc,  VX_COMMAND, SET_TX_START_THRESH |
442	((len / 4 + sc->tx_start_thresh) >> 2));
443
444    if (sc->arpcom.ac_if.if_bpf) {
445	bpf_mtap(&sc->arpcom.ac_if, m0);
446    }
447
448    /*
449     * Do the output at splhigh() so that an interrupt from another device
450     * won't cause a FIFO underrun.
451     */
452    sh = splhigh();
453
454    CSR_WRITE_4(sc,  VX_W1_TX_PIO_WR_1, len | TX_INDICATE);
455
456    for (m = m0; m != 0;) {
457        if (m->m_len > 3)
458	    bus_space_write_multi_4(sc->vx_btag, sc->vx_bhandle,
459		VX_W1_TX_PIO_WR_1, (u_int32_t *)mtod(m, caddr_t), m->m_len / 4);
460        if (m->m_len & 3)
461	    bus_space_write_multi_1(sc->vx_btag, sc->vx_bhandle,
462		VX_W1_TX_PIO_WR_1,
463		mtod(m, caddr_t) + (m->m_len & ~3) , m->m_len & 3);
464        MFREE(m, m0);
465        m = m0;
466    }
467    while (pad--)
468	CSR_WRITE_1(sc,  VX_W1_TX_PIO_WR_1, 0);	/* Padding */
469
470    splx(sh);
471
472    ++ifp->if_opackets;
473    ifp->if_timer = 1;
474
475readcheck:
476    if ((CSR_READ_2(sc, VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) {
477	/* We received a complete packet. */
478
479	if ((CSR_READ_2(sc, VX_STATUS) & S_INTR_LATCH) == 0) {
480	    /*
481	     * No interrupt, read the packet and continue
482	     * Is  this supposed to happen? Is my motherboard
483	     * completely busted?
484	     */
485	    vxread(sc);
486	} else
487	    /* Got an interrupt, return so that it gets serviced. */
488	    return;
489    } else {
490	/* Check if we are stuck and reset [see XXX comment] */
491	if (vxstatus(sc)) {
492	    if (ifp->if_flags & IFF_DEBUG)
493	       printf("vx%d: adapter reset\n", ifp->if_unit);
494	    vxreset(sc);
495	}
496    }
497
498    goto startagain;
499}
500
501/*
502 * XXX: The 3c509 card can get in a mode where both the fifo status bit
503 *      FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set
504 *      We detect this situation and we reset the adapter.
505 *      It happens at times when there is a lot of broadcast traffic
506 *      on the cable (once in a blue moon).
507 */
508static int
509vxstatus(sc)
510    struct vx_softc *sc;
511{
512    int fifost;
513
514    /*
515     * Check the FIFO status and act accordingly
516     */
517    GO_WINDOW(4);
518    fifost = CSR_READ_2(sc, VX_W4_FIFO_DIAG);
519    GO_WINDOW(1);
520
521    if (fifost & FIFOS_RX_UNDERRUN) {
522	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
523	    printf("vx%d: RX underrun\n", sc->unit);
524	vxreset(sc);
525	return 0;
526    }
527
528    if (fifost & FIFOS_RX_STATUS_OVERRUN) {
529	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
530	    printf("vx%d: RX Status overrun\n", sc->unit);
531	return 1;
532    }
533
534    if (fifost & FIFOS_RX_OVERRUN) {
535	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
536	    printf("vx%d: RX overrun\n", sc->unit);
537	return 1;
538    }
539
540    if (fifost & FIFOS_TX_OVERRUN) {
541	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
542	    printf("vx%d: TX overrun\n", sc->unit);
543	vxreset(sc);
544	return 0;
545    }
546
547    return 0;
548}
549
550static void
551vxtxstat(sc)
552    struct vx_softc *sc;
553{
554    int i;
555
556    /*
557    * We need to read+write TX_STATUS until we get a 0 status
558    * in order to turn off the interrupt flag.
559    */
560    while ((i = CSR_READ_1(sc,  VX_W1_TX_STATUS)) & TXS_COMPLETE) {
561	CSR_WRITE_1(sc,  VX_W1_TX_STATUS, 0x0);
562
563    if (i & TXS_JABBER) {
564	++sc->arpcom.ac_if.if_oerrors;
565	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
566	    printf("vx%d: jabber (%x)\n", sc->unit, i);
567	vxreset(sc);
568    } else if (i & TXS_UNDERRUN) {
569	++sc->arpcom.ac_if.if_oerrors;
570	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
571	    printf("vx%d: fifo underrun (%x) @%d\n",
572		sc->unit, i, sc->tx_start_thresh);
573	if (sc->tx_succ_ok < 100)
574	    sc->tx_start_thresh = min(ETHER_MAX_LEN, sc->tx_start_thresh + 20);
575	sc->tx_succ_ok = 0;
576	vxreset(sc);
577    } else if (i & TXS_MAX_COLLISION) {
578	++sc->arpcom.ac_if.if_collisions;
579	CSR_WRITE_2(sc,  VX_COMMAND, TX_ENABLE);
580	sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
581    } else
582	sc->tx_succ_ok = (sc->tx_succ_ok+1) & 127;
583    }
584}
585
586void
587vxintr(voidsc)
588    void *voidsc;
589{
590    register short status;
591    struct vx_softc *sc = voidsc;
592    struct ifnet *ifp = &sc->arpcom.ac_if;
593
594    for (;;) {
595	CSR_WRITE_2(sc,  VX_COMMAND, C_INTR_LATCH);
596
597	status = CSR_READ_2(sc, VX_STATUS);
598
599	if ((status & (S_TX_COMPLETE | S_TX_AVAIL |
600		S_RX_COMPLETE | S_CARD_FAILURE)) == 0)
601	    break;
602
603	/*
604	 * Acknowledge any interrupts.  It's important that we do this
605	 * first, since there would otherwise be a race condition.
606	 * Due to the i386 interrupt queueing, we may get spurious
607	 * interrupts occasionally.
608	 */
609	CSR_WRITE_2(sc,  VX_COMMAND, ACK_INTR | status);
610
611	if (status & S_RX_COMPLETE)
612	    vxread(sc);
613	if (status & S_TX_AVAIL) {
614	    ifp->if_timer = 0;
615	    sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
616	    vxstart(&sc->arpcom.ac_if);
617	}
618	if (status & S_CARD_FAILURE) {
619	    printf("vx%d: adapter failure (%x)\n", sc->unit, status);
620	    ifp->if_timer = 0;
621	    vxreset(sc);
622	    return;
623	}
624	if (status & S_TX_COMPLETE) {
625	    ifp->if_timer = 0;
626	    vxtxstat(sc);
627	    vxstart(ifp);
628	}
629    }
630
631    /* no more interrupts */
632    return;
633}
634
635static void
636vxread(sc)
637    struct vx_softc *sc;
638{
639    struct ifnet *ifp = &sc->arpcom.ac_if;
640    struct mbuf *m;
641    struct ether_header *eh;
642    u_int len;
643
644    len = CSR_READ_2(sc, VX_W1_RX_STATUS);
645
646again:
647
648    if (ifp->if_flags & IFF_DEBUG) {
649	int err = len & ERR_MASK;
650	char *s = NULL;
651
652	if (len & ERR_INCOMPLETE)
653	    s = "incomplete packet";
654	else if (err == ERR_OVERRUN)
655	    s = "packet overrun";
656	else if (err == ERR_RUNT)
657	    s = "runt packet";
658	else if (err == ERR_ALIGNMENT)
659	    s = "bad alignment";
660	else if (err == ERR_CRC)
661	    s = "bad crc";
662	else if (err == ERR_OVERSIZE)
663	    s = "oversized packet";
664	else if (err == ERR_DRIBBLE)
665	    s = "dribble bits";
666
667	if (s)
668	printf("vx%d: %s\n", sc->unit, s);
669    }
670
671    if (len & ERR_INCOMPLETE)
672	return;
673
674    if (len & ERR_RX) {
675	++ifp->if_ierrors;
676	goto abort;
677    }
678
679    len &= RX_BYTES_MASK;	/* Lower 11 bits = RX bytes. */
680
681    /* Pull packet off interface. */
682    m = vxget(sc, len);
683    if (m == 0) {
684	ifp->if_ierrors++;
685	goto abort;
686    }
687
688    ++ifp->if_ipackets;
689
690    /* We assume the header fit entirely in one mbuf. */
691    eh = mtod(m, struct ether_header *);
692
693    /*
694     * XXX: Some cards seem to be in promiscous mode all the time.
695     * we need to make sure we only get our own stuff always.
696     * bleah!
697     */
698
699    if ((eh->ether_dhost[0] & 1) == 0		/* !mcast and !bcast */
700      && bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) != 0) {
701	m_freem(m);
702	return;
703    }
704
705    m_adj(m, sizeof(struct ether_header));
706    ether_input(ifp, eh, m);
707
708    /*
709    * In periods of high traffic we can actually receive enough
710    * packets so that the fifo overrun bit will be set at this point,
711    * even though we just read a packet. In this case we
712    * are not going to receive any more interrupts. We check for
713    * this condition and read again until the fifo is not full.
714    * We could simplify this test by not using vxstatus(), but
715    * rechecking the RX_STATUS register directly. This test could
716    * result in unnecessary looping in cases where there is a new
717    * packet but the fifo is not full, but it will not fix the
718    * stuck behavior.
719    *
720    * Even with this improvement, we still get packet overrun errors
721    * which are hurting performance. Maybe when I get some more time
722    * I'll modify vxread() so that it can handle RX_EARLY interrupts.
723    */
724    if (vxstatus(sc)) {
725	len = CSR_READ_2(sc, VX_W1_RX_STATUS);
726	/* Check if we are stuck and reset [see XXX comment] */
727	if (len & ERR_INCOMPLETE) {
728	    if (ifp->if_flags & IFF_DEBUG)
729		printf("vx%d: adapter reset\n", sc->unit);
730	    vxreset(sc);
731	    return;
732	}
733	goto again;
734    }
735
736    return;
737
738abort:
739    CSR_WRITE_2(sc,  VX_COMMAND, RX_DISCARD_TOP_PACK);
740}
741
742static struct mbuf *
743vxget(sc, totlen)
744    struct vx_softc *sc;
745    u_int totlen;
746{
747    struct ifnet *ifp = &sc->arpcom.ac_if;
748    struct mbuf *top, **mp, *m;
749    int len;
750    int sh;
751
752    m = sc->mb[sc->next_mb];
753    sc->mb[sc->next_mb] = 0;
754    if (m == 0) {
755        MGETHDR(m, M_DONTWAIT, MT_DATA);
756        if (m == 0)
757            return 0;
758    } else {
759        /* If the queue is no longer full, refill. */
760        if (sc->last_mb == sc->next_mb && sc->buffill_pending == 0) {
761	    sc->ch = timeout(vxmbuffill, sc, 1);
762	    sc->buffill_pending = 1;
763	}
764        /* Convert one of our saved mbuf's. */
765        sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
766        m->m_data = m->m_pktdat;
767        m->m_flags = M_PKTHDR;
768	bzero(&m->m_pkthdr, sizeof(m->m_pkthdr));
769    }
770    m->m_pkthdr.rcvif = ifp;
771    m->m_pkthdr.len = totlen;
772    len = MHLEN;
773    top = 0;
774    mp = &top;
775
776    /*
777     * We read the packet at splhigh() so that an interrupt from another
778     * device doesn't cause the card's buffer to overflow while we're
779     * reading it.  We may still lose packets at other times.
780     */
781    sh = splhigh();
782
783    /*
784     * Since we don't set allowLargePackets bit in MacControl register,
785     * we can assume that totlen <= 1500bytes.
786     * The while loop will be performed iff we have a packet with
787     * MLEN < m_len < MINCLSIZE.
788     */
789    while (totlen > 0) {
790        if (top) {
791            m = sc->mb[sc->next_mb];
792            sc->mb[sc->next_mb] = 0;
793            if (m == 0) {
794                MGET(m, M_DONTWAIT, MT_DATA);
795                if (m == 0) {
796                    splx(sh);
797                    m_freem(top);
798                    return 0;
799                }
800            } else {
801                sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
802            }
803            len = MLEN;
804        }
805        if (totlen >= MINCLSIZE) {
806	    MCLGET(m, M_DONTWAIT);
807	    if (m->m_flags & M_EXT)
808		len = MCLBYTES;
809        }
810        len = min(totlen, len);
811        if (len > 3)
812            bus_space_read_multi_4(sc->vx_btag, sc->vx_bhandle,
813		VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), len / 4);
814	if (len & 3) {
815            bus_space_read_multi_1(sc->vx_btag, sc->vx_bhandle,
816		VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3),
817		len & 3);
818	}
819        m->m_len = len;
820        totlen -= len;
821        *mp = m;
822        mp = &m->m_next;
823    }
824
825    CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK);
826
827    splx(sh);
828
829    return top;
830}
831
832
833static int
834vxioctl(ifp, cmd, data)
835    register struct ifnet *ifp;
836    u_long cmd;
837    caddr_t data;
838{
839    struct vx_softc *sc = ifp->if_softc;
840    struct ifreq *ifr = (struct ifreq *) data;
841    int s, error = 0;
842
843    s = splimp();
844
845    switch (cmd) {
846    case SIOCSIFADDR:
847    case SIOCGIFADDR:
848	ether_ioctl(ifp, cmd, data);
849	break;
850
851    case SIOCSIFFLAGS:
852	if ((ifp->if_flags & IFF_UP) == 0 &&
853	    (ifp->if_flags & IFF_RUNNING) != 0) {
854	    /*
855             * If interface is marked up and it is stopped, then
856             * start it.
857             */
858	    vxstop(sc);
859	    ifp->if_flags &= ~IFF_RUNNING;
860        } else if ((ifp->if_flags & IFF_UP) != 0 &&
861                   (ifp->if_flags & IFF_RUNNING) == 0) {
862            /*
863             * If interface is marked up and it is stopped, then
864             * start it.
865             */
866            vxinit(sc);
867        } else {
868            /*
869             * deal with flags changes:
870             * IFF_MULTICAST, IFF_PROMISC,
871             * IFF_LINK0, IFF_LINK1,
872             */
873            vxsetfilter(sc);
874            vxsetlink(sc);
875        }
876        break;
877
878    case SIOCSIFMTU:
879        /*
880         * Set the interface MTU.
881         */
882        if (ifr->ifr_mtu > ETHERMTU) {
883            error = EINVAL;
884        } else {
885            ifp->if_mtu = ifr->ifr_mtu;
886        }
887        break;
888
889    case SIOCADDMULTI:
890    case SIOCDELMULTI:
891	/*
892	 * Multicast list has changed; set the hardware filter
893	 * accordingly.
894	 */
895	vxreset(sc);
896	error = 0;
897        break;
898
899
900    default:
901        error = EINVAL;
902    }
903
904    splx(s);
905
906    return (error);
907}
908
909static void
910vxreset(sc)
911    struct vx_softc *sc;
912{
913    int s;
914    s = splimp();
915
916    vxstop(sc);
917    vxinit(sc);
918    splx(s);
919}
920
921static void
922vxwatchdog(ifp)
923    struct ifnet *ifp;
924{
925    struct vx_softc *sc = ifp->if_softc;
926
927    if (ifp->if_flags & IFF_DEBUG)
928	printf("vx%d: device timeout\n", ifp->if_unit);
929    ifp->if_flags &= ~IFF_OACTIVE;
930    vxstart(ifp);
931    vxintr(sc);
932}
933
934void
935vxstop(sc)
936    struct vx_softc *sc;
937{
938    struct ifnet *ifp = &sc->arpcom.ac_if;
939
940    ifp->if_timer = 0;
941
942    CSR_WRITE_2(sc,  VX_COMMAND, RX_DISABLE);
943    CSR_WRITE_2(sc,  VX_COMMAND, RX_DISCARD_TOP_PACK);
944    VX_BUSY_WAIT;
945    CSR_WRITE_2(sc,  VX_COMMAND, TX_DISABLE);
946    CSR_WRITE_2(sc,  VX_COMMAND, STOP_TRANSCEIVER);
947    DELAY(800);
948    CSR_WRITE_2(sc,  VX_COMMAND, RX_RESET);
949    VX_BUSY_WAIT;
950    CSR_WRITE_2(sc,  VX_COMMAND, TX_RESET);
951    VX_BUSY_WAIT;
952    CSR_WRITE_2(sc,  VX_COMMAND, C_INTR_LATCH);
953    CSR_WRITE_2(sc,  VX_COMMAND, SET_RD_0_MASK);
954    CSR_WRITE_2(sc,  VX_COMMAND, SET_INTR_MASK);
955    CSR_WRITE_2(sc,  VX_COMMAND, SET_RX_FILTER);
956
957    vxmbufempty(sc);
958}
959
960int
961vxbusyeeprom(sc)
962    struct vx_softc *sc;
963{
964    int j, i = 100;
965
966    while (i--) {
967        j = CSR_READ_2(sc, VX_W0_EEPROM_COMMAND);
968        if (j & EEPROM_BUSY)
969            DELAY(100);
970        else
971            break;
972    }
973    if (!i) {
974        printf("vx%d: eeprom failed to come ready\n", sc->unit);
975        return (1);
976    }
977    return (0);
978}
979
980static void
981vxmbuffill(sp)
982    void *sp;
983{
984    struct vx_softc *sc = (struct vx_softc *) sp;
985    int s, i;
986
987    s = splimp();
988    i = sc->last_mb;
989    do {
990	if (sc->mb[i] == NULL)
991	    MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
992	if (sc->mb[i] == NULL)
993	    break;
994	i = (i + 1) % MAX_MBS;
995    } while (i != sc->next_mb);
996    sc->last_mb = i;
997    /* If the queue was not filled, try again. */
998    if (sc->last_mb != sc->next_mb) {
999	sc->ch = timeout(vxmbuffill, sc, 1);
1000	sc->buffill_pending = 1;
1001    } else {
1002	sc->buffill_pending = 0;
1003    }
1004    splx(s);
1005}
1006
1007static void
1008vxmbufempty(sc)
1009    struct vx_softc *sc;
1010{
1011    int s, i;
1012
1013    s = splimp();
1014    for (i = 0; i < MAX_MBS; i++) {
1015	if (sc->mb[i]) {
1016	    m_freem(sc->mb[i]);
1017	    sc->mb[i] = NULL;
1018	}
1019    }
1020    sc->last_mb = sc->next_mb = 0;
1021    if (sc->buffill_pending != 0)
1022	untimeout(vxmbuffill, sc, sc->ch);
1023    splx(s);
1024}
1025