if_vx.c revision 148284
1139826Simp/*-
253541Sshin * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
353541Sshin * All rights reserved.
453541Sshin *
553541Sshin * Redistribution and use in source and binary forms, with or without
653541Sshin * modification, are permitted provided that the following conditions
753541Sshin * are met:
853541Sshin * 1. Redistributions of source code must retain the above copyright
953541Sshin *    notice, this list of conditions and the following disclaimer.
1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1153541Sshin *    notice, this list of conditions and the following disclaimer in the
1253541Sshin *    documentation and/or other materials provided with the distribution.
1353541Sshin * 3. All advertising materials mentioning features or use of this software
1453541Sshin *    must display the following acknowledgement:
1553541Sshin *      This product includes software developed by Herb Peyerl.
1653541Sshin * 4. The name of Herb Peyerl may not be used to endorse or promote products
1753541Sshin *    derived from this software without specific prior written permission.
1853541Sshin *
1953541Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2053541Sshin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2153541Sshin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2253541Sshin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2353541Sshin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2453541Sshin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2553541Sshin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2653541Sshin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2753541Sshin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28174510Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29174510Sobrien *
30174510Sobrien *
3153541Sshin */
3253541Sshin
3353541Sshin#include <sys/cdefs.h>
3462587Sitojun__FBSDID("$FreeBSD: head/sys/dev/vx/if_vx.c 148284 2005-07-22 11:27:07Z ru $");
3553541Sshin
3662587Sitojun/*
3762587Sitojun * Created from if_ep.c driver by Fred Gray (fgray@rice.edu) to support
3862587Sitojun * the 3c590 family.
3962587Sitojun */
4062587Sitojun
4153541Sshin/*
4278064Sume *	Modified from the FreeBSD 1.1.5.1 version by:
4353541Sshin *		 	Andres Vega Garcia
44186119Sqingli *			INRIA - Sophia Antipolis, France
45151539Ssuz *			avega@sophia.inria.fr
4662587Sitojun */
4778064Sume
4878064Sume/*
4978064Sume *  Promiscuous mode added and interrupt logic slightly changed
5078064Sume *  to reduce the number of adapter failures. Transceiver select
5178064Sume *  logic changed to use value from EEPROM. Autoconfiguration
5278064Sume *  features added.
5378064Sume *  Done by:
5478064Sume *          Serge Babkin
5562587Sitojun *          Chelindbank (Chelyabinsk, Russia)
5662587Sitojun *          babkin@hq.icb.chel.su
5762587Sitojun */
5862587Sitojun
5962587Sitojun
6053541Sshin#include <sys/param.h>
6162587Sitojun#include <sys/systm.h>
62186119Sqingli#include <sys/sockio.h>
6362587Sitojun#include <sys/malloc.h>
6453541Sshin#include <sys/mbuf.h>
6562587Sitojun#include <sys/socket.h>
6662587Sitojun
6762587Sitojun#include <net/if.h>
6862587Sitojun
6962587Sitojun#include <net/ethernet.h>
7062587Sitojun#include <net/if_arp.h>
7162587Sitojun#include <net/if_types.h>
7262587Sitojun
73121161Sume#include <machine/bus.h>
7495023Ssuz
7578064Sume#include <sys/bus.h>
7678064Sume
7778064Sume#include <net/bpf.h>
7853541Sshin
7953541Sshin#include <dev/vx/if_vxreg.h>
8062587Sitojun#include <dev/vx/if_vxvar.h>
81118498Sume
82238273Shrs#define ETHER_MAX_LEN	1518
83151474Ssuz#define ETHER_ADDR_LEN	6
84151474Ssuz#define ETHER_ALIGN 	2
85151474Ssuz
86151539Ssuzstatic struct connector_entry {
87197138Shrs	int bit;
88222728Shrs	char *name;
89245230Sume} conn_tab[VX_CONNECTORS] = {
90282805Shrs
9162587Sitojun#define CONNECTOR_UTP	0
92121161Sume	{
93121161Sume		0x08, "utp"
94121161Sume	},
95121161Sume#define CONNECTOR_AUI	1
96121161Sume	{
97121161Sume		0x20, "aui"
98121161Sume	},
99121161Sume/* dummy */
100121161Sume	{
101121161Sume		0, "???"
10253541Sshin	},
10362587Sitojun#define CONNECTOR_BNC	3
10462587Sitojun	{
10553541Sshin		0x10, "bnc"
10653541Sshin	},
10753541Sshin#define CONNECTOR_TX	4
10853541Sshin	{
10953541Sshin		0x02, "tx"
11053541Sshin	},
11162587Sitojun#define CONNECTOR_FX	5
11262587Sitojun	{
11353541Sshin		0x04, "fx"
11462587Sitojun	},
11553541Sshin#define CONNECTOR_MII	6
11653541Sshin	{
11753541Sshin		0x40, "mii"
11853541Sshin	},
11953541Sshin	{
12062587Sitojun		0, "???"
12153541Sshin	}
12253541Sshin};
12353541Sshin
12478064Sume/* int vxattach(struct vx_softc *); */
12578064Sumestatic void vxtxstat(struct vx_softc *);
12678064Sumestatic int vxstatus(struct vx_softc *);
12778064Sumestatic void vxinit(void *);
12878064Sumestatic int vxioctl(struct ifnet *, u_long, caddr_t);
12978064Sumestatic void vxstart(struct ifnet *);
13081369Ssimokawastatic void vxwatchdog(struct ifnet *);
13178064Sumestatic void vxreset(struct vx_softc *);
132121472Sumestatic void vxread(struct vx_softc *);
133121472Sumestatic struct mbuf *vxget(struct vx_softc *, u_int);
134121472Sumestatic void vxmbuffill(void *);
135121472Sumestatic void vxmbufempty(struct vx_softc *);
136121472Sumestatic void vxsetfilter(struct vx_softc *);
137121472Sumestatic void vxgetlink(struct vx_softc *);
138121472Sumestatic void vxsetlink(struct vx_softc *);
139121472Sume
140121472Sumeint
141121472Sumevxattach(device_t dev)
142121472Sume{
143121472Sume	struct vx_softc *sc = device_get_softc(dev);
144121472Sume	struct ifnet *ifp;
145121472Sume	int i;
146121472Sume	u_char eaddr[6];
147121472Sume
148121472Sume	ifp = sc->ifp = if_alloc(IFT_ETHER);
149121472Sume	if (ifp == NULL) {
15053541Sshin		device_printf(dev, "can not if_alloc()\n");
15162587Sitojun		return 0;
15253541Sshin	}
15353541Sshin
15462587Sitojun	callout_handle_init(&sc->ch);
15553541Sshin	GO_WINDOW(0);
15662587Sitojun	CSR_WRITE_2(sc, VX_COMMAND, GLOBAL_RESET);
15795023Ssuz	VX_BUSY_WAIT;
15895023Ssuz
15995023Ssuz	vxgetlink(sc);
16062587Sitojun
16162587Sitojun	/*
16253541Sshin         * Read the station address from the eeprom
16353541Sshin         */
16453541Sshin	GO_WINDOW(0);
16553541Sshin	for (i = 0; i < 3; i++) {
16678064Sume		int x;
16778064Sume
16878064Sume		if (vxbusyeeprom(sc))
16978064Sume			return 0;
17078064Sume		CSR_WRITE_2(sc, VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD
171121472Sume		    | (EEPROM_OEM_ADDR0 + i));
172121472Sume		if (vxbusyeeprom(sc))
173121472Sume			return 0;
17478064Sume		x = CSR_READ_2(sc, VX_W0_EEPROM_DATA);
17578064Sume		eaddr[(i << 1)] = x >> 8;
17678064Sume		eaddr[(i << 1) + 1] = x;
17778064Sume	}
17878064Sume
17981369Ssimokawa	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
18078064Sume	ifp->if_mtu = ETHERMTU;
18178064Sume	ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
18278064Sume	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
18378064Sume	    IFF_NEEDSGIANT;
18478064Sume	ifp->if_start = vxstart;
18578064Sume	ifp->if_ioctl = vxioctl;
18678064Sume	ifp->if_init = vxinit;
18778064Sume	ifp->if_watchdog = vxwatchdog;
18878064Sume	ifp->if_softc = sc;
18978064Sume
19078064Sume	ether_ifattach(ifp, eaddr);
19178064Sume
19278064Sume	sc->tx_start_thresh = 20;	/* probably a good starting point. */
19378064Sume
19478064Sume	vxstop(sc);
19578064Sume
19678064Sume	return 1;
19778064Sume}
19853541Sshin
19962587Sitojun/*
20062587Sitojun * The order in here seems important. Otherwise we may not receive
20153541Sshin * interrupts. ?!
20253541Sshin */
20362587Sitojunstatic void
20462587Sitojunvxinit(void *xsc)
20562587Sitojun{
20662587Sitojun	struct vx_softc *sc = (struct vx_softc *)xsc;
20762587Sitojun	struct ifnet *ifp = sc->ifp;
20878064Sume	int i;
20978064Sume
21078064Sume	VX_BUSY_WAIT;
21162587Sitojun
21253541Sshin	GO_WINDOW(2);
21395023Ssuz
21495023Ssuz	for (i = 0; i < 6; i++)	/* Reload the ether_addr. */
21562587Sitojun		CSR_WRITE_1(sc, VX_W2_ADDR_0 + i, IFP2ENADDR(sc->ifp)[i]);
21653541Sshin
21762587Sitojun	CSR_WRITE_2(sc, VX_COMMAND, RX_RESET);
21853541Sshin	VX_BUSY_WAIT;
21953541Sshin	CSR_WRITE_2(sc, VX_COMMAND, TX_RESET);
22053541Sshin	VX_BUSY_WAIT;
22162587Sitojun
22262587Sitojun	GO_WINDOW(1);		/* Window 1 is operating window */
22362587Sitojun	for (i = 0; i < 31; i++)
22462587Sitojun		CSR_READ_1(sc, VX_W1_TX_STATUS);
22562587Sitojun
22678064Sume	CSR_WRITE_2(sc, VX_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE |
22778064Sume	    S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL);
22878064Sume	CSR_WRITE_2(sc, VX_COMMAND, SET_INTR_MASK | S_CARD_FAILURE |
22978064Sume	    S_RX_COMPLETE | S_TX_COMPLETE | S_TX_AVAIL);
23062587Sitojun
231121807Sume	/*
23253541Sshin         * Attempt to get rid of any stray interrupts that occured during
23353541Sshin         * configuration.  On the i386 this isn't possible because one may
23462587Sitojun         * already be queued.  However, a single stray interrupt is
235295583Smarkj         * unimportant.
23662587Sitojun         */
237295583Smarkj	CSR_WRITE_2(sc, VX_COMMAND, ACK_INTR | 0xff);
238295583Smarkj
23953541Sshin	vxsetfilter(sc);
24053541Sshin	vxsetlink(sc);
241295583Smarkj
242151539Ssuz	CSR_WRITE_2(sc, VX_COMMAND, RX_ENABLE);
243296063Smarkj	CSR_WRITE_2(sc, VX_COMMAND, TX_ENABLE);
24453541Sshin
24553541Sshin	vxmbuffill((caddr_t) sc);
246151539Ssuz
247151539Ssuz	/* Interface is now `running', with no output active. */
248151539Ssuz	ifp->if_flags |= IFF_RUNNING;
249151539Ssuz	ifp->if_flags &= ~IFF_OACTIVE;
250151539Ssuz
251151539Ssuz	/* Attempt to start output, if any. */
252151539Ssuz	vxstart(ifp);
253151539Ssuz}
254151539Ssuz
255151539Ssuzstatic void
256151539Ssuzvxsetfilter(struct vx_softc *sc)
257151539Ssuz{
258151539Ssuz	register struct ifnet *ifp = sc->ifp;
259151539Ssuz
26053541Sshin	GO_WINDOW(1);		/* Window 1 is operating window */
26162587Sitojun	CSR_WRITE_2(sc, VX_COMMAND, SET_RX_FILTER |
26260938Sjake	    FIL_INDIVIDUAL | FIL_BRDCST | FIL_MULTICAST |
26362587Sitojun	    ((ifp->if_flags & IFF_PROMISC) ? FIL_PROMISC : 0));
26462587Sitojun}
265151539Ssuz
26662587Sitojunstatic void
26762587Sitojunvxgetlink(struct vx_softc *sc)
268151539Ssuz{
26962587Sitojun	int n, k;
27062587Sitojun
271151539Ssuz	GO_WINDOW(3);
272151539Ssuz	sc->vx_connectors = CSR_READ_2(sc, VX_W3_RESET_OPT) & 0x7f;
27362587Sitojun	for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
27478064Sume		if (sc->vx_connectors & conn_tab[k].bit) {
27553541Sshin			if (n > 0)
27660938Sjake				printf("/");
27753541Sshin			printf("%s", conn_tab[k].name);
27878064Sume			n++;
27953541Sshin		}
28053541Sshin	}
28162587Sitojun	if (sc->vx_connectors == 0) {
28262587Sitojun		printf("no connectors!");
28362587Sitojun		return;
284151539Ssuz	}
28553541Sshin	GO_WINDOW(3);
28653541Sshin	sc->vx_connector =
28753541Sshin	    (CSR_READ_4(sc, VX_W3_INTERNAL_CFG) & INTERNAL_CONNECTOR_MASK)
28853541Sshin	    >> INTERNAL_CONNECTOR_BITS;
28953541Sshin	if (sc->vx_connector & 0x10) {
29053541Sshin		sc->vx_connector &= 0x0f;
29153541Sshin		printf("[*%s*]", conn_tab[(int)sc->vx_connector].name);
29272093Sasmodai		printf(": disable 'auto select' with DOS util!");
29353541Sshin	} else {
29462587Sitojun		printf("[*%s*]", conn_tab[(int)sc->vx_connector].name);
29553541Sshin	}
29653541Sshin}
29753541Sshin
29853541Sshinstatic void
29962587Sitojunvxsetlink(struct vx_softc *sc)
30053541Sshin{
30153541Sshin	register struct ifnet *ifp = sc->ifp;
30253541Sshin	int i, j, k;
30353541Sshin	char *reason, *warning;
30462587Sitojun	static int prev_flags;
30562587Sitojun	static signed char prev_conn = -1;
30653541Sshin
30762587Sitojun	if (prev_conn == -1)
30853541Sshin		prev_conn = sc->vx_connector;
30962587Sitojun
31062587Sitojun	/*
31153541Sshin         * S.B.
31253541Sshin         *
31360938Sjake         * Now behavior was slightly changed:
31462587Sitojun         *
31553541Sshin         * if any of flags link[0-2] is used and its connector is
31653541Sshin         * physically present the following connectors are used:
31760938Sjake         *
31853541Sshin         *   link0 - AUI * highest precedence
319300262Smarkj         *   link1 - BNC
320300262Smarkj         *   link2 - UTP * lowest precedence
321300262Smarkj         *
322300262Smarkj         * If none of them is specified then
32353541Sshin         * connector specified in the EEPROM is used
324195699Srwatson         * (if present on card or UTP if not).
325195699Srwatson         */
326195699Srwatson	i = sc->vx_connector;	/* default in EEPROM */
327195699Srwatson	reason = "default";
328195699Srwatson	warning = 0;
329195699Srwatson
330195699Srwatson	if (ifp->if_flags & IFF_LINK0) {
331195699Srwatson		if (sc->vx_connectors & conn_tab[CONNECTOR_AUI].bit) {
332195699Srwatson			i = CONNECTOR_AUI;
333195699Srwatson			reason = "link0";
334195699Srwatson		} else {
335195727Srwatson			warning = "aui not present! (link0)";
336195727Srwatson		}
337195727Srwatson	} else if (ifp->if_flags & IFF_LINK1) {
338195727Srwatson		if (sc->vx_connectors & conn_tab[CONNECTOR_BNC].bit) {
339195727Srwatson			i = CONNECTOR_BNC;
340195727Srwatson			reason = "link1";
341195727Srwatson		} else {
342195727Srwatson			warning = "bnc not present! (link1)";
343195727Srwatson		}
344195727Srwatson	} else if (ifp->if_flags & IFF_LINK2) {
345195727Srwatson		if (sc->vx_connectors & conn_tab[CONNECTOR_UTP].bit) {
346207369Sbz			i = CONNECTOR_UTP;
347296063Smarkj			reason = "link2";
348296063Smarkj		} else {
349296063Smarkj			warning = "utp not present! (link2)";
350296063Smarkj		}
351296063Smarkj	} else if ((sc->vx_connectors & conn_tab[(int)sc->vx_connector].bit) == 0) {
352296063Smarkj		warning = "strange connector type in EEPROM.";
353296063Smarkj		reason = "forced";
354296063Smarkj		i = CONNECTOR_UTP;
355296063Smarkj	}
356296063Smarkj	/* Avoid unnecessary message. */
357296063Smarkj	k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2);
358296063Smarkj	if ((k != 0) || (prev_conn != i)) {
359296063Smarkj		if (warning != 0) {
360207369Sbz			printf("vx%d: warning: %s\n", sc->unit, warning);
361207369Sbz		}
36262587Sitojun		printf("vx%d: selected %s. (%s)\n",
363195699Srwatson		    sc->unit, conn_tab[i].name, reason);
364195699Srwatson	}
365195699Srwatson	/* Set the selected connector. */
366195699Srwatson	GO_WINDOW(3);
367195699Srwatson	j = CSR_READ_4(sc, VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
368195727Srwatson	CSR_WRITE_4(sc, VX_W3_INTERNAL_CFG, j | (i << INTERNAL_CONNECTOR_BITS));
369195727Srwatson
370195727Srwatson	/* First, disable all. */
371195727Srwatson	CSR_WRITE_2(sc, VX_COMMAND, STOP_TRANSCEIVER);
372195727Srwatson	DELAY(800);
373195699Srwatson	GO_WINDOW(4);
37453541Sshin	CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, 0);
375279531Shrs
37653541Sshin	/* Second, enable the selected one. */
37762587Sitojun	switch (i) {
37862587Sitojun	case CONNECTOR_UTP:
37962587Sitojun		GO_WINDOW(4);
38095023Ssuz		CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, ENABLE_UTP);
38162587Sitojun		break;
38262587Sitojun	case CONNECTOR_BNC:
383279531Shrs		CSR_WRITE_2(sc, VX_COMMAND, START_TRANSCEIVER);
384279531Shrs		DELAY(800);
385279531Shrs		break;
386279531Shrs	case CONNECTOR_TX:
387279531Shrs	case CONNECTOR_FX:
388279531Shrs		GO_WINDOW(4);
389279531Shrs		CSR_WRITE_2(sc, VX_W4_MEDIA_TYPE, LINKBEAT_ENABLE);
390279531Shrs		break;
391279531Shrs	default:		/* AUI and MII fall here */
392279531Shrs		break;
39362587Sitojun	}
39462587Sitojun	GO_WINDOW(1);
39562587Sitojun
39662587Sitojun	prev_flags = ifp->if_flags;
39753541Sshin	prev_conn = i;
39853541Sshin}
39962587Sitojun
40062587Sitojunstatic void
40162587Sitojunvxstart(struct ifnet *ifp)
40262587Sitojun{
40362587Sitojun	register struct vx_softc *sc = ifp->if_softc;
40462587Sitojun	register struct mbuf *m;
405279531Shrs	int sh, len, pad;
40662587Sitojun
40762587Sitojun	/* Don't transmit if interface is busy or not running */
40862587Sitojun	if ((sc->ifp->if_flags &
40953541Sshin	    (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
41053541Sshin		return;
41153541Sshin
412241916Sdelphijstartagain:
413193731Szec	/* Sneak a peek at the next packet */
414241916Sdelphij	m = ifp->if_snd.ifq_head;
415193731Szec	if (m == NULL) {
416241916Sdelphij		return;
417241916Sdelphij	}
418287857Smelifaro	/* We need to use m->m_pkthdr.len, so require the header */
419241916Sdelphij	M_ASSERTPKTHDR(m);
420241916Sdelphij	len = m->m_pkthdr.len;
421241916Sdelphij
422287857Smelifaro	pad = (4 - len) & 3;
423287857Smelifaro
424241916Sdelphij	/*
425288062Smelifaro         * The 3c509 automatically pads short packets to minimum ethernet
426241916Sdelphij	 * length, but we drop packets that are too large. Perhaps we should
427241916Sdelphij	 * truncate them instead?
428292978Smelifaro         */
429292978Smelifaro	if (len + pad > ETHER_MAX_LEN) {
430287861Smelifaro		/* packet is obviously too large: toss it */
431301217Sgnn		++ifp->if_oerrors;
432241916Sdelphij		IF_DEQUEUE(&ifp->if_snd, m);
433287826Smelifaro		m_freem(m);
434241916Sdelphij		goto readcheck;
435276844Smelifaro	}
436276844Smelifaro	VX_BUSY_WAIT;
437276844Smelifaro	if (CSR_READ_2(sc, VX_W1_FREE_TX) < len + pad + 4) {
438276844Smelifaro		CSR_WRITE_2(sc, VX_COMMAND,
439260882Smelifaro		    SET_TX_AVAIL_THRESH | ((len + pad + 4) >> 2));
440287789Smelifaro		/* not enough room in FIFO - make sure */
441287861Smelifaro		if (CSR_READ_2(sc, VX_W1_FREE_TX) < len + pad + 4) {
442290867Smelifaro			ifp->if_flags |= IFF_OACTIVE;
44353541Sshin			ifp->if_timer = 1;
44453541Sshin			return;
445241916Sdelphij		}
446241916Sdelphij	}
447241916Sdelphij	CSR_WRITE_2(sc, VX_COMMAND, SET_TX_AVAIL_THRESH | (8188 >> 2));
448241916Sdelphij	IF_DEQUEUE(&ifp->if_snd, m);
449241916Sdelphij	if (m == NULL)		/* not really needed */
450287484Smelifaro		return;
451241916Sdelphij
452275593Smarkj	VX_BUSY_WAIT;
453241916Sdelphij	CSR_WRITE_2(sc, VX_COMMAND, SET_TX_START_THRESH |
454241916Sdelphij	    ((len / 4 + sc->tx_start_thresh) >> 2));
45553541Sshin
45653541Sshin	BPF_MTAP(sc->ifp, m);
457241916Sdelphij
458241916Sdelphij	/*
459241916Sdelphij         * Do the output at splhigh() so that an interrupt from another device
460241916Sdelphij         * won't cause a FIFO underrun.
461296063Smarkj         */
462296063Smarkj	sh = splhigh();
463296991Smarkj
464296063Smarkj	CSR_WRITE_4(sc, VX_W1_TX_PIO_WR_1, len | TX_INDICATE);
465296063Smarkj
466241916Sdelphij	while (m) {
467241916Sdelphij		if (m->m_len > 3)
468241916Sdelphij			bus_space_write_multi_4(sc->bst, sc->bsh,
469241916Sdelphij			    VX_W1_TX_PIO_WR_1, (u_int32_t *)mtod(m, caddr_t),
470241916Sdelphij			    m->m_len / 4);
471296063Smarkj		if (m->m_len & 3)
472241916Sdelphij			bus_space_write_multi_1(sc->bst, sc->bsh,
473241916Sdelphij			    VX_W1_TX_PIO_WR_1,
474241916Sdelphij			    mtod(m, caddr_t) + (m->m_len & ~3), m->m_len & 3);
475241916Sdelphij		m = m_free(m);
47653541Sshin	}
47753541Sshin	while (pad--)
47853541Sshin		CSR_WRITE_1(sc, VX_W1_TX_PIO_WR_1, 0);	/* Padding */
47953541Sshin
480	splx(sh);
481
482	++ifp->if_opackets;
483	ifp->if_timer = 1;
484
485readcheck:
486	if ((CSR_READ_2(sc, VX_W1_RX_STATUS) & ERR_INCOMPLETE) == 0) {
487		/* We received a complete packet. */
488
489		if ((CSR_READ_2(sc, VX_STATUS) & S_INTR_LATCH) == 0) {
490			/*
491		         * No interrupt, read the packet and continue
492		         * Is this supposed to happen?  Is my motherboard
493		         * completely busted?
494		         */
495			vxread(sc);
496		} else
497			/*
498			 * Got an interrupt, return so that it gets
499			 * serviced.
500			 */
501			return;
502	} else {
503		/* Check if we are stuck and reset [see XXX comment] */
504		if (vxstatus(sc)) {
505			if (ifp->if_flags & IFF_DEBUG)
506				if_printf(ifp, "adapter reset\n");
507			vxreset(sc);
508		}
509	}
510
511	goto startagain;
512}
513
514/*
515 * XXX: The 3c509 card can get in a mode where both the fifo status bit
516 *      FIFOS_RX_OVERRUN and the status bit ERR_INCOMPLETE are set
517 *      We detect this situation and we reset the adapter.
518 *      It happens at times when there is a lot of broadcast traffic
519 *      on the cable (once in a blue moon).
520 */
521static int
522vxstatus(struct vx_softc *sc)
523{
524	int fifost;
525
526	/*
527         * Check the FIFO status and act accordingly
528         */
529	GO_WINDOW(4);
530	fifost = CSR_READ_2(sc, VX_W4_FIFO_DIAG);
531	GO_WINDOW(1);
532
533	if (fifost & FIFOS_RX_UNDERRUN) {
534		if (sc->ifp->if_flags & IFF_DEBUG)
535			printf("vx%d: RX underrun\n", sc->unit);
536		vxreset(sc);
537		return 0;
538	}
539	if (fifost & FIFOS_RX_STATUS_OVERRUN) {
540		if (sc->ifp->if_flags & IFF_DEBUG)
541			printf("vx%d: RX Status overrun\n", sc->unit);
542		return 1;
543	}
544	if (fifost & FIFOS_RX_OVERRUN) {
545		if (sc->ifp->if_flags & IFF_DEBUG)
546			printf("vx%d: RX overrun\n", sc->unit);
547		return 1;
548	}
549	if (fifost & FIFOS_TX_OVERRUN) {
550		if (sc->ifp->if_flags & IFF_DEBUG)
551			printf("vx%d: TX overrun\n", sc->unit);
552		vxreset(sc);
553		return 0;
554	}
555	return 0;
556}
557
558static void
559vxtxstat(struct vx_softc *sc)
560{
561	int i;
562
563	/*
564        * We need to read+write TX_STATUS until we get a 0 status
565        * in order to turn off the interrupt flag.
566        */
567	while ((i = CSR_READ_1(sc, VX_W1_TX_STATUS)) & TXS_COMPLETE) {
568		CSR_WRITE_1(sc, VX_W1_TX_STATUS, 0x0);
569
570		if (i & TXS_JABBER) {
571			++sc->ifp->if_oerrors;
572			if (sc->ifp->if_flags & IFF_DEBUG)
573				printf("vx%d: jabber (%x)\n", sc->unit, i);
574			vxreset(sc);
575		} else if (i & TXS_UNDERRUN) {
576			++sc->ifp->if_oerrors;
577			if (sc->ifp->if_flags & IFF_DEBUG)
578				printf("vx%d: fifo underrun (%x) @%d\n",
579				    sc->unit, i, sc->tx_start_thresh);
580			if (sc->tx_succ_ok < 100)
581				sc->tx_start_thresh =
582				    min(ETHER_MAX_LEN,sc->tx_start_thresh + 20);
583			sc->tx_succ_ok = 0;
584			vxreset(sc);
585		} else if (i & TXS_MAX_COLLISION) {
586			++sc->ifp->if_collisions;
587			CSR_WRITE_2(sc, VX_COMMAND, TX_ENABLE);
588			sc->ifp->if_flags &= ~IFF_OACTIVE;
589		} else
590			sc->tx_succ_ok = (sc->tx_succ_ok + 1) & 127;
591	}
592}
593
594void
595vxintr(void *voidsc)
596{
597	register short status;
598	struct vx_softc *sc = voidsc;
599	struct ifnet *ifp = sc->ifp;
600
601	for (;;) {
602		CSR_WRITE_2(sc, VX_COMMAND, C_INTR_LATCH);
603
604		status = CSR_READ_2(sc, VX_STATUS);
605
606		if ((status & (S_TX_COMPLETE | S_TX_AVAIL |
607		    S_RX_COMPLETE | S_CARD_FAILURE)) == 0)
608			break;
609
610		/*
611		 * Acknowledge any interrupts.  It's important that we do this
612		 * first, since there would otherwise be a race condition.
613		 * Due to the i386 interrupt queueing, we may get spurious
614		 * interrupts occasionally.
615		 */
616		CSR_WRITE_2(sc, VX_COMMAND, ACK_INTR | status);
617
618		if (status & S_RX_COMPLETE)
619			vxread(sc);
620		if (status & S_TX_AVAIL) {
621			ifp->if_timer = 0;
622			sc->ifp->if_flags &= ~IFF_OACTIVE;
623			vxstart(sc->ifp);
624		}
625		if (status & S_CARD_FAILURE) {
626			printf("vx%d: adapter failure (%x)\n",
627			    sc->unit, status);
628			ifp->if_timer = 0;
629			vxreset(sc);
630			return;
631		}
632		if (status & S_TX_COMPLETE) {
633			ifp->if_timer = 0;
634			vxtxstat(sc);
635			vxstart(ifp);
636		}
637	}
638
639	/* no more interrupts */
640	return;
641}
642
643static void
644vxread(struct vx_softc *sc)
645{
646	struct ifnet *ifp = sc->ifp;
647	struct mbuf *m;
648	struct ether_header *eh;
649	u_int len;
650
651	len = CSR_READ_2(sc, VX_W1_RX_STATUS);
652
653again:
654
655	if (ifp->if_flags & IFF_DEBUG) {
656		int err = len & ERR_MASK;
657		char *s = NULL;
658
659		if (len & ERR_INCOMPLETE)
660			s = "incomplete packet";
661		else if (err == ERR_OVERRUN)
662			s = "packet overrun";
663		else if (err == ERR_RUNT)
664			s = "runt packet";
665		else if (err == ERR_ALIGNMENT)
666			s = "bad alignment";
667		else if (err == ERR_CRC)
668			s = "bad crc";
669		else if (err == ERR_OVERSIZE)
670			s = "oversized packet";
671		else if (err == ERR_DRIBBLE)
672			s = "dribble bits";
673
674		if (s)
675			printf("vx%d: %s\n", sc->unit, s);
676	}
677	if (len & ERR_INCOMPLETE)
678		return;
679
680	if (len & ERR_RX) {
681		++ifp->if_ierrors;
682		goto abort;
683	}
684	len &= RX_BYTES_MASK;	/* Lower 11 bits = RX bytes. */
685
686	/* Pull packet off interface. */
687	m = vxget(sc, len);
688	if (m == 0) {
689		ifp->if_ierrors++;
690		goto abort;
691	}
692	++ifp->if_ipackets;
693
694	{
695		struct mbuf *m0;
696
697		m0 = m_devget(mtod(m, char *), m->m_pkthdr.len, ETHER_ALIGN, ifp, NULL);
698		if (m0 == NULL) {
699			ifp->if_ierrors++;
700			goto abort;
701		}
702		m_freem(m);
703		m = m0;
704	}
705
706	/* We assume the header fit entirely in one mbuf. */
707	eh = mtod(m, struct ether_header *);
708
709	/*
710         * XXX: Some cards seem to be in promiscous mode all the time.
711         * we need to make sure we only get our own stuff always.
712         * bleah!
713         */
714
715	if (!(ifp->if_flags & IFF_PROMISC)
716	    && (eh->ether_dhost[0] & 1) == 0	/* !mcast and !bcast */
717	    && bcmp(eh->ether_dhost, IFP2ENADDR(sc->ifp), ETHER_ADDR_LEN)!=0) {
718		m_freem(m);
719		return;
720	}
721	(*ifp->if_input) (ifp, m);
722
723	/*
724        * In periods of high traffic we can actually receive enough
725        * packets so that the fifo overrun bit will be set at this point,
726        * even though we just read a packet. In this case we
727        * are not going to receive any more interrupts. We check for
728        * this condition and read again until the fifo is not full.
729        * We could simplify this test by not using vxstatus(), but
730        * rechecking the RX_STATUS register directly. This test could
731        * result in unnecessary looping in cases where there is a new
732        * packet but the fifo is not full, but it will not fix the
733        * stuck behavior.
734        *
735        * Even with this improvement, we still get packet overrun errors
736        * which are hurting performance. Maybe when I get some more time
737        * I'll modify vxread() so that it can handle RX_EARLY interrupts.
738        */
739	if (vxstatus(sc)) {
740		len = CSR_READ_2(sc, VX_W1_RX_STATUS);
741		/* Check if we are stuck and reset [see XXX comment] */
742		if (len & ERR_INCOMPLETE) {
743			if (ifp->if_flags & IFF_DEBUG)
744				printf("vx%d: adapter reset\n", sc->unit);
745			vxreset(sc);
746			return;
747		}
748		goto again;
749	}
750	return;
751
752abort:
753	CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK);
754}
755
756static struct mbuf *
757vxget(struct vx_softc *sc, u_int totlen)
758{
759	struct ifnet *ifp = sc->ifp;
760	struct mbuf *top, **mp, *m;
761	int len;
762	int sh;
763
764	m = sc->mb[sc->next_mb];
765	sc->mb[sc->next_mb] = 0;
766	if (m == 0) {
767		MGETHDR(m, M_DONTWAIT, MT_DATA);
768		if (m == 0)
769			return 0;
770	} else {
771		/* If the queue is no longer full, refill. */
772		if (sc->last_mb == sc->next_mb && sc->buffill_pending == 0) {
773			sc->ch = timeout(vxmbuffill, sc, 1);
774			sc->buffill_pending = 1;
775		}
776		/* Convert one of our saved mbuf's. */
777		sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
778		m->m_data = m->m_pktdat;
779		m->m_flags = M_PKTHDR;
780		bzero(&m->m_pkthdr, sizeof(m->m_pkthdr));
781	}
782	m->m_pkthdr.rcvif = ifp;
783	m->m_pkthdr.len = totlen;
784	len = MHLEN;
785	top = 0;
786	mp = &top;
787
788	/*
789         * We read the packet at splhigh() so that an interrupt from another
790         * device doesn't cause the card's buffer to overflow while we're
791         * reading it.  We may still lose packets at other times.
792         */
793	sh = splhigh();
794
795	/*
796         * Since we don't set allowLargePackets bit in MacControl register,
797         * we can assume that totlen <= 1500bytes.
798         * The while loop will be performed iff we have a packet with
799         * MLEN < m_len < MINCLSIZE.
800         */
801	while (totlen > 0) {
802		if (top) {
803			m = sc->mb[sc->next_mb];
804			sc->mb[sc->next_mb] = 0;
805			if (m == 0) {
806				MGET(m, M_DONTWAIT, MT_DATA);
807				if (m == 0) {
808					splx(sh);
809					m_freem(top);
810					return 0;
811				}
812			} else {
813				sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
814			}
815			len = MLEN;
816		}
817		if (totlen >= MINCLSIZE) {
818			MCLGET(m, M_DONTWAIT);
819			if (m->m_flags & M_EXT)
820				len = MCLBYTES;
821		}
822		len = min(totlen, len);
823		if (len > 3)
824			bus_space_read_multi_4(sc->bst, sc->bsh,
825			    VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), len / 4);
826		if (len & 3) {
827			bus_space_read_multi_1(sc->bst, sc->bsh,
828			    VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3),
829			    len & 3);
830		}
831		m->m_len = len;
832		totlen -= len;
833		*mp = m;
834		mp = &m->m_next;
835	}
836
837	CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK);
838
839	splx(sh);
840
841	return top;
842}
843
844
845static int
846vxioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
847{
848	struct vx_softc *sc = ifp->if_softc;
849	struct ifreq *ifr = (struct ifreq *) data;
850	int s, error = 0;
851
852	s = splimp();
853
854	switch (cmd) {
855	case SIOCSIFFLAGS:
856		if ((ifp->if_flags & IFF_UP) == 0 &&
857		    (ifp->if_flags & IFF_RUNNING) != 0) {
858			/*
859	                 * If interface is marked up and it is stopped, then
860	                 * start it.
861	                 */
862			vxstop(sc);
863			ifp->if_flags &= ~IFF_RUNNING;
864		} else if ((ifp->if_flags & IFF_UP) != 0 &&
865		    (ifp->if_flags & IFF_RUNNING) == 0) {
866			/*
867	                 * If interface is marked up and it is stopped, then
868	                 * start it.
869	                 */
870			vxinit(sc);
871		} else {
872			/*
873	                 * deal with flags changes:
874	                 * IFF_MULTICAST, IFF_PROMISC,
875	                 * IFF_LINK0, IFF_LINK1,
876	                 */
877			vxsetfilter(sc);
878			vxsetlink(sc);
879		}
880		break;
881
882	case SIOCSIFMTU:
883		/*
884	         * Set the interface MTU.
885	         */
886		if (ifr->ifr_mtu > ETHERMTU) {
887			error = EINVAL;
888		} else {
889			ifp->if_mtu = ifr->ifr_mtu;
890		}
891		break;
892
893	case SIOCADDMULTI:
894	case SIOCDELMULTI:
895		/*
896		 * Multicast list has changed; set the hardware filter
897		 * accordingly.
898		 */
899		vxreset(sc);
900		error = 0;
901		break;
902
903
904	default:
905		error = ether_ioctl(ifp, cmd, data);
906		break;
907	}
908
909	splx(s);
910
911	return (error);
912}
913
914static void
915vxreset(struct vx_softc *sc)
916{
917	int s;
918
919	s = splimp();
920
921	vxstop(sc);
922	vxinit(sc);
923	splx(s);
924}
925
926static void
927vxwatchdog(struct ifnet *ifp)
928{
929	struct vx_softc *sc = ifp->if_softc;
930
931	if (ifp->if_flags & IFF_DEBUG)
932		if_printf(ifp, "device timeout\n");
933	ifp->if_flags &= ~IFF_OACTIVE;
934	vxstart(ifp);
935	vxintr(sc);
936}
937
938void
939vxstop(struct vx_softc *sc)
940{
941	struct ifnet *ifp = sc->ifp;
942
943	ifp->if_timer = 0;
944
945	CSR_WRITE_2(sc, VX_COMMAND, RX_DISABLE);
946	CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK);
947	VX_BUSY_WAIT;
948	CSR_WRITE_2(sc, VX_COMMAND, TX_DISABLE);
949	CSR_WRITE_2(sc, VX_COMMAND, STOP_TRANSCEIVER);
950	DELAY(800);
951	CSR_WRITE_2(sc, VX_COMMAND, RX_RESET);
952	VX_BUSY_WAIT;
953	CSR_WRITE_2(sc, VX_COMMAND, TX_RESET);
954	VX_BUSY_WAIT;
955	CSR_WRITE_2(sc, VX_COMMAND, C_INTR_LATCH);
956	CSR_WRITE_2(sc, VX_COMMAND, SET_RD_0_MASK);
957	CSR_WRITE_2(sc, VX_COMMAND, SET_INTR_MASK);
958	CSR_WRITE_2(sc, VX_COMMAND, SET_RX_FILTER);
959
960	vxmbufempty(sc);
961}
962
963int
964vxbusyeeprom(struct vx_softc *sc)
965{
966	int j, i = 100;
967
968	while (i--) {
969		j = CSR_READ_2(sc, VX_W0_EEPROM_COMMAND);
970		if (j & EEPROM_BUSY)
971			DELAY(100);
972		else
973			break;
974	}
975	if (!i) {
976		printf("vx%d: eeprom failed to come ready\n", sc->unit);
977		return (1);
978	}
979	return (0);
980}
981
982static void
983vxmbuffill(void *sp)
984{
985	struct vx_softc *sc = (struct vx_softc *)sp;
986	int s, i;
987
988	s = splimp();
989	i = sc->last_mb;
990	do {
991		if (sc->mb[i] == NULL)
992			MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
993		if (sc->mb[i] == NULL)
994			break;
995		i = (i + 1) % MAX_MBS;
996	} while (i != sc->next_mb);
997	sc->last_mb = i;
998	/* If the queue was not filled, try again. */
999	if (sc->last_mb != sc->next_mb) {
1000		sc->ch = timeout(vxmbuffill, sc, 1);
1001		sc->buffill_pending = 1;
1002	} else {
1003		sc->buffill_pending = 0;
1004	}
1005	splx(s);
1006}
1007
1008static void
1009vxmbufempty(struct vx_softc *sc)
1010{
1011	int s, i;
1012
1013	s = splimp();
1014	for (i = 0; i < MAX_MBS; i++) {
1015		if (sc->mb[i]) {
1016			m_freem(sc->mb[i]);
1017			sc->mb[i] = NULL;
1018		}
1019	}
1020	sc->last_mb = sc->next_mb = 0;
1021	if (sc->buffill_pending != 0)
1022		untimeout(vxmbuffill, sc, sc->ch);
1023	splx(s);
1024}
1025