if_vx.c revision 67164
1/*
2 * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *      This product includes software developed by Herb Peyerl.
16 * 4. The name of Herb Peyerl may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $FreeBSD: head/sys/dev/vx/if_vx.c 67164 2000-10-15 14:19:01Z phk $
31 *
32 */
33
34/*
35 * Created from if_ep.c driver by Fred Gray (fgray@rice.edu) to support
36 * the 3c590 family.
37 */
38
39/*
40 *	Modified from the FreeBSD 1.1.5.1 version by:
41 *		 	Andres Vega Garcia
42 *			INRIA - Sophia Antipolis, France
43 *			avega@sophia.inria.fr
44 */
45
46/*
47 *  Promiscuous mode added and interrupt logic slightly changed
48 *  to reduce the number of adapter failures. Transceiver select
49 *  logic changed to use value from EEPROM. Autoconfiguration
50 *  features added.
51 *  Done by:
52 *          Serge Babkin
53 *          Chelindbank (Chelyabinsk, Russia)
54 *          babkin@hq.icb.chel.su
55 */
56
57#include "vx.h"
58
59#if NVX < 4	/* These cost 4 bytes apiece, so give us 4 */
60#undef NVX
61#define NVX 4
62#endif
63
64
65#include <sys/param.h>
66#include <sys/systm.h>
67#include <sys/sockio.h>
68#include <sys/malloc.h>
69#include <sys/mbuf.h>
70#include <sys/socket.h>
71
72#include <net/if.h>
73
74#include <net/ethernet.h>
75#include <net/if_arp.h>
76
77#include <net/bpf.h>
78
79
80#include <dev/vx/if_vxreg.h>
81
82#define ETHER_MAX_LEN	1518
83#define ETHER_ADDR_LEN	6
84
85struct vx_softc *vx_softc[NVX];
86
87u_long vx_count;	/* both PCI and EISA */
88
89static struct connector_entry {
90  int bit;
91  char *name;
92} conn_tab[VX_CONNECTORS] = {
93#define CONNECTOR_UTP	0
94  { 0x08, "utp"},
95#define CONNECTOR_AUI	1
96  { 0x20, "aui"},
97/* dummy */
98  { 0, "???"},
99#define CONNECTOR_BNC	3
100  { 0x10, "bnc"},
101#define CONNECTOR_TX	4
102  { 0x02, "tx"},
103#define CONNECTOR_FX	5
104  { 0x04, "fx"},
105#define CONNECTOR_MII	6
106  { 0x40, "mii"},
107  { 0, "???"}
108};
109
110/* struct vx_softc *vxalloc __P((int)); */
111/* void *vxfree __P((struct vx_softc *)); */
112/* int vxattach __P((struct vx_softc *)); */
113static void vxtxstat __P((struct vx_softc *));
114static int vxstatus __P((struct vx_softc *));
115static void vxinit __P((void *));
116static int vxioctl __P((struct ifnet *, u_long, caddr_t));
117static void vxstart __P((struct ifnet *ifp));
118static void vxwatchdog __P((struct ifnet *));
119static void vxreset __P((struct vx_softc *));
120/* void vxstop __P((struct vx_softc *)); */
121static void vxread __P((struct vx_softc *));
122static struct mbuf *vxget __P((struct vx_softc *, u_int));
123static void vxmbuffill __P((void *));
124static void vxmbufempty __P((struct vx_softc *));
125static void vxsetfilter __P((struct vx_softc *));
126static void vxgetlink __P((struct vx_softc *));
127static void vxsetlink __P((struct vx_softc *));
128/* int vxbusyeeprom __P((struct vx_softc *)); */
129
130struct vx_softc *
131vxalloc(unit)
132    int unit;
133{
134    struct vx_softc *sc;
135
136    if (unit >= NVX) {
137	printf("vx%d: unit number too high.\n", unit);
138	return NULL;
139    }
140
141    if (vx_softc[unit]) {
142	printf("vx%d: already allocated.\n", unit);
143	return NULL;
144    }
145
146    sc = malloc(sizeof(struct vx_softc), M_DEVBUF, M_NOWAIT);
147    if (sc == NULL) {
148	printf("vx%d: cannot malloc.\n", unit);
149	return NULL;
150    }
151    bzero(sc, sizeof(struct vx_softc));
152    callout_handle_init(&sc->ch);
153
154    vx_softc[unit] = sc;
155    sc->unit = unit;
156    return (sc);
157}
158
159void
160vxfree(sc)
161    struct vx_softc *sc;
162{
163    vx_softc[sc->unit] = NULL;
164    free(sc, M_DEVBUF);
165    return;
166}
167
168int
169vxattach(sc)
170    struct vx_softc *sc;
171{
172    struct ifnet *ifp = &sc->arpcom.ac_if;
173    int i;
174
175    GO_WINDOW(0);
176    outw(VX_COMMAND, GLOBAL_RESET);
177    VX_BUSY_WAIT;
178
179    vxgetlink(sc);
180
181    /*
182     * Read the station address from the eeprom
183     */
184    GO_WINDOW(0);
185    for (i = 0; i < 3; i++) {
186        int x;
187        if (vxbusyeeprom(sc))
188            return 0;
189        outw(BASE + VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD
190	     | (EEPROM_OEM_ADDR_0 + i));
191        if (vxbusyeeprom(sc))
192            return 0;
193        x = inw(BASE + VX_W0_EEPROM_DATA);
194        sc->arpcom.ac_enaddr[(i << 1)] = x >> 8;
195        sc->arpcom.ac_enaddr[(i << 1) + 1] = x;
196    }
197
198    printf(" address %6D\n", sc->arpcom.ac_enaddr, ":");
199
200    ifp->if_unit = sc->unit;
201    ifp->if_name = "vx";
202    ifp->if_mtu = ETHERMTU;
203    ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
204    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
205    ifp->if_output = ether_output;
206    ifp->if_start = vxstart;
207    ifp->if_ioctl = vxioctl;
208    ifp->if_init = vxinit;
209    ifp->if_watchdog = vxwatchdog;
210    ifp->if_softc = sc;
211
212    ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
213
214    sc->tx_start_thresh = 20;	/* probably a good starting point. */
215
216    vxstop(sc);
217
218    return 1;
219}
220
221
222
223/*
224 * The order in here seems important. Otherwise we may not receive
225 * interrupts. ?!
226 */
227static void
228vxinit(xsc)
229	void *xsc;
230{
231    struct vx_softc *sc = (struct vx_softc *) xsc;
232    struct ifnet *ifp = &sc->arpcom.ac_if;
233    int i;
234
235    VX_BUSY_WAIT;
236
237    GO_WINDOW(2);
238
239    for (i = 0; i < 6; i++) /* Reload the ether_addr. */
240	outb(BASE + VX_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
241
242    outw(BASE + VX_COMMAND, RX_RESET);
243    VX_BUSY_WAIT;
244    outw(BASE + VX_COMMAND, TX_RESET);
245    VX_BUSY_WAIT;
246
247    GO_WINDOW(1);	/* Window 1 is operating window */
248    for (i = 0; i < 31; i++)
249	inb(BASE + VX_W1_TX_STATUS);
250
251    outw(BASE + VX_COMMAND,SET_RD_0_MASK | S_CARD_FAILURE |
252			S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL);
253    outw(BASE + VX_COMMAND,SET_INTR_MASK | S_CARD_FAILURE |
254			S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL);
255
256    /*
257     * Attempt to get rid of any stray interrupts that occured during
258     * configuration.  On the i386 this isn't possible because one may
259     * already be queued.  However, a single stray interrupt is
260     * unimportant.
261     */
262    outw(BASE + VX_COMMAND, ACK_INTR | 0xff);
263
264    vxsetfilter(sc);
265    vxsetlink(sc);
266
267    outw(BASE + VX_COMMAND, RX_ENABLE);
268    outw(BASE + VX_COMMAND, TX_ENABLE);
269
270    vxmbuffill((caddr_t) sc);
271
272    /* Interface is now `running', with no output active. */
273    ifp->if_flags |= IFF_RUNNING;
274    ifp->if_flags &= ~IFF_OACTIVE;
275
276    /* Attempt to start output, if any. */
277    vxstart(ifp);
278}
279
280static void
281vxsetfilter(sc)
282    struct vx_softc *sc;
283{
284    register struct ifnet *ifp = &sc->arpcom.ac_if;
285
286    GO_WINDOW(1);           /* Window 1 is operating window */
287    outw(BASE + VX_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST |
288	 FIL_MULTICAST |
289	 ((ifp->if_flags & IFF_PROMISC) ? FIL_PROMISC : 0 ));
290}
291
292static void
293vxgetlink(sc)
294    struct vx_softc *sc;
295{
296    int n, k;
297
298    GO_WINDOW(3);
299    sc->vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
300    for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
301      if (sc->vx_connectors & conn_tab[k].bit) {
302	if (n > 0) {
303	  printf("/");
304	}
305	printf(conn_tab[k].name);
306	n++;
307      }
308    }
309    if (sc->vx_connectors == 0) {
310	printf("no connectors!");
311	return;
312    }
313    GO_WINDOW(3);
314    sc->vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG)
315			& INTERNAL_CONNECTOR_MASK)
316			>> INTERNAL_CONNECTOR_BITS;
317    if (sc->vx_connector & 0x10) {
318	sc->vx_connector &= 0x0f;
319	printf("[*%s*]", conn_tab[(int)sc->vx_connector].name);
320	printf(": disable 'auto select' with DOS util!");
321    } else {
322	printf("[*%s*]", conn_tab[(int)sc->vx_connector].name);
323    }
324}
325
326static void
327vxsetlink(sc)
328    struct vx_softc *sc;
329{
330    register struct ifnet *ifp = &sc->arpcom.ac_if;
331    int i, j, k;
332    char *reason, *warning;
333    static short prev_flags;
334    static char prev_conn = -1;
335
336    if (prev_conn == -1) {
337	prev_conn = sc->vx_connector;
338    }
339
340    /*
341     * S.B.
342     *
343     * Now behavior was slightly changed:
344     *
345     * if any of flags link[0-2] is used and its connector is
346     * physically present the following connectors are used:
347     *
348     *   link0 - AUI * highest precedence
349     *   link1 - BNC
350     *   link2 - UTP * lowest precedence
351     *
352     * If none of them is specified then
353     * connector specified in the EEPROM is used
354     * (if present on card or UTP if not).
355     */
356
357    i = sc->vx_connector;	/* default in EEPROM */
358    reason = "default";
359    warning = 0;
360
361    if (ifp->if_flags & IFF_LINK0) {
362	if (sc->vx_connectors & conn_tab[CONNECTOR_AUI].bit) {
363	    i = CONNECTOR_AUI;
364	    reason = "link0";
365	} else {
366	    warning = "aui not present! (link0)";
367	}
368    } else if (ifp->if_flags & IFF_LINK1) {
369	if (sc->vx_connectors & conn_tab[CONNECTOR_BNC].bit) {
370	    i = CONNECTOR_BNC;
371	    reason = "link1";
372	} else {
373	    warning = "bnc not present! (link1)";
374	}
375    } else if (ifp->if_flags & IFF_LINK2) {
376	if (sc->vx_connectors & conn_tab[CONNECTOR_UTP].bit) {
377	    i = CONNECTOR_UTP;
378	    reason = "link2";
379	} else {
380	    warning = "utp not present! (link2)";
381	}
382    } else if ((sc->vx_connectors & conn_tab[(int)sc->vx_connector].bit) == 0) {
383	warning = "strange connector type in EEPROM.";
384	reason = "forced";
385	i = CONNECTOR_UTP;
386    }
387
388    /* Avoid unnecessary message. */
389    k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2);
390    if ((k != 0) || (prev_conn != i)) {
391	if (warning != 0) {
392	    printf("vx%d: warning: %s\n", sc->unit, warning);
393	}
394	printf("vx%d: selected %s. (%s)\n",
395	       sc->unit, conn_tab[i].name, reason);
396    }
397
398    /* Set the selected connector. */
399    GO_WINDOW(3);
400    j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
401    outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
402
403    /* First, disable all. */
404    outw(BASE + VX_COMMAND, STOP_TRANSCEIVER);
405    DELAY(800);
406    GO_WINDOW(4);
407    outw(BASE + VX_W4_MEDIA_TYPE, 0);
408
409    /* Second, enable the selected one. */
410    switch(i) {
411      case CONNECTOR_UTP:
412	GO_WINDOW(4);
413	outw(BASE + VX_W4_MEDIA_TYPE, ENABLE_UTP);
414	break;
415      case CONNECTOR_BNC:
416	outw(BASE + VX_COMMAND, START_TRANSCEIVER);
417	DELAY(800);
418	break;
419      case CONNECTOR_TX:
420      case CONNECTOR_FX:
421	GO_WINDOW(4);
422	outw(BASE + VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
423	break;
424      default:	/* AUI and MII fall here */
425	break;
426    }
427    GO_WINDOW(1);
428
429    prev_flags = ifp->if_flags;
430    prev_conn = i;
431}
432
433static void
434vxstart(ifp)
435    struct ifnet *ifp;
436{
437    register struct vx_softc *sc = vx_softc[ifp->if_unit];
438    register struct mbuf *m, *m0;
439    int sh, len, pad;
440
441    /* Don't transmit if interface is busy or not running */
442    if ((sc->arpcom.ac_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
443	return;
444
445startagain:
446    /* Sneak a peek at the next packet */
447    m0 = ifp->if_snd.ifq_head;
448    if (m0 == 0) {
449	return;
450    }
451    /* We need to use m->m_pkthdr.len, so require the header */
452     if ((m0->m_flags & M_PKTHDR) == 0)
453	panic("vxstart: no header mbuf");
454     len = m0->m_pkthdr.len;
455
456     pad = (4 - len) & 3;
457
458    /*
459     * The 3c509 automatically pads short packets to minimum ethernet length,
460     * but we drop packets that are too large. Perhaps we should truncate
461     * them instead?
462     */
463    if (len + pad > ETHER_MAX_LEN) {
464	/* packet is obviously too large: toss it */
465	++ifp->if_oerrors;
466	IF_DEQUEUE(&ifp->if_snd, m0);
467	m_freem(m0);
468	goto readcheck;
469    }
470    VX_BUSY_WAIT;
471    if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
472	outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2));
473	/* not enough room in FIFO */
474	if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) { /* make sure */
475	    ifp->if_flags |= IFF_OACTIVE;
476	    ifp->if_timer = 1;
477	    return;
478	}
479    }
480    outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2));
481    IF_DEQUEUE(&ifp->if_snd, m0);
482    if (m0 == 0) {		/* not really needed */
483	return;
484    }
485
486    VX_BUSY_WAIT;
487    outw(BASE + VX_COMMAND, SET_TX_START_THRESH |
488	((len / 4 + sc->tx_start_thresh) >> 2));
489
490    if (sc->arpcom.ac_if.if_bpf) {
491	bpf_mtap(&sc->arpcom.ac_if, m0);
492    }
493
494    /*
495     * Do the output at splhigh() so that an interrupt from another device
496     * won't cause a FIFO underrun.
497     */
498    sh = splhigh();
499
500    outl(BASE + VX_W1_TX_PIO_WR_1, len | TX_INDICATE);
501
502    for (m = m0; m != 0;) {
503        if (m->m_len > 3)
504	    outsl(BASE + VX_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 4);
505        if (m->m_len & 3)
506	    outsb(BASE + VX_W1_TX_PIO_WR_1,
507	      mtod(m, caddr_t) + (m->m_len & ~3) , m->m_len & 3);
508        MFREE(m, m0);
509        m = m0;
510    }
511    while (pad--)
512	outb(BASE + VX_W1_TX_PIO_WR_1, 0);	/* Padding */
513
514    splx(sh);
515
516    ++ifp->if_opackets;
517    ifp->if_timer = 1;
518
519readcheck:
520    if ((inw(BASE + VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) {
521	/* We received a complete packet. */
522
523	if ((inw(BASE + VX_STATUS) & S_INTR_LATCH) == 0) {
524	    /*
525	     * No interrupt, read the packet and continue
526	     * Is  this supposed to happen? Is my motherboard
527	     * completely busted?
528	     */
529	    vxread(sc);
530	} else
531	    /* Got an interrupt, return so that it gets serviced. */
532	    return;
533    } else {
534	/* Check if we are stuck and reset [see XXX comment] */
535	if (vxstatus(sc)) {
536	    if (ifp->if_flags & IFF_DEBUG)
537	       printf("vx%d: adapter reset\n", ifp->if_unit);
538	    vxreset(sc);
539	}
540    }
541
542    goto startagain;
543}
544
545/*
546 * XXX: The 3c509 card can get in a mode where both the fifo status bit
547 *      FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set
548 *      We detect this situation and we reset the adapter.
549 *      It happens at times when there is a lot of broadcast traffic
550 *      on the cable (once in a blue moon).
551 */
552static int
553vxstatus(sc)
554    struct vx_softc *sc;
555{
556    int fifost;
557
558    /*
559     * Check the FIFO status and act accordingly
560     */
561    GO_WINDOW(4);
562    fifost = inw(BASE + VX_W4_FIFO_DIAG);
563    GO_WINDOW(1);
564
565    if (fifost & FIFOS_RX_UNDERRUN) {
566	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
567	    printf("vx%d: RX underrun\n", sc->unit);
568	vxreset(sc);
569	return 0;
570    }
571
572    if (fifost & FIFOS_RX_STATUS_OVERRUN) {
573	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
574	    printf("vx%d: RX Status overrun\n", sc->unit);
575	return 1;
576    }
577
578    if (fifost & FIFOS_RX_OVERRUN) {
579	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
580	    printf("vx%d: RX overrun\n", sc->unit);
581	return 1;
582    }
583
584    if (fifost & FIFOS_TX_OVERRUN) {
585	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
586	    printf("vx%d: TX overrun\n", sc->unit);
587	vxreset(sc);
588	return 0;
589    }
590
591    return 0;
592}
593
594static void
595vxtxstat(sc)
596    struct vx_softc *sc;
597{
598    int i;
599
600    /*
601    * We need to read+write TX_STATUS until we get a 0 status
602    * in order to turn off the interrupt flag.
603    */
604    while ((i = inb(BASE + VX_W1_TX_STATUS)) & TXS_COMPLETE) {
605	outb(BASE + VX_W1_TX_STATUS, 0x0);
606
607    if (i & TXS_JABBER) {
608	++sc->arpcom.ac_if.if_oerrors;
609	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
610	    printf("vx%d: jabber (%x)\n", sc->unit, i);
611	vxreset(sc);
612    } else if (i & TXS_UNDERRUN) {
613	++sc->arpcom.ac_if.if_oerrors;
614	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
615	    printf("vx%d: fifo underrun (%x) @%d\n",
616		sc->unit, i, sc->tx_start_thresh);
617	if (sc->tx_succ_ok < 100)
618	    sc->tx_start_thresh = min(ETHER_MAX_LEN, sc->tx_start_thresh + 20);
619	sc->tx_succ_ok = 0;
620	vxreset(sc);
621    } else if (i & TXS_MAX_COLLISION) {
622	++sc->arpcom.ac_if.if_collisions;
623	outw(BASE + VX_COMMAND, TX_ENABLE);
624	sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
625    } else
626	sc->tx_succ_ok = (sc->tx_succ_ok+1) & 127;
627    }
628}
629
630void
631vxintr(voidsc)
632    void *voidsc;
633{
634    register short status;
635    struct vx_softc *sc = voidsc;
636    struct ifnet *ifp = &sc->arpcom.ac_if;
637
638    for (;;) {
639	outw(BASE + VX_COMMAND, C_INTR_LATCH);
640
641	status = inw(BASE + VX_STATUS);
642
643	if ((status & (S_TX_COMPLETE | S_TX_AVAIL |
644		S_RX_COMPLETE | S_CARD_FAILURE)) == 0)
645	    break;
646
647	/*
648	 * Acknowledge any interrupts.  It's important that we do this
649	 * first, since there would otherwise be a race condition.
650	 * Due to the i386 interrupt queueing, we may get spurious
651	 * interrupts occasionally.
652	 */
653	outw(BASE + VX_COMMAND, ACK_INTR | status);
654
655	if (status & S_RX_COMPLETE)
656	    vxread(sc);
657	if (status & S_TX_AVAIL) {
658	    ifp->if_timer = 0;
659	    sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
660	    vxstart(&sc->arpcom.ac_if);
661	}
662	if (status & S_CARD_FAILURE) {
663	    printf("vx%d: adapter failure (%x)\n", sc->unit, status);
664	    ifp->if_timer = 0;
665	    vxreset(sc);
666	    return;
667	}
668	if (status & S_TX_COMPLETE) {
669	    ifp->if_timer = 0;
670	    vxtxstat(sc);
671	    vxstart(ifp);
672	}
673    }
674
675    /* no more interrupts */
676    return;
677}
678
679static void
680vxread(sc)
681    struct vx_softc *sc;
682{
683    struct ifnet *ifp = &sc->arpcom.ac_if;
684    struct mbuf *m;
685    struct ether_header *eh;
686    u_int len;
687
688    len = inw(BASE + VX_W1_RX_STATUS);
689
690again:
691
692    if (ifp->if_flags & IFF_DEBUG) {
693	int err = len & ERR_MASK;
694	char *s = NULL;
695
696	if (len & ERR_INCOMPLETE)
697	    s = "incomplete packet";
698	else if (err == ERR_OVERRUN)
699	    s = "packet overrun";
700	else if (err == ERR_RUNT)
701	    s = "runt packet";
702	else if (err == ERR_ALIGNMENT)
703	    s = "bad alignment";
704	else if (err == ERR_CRC)
705	    s = "bad crc";
706	else if (err == ERR_OVERSIZE)
707	    s = "oversized packet";
708	else if (err == ERR_DRIBBLE)
709	    s = "dribble bits";
710
711	if (s)
712	printf("vx%d: %s\n", sc->unit, s);
713    }
714
715    if (len & ERR_INCOMPLETE)
716	return;
717
718    if (len & ERR_RX) {
719	++ifp->if_ierrors;
720	goto abort;
721    }
722
723    len &= RX_BYTES_MASK;	/* Lower 11 bits = RX bytes. */
724
725    /* Pull packet off interface. */
726    m = vxget(sc, len);
727    if (m == 0) {
728	ifp->if_ierrors++;
729	goto abort;
730    }
731
732    ++ifp->if_ipackets;
733
734    /* We assume the header fit entirely in one mbuf. */
735    eh = mtod(m, struct ether_header *);
736
737    /*
738     * XXX: Some cards seem to be in promiscous mode all the time.
739     * we need to make sure we only get our own stuff always.
740     * bleah!
741     */
742
743    if ((eh->ether_dhost[0] & 1) == 0		/* !mcast and !bcast */
744      && bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN) != 0) {
745	m_freem(m);
746	return;
747    }
748
749    m_adj(m, sizeof(struct ether_header));
750    ether_input(ifp, eh, m);
751
752    /*
753    * In periods of high traffic we can actually receive enough
754    * packets so that the fifo overrun bit will be set at this point,
755    * even though we just read a packet. In this case we
756    * are not going to receive any more interrupts. We check for
757    * this condition and read again until the fifo is not full.
758    * We could simplify this test by not using vxstatus(), but
759    * rechecking the RX_STATUS register directly. This test could
760    * result in unnecessary looping in cases where there is a new
761    * packet but the fifo is not full, but it will not fix the
762    * stuck behavior.
763    *
764    * Even with this improvement, we still get packet overrun errors
765    * which are hurting performance. Maybe when I get some more time
766    * I'll modify vxread() so that it can handle RX_EARLY interrupts.
767    */
768    if (vxstatus(sc)) {
769	len = inw(BASE + VX_W1_RX_STATUS);
770	/* Check if we are stuck and reset [see XXX comment] */
771	if (len & ERR_INCOMPLETE) {
772	    if (ifp->if_flags & IFF_DEBUG)
773		printf("vx%d: adapter reset\n", sc->unit);
774	    vxreset(sc);
775	    return;
776	}
777	goto again;
778    }
779
780    return;
781
782abort:
783    outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK);
784}
785
786static struct mbuf *
787vxget(sc, totlen)
788    struct vx_softc *sc;
789    u_int totlen;
790{
791    struct ifnet *ifp = &sc->arpcom.ac_if;
792    struct mbuf *top, **mp, *m;
793    int len;
794    int sh;
795
796    m = sc->mb[sc->next_mb];
797    sc->mb[sc->next_mb] = 0;
798    if (m == 0) {
799        MGETHDR(m, M_DONTWAIT, MT_DATA);
800        if (m == 0)
801            return 0;
802    } else {
803        /* If the queue is no longer full, refill. */
804        if (sc->last_mb == sc->next_mb && sc->buffill_pending == 0) {
805	    sc->ch = timeout(vxmbuffill, sc, 1);
806	    sc->buffill_pending = 1;
807	}
808        /* Convert one of our saved mbuf's. */
809        sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
810        m->m_data = m->m_pktdat;
811        m->m_flags = M_PKTHDR;
812	bzero(&m->m_pkthdr, sizeof(m->m_pkthdr));
813    }
814    m->m_pkthdr.rcvif = ifp;
815    m->m_pkthdr.len = totlen;
816    len = MHLEN;
817    top = 0;
818    mp = &top;
819
820    /*
821     * We read the packet at splhigh() so that an interrupt from another
822     * device doesn't cause the card's buffer to overflow while we're
823     * reading it.  We may still lose packets at other times.
824     */
825    sh = splhigh();
826
827    /*
828     * Since we don't set allowLargePackets bit in MacControl register,
829     * we can assume that totlen <= 1500bytes.
830     * The while loop will be performed iff we have a packet with
831     * MLEN < m_len < MINCLSIZE.
832     */
833    while (totlen > 0) {
834        if (top) {
835            m = sc->mb[sc->next_mb];
836            sc->mb[sc->next_mb] = 0;
837            if (m == 0) {
838                MGET(m, M_DONTWAIT, MT_DATA);
839                if (m == 0) {
840                    splx(sh);
841                    m_freem(top);
842                    return 0;
843                }
844            } else {
845                sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
846            }
847            len = MLEN;
848        }
849        if (totlen >= MINCLSIZE) {
850	    MCLGET(m, M_DONTWAIT);
851	    if (m->m_flags & M_EXT)
852		len = MCLBYTES;
853        }
854        len = min(totlen, len);
855        if (len > 3)
856            insl(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), len / 4);
857	if (len & 3) {
858	    insb(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3),
859		len & 3);
860	}
861        m->m_len = len;
862        totlen -= len;
863        *mp = m;
864        mp = &m->m_next;
865    }
866
867    outw(BASE +VX_COMMAND, RX_DISCARD_TOP_PACK);
868
869    splx(sh);
870
871    return top;
872}
873
874
875static int
876vxioctl(ifp, cmd, data)
877    register struct ifnet *ifp;
878    u_long cmd;
879    caddr_t data;
880{
881    struct vx_softc *sc = vx_softc[ifp->if_unit];
882    struct ifreq *ifr = (struct ifreq *) data;
883    int s, error = 0;
884
885    s = splimp();
886
887    switch (cmd) {
888    case SIOCSIFADDR:
889    case SIOCGIFADDR:
890	ether_ioctl(ifp, cmd, data);
891	break;
892
893    case SIOCSIFFLAGS:
894	if ((ifp->if_flags & IFF_UP) == 0 &&
895	    (ifp->if_flags & IFF_RUNNING) != 0) {
896	    /*
897             * If interface is marked up and it is stopped, then
898             * start it.
899             */
900	    vxstop(sc);
901	    ifp->if_flags &= ~IFF_RUNNING;
902        } else if ((ifp->if_flags & IFF_UP) != 0 &&
903                   (ifp->if_flags & IFF_RUNNING) == 0) {
904            /*
905             * If interface is marked up and it is stopped, then
906             * start it.
907             */
908            vxinit(sc);
909        } else {
910            /*
911             * deal with flags changes:
912             * IFF_MULTICAST, IFF_PROMISC,
913             * IFF_LINK0, IFF_LINK1,
914             */
915            vxsetfilter(sc);
916            vxsetlink(sc);
917        }
918        break;
919
920    case SIOCSIFMTU:
921        /*
922         * Set the interface MTU.
923         */
924        if (ifr->ifr_mtu > ETHERMTU) {
925            error = EINVAL;
926        } else {
927            ifp->if_mtu = ifr->ifr_mtu;
928        }
929        break;
930
931    case SIOCADDMULTI:
932    case SIOCDELMULTI:
933	/*
934	 * Multicast list has changed; set the hardware filter
935	 * accordingly.
936	 */
937	vxreset(sc);
938	error = 0;
939        break;
940
941
942    default:
943        error = EINVAL;
944    }
945
946    splx(s);
947
948    return (error);
949}
950
951static void
952vxreset(sc)
953    struct vx_softc *sc;
954{
955    int s;
956    s = splimp();
957
958    vxstop(sc);
959    vxinit(sc);
960    splx(s);
961}
962
963static void
964vxwatchdog(ifp)
965    struct ifnet *ifp;
966{
967    struct vx_softc *sc = vx_softc[ifp->if_unit];
968
969    if (ifp->if_flags & IFF_DEBUG)
970	printf("vx%d: device timeout\n", ifp->if_unit);
971    ifp->if_flags &= ~IFF_OACTIVE;
972    vxstart(ifp);
973    vxintr(sc);
974}
975
976void
977vxstop(sc)
978    struct vx_softc *sc;
979{
980    struct ifnet *ifp = &sc->arpcom.ac_if;
981
982    ifp->if_timer = 0;
983
984    outw(BASE + VX_COMMAND, RX_DISABLE);
985    outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK);
986    VX_BUSY_WAIT;
987    outw(BASE + VX_COMMAND, TX_DISABLE);
988    outw(BASE + VX_COMMAND, STOP_TRANSCEIVER);
989    DELAY(800);
990    outw(BASE + VX_COMMAND, RX_RESET);
991    VX_BUSY_WAIT;
992    outw(BASE + VX_COMMAND, TX_RESET);
993    VX_BUSY_WAIT;
994    outw(BASE + VX_COMMAND, C_INTR_LATCH);
995    outw(BASE + VX_COMMAND, SET_RD_0_MASK);
996    outw(BASE + VX_COMMAND, SET_INTR_MASK);
997    outw(BASE + VX_COMMAND, SET_RX_FILTER);
998
999    vxmbufempty(sc);
1000}
1001
1002int
1003vxbusyeeprom(sc)
1004    struct vx_softc *sc;
1005{
1006    int j, i = 100;
1007
1008    while (i--) {
1009        j = inw(BASE + VX_W0_EEPROM_COMMAND);
1010        if (j & EEPROM_BUSY)
1011            DELAY(100);
1012        else
1013            break;
1014    }
1015    if (!i) {
1016        printf("vx%d: eeprom failed to come ready\n", sc->unit);
1017        return (1);
1018    }
1019    return (0);
1020}
1021
1022static void
1023vxmbuffill(sp)
1024    void *sp;
1025{
1026    struct vx_softc *sc = (struct vx_softc *) sp;
1027    int s, i;
1028
1029    s = splimp();
1030    i = sc->last_mb;
1031    do {
1032	if (sc->mb[i] == NULL)
1033	    MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
1034	if (sc->mb[i] == NULL)
1035	    break;
1036	i = (i + 1) % MAX_MBS;
1037    } while (i != sc->next_mb);
1038    sc->last_mb = i;
1039    /* If the queue was not filled, try again. */
1040    if (sc->last_mb != sc->next_mb) {
1041	sc->ch = timeout(vxmbuffill, sc, 1);
1042	sc->buffill_pending = 1;
1043    } else {
1044	sc->buffill_pending = 0;
1045    }
1046    splx(s);
1047}
1048
1049static void
1050vxmbufempty(sc)
1051    struct vx_softc *sc;
1052{
1053    int s, i;
1054
1055    s = splimp();
1056    for (i = 0; i < MAX_MBS; i++) {
1057	if (sc->mb[i]) {
1058	    m_freem(sc->mb[i]);
1059	    sc->mb[i] = NULL;
1060	}
1061    }
1062    sc->last_mb = sc->next_mb = 0;
1063    if (sc->buffill_pending != 0)
1064	untimeout(vxmbuffill, sc, sc->ch);
1065    splx(s);
1066}
1067