if_vr.c revision 51533
141502Swpaul/*
241502Swpaul * Copyright (c) 1997, 1998
341502Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
441502Swpaul *
541502Swpaul * Redistribution and use in source and binary forms, with or without
641502Swpaul * modification, are permitted provided that the following conditions
741502Swpaul * are met:
841502Swpaul * 1. Redistributions of source code must retain the above copyright
941502Swpaul *    notice, this list of conditions and the following disclaimer.
1041502Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1141502Swpaul *    notice, this list of conditions and the following disclaimer in the
1241502Swpaul *    documentation and/or other materials provided with the distribution.
1341502Swpaul * 3. All advertising materials mentioning features or use of this software
1441502Swpaul *    must display the following acknowledgement:
1541502Swpaul *	This product includes software developed by Bill Paul.
1641502Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1741502Swpaul *    may be used to endorse or promote products derived from this software
1841502Swpaul *    without specific prior written permission.
1941502Swpaul *
2041502Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2141502Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2241502Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2341502Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2441502Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2541502Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2641502Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2741502Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2841502Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2941502Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3041502Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3141502Swpaul *
3250477Speter * $FreeBSD: head/sys/dev/vr/if_vr.c 51533 1999-09-22 06:08:11Z wpaul $
3341502Swpaul */
3441502Swpaul
3541502Swpaul/*
3641502Swpaul * VIA Rhine fast ethernet PCI NIC driver
3741502Swpaul *
3841502Swpaul * Supports various network adapters based on the VIA Rhine
3941502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX.
4041502Swpaul * Datasheets are available at http://www.via.com.tw.
4141502Swpaul *
4241502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4341502Swpaul * Electrical Engineering Department
4441502Swpaul * Columbia University, New York City
4541502Swpaul */
4641502Swpaul
4741502Swpaul/*
4841502Swpaul * The VIA Rhine controllers are similar in some respects to the
4941502Swpaul * the DEC tulip chips, except less complicated. The controller
5041502Swpaul * uses an MII bus and an external physical layer interface. The
5141502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table
5241502Swpaul * multicast filter. Transmit and receive descriptors are similar
5341502Swpaul * to the tulip.
5441502Swpaul *
5541502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism:
5641502Swpaul * transmit buffers must be longword aligned. Unfortunately,
5741502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting
5841502Swpaul * at longword boundaries, so we have to do a buffer copy before
5941502Swpaul * transmission.
6041502Swpaul */
6141502Swpaul
6248645Sdes#include "bpf.h"
6341502Swpaul
6441502Swpaul#include <sys/param.h>
6541502Swpaul#include <sys/systm.h>
6641502Swpaul#include <sys/sockio.h>
6741502Swpaul#include <sys/mbuf.h>
6841502Swpaul#include <sys/malloc.h>
6941502Swpaul#include <sys/kernel.h>
7041502Swpaul#include <sys/socket.h>
7141502Swpaul
7241502Swpaul#include <net/if.h>
7341502Swpaul#include <net/if_arp.h>
7441502Swpaul#include <net/ethernet.h>
7541502Swpaul#include <net/if_dl.h>
7641502Swpaul#include <net/if_media.h>
7741502Swpaul
7848645Sdes#if NBPF > 0
7941502Swpaul#include <net/bpf.h>
8041502Swpaul#endif
8141502Swpaul
8251354Swpaul#include "opt_bdg.h"
8351354Swpaul#ifdef BRIDGE
8451354Swpaul#include <net/bridge.h>
8551354Swpaul#endif /* BRIDGE */
8651354Swpaul
8741502Swpaul#include <vm/vm.h>              /* for vtophys */
8841502Swpaul#include <vm/pmap.h>            /* for vtophys */
8941502Swpaul#include <machine/clock.h>      /* for DELAY */
9041502Swpaul#include <machine/bus_pio.h>
9141502Swpaul#include <machine/bus_memio.h>
9241502Swpaul#include <machine/bus.h>
9349610Swpaul#include <machine/resource.h>
9449610Swpaul#include <sys/bus.h>
9549610Swpaul#include <sys/rman.h>
9641502Swpaul
9751432Swpaul#include <dev/mii/mii.h>
9851432Swpaul#include <dev/mii/miivar.h>
9951432Swpaul
10041502Swpaul#include <pci/pcireg.h>
10141502Swpaul#include <pci/pcivar.h>
10241502Swpaul
10341502Swpaul#define VR_USEIOSPACE
10441502Swpaul
10541502Swpaul#include <pci/if_vrreg.h>
10641502Swpaul
10751432Swpaul/* "controller miibus0" required.  See GENERIC if you get errors here. */
10851432Swpaul#include "miibus_if.h"
10951432Swpaul
11041502Swpaul#ifndef lint
11141591Sarchiestatic const char rcsid[] =
11250477Speter  "$FreeBSD: head/sys/dev/vr/if_vr.c 51533 1999-09-22 06:08:11Z wpaul $";
11341502Swpaul#endif
11441502Swpaul
11541502Swpaul/*
11641502Swpaul * Various supported device vendors/types and their names.
11741502Swpaul */
11841502Swpaulstatic struct vr_type vr_devs[] = {
11941502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
12041502Swpaul		"VIA VT3043 Rhine I 10/100BaseTX" },
12141502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
12241502Swpaul		"VIA VT86C100A Rhine II 10/100BaseTX" },
12344238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
12444238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
12544238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
12644238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
12741502Swpaul	{ 0, 0, NULL }
12841502Swpaul};
12941502Swpaul
13049610Swpaulstatic int vr_probe		__P((device_t));
13149610Swpaulstatic int vr_attach		__P((device_t));
13249610Swpaulstatic int vr_detach		__P((device_t));
13341502Swpaul
13441502Swpaulstatic int vr_newbuf		__P((struct vr_softc *,
13549610Swpaul					struct vr_chain_onefrag *,
13649610Swpaul					struct mbuf *));
13741502Swpaulstatic int vr_encap		__P((struct vr_softc *, struct vr_chain *,
13841502Swpaul						struct mbuf * ));
13941502Swpaul
14041502Swpaulstatic void vr_rxeof		__P((struct vr_softc *));
14141502Swpaulstatic void vr_rxeoc		__P((struct vr_softc *));
14241502Swpaulstatic void vr_txeof		__P((struct vr_softc *));
14341502Swpaulstatic void vr_txeoc		__P((struct vr_softc *));
14451432Swpaulstatic void vr_tick		__P((void *));
14541502Swpaulstatic void vr_intr		__P((void *));
14641502Swpaulstatic void vr_start		__P((struct ifnet *));
14741502Swpaulstatic int vr_ioctl		__P((struct ifnet *, u_long, caddr_t));
14841502Swpaulstatic void vr_init		__P((void *));
14941502Swpaulstatic void vr_stop		__P((struct vr_softc *));
15041502Swpaulstatic void vr_watchdog		__P((struct ifnet *));
15149610Swpaulstatic void vr_shutdown		__P((device_t));
15241502Swpaulstatic int vr_ifmedia_upd	__P((struct ifnet *));
15341502Swpaulstatic void vr_ifmedia_sts	__P((struct ifnet *, struct ifmediareq *));
15441502Swpaul
15541502Swpaulstatic void vr_mii_sync		__P((struct vr_softc *));
15641502Swpaulstatic void vr_mii_send		__P((struct vr_softc *, u_int32_t, int));
15741502Swpaulstatic int vr_mii_readreg	__P((struct vr_softc *, struct vr_mii_frame *));
15841502Swpaulstatic int vr_mii_writereg	__P((struct vr_softc *, struct vr_mii_frame *));
15951432Swpaulstatic int vr_miibus_readreg	__P((device_t, int, int));
16051432Swpaulstatic int vr_miibus_writereg	__P((device_t, int, int, int));
16151432Swpaulstatic void vr_miibus_statchg	__P((device_t));
16241502Swpaul
16351432Swpaulstatic void vr_setcfg		__P((struct vr_softc *, int));
16441502Swpaulstatic u_int8_t vr_calchash	__P((u_int8_t *));
16541502Swpaulstatic void vr_setmulti		__P((struct vr_softc *));
16641502Swpaulstatic void vr_reset		__P((struct vr_softc *));
16741502Swpaulstatic int vr_list_rx_init	__P((struct vr_softc *));
16841502Swpaulstatic int vr_list_tx_init	__P((struct vr_softc *));
16941502Swpaul
17049610Swpaul#ifdef VR_USEIOSPACE
17149610Swpaul#define VR_RES			SYS_RES_IOPORT
17249610Swpaul#define VR_RID			VR_PCI_LOIO
17349610Swpaul#else
17449610Swpaul#define VR_RES			SYS_RES_MEMORY
17549610Swpaul#define VR_RID			VR_PCI_LOMEM
17649610Swpaul#endif
17749610Swpaul
17849610Swpaulstatic device_method_t vr_methods[] = {
17949610Swpaul	/* Device interface */
18049610Swpaul	DEVMETHOD(device_probe,		vr_probe),
18149610Swpaul	DEVMETHOD(device_attach,	vr_attach),
18249610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
18349610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
18451432Swpaul
18551432Swpaul	/* bus interface */
18651432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18751432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
18851432Swpaul
18951432Swpaul	/* MII interface */
19051432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
19151432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
19251432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
19351432Swpaul
19449610Swpaul	{ 0, 0 }
19549610Swpaul};
19649610Swpaul
19749610Swpaulstatic driver_t vr_driver = {
19851455Swpaul	"vr",
19949610Swpaul	vr_methods,
20049610Swpaul	sizeof(struct vr_softc)
20149610Swpaul};
20249610Swpaul
20349610Swpaulstatic devclass_t vr_devclass;
20449610Swpaul
20551533SwpaulDRIVER_MODULE(if_vr, pci, vr_driver, vr_devclass, 0, 0);
20651473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
20749610Swpaul
20841502Swpaul#define VR_SETBIT(sc, reg, x)				\
20941502Swpaul	CSR_WRITE_1(sc, reg,				\
21041502Swpaul		CSR_READ_1(sc, reg) | x)
21141502Swpaul
21241502Swpaul#define VR_CLRBIT(sc, reg, x)				\
21341502Swpaul	CSR_WRITE_1(sc, reg,				\
21441502Swpaul		CSR_READ_1(sc, reg) & ~x)
21541502Swpaul
21641502Swpaul#define VR_SETBIT16(sc, reg, x)				\
21741502Swpaul	CSR_WRITE_2(sc, reg,				\
21841502Swpaul		CSR_READ_2(sc, reg) | x)
21941502Swpaul
22041502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
22141502Swpaul	CSR_WRITE_2(sc, reg,				\
22241502Swpaul		CSR_READ_2(sc, reg) & ~x)
22341502Swpaul
22441502Swpaul#define VR_SETBIT32(sc, reg, x)				\
22541502Swpaul	CSR_WRITE_4(sc, reg,				\
22641502Swpaul		CSR_READ_4(sc, reg) | x)
22741502Swpaul
22841502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
22941502Swpaul	CSR_WRITE_4(sc, reg,				\
23041502Swpaul		CSR_READ_4(sc, reg) & ~x)
23141502Swpaul
23241502Swpaul#define SIO_SET(x)					\
23341502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
23441502Swpaul		CSR_READ_1(sc, VR_MIICMD) | x)
23541502Swpaul
23641502Swpaul#define SIO_CLR(x)					\
23741502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
23841502Swpaul		CSR_READ_1(sc, VR_MIICMD) & ~x)
23941502Swpaul
24041502Swpaul/*
24141502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
24241502Swpaul */
24341502Swpaulstatic void vr_mii_sync(sc)
24441502Swpaul	struct vr_softc		*sc;
24541502Swpaul{
24641502Swpaul	register int		i;
24741502Swpaul
24841502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
24941502Swpaul
25041502Swpaul	for (i = 0; i < 32; i++) {
25141502Swpaul		SIO_SET(VR_MIICMD_CLK);
25241502Swpaul		DELAY(1);
25341502Swpaul		SIO_CLR(VR_MIICMD_CLK);
25441502Swpaul		DELAY(1);
25541502Swpaul	}
25641502Swpaul
25741502Swpaul	return;
25841502Swpaul}
25941502Swpaul
26041502Swpaul/*
26141502Swpaul * Clock a series of bits through the MII.
26241502Swpaul */
26341502Swpaulstatic void vr_mii_send(sc, bits, cnt)
26441502Swpaul	struct vr_softc		*sc;
26541502Swpaul	u_int32_t		bits;
26641502Swpaul	int			cnt;
26741502Swpaul{
26841502Swpaul	int			i;
26941502Swpaul
27041502Swpaul	SIO_CLR(VR_MIICMD_CLK);
27141502Swpaul
27241502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
27341502Swpaul                if (bits & i) {
27441502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
27541502Swpaul                } else {
27641502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
27741502Swpaul                }
27841502Swpaul		DELAY(1);
27941502Swpaul		SIO_CLR(VR_MIICMD_CLK);
28041502Swpaul		DELAY(1);
28141502Swpaul		SIO_SET(VR_MIICMD_CLK);
28241502Swpaul	}
28341502Swpaul}
28441502Swpaul
28541502Swpaul/*
28641502Swpaul * Read an PHY register through the MII.
28741502Swpaul */
28841502Swpaulstatic int vr_mii_readreg(sc, frame)
28941502Swpaul	struct vr_softc		*sc;
29041502Swpaul	struct vr_mii_frame	*frame;
29141502Swpaul
29241502Swpaul{
29341502Swpaul	int			i, ack, s;
29441502Swpaul
29541502Swpaul	s = splimp();
29641502Swpaul
29741502Swpaul	/*
29841502Swpaul	 * Set up frame for RX.
29941502Swpaul	 */
30041502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
30141502Swpaul	frame->mii_opcode = VR_MII_READOP;
30241502Swpaul	frame->mii_turnaround = 0;
30341502Swpaul	frame->mii_data = 0;
30441502Swpaul
30541502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
30641502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
30741502Swpaul
30841502Swpaul	/*
30941502Swpaul 	 * Turn on data xmit.
31041502Swpaul	 */
31141502Swpaul	SIO_SET(VR_MIICMD_DIR);
31241502Swpaul
31341502Swpaul	vr_mii_sync(sc);
31441502Swpaul
31541502Swpaul	/*
31641502Swpaul	 * Send command/address info.
31741502Swpaul	 */
31841502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
31941502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
32041502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
32141502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
32241502Swpaul
32341502Swpaul	/* Idle bit */
32441502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
32541502Swpaul	DELAY(1);
32641502Swpaul	SIO_SET(VR_MIICMD_CLK);
32741502Swpaul	DELAY(1);
32841502Swpaul
32941502Swpaul	/* Turn off xmit. */
33041502Swpaul	SIO_CLR(VR_MIICMD_DIR);
33141502Swpaul
33241502Swpaul	/* Check for ack */
33341502Swpaul	SIO_CLR(VR_MIICMD_CLK);
33441502Swpaul	DELAY(1);
33541502Swpaul	SIO_SET(VR_MIICMD_CLK);
33641502Swpaul	DELAY(1);
33741502Swpaul	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
33841502Swpaul
33941502Swpaul	/*
34041502Swpaul	 * Now try reading data bits. If the ack failed, we still
34141502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
34241502Swpaul	 */
34341502Swpaul	if (ack) {
34441502Swpaul		for(i = 0; i < 16; i++) {
34541502Swpaul			SIO_CLR(VR_MIICMD_CLK);
34641502Swpaul			DELAY(1);
34741502Swpaul			SIO_SET(VR_MIICMD_CLK);
34841502Swpaul			DELAY(1);
34941502Swpaul		}
35041502Swpaul		goto fail;
35141502Swpaul	}
35241502Swpaul
35341502Swpaul	for (i = 0x8000; i; i >>= 1) {
35441502Swpaul		SIO_CLR(VR_MIICMD_CLK);
35541502Swpaul		DELAY(1);
35641502Swpaul		if (!ack) {
35741502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
35841502Swpaul				frame->mii_data |= i;
35941502Swpaul			DELAY(1);
36041502Swpaul		}
36141502Swpaul		SIO_SET(VR_MIICMD_CLK);
36241502Swpaul		DELAY(1);
36341502Swpaul	}
36441502Swpaul
36541502Swpaulfail:
36641502Swpaul
36741502Swpaul	SIO_CLR(VR_MIICMD_CLK);
36841502Swpaul	DELAY(1);
36941502Swpaul	SIO_SET(VR_MIICMD_CLK);
37041502Swpaul	DELAY(1);
37141502Swpaul
37241502Swpaul	splx(s);
37341502Swpaul
37441502Swpaul	if (ack)
37541502Swpaul		return(1);
37641502Swpaul	return(0);
37741502Swpaul}
37841502Swpaul
37941502Swpaul/*
38041502Swpaul * Write to a PHY register through the MII.
38141502Swpaul */
38241502Swpaulstatic int vr_mii_writereg(sc, frame)
38341502Swpaul	struct vr_softc		*sc;
38441502Swpaul	struct vr_mii_frame	*frame;
38541502Swpaul
38641502Swpaul{
38741502Swpaul	int			s;
38841502Swpaul
38941502Swpaul	s = splimp();
39041502Swpaul
39141502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
39241502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
39341502Swpaul
39441502Swpaul	/*
39541502Swpaul	 * Set up frame for TX.
39641502Swpaul	 */
39741502Swpaul
39841502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
39941502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
40041502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
40141502Swpaul
40241502Swpaul	/*
40341502Swpaul 	 * Turn on data output.
40441502Swpaul	 */
40541502Swpaul	SIO_SET(VR_MIICMD_DIR);
40641502Swpaul
40741502Swpaul	vr_mii_sync(sc);
40841502Swpaul
40941502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
41041502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
41141502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
41241502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
41341502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
41441502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
41541502Swpaul
41641502Swpaul	/* Idle bit. */
41741502Swpaul	SIO_SET(VR_MIICMD_CLK);
41841502Swpaul	DELAY(1);
41941502Swpaul	SIO_CLR(VR_MIICMD_CLK);
42041502Swpaul	DELAY(1);
42141502Swpaul
42241502Swpaul	/*
42341502Swpaul	 * Turn off xmit.
42441502Swpaul	 */
42541502Swpaul	SIO_CLR(VR_MIICMD_DIR);
42641502Swpaul
42741502Swpaul	splx(s);
42841502Swpaul
42941502Swpaul	return(0);
43041502Swpaul}
43141502Swpaul
43251432Swpaulstatic int vr_miibus_readreg(dev, phy, reg)
43351432Swpaul	device_t		dev;
43451432Swpaul	int			phy, reg;
43551432Swpaul{
43641502Swpaul	struct vr_softc		*sc;
43741502Swpaul	struct vr_mii_frame	frame;
43841502Swpaul
43951432Swpaul	sc = device_get_softc(dev);
44041502Swpaul	bzero((char *)&frame, sizeof(frame));
44141502Swpaul
44251432Swpaul	frame.mii_phyaddr = phy;
44341502Swpaul	frame.mii_regaddr = reg;
44441502Swpaul	vr_mii_readreg(sc, &frame);
44541502Swpaul
44641502Swpaul	return(frame.mii_data);
44741502Swpaul}
44841502Swpaul
44951432Swpaulstatic int vr_miibus_writereg(dev, phy, reg, data)
45051432Swpaul	device_t		dev;
45151432Swpaul	u_int16_t		phy, reg, data;
45251432Swpaul{
45341502Swpaul	struct vr_softc		*sc;
45441502Swpaul	struct vr_mii_frame	frame;
45541502Swpaul
45651432Swpaul	sc = device_get_softc(dev);
45741502Swpaul	bzero((char *)&frame, sizeof(frame));
45841502Swpaul
45951432Swpaul	frame.mii_phyaddr = phy;
46041502Swpaul	frame.mii_regaddr = reg;
46141502Swpaul	frame.mii_data = data;
46241502Swpaul
46341502Swpaul	vr_mii_writereg(sc, &frame);
46441502Swpaul
46551432Swpaul	return(0);
46651432Swpaul}
46751432Swpaul
46851432Swpaulstatic void vr_miibus_statchg(dev)
46951432Swpaul	device_t		dev;
47051432Swpaul{
47151432Swpaul	struct vr_softc		*sc;
47251432Swpaul	struct mii_data		*mii;
47351432Swpaul
47451432Swpaul	sc = device_get_softc(dev);
47551432Swpaul	mii = device_get_softc(sc->vr_miibus);
47651432Swpaul	vr_setcfg(sc, mii->mii_media_active);
47751432Swpaul
47841502Swpaul	return;
47941502Swpaul}
48041502Swpaul
48141502Swpaul/*
48241502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits.
48341502Swpaul */
48441502Swpaulstatic u_int8_t vr_calchash(addr)
48541502Swpaul	u_int8_t		*addr;
48641502Swpaul{
48741502Swpaul	u_int32_t		crc, carry;
48841502Swpaul	int			i, j;
48941502Swpaul	u_int8_t		c;
49041502Swpaul
49141502Swpaul	/* Compute CRC for the address value. */
49241502Swpaul	crc = 0xFFFFFFFF; /* initial value */
49341502Swpaul
49441502Swpaul	for (i = 0; i < 6; i++) {
49541502Swpaul		c = *(addr + i);
49641502Swpaul		for (j = 0; j < 8; j++) {
49741502Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
49841502Swpaul			crc <<= 1;
49941502Swpaul			c >>= 1;
50041502Swpaul			if (carry)
50141502Swpaul				crc = (crc ^ 0x04c11db6) | carry;
50241502Swpaul		}
50341502Swpaul	}
50441502Swpaul
50541502Swpaul	/* return the filter bit position */
50641502Swpaul	return((crc >> 26) & 0x0000003F);
50741502Swpaul}
50841502Swpaul
50941502Swpaul/*
51041502Swpaul * Program the 64-bit multicast hash filter.
51141502Swpaul */
51241502Swpaulstatic void vr_setmulti(sc)
51341502Swpaul	struct vr_softc		*sc;
51441502Swpaul{
51541502Swpaul	struct ifnet		*ifp;
51641502Swpaul	int			h = 0;
51741502Swpaul	u_int32_t		hashes[2] = { 0, 0 };
51841502Swpaul	struct ifmultiaddr	*ifma;
51941502Swpaul	u_int8_t		rxfilt;
52041502Swpaul	int			mcnt = 0;
52141502Swpaul
52241502Swpaul	ifp = &sc->arpcom.ac_if;
52341502Swpaul
52441502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
52541502Swpaul
52641502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
52741502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
52841502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
52941502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
53041502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
53141502Swpaul		return;
53241502Swpaul	}
53341502Swpaul
53441502Swpaul	/* first, zot all the existing hash bits */
53541502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
53641502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
53741502Swpaul
53841502Swpaul	/* now program new ones */
53941502Swpaul	for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
54041502Swpaul				ifma = ifma->ifma_link.le_next) {
54141502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
54241502Swpaul			continue;
54341502Swpaul		h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
54441502Swpaul		if (h < 32)
54541502Swpaul			hashes[0] |= (1 << h);
54641502Swpaul		else
54741502Swpaul			hashes[1] |= (1 << (h - 32));
54841502Swpaul		mcnt++;
54941502Swpaul	}
55041502Swpaul
55141502Swpaul	if (mcnt)
55241502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
55341502Swpaul	else
55441502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
55541502Swpaul
55641502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
55741502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
55841502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
55941502Swpaul
56041502Swpaul	return;
56141502Swpaul}
56241502Swpaul
56341502Swpaul/*
56441502Swpaul * In order to fiddle with the
56541502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
56641502Swpaul * first have to put the transmit and/or receive logic in the idle state.
56741502Swpaul */
56851432Swpaulstatic void vr_setcfg(sc, media)
56941502Swpaul	struct vr_softc		*sc;
57051432Swpaul	int			media;
57141502Swpaul{
57241502Swpaul	int			restart = 0;
57341502Swpaul
57441502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
57541502Swpaul		restart = 1;
57641502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
57741502Swpaul	}
57841502Swpaul
57951432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
58041502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58141502Swpaul	else
58241502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58341502Swpaul
58441502Swpaul	if (restart)
58541502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
58641502Swpaul
58741502Swpaul	return;
58841502Swpaul}
58941502Swpaul
59041502Swpaulstatic void vr_reset(sc)
59141502Swpaul	struct vr_softc		*sc;
59241502Swpaul{
59341502Swpaul	register int		i;
59441502Swpaul
59541502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
59641502Swpaul
59741502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
59841502Swpaul		DELAY(10);
59941502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
60041502Swpaul			break;
60141502Swpaul	}
60241502Swpaul	if (i == VR_TIMEOUT)
60341502Swpaul		printf("vr%d: reset never completed!\n", sc->vr_unit);
60441502Swpaul
60541502Swpaul	/* Wait a little while for the chip to get its brains in order. */
60641502Swpaul	DELAY(1000);
60741502Swpaul
60841502Swpaul        return;
60941502Swpaul}
61041502Swpaul
61141502Swpaul/*
61241502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
61341502Swpaul * IDs against our list and return a device name if we find a match.
61441502Swpaul */
61549610Swpaulstatic int vr_probe(dev)
61649610Swpaul	device_t		dev;
61741502Swpaul{
61841502Swpaul	struct vr_type		*t;
61941502Swpaul
62041502Swpaul	t = vr_devs;
62141502Swpaul
62241502Swpaul	while(t->vr_name != NULL) {
62349610Swpaul		if ((pci_get_vendor(dev) == t->vr_vid) &&
62449610Swpaul		    (pci_get_device(dev) == t->vr_did)) {
62549610Swpaul			device_set_desc(dev, t->vr_name);
62649610Swpaul			return(0);
62741502Swpaul		}
62841502Swpaul		t++;
62941502Swpaul	}
63041502Swpaul
63149610Swpaul	return(ENXIO);
63241502Swpaul}
63341502Swpaul
63441502Swpaul/*
63541502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
63641502Swpaul * setup and ethernet/BPF attach.
63741502Swpaul */
63849610Swpaulstatic int vr_attach(dev)
63949610Swpaul	device_t		dev;
64041502Swpaul{
64151432Swpaul	int			i, s;
64241502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
64341502Swpaul	u_int32_t		command;
64441502Swpaul	struct vr_softc		*sc;
64541502Swpaul	struct ifnet		*ifp;
64649610Swpaul	int			unit, error = 0, rid;
64741502Swpaul
64841502Swpaul	s = splimp();
64941502Swpaul
65049610Swpaul	sc = device_get_softc(dev);
65149610Swpaul	unit = device_get_unit(dev);
65249610Swpaul	bzero(sc, sizeof(struct vr_softc *));
65341502Swpaul
65441502Swpaul	/*
65541502Swpaul	 * Handle power management nonsense.
65641502Swpaul	 */
65741502Swpaul
65849610Swpaul	command = pci_read_config(dev, VR_PCI_CAPID, 4) & 0x000000FF;
65941502Swpaul	if (command == 0x01) {
66041502Swpaul
66149610Swpaul		command = pci_read_config(dev, VR_PCI_PWRMGMTCTRL, 4);
66241502Swpaul		if (command & VR_PSTATE_MASK) {
66341502Swpaul			u_int32_t		iobase, membase, irq;
66441502Swpaul
66541502Swpaul			/* Save important PCI config data. */
66649610Swpaul			iobase = pci_read_config(dev, VR_PCI_LOIO, 4);
66749610Swpaul			membase = pci_read_config(dev, VR_PCI_LOMEM, 4);
66849610Swpaul			irq = pci_read_config(dev, VR_PCI_INTLINE, 4);
66941502Swpaul
67041502Swpaul			/* Reset the power state. */
67141502Swpaul			printf("vr%d: chip is in D%d power mode "
67241502Swpaul			"-- setting to D0\n", unit, command & VR_PSTATE_MASK);
67341502Swpaul			command &= 0xFFFFFFFC;
67449610Swpaul			pci_write_config(dev, VR_PCI_PWRMGMTCTRL, command, 4);
67541502Swpaul
67641502Swpaul			/* Restore PCI config data. */
67749610Swpaul			pci_write_config(dev, VR_PCI_LOIO, iobase, 4);
67849610Swpaul			pci_write_config(dev, VR_PCI_LOMEM, membase, 4);
67949610Swpaul			pci_write_config(dev, VR_PCI_INTLINE, irq, 4);
68041502Swpaul		}
68141502Swpaul	}
68241502Swpaul
68341502Swpaul	/*
68441502Swpaul	 * Map control/status registers.
68541502Swpaul	 */
68649610Swpaul	command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
68741502Swpaul	command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
68849610Swpaul	pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
68949610Swpaul	command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
69041502Swpaul
69141502Swpaul#ifdef VR_USEIOSPACE
69241502Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
69341502Swpaul		printf("vr%d: failed to enable I/O ports!\n", unit);
69441502Swpaul		free(sc, M_DEVBUF);
69541502Swpaul		goto fail;
69641502Swpaul	}
69741502Swpaul#else
69841502Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
69941502Swpaul		printf("vr%d: failed to enable memory mapping!\n", unit);
70041502Swpaul		goto fail;
70141502Swpaul	}
70249610Swpaul#endif
70341502Swpaul
70449610Swpaul	rid = VR_RID;
70549610Swpaul	sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid,
70649610Swpaul	    0, ~0, 1, RF_ACTIVE);
70749610Swpaul
70849610Swpaul	if (sc->vr_res == NULL) {
70949610Swpaul		printf("vr%d: couldn't map ports/memory\n", unit);
71049610Swpaul		error = ENXIO;
71141502Swpaul		goto fail;
71241502Swpaul	}
71341502Swpaul
71449610Swpaul	sc->vr_btag = rman_get_bustag(sc->vr_res);
71549610Swpaul	sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
71641502Swpaul
71741502Swpaul	/* Allocate interrupt */
71849610Swpaul	rid = 0;
71949610Swpaul	sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
72049610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
72149610Swpaul
72249610Swpaul	if (sc->vr_irq == NULL) {
72341502Swpaul		printf("vr%d: couldn't map interrupt\n", unit);
72449610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
72549610Swpaul		error = ENXIO;
72641502Swpaul		goto fail;
72741502Swpaul	}
72841502Swpaul
72949610Swpaul	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET,
73049610Swpaul	    vr_intr, sc, &sc->vr_intrhand);
73149610Swpaul
73249610Swpaul	if (error) {
73349610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
73449610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
73549610Swpaul		printf("vr%d: couldn't set up irq\n", unit);
73649610Swpaul		goto fail;
73749610Swpaul	}
73849610Swpaul
73941502Swpaul	/* Reset the adapter. */
74041502Swpaul	vr_reset(sc);
74141502Swpaul
74241502Swpaul	/*
74341502Swpaul	 * Get station address. The way the Rhine chips work,
74441502Swpaul	 * you're not allowed to directly access the EEPROM once
74541502Swpaul	 * they've been programmed a special way. Consequently,
74641502Swpaul	 * we need to read the node address from the PAR0 and PAR1
74741502Swpaul	 * registers.
74841502Swpaul	 */
74941502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
75041502Swpaul	DELAY(200);
75141502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
75241502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
75341502Swpaul
75441502Swpaul	/*
75541502Swpaul	 * A Rhine chip was detected. Inform the world.
75641502Swpaul	 */
75741502Swpaul	printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":");
75841502Swpaul
75941502Swpaul	sc->vr_unit = unit;
76041502Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
76141502Swpaul
76251432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
76351432Swpaul	    M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0);
76451432Swpaul
76551432Swpaul	if (sc->vr_ldata == NULL) {
76641502Swpaul		printf("vr%d: no memory for list buffers!\n", unit);
76749610Swpaul		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
76849610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
76949610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
77049610Swpaul		error = ENXIO;
77149610Swpaul		goto fail;
77241502Swpaul	}
77341502Swpaul
77441502Swpaul	bzero(sc->vr_ldata, sizeof(struct vr_list_data));
77541502Swpaul
77641502Swpaul	ifp = &sc->arpcom.ac_if;
77741502Swpaul	ifp->if_softc = sc;
77841502Swpaul	ifp->if_unit = unit;
77941502Swpaul	ifp->if_name = "vr";
78041502Swpaul	ifp->if_mtu = ETHERMTU;
78141502Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
78241502Swpaul	ifp->if_ioctl = vr_ioctl;
78341502Swpaul	ifp->if_output = ether_output;
78441502Swpaul	ifp->if_start = vr_start;
78541502Swpaul	ifp->if_watchdog = vr_watchdog;
78641502Swpaul	ifp->if_init = vr_init;
78741502Swpaul	ifp->if_baudrate = 10000000;
78843515Swpaul	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
78941502Swpaul
79051432Swpaul	/*
79151432Swpaul	 * Do MII setup.
79251432Swpaul	 */
79351432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
79451432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
79541502Swpaul		printf("vr%d: MII without any phy!\n", sc->vr_unit);
79649610Swpaul		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
79749610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
79849610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
79951432Swpaul		contigfree(sc->vr_ldata,
80051432Swpaul		    sizeof(struct vr_list_data), M_DEVBUF);
80149610Swpaul		error = ENXIO;
80241502Swpaul		goto fail;
80341502Swpaul	}
80441502Swpaul
80551432Swpaul	callout_handle_init(&sc->vr_stat_ch);
80641502Swpaul
80741502Swpaul	/*
80841502Swpaul	 * Call MI attach routines.
80941502Swpaul	 */
81041502Swpaul	if_attach(ifp);
81141502Swpaul	ether_ifattach(ifp);
81241502Swpaul
81348645Sdes#if NBPF > 0
81441502Swpaul	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
81541502Swpaul#endif
81641502Swpaul
81741502Swpaulfail:
81841502Swpaul	splx(s);
81949610Swpaul	return(error);
82041502Swpaul}
82141502Swpaul
82249610Swpaulstatic int vr_detach(dev)
82349610Swpaul	device_t		dev;
82449610Swpaul{
82549610Swpaul	struct vr_softc		*sc;
82649610Swpaul	struct ifnet		*ifp;
82749610Swpaul	int			s;
82849610Swpaul
82949610Swpaul	s = splimp();
83049610Swpaul
83149610Swpaul	sc = device_get_softc(dev);
83249610Swpaul	ifp = &sc->arpcom.ac_if;
83349610Swpaul
83449610Swpaul	vr_stop(sc);
83549610Swpaul	if_detach(ifp);
83649610Swpaul
83751432Swpaul	bus_generic_detach(dev);
83851432Swpaul	device_delete_child(dev, sc->vr_miibus);
83951432Swpaul
84049610Swpaul	bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
84149610Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
84249610Swpaul	bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
84349610Swpaul
84451432Swpaul	contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
84549610Swpaul
84649610Swpaul	splx(s);
84749610Swpaul
84849610Swpaul	return(0);
84949610Swpaul}
85049610Swpaul
85141502Swpaul/*
85241502Swpaul * Initialize the transmit descriptors.
85341502Swpaul */
85441502Swpaulstatic int vr_list_tx_init(sc)
85541502Swpaul	struct vr_softc		*sc;
85641502Swpaul{
85741502Swpaul	struct vr_chain_data	*cd;
85841502Swpaul	struct vr_list_data	*ld;
85941502Swpaul	int			i;
86041502Swpaul
86141502Swpaul	cd = &sc->vr_cdata;
86241502Swpaul	ld = sc->vr_ldata;
86341502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
86441502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
86541502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
86641502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
86741502Swpaul				&cd->vr_tx_chain[0];
86841502Swpaul		else
86941502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
87041502Swpaul				&cd->vr_tx_chain[i + 1];
87141502Swpaul	}
87241502Swpaul
87341502Swpaul	cd->vr_tx_free = &cd->vr_tx_chain[0];
87441502Swpaul	cd->vr_tx_tail = cd->vr_tx_head = NULL;
87541502Swpaul
87641502Swpaul	return(0);
87741502Swpaul}
87841502Swpaul
87941502Swpaul
88041502Swpaul/*
88141502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
88241502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
88341502Swpaul * points back to the first.
88441502Swpaul */
88541502Swpaulstatic int vr_list_rx_init(sc)
88641502Swpaul	struct vr_softc		*sc;
88741502Swpaul{
88841502Swpaul	struct vr_chain_data	*cd;
88941502Swpaul	struct vr_list_data	*ld;
89041502Swpaul	int			i;
89141502Swpaul
89241502Swpaul	cd = &sc->vr_cdata;
89341502Swpaul	ld = sc->vr_ldata;
89441502Swpaul
89541502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
89641502Swpaul		cd->vr_rx_chain[i].vr_ptr =
89741502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
89849610Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
89941502Swpaul			return(ENOBUFS);
90041502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
90141502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
90241502Swpaul					&cd->vr_rx_chain[0];
90341502Swpaul			ld->vr_rx_list[i].vr_next =
90441502Swpaul					vtophys(&ld->vr_rx_list[0]);
90541502Swpaul		} else {
90641502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
90741502Swpaul					&cd->vr_rx_chain[i + 1];
90841502Swpaul			ld->vr_rx_list[i].vr_next =
90941502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
91041502Swpaul		}
91141502Swpaul	}
91241502Swpaul
91341502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
91441502Swpaul
91541502Swpaul	return(0);
91641502Swpaul}
91741502Swpaul
91841502Swpaul/*
91941502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
92041502Swpaul * Note: the length fields are only 11 bits wide, which means the
92141502Swpaul * largest size we can specify is 2047. This is important because
92241502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
92341502Swpaul * overflow the field and make a mess.
92441502Swpaul */
92549610Swpaulstatic int vr_newbuf(sc, c, m)
92641502Swpaul	struct vr_softc		*sc;
92741502Swpaul	struct vr_chain_onefrag	*c;
92849610Swpaul	struct mbuf		*m;
92941502Swpaul{
93041502Swpaul	struct mbuf		*m_new = NULL;
93141502Swpaul
93249610Swpaul	if (m == NULL) {
93349610Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
93449610Swpaul		if (m_new == NULL) {
93549610Swpaul			printf("vr%d: no memory for rx list "
93649610Swpaul			    "-- packet dropped!\n", sc->vr_unit);
93749610Swpaul			return(ENOBUFS);
93849610Swpaul		}
93941502Swpaul
94049610Swpaul		MCLGET(m_new, M_DONTWAIT);
94149610Swpaul		if (!(m_new->m_flags & M_EXT)) {
94249610Swpaul			printf("vr%d: no memory for rx list "
94349610Swpaul			    "-- packet dropped!\n", sc->vr_unit);
94449610Swpaul			m_freem(m_new);
94549610Swpaul			return(ENOBUFS);
94649610Swpaul		}
94749610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
94849610Swpaul	} else {
94949610Swpaul		m_new = m;
95049610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
95149610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
95241502Swpaul	}
95341502Swpaul
95449610Swpaul	m_adj(m_new, sizeof(u_int64_t));
95549610Swpaul
95641502Swpaul	c->vr_mbuf = m_new;
95741502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
95841502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
95942491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
96041502Swpaul
96141502Swpaul	return(0);
96241502Swpaul}
96341502Swpaul
96441502Swpaul/*
96541502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
96641502Swpaul * the higher level protocols.
96741502Swpaul */
96841502Swpaulstatic void vr_rxeof(sc)
96941502Swpaul	struct vr_softc		*sc;
97041502Swpaul{
97141502Swpaul        struct ether_header	*eh;
97241502Swpaul        struct mbuf		*m;
97341502Swpaul        struct ifnet		*ifp;
97441502Swpaul	struct vr_chain_onefrag	*cur_rx;
97541502Swpaul	int			total_len = 0;
97641502Swpaul	u_int32_t		rxstat;
97741502Swpaul
97841502Swpaul	ifp = &sc->arpcom.ac_if;
97941502Swpaul
98041502Swpaul	while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
98141502Swpaul							VR_RXSTAT_OWN)) {
98249610Swpaul		struct mbuf		*m0 = NULL;
98349610Swpaul
98441502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
98541502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
98649610Swpaul		m = cur_rx->vr_mbuf;
98741502Swpaul
98841502Swpaul		/*
98941502Swpaul		 * If an error occurs, update stats, clear the
99041502Swpaul		 * status word and leave the mbuf cluster in place:
99141502Swpaul		 * it should simply get re-used next time this descriptor
99241502Swpaul	 	 * comes up in the ring.
99341502Swpaul		 */
99441502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
99541502Swpaul			ifp->if_ierrors++;
99641502Swpaul			printf("vr%d: rx error: ", sc->vr_unit);
99741502Swpaul			switch(rxstat & 0x000000FF) {
99841502Swpaul			case VR_RXSTAT_CRCERR:
99941502Swpaul				printf("crc error\n");
100041502Swpaul				break;
100141502Swpaul			case VR_RXSTAT_FRAMEALIGNERR:
100241502Swpaul				printf("frame alignment error\n");
100341502Swpaul				break;
100441502Swpaul			case VR_RXSTAT_FIFOOFLOW:
100541502Swpaul				printf("FIFO overflow\n");
100641502Swpaul				break;
100741502Swpaul			case VR_RXSTAT_GIANT:
100841502Swpaul				printf("received giant packet\n");
100941502Swpaul				break;
101041502Swpaul			case VR_RXSTAT_RUNT:
101141502Swpaul				printf("received runt packet\n");
101241502Swpaul				break;
101341502Swpaul			case VR_RXSTAT_BUSERR:
101441502Swpaul				printf("system bus error\n");
101541502Swpaul				break;
101641502Swpaul			case VR_RXSTAT_BUFFERR:
101741502Swpaul				printf("rx buffer error\n");
101841502Swpaul				break;
101941502Swpaul			default:
102041502Swpaul				printf("unknown rx error\n");
102141502Swpaul				break;
102241502Swpaul			}
102349610Swpaul			vr_newbuf(sc, cur_rx, m);
102441502Swpaul			continue;
102541502Swpaul		}
102641502Swpaul
102741502Swpaul		/* No errors; receive the packet. */
102841502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
102941502Swpaul
103041502Swpaul		/*
103142048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
103242048Swpaul		 * received frame, and there's no way to turn this
103342048Swpaul		 * behavior off (at least, I can't find anything in
103442048Swpaul	 	 * the manual that explains how to do it) so we have
103542048Swpaul		 * to trim off the CRC manually.
103642048Swpaul		 */
103742048Swpaul		total_len -= ETHER_CRC_LEN;
103842048Swpaul
103949610Swpaul		m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
104049610Swpaul		    total_len + ETHER_ALIGN, 0, ifp, NULL);
104149610Swpaul		vr_newbuf(sc, cur_rx, m);
104249610Swpaul		if (m0 == NULL) {
104341502Swpaul			ifp->if_ierrors++;
104441502Swpaul			continue;
104541502Swpaul		}
104649610Swpaul		m_adj(m0, ETHER_ALIGN);
104749610Swpaul		m = m0;
104841502Swpaul
104941502Swpaul		ifp->if_ipackets++;
105041502Swpaul		eh = mtod(m, struct ether_header *);
105149610Swpaul
105248645Sdes#if NBPF > 0
105341502Swpaul		/*
105441502Swpaul		 * Handle BPF listeners. Let the BPF user see the packet, but
105541502Swpaul		 * don't pass it up to the ether_input() layer unless it's
105641502Swpaul		 * a broadcast packet, multicast packet, matches our ethernet
105741502Swpaul		 * address or the interface is in promiscuous mode.
105841502Swpaul		 */
105941502Swpaul		if (ifp->if_bpf) {
106041502Swpaul			bpf_mtap(ifp, m);
106141502Swpaul			if (ifp->if_flags & IFF_PROMISC &&
106241502Swpaul				(bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
106341502Swpaul						ETHER_ADDR_LEN) &&
106441502Swpaul					(eh->ether_dhost[0] & 1) == 0)) {
106541502Swpaul				m_freem(m);
106641502Swpaul				continue;
106741502Swpaul			}
106841502Swpaul		}
106951354Swpaul#endif /* NBPF>0 */
107051354Swpaul#ifdef BRIDGE
107151354Swpaul		if (do_bridge) {
107251354Swpaul			struct ifnet		*bdg_ifp;
107351354Swpaul			bdg_ifp = bridge_in(m);
107451354Swpaul			if (bdg_ifp != BDG_LOCAL && bdg_ifp != BDG_DROP)
107551354Swpaul				bdg_forward(&m, bdg_ifp);
107651354Swpaul			if (((bdg_ifp != BDG_LOCAL) && (bdg_ifp != BDG_BCAST) &&
107751354Swpaul			    (bdg_ifp != BDG_MCAST)) || bdg_ifp == BDG_DROP) {
107851354Swpaul				m_freem(m);
107951354Swpaul				continue;
108051354Swpaul			}
108151354Swpaul		}
108251354Swpaul#endif /* BRIDGE */
108351354Swpaul
108441502Swpaul		/* Remove header from mbuf and pass it on. */
108541502Swpaul		m_adj(m, sizeof(struct ether_header));
108641502Swpaul		ether_input(ifp, eh, m);
108741502Swpaul	}
108841502Swpaul
108941502Swpaul	return;
109041502Swpaul}
109141502Swpaul
109241502Swpaulvoid vr_rxeoc(sc)
109341502Swpaul	struct vr_softc		*sc;
109441502Swpaul{
109541502Swpaul
109641502Swpaul	vr_rxeof(sc);
109741502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
109841502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
109941502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
110041502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
110141502Swpaul
110241502Swpaul	return;
110341502Swpaul}
110441502Swpaul
110541502Swpaul/*
110641502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
110741502Swpaul * the list buffers.
110841502Swpaul */
110941502Swpaul
111041502Swpaulstatic void vr_txeof(sc)
111141502Swpaul	struct vr_softc		*sc;
111241502Swpaul{
111341502Swpaul	struct vr_chain		*cur_tx;
111441502Swpaul	struct ifnet		*ifp;
111541502Swpaul
111641502Swpaul	ifp = &sc->arpcom.ac_if;
111741502Swpaul
111841502Swpaul	/* Clear the timeout timer. */
111941502Swpaul	ifp->if_timer = 0;
112041502Swpaul
112141502Swpaul	/* Sanity check. */
112241502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
112341502Swpaul		return;
112441502Swpaul
112541502Swpaul	/*
112641502Swpaul	 * Go through our tx list and free mbufs for those
112741502Swpaul	 * frames that have been transmitted.
112841502Swpaul	 */
112941502Swpaul	while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) {
113041502Swpaul		u_int32_t		txstat;
113141502Swpaul
113241502Swpaul		cur_tx = sc->vr_cdata.vr_tx_head;
113341502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
113441502Swpaul
113542491Swpaul		if (txstat & VR_TXSTAT_OWN)
113641502Swpaul			break;
113741502Swpaul
113841502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
113941502Swpaul			ifp->if_oerrors++;
114041502Swpaul			if (txstat & VR_TXSTAT_DEFER)
114141502Swpaul				ifp->if_collisions++;
114241502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
114341502Swpaul				ifp->if_collisions++;
114441502Swpaul		}
114541502Swpaul
114641502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
114741502Swpaul
114841502Swpaul		ifp->if_opackets++;
114951432Swpaul		if (cur_tx->vr_mbuf != NULL) {
115051432Swpaul			m_freem(cur_tx->vr_mbuf);
115151432Swpaul			cur_tx->vr_mbuf = NULL;
115251432Swpaul		}
115341502Swpaul
115441502Swpaul		if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {
115541502Swpaul			sc->vr_cdata.vr_tx_head = NULL;
115641502Swpaul			sc->vr_cdata.vr_tx_tail = NULL;
115741502Swpaul			break;
115841502Swpaul		}
115941502Swpaul
116041502Swpaul		sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc;
116141502Swpaul	}
116241502Swpaul
116341502Swpaul	return;
116441502Swpaul}
116541502Swpaul
116641502Swpaul/*
116741502Swpaul * TX 'end of channel' interrupt handler.
116841502Swpaul */
116941502Swpaulstatic void vr_txeoc(sc)
117041502Swpaul	struct vr_softc		*sc;
117141502Swpaul{
117241502Swpaul	struct ifnet		*ifp;
117341502Swpaul
117441502Swpaul	ifp = &sc->arpcom.ac_if;
117541502Swpaul
117641502Swpaul	ifp->if_timer = 0;
117741502Swpaul
117841502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL) {
117941502Swpaul		ifp->if_flags &= ~IFF_OACTIVE;
118041502Swpaul		sc->vr_cdata.vr_tx_tail = NULL;
118141502Swpaul	}
118241502Swpaul
118341502Swpaul	return;
118441502Swpaul}
118541502Swpaul
118651432Swpaulstatic void vr_tick(xsc)
118751432Swpaul	void			*xsc;
118851432Swpaul{
118951432Swpaul	struct vr_softc		*sc;
119051432Swpaul	struct mii_data		*mii;
119151432Swpaul	int			s;
119251432Swpaul
119351432Swpaul	s = splimp();
119451432Swpaul
119551432Swpaul	sc = xsc;
119651432Swpaul	mii = device_get_softc(sc->vr_miibus);
119751432Swpaul	mii_tick(mii);
119851432Swpaul
119951432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
120051432Swpaul
120151432Swpaul	splx(s);
120251432Swpaul
120351432Swpaul	return;
120451432Swpaul}
120551432Swpaul
120641502Swpaulstatic void vr_intr(arg)
120741502Swpaul	void			*arg;
120841502Swpaul{
120941502Swpaul	struct vr_softc		*sc;
121041502Swpaul	struct ifnet		*ifp;
121141502Swpaul	u_int16_t		status;
121241502Swpaul
121341502Swpaul	sc = arg;
121441502Swpaul	ifp = &sc->arpcom.ac_if;
121541502Swpaul
121641502Swpaul	/* Supress unwanted interrupts. */
121741502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
121841502Swpaul		vr_stop(sc);
121941502Swpaul		return;
122041502Swpaul	}
122141502Swpaul
122241502Swpaul	/* Disable interrupts. */
122341502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
122441502Swpaul
122541502Swpaul	for (;;) {
122641502Swpaul
122741502Swpaul		status = CSR_READ_2(sc, VR_ISR);
122841502Swpaul		if (status)
122941502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
123041502Swpaul
123141502Swpaul		if ((status & VR_INTRS) == 0)
123241502Swpaul			break;
123341502Swpaul
123441502Swpaul		if (status & VR_ISR_RX_OK)
123541502Swpaul			vr_rxeof(sc);
123641502Swpaul
123741502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
123841502Swpaul		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) ||
123941502Swpaul		    (status & VR_ISR_RX_DROPPED)) {
124041502Swpaul			vr_rxeof(sc);
124141502Swpaul			vr_rxeoc(sc);
124241502Swpaul		}
124341502Swpaul
124441502Swpaul		if (status & VR_ISR_TX_OK) {
124541502Swpaul			vr_txeof(sc);
124641502Swpaul			vr_txeoc(sc);
124741502Swpaul		}
124841502Swpaul
124941502Swpaul		if ((status & VR_ISR_TX_UNDERRUN)||(status & VR_ISR_TX_ABRT)){
125041502Swpaul			ifp->if_oerrors++;
125141502Swpaul			vr_txeof(sc);
125241502Swpaul			if (sc->vr_cdata.vr_tx_head != NULL) {
125341502Swpaul				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
125441502Swpaul				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
125541502Swpaul			}
125641502Swpaul		}
125741502Swpaul
125841502Swpaul		if (status & VR_ISR_BUSERR) {
125941502Swpaul			vr_reset(sc);
126041502Swpaul			vr_init(sc);
126141502Swpaul		}
126241502Swpaul	}
126341502Swpaul
126441502Swpaul	/* Re-enable interrupts. */
126541502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
126641502Swpaul
126741502Swpaul	if (ifp->if_snd.ifq_head != NULL) {
126841502Swpaul		vr_start(ifp);
126941502Swpaul	}
127041502Swpaul
127141502Swpaul	return;
127241502Swpaul}
127341502Swpaul
127441502Swpaul/*
127541502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
127641502Swpaul * pointers to the fragment pointers.
127741502Swpaul */
127841502Swpaulstatic int vr_encap(sc, c, m_head)
127941502Swpaul	struct vr_softc		*sc;
128041502Swpaul	struct vr_chain		*c;
128141502Swpaul	struct mbuf		*m_head;
128241502Swpaul{
128341502Swpaul	int			frag = 0;
128441502Swpaul	struct vr_desc		*f = NULL;
128541502Swpaul	int			total_len;
128641502Swpaul	struct mbuf		*m;
128741502Swpaul
128841502Swpaul	m = m_head;
128941502Swpaul	total_len = 0;
129041502Swpaul
129141502Swpaul	/*
129241502Swpaul	 * The VIA Rhine wants packet buffers to be longword
129341502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
129441502Swpaul	 * waste time trying to decide when to copy and when not
129541502Swpaul	 * to copy, just do it all the time.
129641502Swpaul	 */
129741502Swpaul	if (m != NULL) {
129841502Swpaul		struct mbuf		*m_new = NULL;
129941502Swpaul
130041502Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
130141502Swpaul		if (m_new == NULL) {
130241502Swpaul			printf("vr%d: no memory for tx list", sc->vr_unit);
130341502Swpaul			return(1);
130441502Swpaul		}
130541502Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
130641502Swpaul			MCLGET(m_new, M_DONTWAIT);
130741502Swpaul			if (!(m_new->m_flags & M_EXT)) {
130841502Swpaul				m_freem(m_new);
130941502Swpaul				printf("vr%d: no memory for tx list",
131041502Swpaul						sc->vr_unit);
131141502Swpaul				return(1);
131241502Swpaul			}
131341502Swpaul		}
131441502Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
131541502Swpaul					mtod(m_new, caddr_t));
131641502Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
131741502Swpaul		m_freem(m_head);
131841502Swpaul		m_head = m_new;
131941502Swpaul		/*
132041502Swpaul		 * The Rhine chip doesn't auto-pad, so we have to make
132141502Swpaul		 * sure to pad short frames out to the minimum frame length
132241502Swpaul		 * ourselves.
132341502Swpaul		 */
132441502Swpaul		if (m_head->m_len < VR_MIN_FRAMELEN) {
132541502Swpaul			m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
132641502Swpaul			m_new->m_len = m_new->m_pkthdr.len;
132741502Swpaul		}
132841502Swpaul		f = c->vr_ptr;
132941502Swpaul		f->vr_data = vtophys(mtod(m_new, caddr_t));
133041502Swpaul		f->vr_ctl = total_len = m_new->m_len;
133141502Swpaul		f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
133241502Swpaul		f->vr_status = 0;
133341502Swpaul		frag = 1;
133441502Swpaul	}
133541502Swpaul
133641502Swpaul	c->vr_mbuf = m_head;
133742491Swpaul	c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
133841502Swpaul	c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
133941502Swpaul
134041502Swpaul	return(0);
134141502Swpaul}
134241502Swpaul
134341502Swpaul/*
134441502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
134541502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
134641502Swpaul * copy of the pointers since the transmit list fragment pointers are
134741502Swpaul * physical addresses.
134841502Swpaul */
134941502Swpaul
135041502Swpaulstatic void vr_start(ifp)
135141502Swpaul	struct ifnet		*ifp;
135241502Swpaul{
135341502Swpaul	struct vr_softc		*sc;
135441502Swpaul	struct mbuf		*m_head = NULL;
135541502Swpaul	struct vr_chain		*cur_tx = NULL, *start_tx;
135641502Swpaul
135741502Swpaul	sc = ifp->if_softc;
135841502Swpaul
135951432Swpaul	if (ifp->if_flags & IFF_OACTIVE)
136041502Swpaul		return;
136141502Swpaul
136241502Swpaul	/*
136341502Swpaul	 * Check for an available queue slot. If there are none,
136441502Swpaul	 * punt.
136541502Swpaul	 */
136641502Swpaul	if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) {
136741502Swpaul		ifp->if_flags |= IFF_OACTIVE;
136841502Swpaul		return;
136941502Swpaul	}
137041502Swpaul
137141502Swpaul	start_tx = sc->vr_cdata.vr_tx_free;
137241502Swpaul
137341502Swpaul	while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) {
137441502Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
137541502Swpaul		if (m_head == NULL)
137641502Swpaul			break;
137741502Swpaul
137841502Swpaul		/* Pick a descriptor off the free list. */
137941502Swpaul		cur_tx = sc->vr_cdata.vr_tx_free;
138041502Swpaul		sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc;
138141502Swpaul
138241502Swpaul		/* Pack the data into the descriptor. */
138341502Swpaul		vr_encap(sc, cur_tx, m_head);
138441502Swpaul
138541502Swpaul		if (cur_tx != start_tx)
138641502Swpaul			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
138741502Swpaul
138848645Sdes#if NBPF > 0
138941502Swpaul		/*
139041502Swpaul		 * If there's a BPF listener, bounce a copy of this frame
139141502Swpaul		 * to him.
139241502Swpaul		 */
139341502Swpaul		if (ifp->if_bpf)
139441502Swpaul			bpf_mtap(ifp, cur_tx->vr_mbuf);
139541502Swpaul#endif
139642491Swpaul		VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
139751432Swpaul		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO);
139841502Swpaul	}
139941502Swpaul
140041502Swpaul	/*
140141526Swpaul	 * If there are no frames queued, bail.
140241526Swpaul	 */
140341526Swpaul	if (cur_tx == NULL)
140441526Swpaul		return;
140541526Swpaul
140641502Swpaul	sc->vr_cdata.vr_tx_tail = cur_tx;
140741502Swpaul
140842491Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
140941502Swpaul		sc->vr_cdata.vr_tx_head = start_tx;
141041502Swpaul
141141502Swpaul	/*
141241502Swpaul	 * Set a timeout in case the chip goes out to lunch.
141341502Swpaul	 */
141441502Swpaul	ifp->if_timer = 5;
141541502Swpaul
141641502Swpaul	return;
141741502Swpaul}
141841502Swpaul
141941502Swpaulstatic void vr_init(xsc)
142041502Swpaul	void			*xsc;
142141502Swpaul{
142241502Swpaul	struct vr_softc		*sc = xsc;
142341502Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
142451432Swpaul	struct mii_data		*mii;
142541502Swpaul	int			s;
142641502Swpaul
142741502Swpaul	s = splimp();
142841502Swpaul
142951432Swpaul	mii = device_get_softc(sc->vr_miibus);
143041502Swpaul
143141502Swpaul	/*
143241502Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
143341502Swpaul	 */
143441502Swpaul	vr_stop(sc);
143541502Swpaul	vr_reset(sc);
143641502Swpaul
143741502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
143841502Swpaul	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD);
143941502Swpaul
144041502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
144141502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
144241502Swpaul
144341502Swpaul	/* Init circular RX list. */
144441502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
144541502Swpaul		printf("vr%d: initialization failed: no "
144641502Swpaul			"memory for rx buffers\n", sc->vr_unit);
144741502Swpaul		vr_stop(sc);
144841502Swpaul		(void)splx(s);
144941502Swpaul		return;
145041502Swpaul	}
145141502Swpaul
145241502Swpaul	/*
145341502Swpaul	 * Init tx descriptors.
145441502Swpaul	 */
145541502Swpaul	vr_list_tx_init(sc);
145641502Swpaul
145741502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
145841502Swpaul	if (ifp->if_flags & IFF_PROMISC)
145941502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
146041502Swpaul	else
146141502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
146241502Swpaul
146341502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
146441502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
146541502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
146641502Swpaul	else
146741502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
146841502Swpaul
146941502Swpaul	/*
147041502Swpaul	 * Program the multicast filter, if necessary.
147141502Swpaul	 */
147241502Swpaul	vr_setmulti(sc);
147341502Swpaul
147441502Swpaul	/*
147541502Swpaul	 * Load the address of the RX list.
147641502Swpaul	 */
147741502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
147841502Swpaul
147941502Swpaul	/* Enable receiver and transmitter. */
148041502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
148141502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
148241502Swpaul				    VR_CMD_RX_GO);
148341502Swpaul
148441502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
148541502Swpaul
148641502Swpaul	/*
148741502Swpaul	 * Enable interrupts.
148841502Swpaul	 */
148941502Swpaul	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
149041502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
149141502Swpaul
149251432Swpaul	mii_mediachg(mii);
149341502Swpaul
149441502Swpaul	ifp->if_flags |= IFF_RUNNING;
149541502Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
149641502Swpaul
149741502Swpaul	(void)splx(s);
149841502Swpaul
149951432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
150051432Swpaul
150141502Swpaul	return;
150241502Swpaul}
150341502Swpaul
150441502Swpaul/*
150541502Swpaul * Set media options.
150641502Swpaul */
150741502Swpaulstatic int vr_ifmedia_upd(ifp)
150841502Swpaul	struct ifnet		*ifp;
150941502Swpaul{
151041502Swpaul	struct vr_softc		*sc;
151141502Swpaul
151241502Swpaul	sc = ifp->if_softc;
151341502Swpaul
151451432Swpaul	if (ifp->if_flags & IFF_UP)
151551432Swpaul		vr_init(sc);
151641502Swpaul
151741502Swpaul	return(0);
151841502Swpaul}
151941502Swpaul
152041502Swpaul/*
152141502Swpaul * Report current media status.
152241502Swpaul */
152341502Swpaulstatic void vr_ifmedia_sts(ifp, ifmr)
152441502Swpaul	struct ifnet		*ifp;
152541502Swpaul	struct ifmediareq	*ifmr;
152641502Swpaul{
152741502Swpaul	struct vr_softc		*sc;
152851432Swpaul	struct mii_data		*mii;
152941502Swpaul
153041502Swpaul	sc = ifp->if_softc;
153151432Swpaul	mii = device_get_softc(sc->vr_miibus);
153251432Swpaul	mii_pollstat(mii);
153351432Swpaul	ifmr->ifm_active = mii->mii_media_active;
153451432Swpaul	ifmr->ifm_status = mii->mii_media_status;
153541502Swpaul
153641502Swpaul	return;
153741502Swpaul}
153841502Swpaul
153941502Swpaulstatic int vr_ioctl(ifp, command, data)
154041502Swpaul	struct ifnet		*ifp;
154141502Swpaul	u_long			command;
154241502Swpaul	caddr_t			data;
154341502Swpaul{
154441502Swpaul	struct vr_softc		*sc = ifp->if_softc;
154541502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
154651432Swpaul	struct mii_data		*mii;
154741502Swpaul	int			s, error = 0;
154841502Swpaul
154941502Swpaul	s = splimp();
155041502Swpaul
155141502Swpaul	switch(command) {
155241502Swpaul	case SIOCSIFADDR:
155341502Swpaul	case SIOCGIFADDR:
155441502Swpaul	case SIOCSIFMTU:
155541502Swpaul		error = ether_ioctl(ifp, command, data);
155641502Swpaul		break;
155741502Swpaul	case SIOCSIFFLAGS:
155841502Swpaul		if (ifp->if_flags & IFF_UP) {
155941502Swpaul			vr_init(sc);
156041502Swpaul		} else {
156141502Swpaul			if (ifp->if_flags & IFF_RUNNING)
156241502Swpaul				vr_stop(sc);
156341502Swpaul		}
156441502Swpaul		error = 0;
156541502Swpaul		break;
156641502Swpaul	case SIOCADDMULTI:
156741502Swpaul	case SIOCDELMULTI:
156841502Swpaul		vr_setmulti(sc);
156941502Swpaul		error = 0;
157041502Swpaul		break;
157141502Swpaul	case SIOCGIFMEDIA:
157241502Swpaul	case SIOCSIFMEDIA:
157351432Swpaul		mii = device_get_softc(sc->vr_miibus);
157451432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
157541502Swpaul		break;
157641502Swpaul	default:
157741502Swpaul		error = EINVAL;
157841502Swpaul		break;
157941502Swpaul	}
158041502Swpaul
158141502Swpaul	(void)splx(s);
158241502Swpaul
158341502Swpaul	return(error);
158441502Swpaul}
158541502Swpaul
158641502Swpaulstatic void vr_watchdog(ifp)
158741502Swpaul	struct ifnet		*ifp;
158841502Swpaul{
158941502Swpaul	struct vr_softc		*sc;
159041502Swpaul
159141502Swpaul	sc = ifp->if_softc;
159241502Swpaul
159341502Swpaul	ifp->if_oerrors++;
159441502Swpaul	printf("vr%d: watchdog timeout\n", sc->vr_unit);
159541502Swpaul
159641502Swpaul	vr_stop(sc);
159741502Swpaul	vr_reset(sc);
159841502Swpaul	vr_init(sc);
159941502Swpaul
160041502Swpaul	if (ifp->if_snd.ifq_head != NULL)
160141502Swpaul		vr_start(ifp);
160241502Swpaul
160341502Swpaul	return;
160441502Swpaul}
160541502Swpaul
160641502Swpaul/*
160741502Swpaul * Stop the adapter and free any mbufs allocated to the
160841502Swpaul * RX and TX lists.
160941502Swpaul */
161041502Swpaulstatic void vr_stop(sc)
161141502Swpaul	struct vr_softc		*sc;
161241502Swpaul{
161341502Swpaul	register int		i;
161441502Swpaul	struct ifnet		*ifp;
161541502Swpaul
161641502Swpaul	ifp = &sc->arpcom.ac_if;
161741502Swpaul	ifp->if_timer = 0;
161841502Swpaul
161951432Swpaul	untimeout(vr_tick, sc, sc->vr_stat_ch);
162051432Swpaul
162141502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
162241502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
162341502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
162441502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
162541502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
162641502Swpaul
162741502Swpaul	/*
162841502Swpaul	 * Free data in the RX lists.
162941502Swpaul	 */
163041502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
163141502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
163241502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
163341502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
163441502Swpaul		}
163541502Swpaul	}
163641502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
163741502Swpaul		sizeof(sc->vr_ldata->vr_rx_list));
163841502Swpaul
163941502Swpaul	/*
164041502Swpaul	 * Free the TX list buffers.
164141502Swpaul	 */
164241502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
164341502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
164441502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
164541502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
164641502Swpaul		}
164741502Swpaul	}
164841502Swpaul
164941502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
165041502Swpaul		sizeof(sc->vr_ldata->vr_tx_list));
165141502Swpaul
165241502Swpaul	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
165341502Swpaul
165441502Swpaul	return;
165541502Swpaul}
165641502Swpaul
165741502Swpaul/*
165841502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
165941502Swpaul * get confused by errant DMAs when rebooting.
166041502Swpaul */
166149610Swpaulstatic void vr_shutdown(dev)
166249610Swpaul	device_t		dev;
166341502Swpaul{
166449610Swpaul	struct vr_softc		*sc;
166541502Swpaul
166649610Swpaul	sc = device_get_softc(dev);
166749610Swpaul
166841502Swpaul	vr_stop(sc);
166941502Swpaul
167041502Swpaul	return;
167141502Swpaul}
1672