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