if_vx.c revision 19410
1145683Sharti/*
2145683Sharti * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
3145683Sharti * All rights reserved.
4145683Sharti *
5145683Sharti * Redistribution and use in source and binary forms, with or without
6145683Sharti * modification, are permitted provided that the following conditions
7145683Sharti * are met:
8145683Sharti * 1. Redistributions of source code must retain the above copyright
9145683Sharti *    notice, this list of conditions and the following disclaimer.
10145683Sharti * 2. Redistributions in binary form must reproduce the above copyright
11145683Sharti *    notice, this list of conditions and the following disclaimer in the
12145683Sharti *    documentation and/or other materials provided with the distribution.
13145683Sharti * 3. All advertising materials mentioning features or use of this software
14145683Sharti *    must display the following acknowledgement:
15145683Sharti *      This product includes software developed by Herb Peyerl.
16145683Sharti * 4. The name of Herb Peyerl may not be used to endorse or promote products
17145683Sharti *    derived from this software without specific prior written permission.
18145683Sharti *
19145683Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20145683Sharti * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21145683Sharti * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22145683Sharti * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23145683Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24145683Sharti * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25145683Sharti * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26145683Sharti * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27145683Sharti * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28145683Sharti * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29145683Sharti *
30145683Sharti */
31145683Sharti
32145683Sharti/*
33145683Sharti * Created from if_ep.c driver by Fred Gray (fgray@rice.edu) to support
34145683Sharti * the 3c590 family.
35145683Sharti */
36145683Sharti
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 & CONNECTOR_AUI) {
375	i = CONNECTOR_AUI;
376    } else if(ifp->if_flags & IFF_LINK1 && sc->vx_connectors & CONNECTOR_BNC) {
377	i = CONNECTOR_BNC;
378    } else if(ifp->if_flags & IFF_LINK2 && sc->vx_connectors & CONNECTOR_UTP) {
379	i = CONNECTOR_UTP;
380    } else {
381	i = sc->vx_connector;
382    }
383    GO_WINDOW(3);
384    j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
385    outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
386    switch(i) {
387      case CONNECTOR_AUI:
388	/* nothing to do */
389	break;
390      case CONNECTOR_UTP:
391	if(sc->vx_connectors & connector_table[CONNECTOR_UTP].bit) {
392	    GO_WINDOW(4);
393	    outw(BASE + VX_W4_MEDIA_TYPE, ENABLE_UTP);
394	}
395	break;
396      case CONNECTOR_BNC:
397	if(sc->vx_connectors & connector_table[CONNECTOR_BNC].bit) {
398	    outw(BASE + VX_COMMAND, START_TRANSCEIVER);
399	    DELAY(800);
400	}
401	break;
402      case CONNECTOR_TX:
403	if(sc->vx_connectors & connector_table[CONNECTOR_TX].bit) {
404	    GO_WINDOW(4);
405	    outw(BASE + VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
406	}
407	break;
408      case CONNECTOR_FX:
409	if(sc->vx_connectors & connector_table[CONNECTOR_FX].bit) {
410	    GO_WINDOW(4);
411	    outw(BASE + VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
412	}
413	break;
414      default:
415	if(sc->vx_connectors & connector_table[CONNECTOR_UTP].bit) {
416	    printf("vx%d: strange connector type in EEPROM: %d\n",
417		   sc->unit, sc->vx_connector);
418	    printf("vx%d: assuming UTP\n", sc->unit);
419	    GO_WINDOW(4);
420	    outw(BASE + VX_W4_MEDIA_TYPE, ENABLE_UTP);
421	} else {
422	    printf("vx%d: strange connector type in EEPROM: %d\n",
423		   sc->unit, sc->vx_connector);
424	    printf("vx%d: assuming AUI\n", sc->unit);
425	}
426	break;
427    }
428    GO_WINDOW(1);
429}
430
431static void
432vxstart(ifp)
433    struct ifnet *ifp;
434{
435    register struct vx_softc *sc = vx_softc[ifp->if_unit];
436    register struct mbuf *m, *m0;
437    int sh, len, pad;
438
439    /* Don't transmit if interface is busy or not running */
440    if ((sc->arpcom.ac_if.if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
441	return;
442
443startagain:
444    /* Sneak a peek at the next packet */
445    m0 = ifp->if_snd.ifq_head;
446    if (m0 == 0) {
447	return;
448    }
449    /* We need to use m->m_pkthdr.len, so require the header */
450     if ((m0->m_flags & M_PKTHDR) == 0)
451	panic("vxstart: no header mbuf");
452     len = m0->m_pkthdr.len;
453
454     pad = (4 - len) & 3;
455
456    /*
457     * The 3c509 automatically pads short packets to minimum ethernet length,
458     * but we drop packets that are too large. Perhaps we should truncate
459     * them instead?
460     */
461    if (len + pad > ETHER_MAX_LEN) {
462	/* packet is obviously too large: toss it */
463	++ifp->if_oerrors;
464	IF_DEQUEUE(&ifp->if_snd, m0);
465	m_freem(m0);
466	goto readcheck;
467    }
468    if (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
469	outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2));
470	/* not enough room in FIFO */
471	ifp->if_flags |= IFF_OACTIVE;
472	ifp->if_timer = 1;
473	return;
474    } else {
475	outw(BASE + VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2));
476    }
477    IF_DEQUEUE(&ifp->if_snd, m0);
478    if (m0 == 0) {		/* not really needed */
479	return;
480    }
481
482    outw(BASE + VX_COMMAND, SET_TX_START_THRESH |
483	((len / 4 + sc->tx_start_thresh) >> 2));
484
485#if NBPFILTER > 0
486    if (sc->arpcom.ac_if.if_bpf) {
487	bpf_mtap(&sc->arpcom.ac_if, m0);
488    }
489#endif
490
491    /*
492     * Do the output at splhigh() so that an interrupt from another device
493     * won't cause a FIFO underrun.
494     */
495    sh = splhigh();
496
497    outl(BASE + VX_W1_TX_PIO_WR_1, len | TX_INDICATE);
498
499    for (m = m0; m != 0;) {
500        if (m->m_len > 3)
501	    outsl(BASE + VX_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 4);
502        if (m->m_len & 3)
503	    outsb(BASE + VX_W1_TX_PIO_WR_1,
504	      mtod(m, caddr_t) + (m->m_len & ~3) , m->m_len & 3);
505        MFREE(m, m0);
506        m = m0;
507    }
508    while (pad--)
509	outb(BASE + VX_W1_TX_PIO_WR_1, 0);	/* Padding */
510
511    splx(sh);
512
513    ++ifp->if_opackets;
514    ifp->if_timer = 1;
515
516readcheck:
517    if ((inw(BASE + VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) {
518	/* We received a complete packet. */
519
520	if ((inw(BASE + VX_STATUS) & S_INTR_LATCH) == 0) {
521	    /*
522	     * No interrupt, read the packet and continue
523	     * Is  this supposed to happen? Is my motherboard
524	     * completely busted?
525	     */
526	    vxread(sc);
527	} else
528	    /* Got an interrupt, return so that it gets serviced. */
529	    return;
530    } else {
531	/* Check if we are stuck and reset [see XXX comment] */
532	if (vxstatus(sc)) {
533	    if (ifp->if_flags & IFF_DEBUG)
534	       printf("vx%d: adapter reset\n", ifp->if_unit);
535	    vxreset(sc);
536	}
537    }
538
539    goto startagain;
540}
541
542/*
543 * XXX: The 3c509 card can get in a mode where both the fifo status bit
544 *      FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set
545 *      We detect this situation and we reset the adapter.
546 *      It happens at times when there is a lot of broadcast traffic
547 *      on the cable (once in a blue moon).
548 */
549static int
550vxstatus(sc)
551    struct vx_softc *sc;
552{
553    int fifost;
554
555    /*
556     * Check the FIFO status and act accordingly
557     */
558    GO_WINDOW(4);
559    fifost = inw(BASE + VX_W4_FIFO_DIAG);
560    GO_WINDOW(1);
561
562    if (fifost & FIFOS_RX_UNDERRUN) {
563	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
564	    printf("vx%d: RX underrun\n", sc->unit);
565	vxreset(sc);
566	return 0;
567    }
568
569    if (fifost & FIFOS_RX_STATUS_OVERRUN) {
570	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
571	    printf("vx%d: RX Status overrun\n", sc->unit);
572	return 1;
573    }
574
575    if (fifost & FIFOS_RX_OVERRUN) {
576	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
577	    printf("vx%d: RX overrun\n", sc->unit);
578	return 1;
579    }
580
581    if (fifost & FIFOS_TX_OVERRUN) {
582	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
583	    printf("vx%d: TX overrun\n", sc->unit);
584	vxreset(sc);
585	return 0;
586    }
587
588    return 0;
589}
590
591static void
592vxtxstat(sc)
593    struct vx_softc *sc;
594{
595    int i;
596
597    /*
598    * We need to read+write TX_STATUS until we get a 0 status
599    * in order to turn off the interrupt flag.
600    */
601    while ((i = inb(BASE + VX_W1_TX_STATUS)) & TXS_COMPLETE) {
602	outb(BASE + VX_W1_TX_STATUS, 0x0);
603
604    if (i & TXS_JABBER) {
605	++sc->arpcom.ac_if.if_oerrors;
606	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
607	    printf("vx%d: jabber (%x)\n", sc->unit, i);
608	vxreset(sc);
609    } else if (i & TXS_UNDERRUN) {
610	++sc->arpcom.ac_if.if_oerrors;
611	if (sc->arpcom.ac_if.if_flags & IFF_DEBUG)
612	    printf("vx%d: fifo underrun (%x) @%d\n",
613		sc->unit, i, sc->tx_start_thresh);
614	if (sc->tx_succ_ok < 100)
615	    sc->tx_start_thresh = min(ETHER_MAX_LEN, sc->tx_start_thresh + 20);
616	sc->tx_succ_ok = 0;
617	vxreset(sc);
618    } else if (i & TXS_MAX_COLLISION) {
619	++sc->arpcom.ac_if.if_collisions;
620	outw(BASE + VX_COMMAND, TX_ENABLE);
621	sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
622    } else
623	sc->tx_succ_ok = (sc->tx_succ_ok+1) & 127;
624    }
625}
626
627void
628vxintr(sc)
629    struct vx_softc *sc;
630{
631    register short status;
632    struct ifnet *ifp = &sc->arpcom.ac_if;
633
634    for (;;) {
635	outw(BASE + VX_COMMAND, C_INTR_LATCH);
636
637	status = inw(BASE + VX_STATUS);
638
639	if ((status & (S_TX_COMPLETE | S_TX_AVAIL |
640		S_RX_COMPLETE | S_CARD_FAILURE)) == 0)
641	    break;
642
643	/*
644	 * Acknowledge any interrupts.  It's important that we do this
645	 * first, since there would otherwise be a race condition.
646	 * Due to the i386 interrupt queueing, we may get spurious
647	 * interrupts occasionally.
648	 */
649	outw(BASE + VX_COMMAND, ACK_INTR | status);
650
651	if (status & S_RX_COMPLETE)
652	    vxread(sc);
653	if (status & S_TX_AVAIL) {
654	    ifp->if_timer = 0;
655	    sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
656	    vxstart(&sc->arpcom.ac_if);
657	}
658	if (status & S_CARD_FAILURE) {
659	    printf("vx%d: adapter failure (%x)\n", sc->unit, status);
660	    ifp->if_timer = 0;
661	    vxreset(sc);
662	    return;
663	}
664	if (status & S_TX_COMPLETE) {
665	    ifp->if_timer = 0;
666	    vxtxstat(sc);
667	    vxstart(ifp);
668	}
669    }
670
671    /* no more interrupts */
672    return;
673}
674
675static void
676vxread(sc)
677    struct vx_softc *sc;
678{
679    struct ifnet *ifp = &sc->arpcom.ac_if;
680    struct mbuf *m;
681    struct ether_header *eh;
682    u_int len;
683
684    len = inw(BASE + VX_W1_RX_STATUS);
685
686again:
687
688    if (ifp->if_flags & IFF_DEBUG) {
689	int err = len & ERR_MASK;
690	char *s = NULL;
691
692	if (len & ERR_INCOMPLETE)
693	    s = "incomplete packet";
694	else if (err == ERR_OVERRUN)
695	    s = "packet overrun";
696	else if (err == ERR_RUNT)
697	    s = "runt packet";
698	else if (err == ERR_ALIGNMENT)
699	    s = "bad alignment";
700	else if (err == ERR_CRC)
701	    s = "bad crc";
702	else if (err == ERR_OVERSIZE)
703	    s = "oversized packet";
704	else if (err == ERR_DRIBBLE)
705	    s = "dribble bits";
706
707	if (s)
708	printf("vx%d: %s\n", sc->unit, s);
709    }
710
711    if (len & ERR_INCOMPLETE)
712	return;
713
714    if (len & ERR_RX) {
715	++ifp->if_ierrors;
716	goto abort;
717    }
718
719    len &= RX_BYTES_MASK;	/* Lower 11 bits = RX bytes. */
720
721    /* Pull packet off interface. */
722    m = vxget(sc, len);
723    if (m == 0) {
724	ifp->if_ierrors++;
725	goto abort;
726    }
727
728    ++ifp->if_ipackets;
729
730    /* We assume the header fit entirely in one mbuf. */
731    eh = mtod(m, struct ether_header *);
732
733#if NBPFILTER > 0
734    /*
735     * Check if there's a BPF listener on this interface.
736     * If so, hand off the raw packet to BPF.
737     */
738    if (sc->arpcom.ac_if.if_bpf) {
739	bpf_mtap(&sc->arpcom.ac_if, m);
740
741	/*
742	 * Note that the interface cannot be in promiscuous mode if
743	 * there are no BPF listeners.  And if we are in promiscuous
744	 * mode, we have to check if this packet is really ours.
745	 */
746	if ((ifp->if_flags & IFF_PROMISC) &&
747	    (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
748	    bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
749	    sizeof(eh->ether_dhost)) != 0) {
750	    m_freem(m);
751	    return;
752	}
753    }
754#endif
755
756    /* We assume the header fit entirely in one mbuf. */
757    m_adj(m, sizeof(struct ether_header));
758    ether_input(ifp, eh, m);
759
760
761
762    /*
763    * In periods of high traffic we can actually receive enough
764    * packets so that the fifo overrun bit will be set at this point,
765    * even though we just read a packet. In this case we
766    * are not going to receive any more interrupts. We check for
767    * this condition and read again until the fifo is not full.
768    * We could simplify this test by not using vxstatus(), but
769    * rechecking the RX_STATUS register directly. This test could
770    * result in unnecessary looping in cases where there is a new
771    * packet but the fifo is not full, but it will not fix the
772    * stuck behavior.
773    *
774    * Even with this improvement, we still get packet overrun errors
775    * which are hurting performance. Maybe when I get some more time
776    * I'll modify vxread() so that it can handle RX_EARLY interrupts.
777    */
778    if (vxstatus(sc)) {
779	len = inw(BASE + VX_W1_RX_STATUS);
780	/* Check if we are stuck and reset [see XXX comment] */
781	if (len & ERR_INCOMPLETE) {
782	    if (ifp->if_flags & IFF_DEBUG)
783		printf("vx%d: adapter reset\n", sc->unit);
784	    vxreset(sc);
785	    return;
786	}
787	goto again;
788    }
789
790    return;
791
792abort:
793    outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK);
794    VX_BUSY_WAIT;
795}
796
797static struct mbuf *
798vxget(sc, totlen)
799    struct vx_softc *sc;
800    u_int totlen;
801{
802    struct ifnet *ifp = &sc->arpcom.ac_if;
803    struct mbuf *top, **mp, *m;
804    int len;
805    int sh;
806
807    m = sc->mb[sc->next_mb];
808    sc->mb[sc->next_mb] = 0;
809    if (m == 0) {
810        MGETHDR(m, M_DONTWAIT, MT_DATA);
811        if (m == 0)
812            return 0;
813    } else {
814        /* If the queue is no longer full, refill. */
815        if (sc->last_mb == sc->next_mb)
816            timeout(vxmbuffill, sc, 1);
817        /* Convert one of our saved mbuf's. */
818        sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
819        m->m_data = m->m_pktdat;
820        m->m_flags = M_PKTHDR;
821    }
822    m->m_pkthdr.rcvif = ifp;
823    m->m_pkthdr.len = totlen;
824    len = MHLEN;
825    top = 0;
826    mp = &top;
827
828    /*
829     * We read the packet at splhigh() so that an interrupt from another
830     * device doesn't cause the card's buffer to overflow while we're
831     * reading it.  We may still lose packets at other times.
832     */
833    sh = splhigh();
834
835    while (totlen > 0) {
836        if (top) {
837            m = sc->mb[sc->next_mb];
838            sc->mb[sc->next_mb] = 0;
839            if (m == 0) {
840                MGET(m, M_DONTWAIT, MT_DATA);
841                if (m == 0) {
842                    splx(sh);
843                    m_freem(top);
844                    return 0;
845                }
846            } else {
847                sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
848            }
849            len = MLEN;
850        }
851        if (totlen >= MINCLSIZE) {
852        MCLGET(m, M_DONTWAIT);
853        if (m->m_flags & M_EXT)
854            len = MCLBYTES;
855        }
856        len = min(totlen, len);
857        if (len > 3) {
858            len &= ~3;
859            insl(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *),
860                len / 4);
861        } else
862            insb(BASE + VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *),
863                len);
864        m->m_len = len;
865        totlen -= len;
866        *mp = m;
867        mp = &m->m_next;
868    }
869
870    outw(BASE +VX_COMMAND, RX_DISCARD_TOP_PACK);
871    VX_BUSY_WAIT;
872
873    splx(sh);
874
875    return top;
876}
877
878
879static int
880vxioctl(ifp, cmd, data)
881    register struct ifnet *ifp;
882    int cmd;
883    caddr_t data;
884{
885    struct vx_softc *sc = vx_softc[ifp->if_unit];
886    struct ifaddr *ifa = (struct ifaddr *) data;
887    struct ifreq *ifr = (struct ifreq *) data;
888    int s, error = 0;
889
890    s = splimp();
891
892    switch (cmd) {
893    case SIOCSIFADDR:
894    case SIOCGIFADDR:
895	ether_ioctl(ifp, cmd, data);
896	break;
897
898    case SIOCSIFFLAGS:
899	if ((ifp->if_flags & IFF_UP) == 0 &&
900	    (ifp->if_flags & IFF_RUNNING) != 0) {
901	    /*
902             * If interface is marked up and it is stopped, then
903             * start it.
904             */
905	    vxstop(sc);
906	    ifp->if_flags &= ~IFF_RUNNING;
907        } else if ((ifp->if_flags & IFF_UP) != 0 &&
908                   (ifp->if_flags & IFF_RUNNING) == 0) {
909            /*
910             * If interface is marked up and it is stopped, then
911             * start it.
912             */
913            vxinit(sc);
914        } else {
915            /*
916             * deal with flags changes:
917             * IFF_MULTICAST, IFF_PROMISC,
918             * IFF_LINK0, IFF_LINK1,
919             */
920            vxsetfilter(sc);
921            vxsetlink(sc);
922        }
923        break;
924
925    case SIOCSIFMTU:
926        /*
927         * Set the interface MTU.
928         */
929        if (ifr->ifr_mtu > ETHERMTU) {
930            error = EINVAL;
931        } else {
932            ifp->if_mtu = ifr->ifr_mtu;
933        }
934        break;
935
936    case SIOCADDMULTI:
937    case SIOCDELMULTI:
938        error = ((u_int) cmd == SIOCADDMULTI) ?
939            ether_addmulti(ifr, &sc->arpcom) :
940            ether_delmulti(ifr, &sc->arpcom);
941
942        if (error == ENETRESET) {
943            /*
944             * Multicast list has changed; set the hardware filter
945             * accordingly.
946             */
947            vxreset(sc);
948            error = 0;
949        }
950        break;
951
952
953    default:
954        error = EINVAL;
955    }
956
957    splx(s);
958
959    return (error);
960}
961
962static void
963vxreset(sc)
964    struct vx_softc *sc;
965{
966    int s;
967    s = splimp();
968
969    vxstop(sc);
970    vxinit(sc);
971    splx(s);
972}
973
974static void
975vxwatchdog(ifp)
976    struct ifnet *ifp;
977{
978    struct vx_softc *sc = vx_softc[ifp->if_unit];
979
980    if (ifp->if_flags & IFF_DEBUG)
981	printf("vx%d: device timeout\n", ifp->if_unit);
982    ifp->if_flags &= ~IFF_OACTIVE;
983    vxstart(ifp);
984    vxintr(sc);
985}
986
987void
988vxstop(sc)
989    struct vx_softc *sc;
990{
991    struct ifnet *ifp = &sc->arpcom.ac_if;
992
993    ifp->if_timer = 0;
994
995    outw(BASE + VX_COMMAND, RX_DISABLE);
996    outw(BASE + VX_COMMAND, RX_DISCARD_TOP_PACK);
997    VX_BUSY_WAIT;
998    outw(BASE + VX_COMMAND, TX_DISABLE);
999    outw(BASE + VX_COMMAND, STOP_TRANSCEIVER);
1000    DELAY(800);
1001    outw(BASE + VX_COMMAND, RX_RESET);
1002    VX_BUSY_WAIT;
1003    outw(BASE + VX_COMMAND, TX_RESET);
1004    VX_BUSY_WAIT;
1005    outw(BASE + VX_COMMAND, C_INTR_LATCH);
1006    outw(BASE + VX_COMMAND, SET_RD_0_MASK);
1007    outw(BASE + VX_COMMAND, SET_INTR_MASK);
1008    outw(BASE + VX_COMMAND, SET_RX_FILTER);
1009
1010    vxmbufempty(sc);
1011}
1012
1013int
1014vxbusyeeprom(sc)
1015    struct vx_softc *sc;
1016{
1017    int j, i = 100;
1018
1019    while (i--) {
1020        j = inw(BASE + VX_W0_EEPROM_COMMAND);
1021        if (j & EEPROM_BUSY)
1022            DELAY(100);
1023        else
1024            break;
1025    }
1026    if (!i) {
1027        printf("vx%d: eeprom failed to come ready\n", sc->unit);
1028        return (1);
1029    }
1030    return (0);
1031}
1032
1033static void
1034vxmbuffill(sp)
1035    void *sp;
1036{
1037    struct vx_softc *sc = (struct vx_softc *) sp;
1038    int s, i;
1039
1040    s = splimp();
1041    i = sc->last_mb;
1042    do {
1043	if (sc->mb[i] == NULL)
1044	    MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
1045	if (sc->mb[i] == NULL)
1046	    break;
1047	i = (i + 1) % MAX_MBS;
1048    } while (i != sc->next_mb);
1049    sc->last_mb = i;
1050    /* If the queue was not filled, try again. */
1051    if (sc->last_mb != sc->next_mb)
1052	timeout(vxmbuffill, sc, 1);
1053    splx(s);
1054}
1055
1056static void
1057vxmbufempty(sc)
1058    struct vx_softc *sc;
1059{
1060    int s, i;
1061
1062    s = splimp();
1063    for (i = 0; i < MAX_MBS; i++) {
1064	if (sc->mb[i]) {
1065	    m_freem(sc->mb[i]);
1066	    sc->mb[i] = NULL;
1067	}
1068    }
1069    sc->last_mb = sc->next_mb = 0;
1070    untimeout(vxmbuffill, sc);
1071    splx(s);
1072}
1073
1074#endif				/* NVX > 0 */
1075