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