if_vx.c revision 19915
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} connector_table[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 & connector_table[k].bit) {
326	if (n > 0) {
327	  printf("/");
328	}
329	printf(connector_table[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*]", connector_table[sc->vx_connector].name);
344	printf(": disable 'auto select' with DOS util!", sc->unit);
345    } else {
346	printf("[*%s*]", connector_table[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;
356
357    /*
358     * S.B.
359     *
360     * Now behavior was slightly changed:
361     *
362     * if any of flags link[0-2] is used and its connector is
363     * physically present the following connectors are used:
364     *
365     *   link0 - AUI * highest precedence
366     *   link1 - BNC
367     *   link2 - UTP * lowest precedence
368     *
369     * If none of them is specified then
370     * connector specified in the EEPROM is used
371     * (if present on card or AUI if not).
372     */
373    /* Set the xcvr. */
374    if(ifp->if_flags & IFF_LINK0 && sc->vx_connectors &
375				connector_table[CONNECTOR_AUI].bit) {
376	i = CONNECTOR_AUI;
377    } else if(ifp->if_flags & IFF_LINK1 && sc->vx_connectors &
378				connector_table[CONNECTOR_BNC].bit) {
379	i = CONNECTOR_BNC;
380    } else if(ifp->if_flags & IFF_LINK2 && sc->vx_connectors &
381				connector_table[CONNECTOR_UTP].bit) {
382	i = CONNECTOR_UTP;
383    } else {
384	i = sc->vx_connector;
385    }
386    GO_WINDOW(3);
387    j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
388    outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
389    switch(i) {
390      case CONNECTOR_AUI:
391	/* nothing to do */
392	break;
393      case CONNECTOR_UTP:
394	if(sc->vx_connectors & connector_table[CONNECTOR_UTP].bit) {
395	    GO_WINDOW(4);
396	    outw(BASE + VX_W4_MEDIA_TYPE, ENABLE_UTP);
397	}
398	break;
399      case CONNECTOR_BNC:
400	if(sc->vx_connectors & connector_table[CONNECTOR_BNC].bit) {
401	    outw(BASE + VX_COMMAND, START_TRANSCEIVER);
402	    DELAY(800);
403	}
404	break;
405      case CONNECTOR_TX:
406	if(sc->vx_connectors & connector_table[CONNECTOR_TX].bit) {
407	    GO_WINDOW(4);
408	    outw(BASE + VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
409	}
410	break;
411      case CONNECTOR_FX:
412	if(sc->vx_connectors & connector_table[CONNECTOR_FX].bit) {
413	    GO_WINDOW(4);
414	    outw(BASE + VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
415	}
416	break;
417      default:
418	if(sc->vx_connectors & connector_table[CONNECTOR_UTP].bit) {
419	    printf("vx%d: strange connector type in EEPROM: %d\n",
420		   sc->unit, sc->vx_connector);
421	    printf("vx%d: assuming UTP\n", sc->unit);
422	    GO_WINDOW(4);
423	    outw(BASE + VX_W4_MEDIA_TYPE, ENABLE_UTP);
424	} else {
425	    printf("vx%d: strange connector type in EEPROM: %d\n",
426		   sc->unit, sc->vx_connector);
427	    printf("vx%d: assuming AUI\n", sc->unit);
428	}
429	break;
430    }
431    GO_WINDOW(1);
432}
433
434static void
435vxstart(ifp)
436    struct ifnet *ifp;
437{
438    register struct vx_softc *sc = vx_softc[ifp->if_unit];
439    register struct mbuf *m, *m0;
440    int sh, len, pad;
441
442    /* Don't transmit if interface is busy or not running */
443    if ((sc->arpcom.ac_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
444	return;
445
446startagain:
447    /* Sneak a peek at the next packet */
448    m0 = ifp->if_snd.ifq_head;
449    if (m0 == 0) {
450	return;
451    }
452    /* We need to use m->m_pkthdr.len, so require the header */
453     if ((m0->m_flags & M_PKTHDR) == 0)
454	panic("vxstart: no header mbuf");
455     len = m0->m_pkthdr.len;
456
457     pad = (4 - len) & 3;
458
459    /*
460     * The 3c509 automatically pads short packets to minimum ethernet length,
461     * but we drop packets that are too large. Perhaps we should truncate
462     * them instead?
463     */
464    if (len + pad > ETHER_MAX_LEN) {
465	/* packet is obviously too large: toss it */
466	++ifp->if_oerrors;
467	IF_DEQUEUE(&ifp->if_snd, m0);
468	m_freem(m0);
469	goto readcheck;
470    }
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	ifp->if_flags |= IFF_OACTIVE;
475	ifp->if_timer = 1;
476	return;
477    } else {
478	outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2));
479    }
480    IF_DEQUEUE(&ifp->if_snd, m0);
481    if (m0 == 0) {		/* not really needed */
482	return;
483    }
484
485    outw(BASE + VX_COMMAND, SET_TX_START_THRESH |
486	((len / 4 + sc->tx_start_thresh) >> 2));
487
488#if NBPFILTER > 0
489    if (sc->arpcom.ac_if.if_bpf) {
490	bpf_mtap(&sc->arpcom.ac_if, m0);
491    }
492#endif
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(sc)
632    struct vx_softc *sc;
633{
634    register short status;
635    struct ifnet *ifp = &sc->arpcom.ac_if;
636
637    for (;;) {
638	outw(BASE + VX_COMMAND, C_INTR_LATCH);
639
640	status = inw(BASE + VX_STATUS);
641
642	if ((status & (S_TX_COMPLETE | S_TX_AVAIL |
643		S_RX_COMPLETE | S_CARD_FAILURE)) == 0)
644	    break;
645
646	/*
647	 * Acknowledge any interrupts.  It's important that we do this
648	 * first, since there would otherwise be a race condition.
649	 * Due to the i386 interrupt queueing, we may get spurious
650	 * interrupts occasionally.
651	 */
652	outw(BASE + VX_COMMAND, ACK_INTR | status);
653
654	if (status & S_RX_COMPLETE)
655	    vxread(sc);
656	if (status & S_TX_AVAIL) {
657	    ifp->if_timer = 0;
658	    sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
659	    vxstart(&sc->arpcom.ac_if);
660	}
661	if (status & S_CARD_FAILURE) {
662	    printf("vx%d: adapter failure (%x)\n", sc->unit, status);
663	    ifp->if_timer = 0;
664	    vxreset(sc);
665	    return;
666	}
667	if (status & S_TX_COMPLETE) {
668	    ifp->if_timer = 0;
669	    vxtxstat(sc);
670	    vxstart(ifp);
671	}
672    }
673
674    /* no more interrupts */
675    return;
676}
677
678static void
679vxread(sc)
680    struct vx_softc *sc;
681{
682    struct ifnet *ifp = &sc->arpcom.ac_if;
683    struct mbuf *m;
684    struct ether_header *eh;
685    u_int len;
686
687    len = inw(BASE + VX_W1_RX_STATUS);
688
689again:
690
691    if (ifp->if_flags & IFF_DEBUG) {
692	int err = len & ERR_MASK;
693	char *s = NULL;
694
695	if (len & ERR_INCOMPLETE)
696	    s = "incomplete packet";
697	else if (err == ERR_OVERRUN)
698	    s = "packet overrun";
699	else if (err == ERR_RUNT)
700	    s = "runt packet";
701	else if (err == ERR_ALIGNMENT)
702	    s = "bad alignment";
703	else if (err == ERR_CRC)
704	    s = "bad crc";
705	else if (err == ERR_OVERSIZE)
706	    s = "oversized packet";
707	else if (err == ERR_DRIBBLE)
708	    s = "dribble bits";
709
710	if (s)
711	printf("vx%d: %s\n", sc->unit, s);
712    }
713
714    if (len & ERR_INCOMPLETE)
715	return;
716
717    if (len & ERR_RX) {
718	++ifp->if_ierrors;
719	goto abort;
720    }
721
722    len &= RX_BYTES_MASK;	/* Lower 11 bits = RX bytes. */
723
724    /* Pull packet off interface. */
725    m = vxget(sc, len);
726    if (m == 0) {
727	ifp->if_ierrors++;
728	goto abort;
729    }
730
731    ++ifp->if_ipackets;
732
733    /* We assume the header fit entirely in one mbuf. */
734    eh = mtod(m, struct ether_header *);
735
736#if NBPFILTER > 0
737    /*
738     * Check if there's a BPF listener on this interface.
739     * If so, hand off the raw packet to BPF.
740     */
741    if (sc->arpcom.ac_if.if_bpf) {
742	bpf_mtap(&sc->arpcom.ac_if, m);
743
744	/*
745	 * Note that the interface cannot be in promiscuous mode if
746	 * there are no BPF listeners.  And if we are in promiscuous
747	 * mode, we have to check if this packet is really ours.
748	 */
749	if ((ifp->if_flags & IFF_PROMISC) &&
750	    (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
751	    bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
752	    sizeof(eh->ether_dhost)) != 0) {
753	    m_freem(m);
754	    return;
755	}
756    }
757#endif
758
759    /* We assume the header fit entirely in one mbuf. */
760    m_adj(m, sizeof(struct ether_header));
761    ether_input(ifp, eh, m);
762
763
764
765    /*
766    * In periods of high traffic we can actually receive enough
767    * packets so that the fifo overrun bit will be set at this point,
768    * even though we just read a packet. In this case we
769    * are not going to receive any more interrupts. We check for
770    * this condition and read again until the fifo is not full.
771    * We could simplify this test by not using vxstatus(), but
772    * rechecking the RX_STATUS register directly. This test could
773    * result in unnecessary looping in cases where there is a new
774    * packet but the fifo is not full, but it will not fix the
775    * stuck behavior.
776    *
777    * Even with this improvement, we still get packet overrun errors
778    * which are hurting performance. Maybe when I get some more time
779    * I'll modify vxread() so that it can handle RX_EARLY interrupts.
780    */
781    if (vxstatus(sc)) {
782	len = inw(BASE + VX_W1_RX_STATUS);
783	/* Check if we are stuck and reset [see XXX comment] */
784	if (len & ERR_INCOMPLETE) {
785	    if (ifp->if_flags & IFF_DEBUG)
786		printf("vx%d: adapter reset\n", sc->unit);
787	    vxreset(sc);
788	    return;
789	}
790	goto again;
791    }
792
793    return;
794
795abort:
796    outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK);
797    VX_BUSY_WAIT;
798}
799
800static struct mbuf *
801vxget(sc, totlen)
802    struct vx_softc *sc;
803    u_int totlen;
804{
805    struct ifnet *ifp = &sc->arpcom.ac_if;
806    struct mbuf *top, **mp, *m;
807    int len;
808    int sh;
809
810    m = sc->mb[sc->next_mb];
811    sc->mb[sc->next_mb] = 0;
812    if (m == 0) {
813        MGETHDR(m, M_DONTWAIT, MT_DATA);
814        if (m == 0)
815            return 0;
816    } else {
817        /* If the queue is no longer full, refill. */
818        if (sc->last_mb == sc->next_mb)
819            timeout(vxmbuffill, sc, 1);
820        /* Convert one of our saved mbuf's. */
821        sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
822        m->m_data = m->m_pktdat;
823        m->m_flags = M_PKTHDR;
824    }
825    m->m_pkthdr.rcvif = ifp;
826    m->m_pkthdr.len = totlen;
827    len = MHLEN;
828    top = 0;
829    mp = &top;
830
831    /*
832     * We read the packet at splhigh() so that an interrupt from another
833     * device doesn't cause the card's buffer to overflow while we're
834     * reading it.  We may still lose packets at other times.
835     */
836    sh = splhigh();
837
838    while (totlen > 0) {
839        if (top) {
840            m = sc->mb[sc->next_mb];
841            sc->mb[sc->next_mb] = 0;
842            if (m == 0) {
843                MGET(m, M_DONTWAIT, MT_DATA);
844                if (m == 0) {
845                    splx(sh);
846                    m_freem(top);
847                    return 0;
848                }
849            } else {
850                sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
851            }
852            len = MLEN;
853        }
854        if (totlen >= MINCLSIZE) {
855        MCLGET(m, M_DONTWAIT);
856        if (m->m_flags & M_EXT)
857            len = MCLBYTES;
858        }
859        len = min(totlen, len);
860        if (len > 3) {
861            len &= ~3;
862            insl(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *),
863                len / 4);
864        } else
865            insb(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *),
866                len);
867        m->m_len = len;
868        totlen -= len;
869        *mp = m;
870        mp = &m->m_next;
871    }
872
873    outw(BASE +VX_COMMAND, RX_DISCARD_TOP_PACK);
874    VX_BUSY_WAIT;
875
876    splx(sh);
877
878    return top;
879}
880
881
882static int
883vxioctl(ifp, cmd, data)
884    register struct ifnet *ifp;
885    int cmd;
886    caddr_t data;
887{
888    struct vx_softc *sc = vx_softc[ifp->if_unit];
889    struct ifaddr *ifa = (struct ifaddr *) data;
890    struct ifreq *ifr = (struct ifreq *) data;
891    int s, error = 0;
892
893    s = splimp();
894
895    switch (cmd) {
896    case SIOCSIFADDR:
897    case SIOCGIFADDR:
898	ether_ioctl(ifp, cmd, data);
899	break;
900
901    case SIOCSIFFLAGS:
902	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	    vxstop(sc);
909	    ifp->if_flags &= ~IFF_RUNNING;
910        } else if ((ifp->if_flags & IFF_UP) != 0 &&
911                   (ifp->if_flags & IFF_RUNNING) == 0) {
912            /*
913             * If interface is marked up and it is stopped, then
914             * start it.
915             */
916            vxinit(sc);
917        } else {
918            /*
919             * deal with flags changes:
920             * IFF_MULTICAST, IFF_PROMISC,
921             * IFF_LINK0, IFF_LINK1,
922             */
923            vxsetfilter(sc);
924            vxsetlink(sc);
925        }
926        break;
927
928    case SIOCSIFMTU:
929        /*
930         * Set the interface MTU.
931         */
932        if (ifr->ifr_mtu > ETHERMTU) {
933            error = EINVAL;
934        } else {
935            ifp->if_mtu = ifr->ifr_mtu;
936        }
937        break;
938
939    case SIOCADDMULTI:
940    case SIOCDELMULTI:
941        error = ((u_int) cmd == SIOCADDMULTI) ?
942            ether_addmulti(ifr, &sc->arpcom) :
943            ether_delmulti(ifr, &sc->arpcom);
944
945        if (error == ENETRESET) {
946            /*
947             * Multicast list has changed; set the hardware filter
948             * accordingly.
949             */
950            vxreset(sc);
951            error = 0;
952        }
953        break;
954
955
956    default:
957        error = EINVAL;
958    }
959
960    splx(s);
961
962    return (error);
963}
964
965static void
966vxreset(sc)
967    struct vx_softc *sc;
968{
969    int s;
970    s = splimp();
971
972    vxstop(sc);
973    vxinit(sc);
974    splx(s);
975}
976
977static void
978vxwatchdog(ifp)
979    struct ifnet *ifp;
980{
981    struct vx_softc *sc = vx_softc[ifp->if_unit];
982
983    if (ifp->if_flags & IFF_DEBUG)
984	printf("vx%d: device timeout\n", ifp->if_unit);
985    ifp->if_flags &= ~IFF_OACTIVE;
986    vxstart(ifp);
987    vxintr(sc);
988}
989
990void
991vxstop(sc)
992    struct vx_softc *sc;
993{
994    struct ifnet *ifp = &sc->arpcom.ac_if;
995
996    ifp->if_timer = 0;
997
998    outw(BASE + VX_COMMAND, RX_DISABLE);
999    outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK);
1000    VX_BUSY_WAIT;
1001    outw(BASE + VX_COMMAND, TX_DISABLE);
1002    outw(BASE + VX_COMMAND, STOP_TRANSCEIVER);
1003    DELAY(800);
1004    outw(BASE + VX_COMMAND, RX_RESET);
1005    VX_BUSY_WAIT;
1006    outw(BASE + VX_COMMAND, TX_RESET);
1007    VX_BUSY_WAIT;
1008    outw(BASE + VX_COMMAND, C_INTR_LATCH);
1009    outw(BASE + VX_COMMAND, SET_RD_0_MASK);
1010    outw(BASE + VX_COMMAND, SET_INTR_MASK);
1011    outw(BASE + VX_COMMAND, SET_RX_FILTER);
1012
1013    vxmbufempty(sc);
1014}
1015
1016int
1017vxbusyeeprom(sc)
1018    struct vx_softc *sc;
1019{
1020    int j, i = 100;
1021
1022    while (i--) {
1023        j = inw(BASE + VX_W0_EEPROM_COMMAND);
1024        if (j & EEPROM_BUSY)
1025            DELAY(100);
1026        else
1027            break;
1028    }
1029    if (!i) {
1030        printf("vx%d: eeprom failed to come ready\n", sc->unit);
1031        return (1);
1032    }
1033    return (0);
1034}
1035
1036static void
1037vxmbuffill(sp)
1038    void *sp;
1039{
1040    struct vx_softc *sc = (struct vx_softc *) sp;
1041    int s, i;
1042
1043    s = splimp();
1044    i = sc->last_mb;
1045    do {
1046	if (sc->mb[i] == NULL)
1047	    MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
1048	if (sc->mb[i] == NULL)
1049	    break;
1050	i = (i + 1) % MAX_MBS;
1051    } while (i != sc->next_mb);
1052    sc->last_mb = i;
1053    /* If the queue was not filled, try again. */
1054    if (sc->last_mb != sc->next_mb)
1055	timeout(vxmbuffill, sc, 1);
1056    splx(s);
1057}
1058
1059static void
1060vxmbufempty(sc)
1061    struct vx_softc *sc;
1062{
1063    int s, i;
1064
1065    s = splimp();
1066    for (i = 0; i < MAX_MBS; i++) {
1067	if (sc->mb[i]) {
1068	    m_freem(sc->mb[i]);
1069	    sc->mb[i] = NULL;
1070	}
1071    }
1072    sc->last_mb = sc->next_mb = 0;
1073    untimeout(vxmbuffill, sc);
1074    splx(s);
1075}
1076
1077#endif				/* NVX > 0 */
1078