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