if_vr.c revision 121816
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 */
3241502Swpaul
3341502Swpaul/*
3441502Swpaul * VIA Rhine fast ethernet PCI NIC driver
3541502Swpaul *
3641502Swpaul * Supports various network adapters based on the VIA Rhine
3741502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX.
3841502Swpaul * Datasheets are available at http://www.via.com.tw.
3941502Swpaul *
4041502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4141502Swpaul * Electrical Engineering Department
4241502Swpaul * Columbia University, New York City
4341502Swpaul */
4441502Swpaul
4541502Swpaul/*
4641502Swpaul * The VIA Rhine controllers are similar in some respects to the
4741502Swpaul * the DEC tulip chips, except less complicated. The controller
4841502Swpaul * uses an MII bus and an external physical layer interface. The
4941502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table
5041502Swpaul * multicast filter. Transmit and receive descriptors are similar
5141502Swpaul * to the tulip.
5241502Swpaul *
5341502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism:
5441502Swpaul * transmit buffers must be longword aligned. Unfortunately,
5541502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting
5641502Swpaul * at longword boundaries, so we have to do a buffer copy before
5741502Swpaul * transmission.
5841502Swpaul */
5941502Swpaul
60113038Sobrien#include <sys/cdefs.h>
61113038Sobrien__FBSDID("$FreeBSD: head/sys/dev/vr/if_vr.c 121816 2003-10-31 18:32:15Z brooks $");
62113038Sobrien
6341502Swpaul#include <sys/param.h>
6441502Swpaul#include <sys/systm.h>
6541502Swpaul#include <sys/sockio.h>
6641502Swpaul#include <sys/mbuf.h>
6741502Swpaul#include <sys/malloc.h>
6841502Swpaul#include <sys/kernel.h>
6941502Swpaul#include <sys/socket.h>
7041502Swpaul
7141502Swpaul#include <net/if.h>
7241502Swpaul#include <net/if_arp.h>
7341502Swpaul#include <net/ethernet.h>
7441502Swpaul#include <net/if_dl.h>
7541502Swpaul#include <net/if_media.h>
7641502Swpaul
7741502Swpaul#include <net/bpf.h>
7841502Swpaul
7941502Swpaul#include <vm/vm.h>              /* for vtophys */
8041502Swpaul#include <vm/pmap.h>            /* for vtophys */
8141502Swpaul#include <machine/bus_pio.h>
8241502Swpaul#include <machine/bus_memio.h>
8341502Swpaul#include <machine/bus.h>
8449610Swpaul#include <machine/resource.h>
8549610Swpaul#include <sys/bus.h>
8649610Swpaul#include <sys/rman.h>
8741502Swpaul
8851432Swpaul#include <dev/mii/mii.h>
8951432Swpaul#include <dev/mii/miivar.h>
9051432Swpaul
91119288Simp#include <dev/pci/pcireg.h>
92119288Simp#include <dev/pci/pcivar.h>
9341502Swpaul
9441502Swpaul#define VR_USEIOSPACE
9541502Swpaul
9641502Swpaul#include <pci/if_vrreg.h>
9741502Swpaul
98113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1);
99113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1);
10059758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
10159758Speter
10251432Swpaul/* "controller miibus0" required.  See GENERIC if you get errors here. */
10351432Swpaul#include "miibus_if.h"
10451432Swpaul
105110168Ssilby#undef VR_USESWSHIFT
106110168Ssilby
10741502Swpaul/*
10841502Swpaul * Various supported device vendors/types and their names.
10941502Swpaul */
11041502Swpaulstatic struct vr_type vr_devs[] = {
11141502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
11241502Swpaul		"VIA VT3043 Rhine I 10/100BaseTX" },
11341502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
11441502Swpaul		"VIA VT86C100A Rhine II 10/100BaseTX" },
11562653Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
11662653Swpaul		"VIA VT6102 Rhine II 10/100BaseTX" },
117110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III,
118110170Ssilby		"VIA VT6105 Rhine III 10/100BaseTX" },
119110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
120110170Ssilby		"VIA VT6105M Rhine III 10/100BaseTX" },
12144238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
12244238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
12344238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
12444238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
12541502Swpaul	{ 0, 0, NULL }
12641502Swpaul};
12741502Swpaul
12892739Salfredstatic int vr_probe		(device_t);
12992739Salfredstatic int vr_attach		(device_t);
13092739Salfredstatic int vr_detach		(device_t);
13141502Swpaul
13292739Salfredstatic int vr_newbuf		(struct vr_softc *,
13349610Swpaul					struct vr_chain_onefrag *,
13492739Salfred					struct mbuf *);
13592739Salfredstatic int vr_encap		(struct vr_softc *, struct vr_chain *,
13692739Salfred						struct mbuf * );
13741502Swpaul
13892739Salfredstatic void vr_rxeof		(struct vr_softc *);
13992739Salfredstatic void vr_rxeoc		(struct vr_softc *);
14092739Salfredstatic void vr_txeof		(struct vr_softc *);
14192739Salfredstatic void vr_txeoc		(struct vr_softc *);
14292739Salfredstatic void vr_tick		(void *);
14392739Salfredstatic void vr_intr		(void *);
14492739Salfredstatic void vr_start		(struct ifnet *);
14592739Salfredstatic int vr_ioctl		(struct ifnet *, u_long, caddr_t);
14692739Salfredstatic void vr_init		(void *);
14792739Salfredstatic void vr_stop		(struct vr_softc *);
14892739Salfredstatic void vr_watchdog		(struct ifnet *);
14992739Salfredstatic void vr_shutdown		(device_t);
15092739Salfredstatic int vr_ifmedia_upd	(struct ifnet *);
15192739Salfredstatic void vr_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
15241502Swpaul
153110168Ssilby#ifdef VR_USESWSHIFT
15492739Salfredstatic void vr_mii_sync		(struct vr_softc *);
15592739Salfredstatic void vr_mii_send		(struct vr_softc *, u_int32_t, int);
156110168Ssilby#endif
15792739Salfredstatic int vr_mii_readreg	(struct vr_softc *, struct vr_mii_frame *);
15892739Salfredstatic int vr_mii_writereg	(struct vr_softc *, struct vr_mii_frame *);
15992739Salfredstatic int vr_miibus_readreg	(device_t, int, int);
16092739Salfredstatic int vr_miibus_writereg	(device_t, int, int, int);
16192739Salfredstatic void vr_miibus_statchg	(device_t);
16241502Swpaul
16392739Salfredstatic void vr_setcfg		(struct vr_softc *, int);
16492739Salfredstatic u_int8_t vr_calchash	(u_int8_t *);
16592739Salfredstatic void vr_setmulti		(struct vr_softc *);
16692739Salfredstatic void vr_reset		(struct vr_softc *);
16792739Salfredstatic int vr_list_rx_init	(struct vr_softc *);
16892739Salfredstatic int vr_list_tx_init	(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
205113506SmdoddDRIVER_MODULE(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,				\
210105221Sphk		CSR_READ_1(sc, reg) | (x))
21141502Swpaul
21241502Swpaul#define VR_CLRBIT(sc, reg, x)				\
21341502Swpaul	CSR_WRITE_1(sc, reg,				\
214105221Sphk		CSR_READ_1(sc, reg) & ~(x))
21541502Swpaul
21641502Swpaul#define VR_SETBIT16(sc, reg, x)				\
21741502Swpaul	CSR_WRITE_2(sc, reg,				\
218105221Sphk		CSR_READ_2(sc, reg) | (x))
21941502Swpaul
22041502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
22141502Swpaul	CSR_WRITE_2(sc, reg,				\
222105221Sphk		CSR_READ_2(sc, reg) & ~(x))
22341502Swpaul
22441502Swpaul#define VR_SETBIT32(sc, reg, x)				\
22541502Swpaul	CSR_WRITE_4(sc, reg,				\
226105221Sphk		CSR_READ_4(sc, reg) | (x))
22741502Swpaul
22841502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
22941502Swpaul	CSR_WRITE_4(sc, reg,				\
230105221Sphk		CSR_READ_4(sc, reg) & ~(x))
23141502Swpaul
23241502Swpaul#define SIO_SET(x)					\
23341502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
234105221Sphk		CSR_READ_1(sc, VR_MIICMD) | (x))
23541502Swpaul
23641502Swpaul#define SIO_CLR(x)					\
23741502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
238105221Sphk		CSR_READ_1(sc, VR_MIICMD) & ~(x))
23941502Swpaul
240110168Ssilby#ifdef VR_USESWSHIFT
24141502Swpaul/*
24241502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
24341502Swpaul */
244102336Salfredstatic void
245102336Salfredvr_mii_sync(sc)
24641502Swpaul	struct vr_softc		*sc;
24741502Swpaul{
24841502Swpaul	register int		i;
24941502Swpaul
25041502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
25141502Swpaul
25241502Swpaul	for (i = 0; i < 32; i++) {
25341502Swpaul		SIO_SET(VR_MIICMD_CLK);
25441502Swpaul		DELAY(1);
25541502Swpaul		SIO_CLR(VR_MIICMD_CLK);
25641502Swpaul		DELAY(1);
25741502Swpaul	}
25841502Swpaul
25941502Swpaul	return;
26041502Swpaul}
26141502Swpaul
26241502Swpaul/*
26341502Swpaul * Clock a series of bits through the MII.
26441502Swpaul */
265102336Salfredstatic void
266102336Salfredvr_mii_send(sc, bits, cnt)
26741502Swpaul	struct vr_softc		*sc;
26841502Swpaul	u_int32_t		bits;
26941502Swpaul	int			cnt;
27041502Swpaul{
27141502Swpaul	int			i;
27241502Swpaul
27341502Swpaul	SIO_CLR(VR_MIICMD_CLK);
27441502Swpaul
27541502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
27641502Swpaul                if (bits & i) {
27741502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
27841502Swpaul                } else {
27941502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
28041502Swpaul                }
28141502Swpaul		DELAY(1);
28241502Swpaul		SIO_CLR(VR_MIICMD_CLK);
28341502Swpaul		DELAY(1);
28441502Swpaul		SIO_SET(VR_MIICMD_CLK);
28541502Swpaul	}
28641502Swpaul}
287110168Ssilby#endif
28841502Swpaul
28941502Swpaul/*
29041502Swpaul * Read an PHY register through the MII.
29141502Swpaul */
292102336Salfredstatic int
293102336Salfredvr_mii_readreg(sc, frame)
29441502Swpaul	struct vr_softc		*sc;
29541502Swpaul	struct vr_mii_frame	*frame;
29641502Swpaul
297110168Ssilby#ifdef VR_USESWSHIFT
29841502Swpaul{
29967087Swpaul	int			i, ack;
30041502Swpaul
30167087Swpaul	VR_LOCK(sc);
30241502Swpaul
30341502Swpaul	/*
30441502Swpaul	 * Set up frame for RX.
30541502Swpaul	 */
30641502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
30741502Swpaul	frame->mii_opcode = VR_MII_READOP;
30841502Swpaul	frame->mii_turnaround = 0;
30941502Swpaul	frame->mii_data = 0;
31041502Swpaul
31141502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
31241502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
31341502Swpaul
31441502Swpaul	/*
31541502Swpaul 	 * Turn on data xmit.
31641502Swpaul	 */
31741502Swpaul	SIO_SET(VR_MIICMD_DIR);
31841502Swpaul
31941502Swpaul	vr_mii_sync(sc);
32041502Swpaul
32141502Swpaul	/*
32241502Swpaul	 * Send command/address info.
32341502Swpaul	 */
32441502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
32541502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
32641502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
32741502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
32841502Swpaul
32941502Swpaul	/* Idle bit */
33041502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
33141502Swpaul	DELAY(1);
33241502Swpaul	SIO_SET(VR_MIICMD_CLK);
33341502Swpaul	DELAY(1);
33441502Swpaul
33541502Swpaul	/* Turn off xmit. */
33641502Swpaul	SIO_CLR(VR_MIICMD_DIR);
33741502Swpaul
33841502Swpaul	/* Check for ack */
33941502Swpaul	SIO_CLR(VR_MIICMD_CLK);
34041502Swpaul	DELAY(1);
341109058Smbr	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
34241502Swpaul	SIO_SET(VR_MIICMD_CLK);
34341502Swpaul	DELAY(1);
34441502Swpaul
34541502Swpaul	/*
34641502Swpaul	 * Now try reading data bits. If the ack failed, we still
34741502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
34841502Swpaul	 */
34941502Swpaul	if (ack) {
35041502Swpaul		for(i = 0; i < 16; i++) {
35141502Swpaul			SIO_CLR(VR_MIICMD_CLK);
35241502Swpaul			DELAY(1);
35341502Swpaul			SIO_SET(VR_MIICMD_CLK);
35441502Swpaul			DELAY(1);
35541502Swpaul		}
35641502Swpaul		goto fail;
35741502Swpaul	}
35841502Swpaul
35941502Swpaul	for (i = 0x8000; i; i >>= 1) {
36041502Swpaul		SIO_CLR(VR_MIICMD_CLK);
36141502Swpaul		DELAY(1);
36241502Swpaul		if (!ack) {
36341502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
36441502Swpaul				frame->mii_data |= i;
36541502Swpaul			DELAY(1);
36641502Swpaul		}
36741502Swpaul		SIO_SET(VR_MIICMD_CLK);
36841502Swpaul		DELAY(1);
36941502Swpaul	}
37041502Swpaul
37141502Swpaulfail:
37241502Swpaul
37341502Swpaul	SIO_CLR(VR_MIICMD_CLK);
37441502Swpaul	DELAY(1);
37541502Swpaul	SIO_SET(VR_MIICMD_CLK);
37641502Swpaul	DELAY(1);
37741502Swpaul
37867087Swpaul	VR_UNLOCK(sc);
37941502Swpaul
38041502Swpaul	if (ack)
38141502Swpaul		return(1);
38241502Swpaul	return(0);
38341502Swpaul}
384110168Ssilby#else
385110168Ssilby{
386110168Ssilby	int			s, i;
38741502Swpaul
388110168Ssilby	s = splimp();
389110168Ssilby
390110168Ssilby  	/* Set the PHY-adress */
391110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
392110168Ssilby	    frame->mii_phyaddr);
393110168Ssilby
394110168Ssilby  	/* Set the register-adress */
395110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
396110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
397110168Ssilby
398110168Ssilby	for (i = 0; i < 10000; i++) {
399110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
400110168Ssilby			break;
401110168Ssilby		DELAY(1);
402110168Ssilby	}
403110168Ssilby
404110168Ssilby	frame->mii_data = CSR_READ_2(sc, VR_MIIDATA);
405110168Ssilby
406110168Ssilby	(void)splx(s);
407110168Ssilby
408110168Ssilby	return(0);
409110168Ssilby}
410110168Ssilby#endif
411110168Ssilby
412110168Ssilby
41341502Swpaul/*
41441502Swpaul * Write to a PHY register through the MII.
41541502Swpaul */
416102336Salfredstatic int
417102336Salfredvr_mii_writereg(sc, frame)
41841502Swpaul	struct vr_softc		*sc;
41941502Swpaul	struct vr_mii_frame	*frame;
42041502Swpaul
421110168Ssilby#ifdef VR_USESWSHIFT
42241502Swpaul{
42367087Swpaul	VR_LOCK(sc);
42441502Swpaul
42541502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
42641502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
42741502Swpaul
42841502Swpaul	/*
42941502Swpaul	 * Set up frame for TX.
43041502Swpaul	 */
43141502Swpaul
43241502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
43341502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
43441502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
43541502Swpaul
43641502Swpaul	/*
43741502Swpaul 	 * Turn on data output.
43841502Swpaul	 */
43941502Swpaul	SIO_SET(VR_MIICMD_DIR);
44041502Swpaul
44141502Swpaul	vr_mii_sync(sc);
44241502Swpaul
44341502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
44441502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
44541502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
44641502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
44741502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
44841502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
44941502Swpaul
45041502Swpaul	/* Idle bit. */
45141502Swpaul	SIO_SET(VR_MIICMD_CLK);
45241502Swpaul	DELAY(1);
45341502Swpaul	SIO_CLR(VR_MIICMD_CLK);
45441502Swpaul	DELAY(1);
45541502Swpaul
45641502Swpaul	/*
45741502Swpaul	 * Turn off xmit.
45841502Swpaul	 */
45941502Swpaul	SIO_CLR(VR_MIICMD_DIR);
46041502Swpaul
46167087Swpaul	VR_UNLOCK(sc);
46241502Swpaul
46341502Swpaul	return(0);
46441502Swpaul}
465110168Ssilby#else
466110168Ssilby{
467110168Ssilby	int			s, i;
46841502Swpaul
469110168Ssilby	s = splimp();
470110168Ssilby
471110168Ssilby  	/* Set the PHY-adress */
472110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
473110168Ssilby		    frame->mii_phyaddr);
474110168Ssilby
475110168Ssilby  	/* Set the register-adress and data to write */
476110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
477110168Ssilby	CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data);
478110168Ssilby
479110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
480110168Ssilby
481110168Ssilby	for (i = 0; i < 10000; i++) {
482110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
483110168Ssilby			break;
484110168Ssilby		DELAY(1);
485110168Ssilby	}
486110168Ssilby
487110168Ssilby	(void)splx(s);
488110168Ssilby
489110168Ssilby	return(0);
490110168Ssilby}
491110168Ssilby#endif
492110168Ssilby
493102336Salfredstatic int
494102336Salfredvr_miibus_readreg(dev, phy, reg)
49551432Swpaul	device_t		dev;
49651432Swpaul	int			phy, reg;
49751432Swpaul{
49841502Swpaul	struct vr_softc		*sc;
49941502Swpaul	struct vr_mii_frame	frame;
50041502Swpaul
50151432Swpaul	sc = device_get_softc(dev);
502110168Ssilby
503110168Ssilby	switch (sc->vr_revid) {
504110168Ssilby		case REV_ID_VT6102_APOLLO:
505110168Ssilby			if (phy != 1)
506110168Ssilby				return 0;
507110168Ssilby		default:
508110168Ssilby			break;
509110168Ssilby		}
510110168Ssilby
51141502Swpaul	bzero((char *)&frame, sizeof(frame));
51241502Swpaul
51351432Swpaul	frame.mii_phyaddr = phy;
51441502Swpaul	frame.mii_regaddr = reg;
51541502Swpaul	vr_mii_readreg(sc, &frame);
51641502Swpaul
51741502Swpaul	return(frame.mii_data);
51841502Swpaul}
51941502Swpaul
520102336Salfredstatic int
521102336Salfredvr_miibus_writereg(dev, phy, reg, data)
52251432Swpaul	device_t		dev;
52351432Swpaul	u_int16_t		phy, reg, data;
52451432Swpaul{
52541502Swpaul	struct vr_softc		*sc;
52641502Swpaul	struct vr_mii_frame	frame;
52741502Swpaul
52851432Swpaul	sc = device_get_softc(dev);
529110168Ssilby
530110168Ssilby	switch (sc->vr_revid) {
531110168Ssilby		case REV_ID_VT6102_APOLLO:
532110168Ssilby			if (phy != 1)
533110168Ssilby				return 0;
534110168Ssilby		default:
535110168Ssilby			break;
536110168Ssilby		}
537110168Ssilby
53841502Swpaul	bzero((char *)&frame, sizeof(frame));
53941502Swpaul
54051432Swpaul	frame.mii_phyaddr = phy;
54141502Swpaul	frame.mii_regaddr = reg;
54241502Swpaul	frame.mii_data = data;
54341502Swpaul
54441502Swpaul	vr_mii_writereg(sc, &frame);
54541502Swpaul
54651432Swpaul	return(0);
54751432Swpaul}
54851432Swpaul
549102336Salfredstatic void
550102336Salfredvr_miibus_statchg(dev)
55151432Swpaul	device_t		dev;
55251432Swpaul{
55351432Swpaul	struct vr_softc		*sc;
55451432Swpaul	struct mii_data		*mii;
55551432Swpaul
55651432Swpaul	sc = device_get_softc(dev);
55767087Swpaul	VR_LOCK(sc);
55851432Swpaul	mii = device_get_softc(sc->vr_miibus);
55951432Swpaul	vr_setcfg(sc, mii->mii_media_active);
56067087Swpaul	VR_UNLOCK(sc);
56151432Swpaul
56241502Swpaul	return;
56341502Swpaul}
56441502Swpaul
56541502Swpaul/*
56641502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits.
56741502Swpaul */
56841502Swpaulstatic u_int8_t vr_calchash(addr)
56941502Swpaul	u_int8_t		*addr;
57041502Swpaul{
57141502Swpaul	u_int32_t		crc, carry;
57241502Swpaul	int			i, j;
57341502Swpaul	u_int8_t		c;
57441502Swpaul
57541502Swpaul	/* Compute CRC for the address value. */
57641502Swpaul	crc = 0xFFFFFFFF; /* initial value */
57741502Swpaul
57841502Swpaul	for (i = 0; i < 6; i++) {
57941502Swpaul		c = *(addr + i);
58041502Swpaul		for (j = 0; j < 8; j++) {
58141502Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
58241502Swpaul			crc <<= 1;
58341502Swpaul			c >>= 1;
58441502Swpaul			if (carry)
58541502Swpaul				crc = (crc ^ 0x04c11db6) | carry;
58641502Swpaul		}
58741502Swpaul	}
58841502Swpaul
58941502Swpaul	/* return the filter bit position */
59041502Swpaul	return((crc >> 26) & 0x0000003F);
59141502Swpaul}
59241502Swpaul
59341502Swpaul/*
59441502Swpaul * Program the 64-bit multicast hash filter.
59541502Swpaul */
596102336Salfredstatic void
597102336Salfredvr_setmulti(sc)
59841502Swpaul	struct vr_softc		*sc;
59941502Swpaul{
60041502Swpaul	struct ifnet		*ifp;
60141502Swpaul	int			h = 0;
60241502Swpaul	u_int32_t		hashes[2] = { 0, 0 };
60341502Swpaul	struct ifmultiaddr	*ifma;
60441502Swpaul	u_int8_t		rxfilt;
60541502Swpaul	int			mcnt = 0;
60641502Swpaul
60741502Swpaul	ifp = &sc->arpcom.ac_if;
60841502Swpaul
60941502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
61041502Swpaul
61141502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
61241502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
61341502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
61441502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
61541502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
61641502Swpaul		return;
61741502Swpaul	}
61841502Swpaul
61941502Swpaul	/* first, zot all the existing hash bits */
62041502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
62141502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
62241502Swpaul
62341502Swpaul	/* now program new ones */
62472084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
62541502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
62641502Swpaul			continue;
62741502Swpaul		h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
62841502Swpaul		if (h < 32)
62941502Swpaul			hashes[0] |= (1 << h);
63041502Swpaul		else
63141502Swpaul			hashes[1] |= (1 << (h - 32));
63241502Swpaul		mcnt++;
63341502Swpaul	}
63441502Swpaul
63541502Swpaul	if (mcnt)
63641502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
63741502Swpaul	else
63841502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
63941502Swpaul
64041502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
64141502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
64241502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
64341502Swpaul
64441502Swpaul	return;
64541502Swpaul}
64641502Swpaul
64741502Swpaul/*
64841502Swpaul * In order to fiddle with the
64941502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
65041502Swpaul * first have to put the transmit and/or receive logic in the idle state.
65141502Swpaul */
652102336Salfredstatic void
653102336Salfredvr_setcfg(sc, media)
65441502Swpaul	struct vr_softc		*sc;
65551432Swpaul	int			media;
65641502Swpaul{
65741502Swpaul	int			restart = 0;
65841502Swpaul
65941502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
66041502Swpaul		restart = 1;
66141502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
66241502Swpaul	}
66341502Swpaul
66451432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
66541502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
66641502Swpaul	else
66741502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
66841502Swpaul
66941502Swpaul	if (restart)
67041502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
67141502Swpaul
67241502Swpaul	return;
67341502Swpaul}
67441502Swpaul
675102336Salfredstatic void
676102336Salfredvr_reset(sc)
67741502Swpaul	struct vr_softc		*sc;
67841502Swpaul{
67941502Swpaul	register int		i;
68041502Swpaul
68141502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
68241502Swpaul
68341502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
68441502Swpaul		DELAY(10);
68541502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
68641502Swpaul			break;
68741502Swpaul	}
688107220Ssilby	if (i == VR_TIMEOUT) {
689107220Ssilby		if (sc->vr_revid < REV_ID_VT3065_A)
690107220Ssilby			printf("vr%d: reset never completed!\n", sc->vr_unit);
691107220Ssilby		else {
692107220Ssilby			/* Use newer force reset command */
693107220Ssilby			printf("vr%d: Using force reset command.\n", sc->vr_unit);
694107220Ssilby			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
695107220Ssilby		}
696107220Ssilby	}
69741502Swpaul
69841502Swpaul	/* Wait a little while for the chip to get its brains in order. */
69941502Swpaul	DELAY(1000);
70041502Swpaul
70141502Swpaul        return;
70241502Swpaul}
70341502Swpaul
70441502Swpaul/*
70541502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
70641502Swpaul * IDs against our list and return a device name if we find a match.
70741502Swpaul */
708102336Salfredstatic int
709102336Salfredvr_probe(dev)
71049610Swpaul	device_t		dev;
71141502Swpaul{
71241502Swpaul	struct vr_type		*t;
71341502Swpaul
71441502Swpaul	t = vr_devs;
71541502Swpaul
71641502Swpaul	while(t->vr_name != NULL) {
71749610Swpaul		if ((pci_get_vendor(dev) == t->vr_vid) &&
71849610Swpaul		    (pci_get_device(dev) == t->vr_did)) {
71949610Swpaul			device_set_desc(dev, t->vr_name);
72049610Swpaul			return(0);
72141502Swpaul		}
72241502Swpaul		t++;
72341502Swpaul	}
72441502Swpaul
72549610Swpaul	return(ENXIO);
72641502Swpaul}
72741502Swpaul
72841502Swpaul/*
72941502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
73041502Swpaul * setup and ethernet/BPF attach.
73141502Swpaul */
732102336Salfredstatic int
733102336Salfredvr_attach(dev)
73449610Swpaul	device_t		dev;
73541502Swpaul{
73667087Swpaul	int			i;
73741502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
73841502Swpaul	struct vr_softc		*sc;
73941502Swpaul	struct ifnet		*ifp;
74049610Swpaul	int			unit, error = 0, rid;
74141502Swpaul
74249610Swpaul	sc = device_get_softc(dev);
74349610Swpaul	unit = device_get_unit(dev);
74441502Swpaul
74593818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
74693818Sjhb	    MTX_DEF | MTX_RECURSE);
747117208Simp#ifndef BURN_BRIDGES
74841502Swpaul	/*
74941502Swpaul	 * Handle power management nonsense.
75041502Swpaul	 */
75172813Swpaul	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
75272813Swpaul		u_int32_t		iobase, membase, irq;
75341502Swpaul
75472813Swpaul		/* Save important PCI config data. */
75572813Swpaul		iobase = pci_read_config(dev, VR_PCI_LOIO, 4);
75672813Swpaul		membase = pci_read_config(dev, VR_PCI_LOMEM, 4);
75772813Swpaul		irq = pci_read_config(dev, VR_PCI_INTLINE, 4);
75841502Swpaul
75972813Swpaul		/* Reset the power state. */
76072813Swpaul		printf("vr%d: chip is in D%d power mode "
76172813Swpaul		    "-- setting to D0\n", unit,
76272813Swpaul		    pci_get_powerstate(dev));
76372813Swpaul		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
76441502Swpaul
76541502Swpaul			/* Restore PCI config data. */
76672813Swpaul		pci_write_config(dev, VR_PCI_LOIO, iobase, 4);
76772813Swpaul		pci_write_config(dev, VR_PCI_LOMEM, membase, 4);
76872813Swpaul		pci_write_config(dev, VR_PCI_INTLINE, irq, 4);
76941502Swpaul	}
770117208Simp#endif
77141502Swpaul	/*
77241502Swpaul	 * Map control/status registers.
77341502Swpaul	 */
77472813Swpaul	pci_enable_busmaster(dev);
775107220Ssilby	sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF;
77641502Swpaul
77749610Swpaul	rid = VR_RID;
77849610Swpaul	sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid,
77949610Swpaul	    0, ~0, 1, RF_ACTIVE);
78049610Swpaul
78149610Swpaul	if (sc->vr_res == NULL) {
78249610Swpaul		printf("vr%d: couldn't map ports/memory\n", unit);
78349610Swpaul		error = ENXIO;
78441502Swpaul		goto fail;
78541502Swpaul	}
78641502Swpaul
78749610Swpaul	sc->vr_btag = rman_get_bustag(sc->vr_res);
78849610Swpaul	sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
78941502Swpaul
79041502Swpaul	/* Allocate interrupt */
79149610Swpaul	rid = 0;
79249610Swpaul	sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
79349610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
79449610Swpaul
79549610Swpaul	if (sc->vr_irq == NULL) {
79641502Swpaul		printf("vr%d: couldn't map interrupt\n", unit);
79749610Swpaul		error = ENXIO;
79841502Swpaul		goto fail;
79941502Swpaul	}
80041502Swpaul
80176586Swpaul	/*
80276586Swpaul	 * Windows may put the chip in suspend mode when it
80376586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
80476586Swpaul	 * up again.
80576586Swpaul	 */
80676586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
80776586Swpaul
80841502Swpaul	/* Reset the adapter. */
80941502Swpaul	vr_reset(sc);
81041502Swpaul
811110168Ssilby        /*
812110168Ssilby	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
813110168Ssilby	 * initialization and disable AUTOPOLL.
814110168Ssilby	 */
815110168Ssilby        pci_write_config(dev, VR_PCI_MODE,
816110168Ssilby	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
817110168Ssilby	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
818110168Ssilby
81941502Swpaul	/*
82041502Swpaul	 * Get station address. The way the Rhine chips work,
82141502Swpaul	 * you're not allowed to directly access the EEPROM once
82241502Swpaul	 * they've been programmed a special way. Consequently,
82341502Swpaul	 * we need to read the node address from the PAR0 and PAR1
82441502Swpaul	 * registers.
82541502Swpaul	 */
82641502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
82741502Swpaul	DELAY(200);
82841502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
82941502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
83041502Swpaul
83141502Swpaul	/*
83241502Swpaul	 * A Rhine chip was detected. Inform the world.
83341502Swpaul	 */
83441502Swpaul	printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":");
83541502Swpaul
83641502Swpaul	sc->vr_unit = unit;
83741502Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
83841502Swpaul
83951432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
84051657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
84151432Swpaul
84251432Swpaul	if (sc->vr_ldata == NULL) {
84341502Swpaul		printf("vr%d: no memory for list buffers!\n", unit);
84449610Swpaul		error = ENXIO;
84549610Swpaul		goto fail;
84641502Swpaul	}
84741502Swpaul
84841502Swpaul	bzero(sc->vr_ldata, sizeof(struct vr_list_data));
84941502Swpaul
85041502Swpaul	ifp = &sc->arpcom.ac_if;
85141502Swpaul	ifp->if_softc = sc;
852121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
85341502Swpaul	ifp->if_mtu = ETHERMTU;
85441502Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
85541502Swpaul	ifp->if_ioctl = vr_ioctl;
85641502Swpaul	ifp->if_output = ether_output;
85741502Swpaul	ifp->if_start = vr_start;
85841502Swpaul	ifp->if_watchdog = vr_watchdog;
85941502Swpaul	ifp->if_init = vr_init;
86041502Swpaul	ifp->if_baudrate = 10000000;
86143515Swpaul	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
86241502Swpaul
86351432Swpaul	/*
86451432Swpaul	 * Do MII setup.
86551432Swpaul	 */
86651432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
86751432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
86841502Swpaul		printf("vr%d: MII without any phy!\n", sc->vr_unit);
86949610Swpaul		error = ENXIO;
87041502Swpaul		goto fail;
87141502Swpaul	}
87241502Swpaul
87351432Swpaul	callout_handle_init(&sc->vr_stat_ch);
87441502Swpaul
87541502Swpaul	/*
87663090Sarchie	 * Call MI attach routine.
87741502Swpaul	 */
878106936Ssam	ether_ifattach(ifp, eaddr);
87941502Swpaul
880113609Snjl	/* Hook interrupt last to avoid having to lock softc */
881112872Snjl	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET,
882112872Snjl	    vr_intr, sc, &sc->vr_intrhand);
883112872Snjl
884112872Snjl	if (error) {
885112872Snjl		printf("vr%d: couldn't set up irq\n", unit);
886113609Snjl		ether_ifdetach(ifp);
887112872Snjl		goto fail;
888112872Snjl	}
889112872Snjl
89041502Swpaulfail:
891112872Snjl	if (error)
892112872Snjl		vr_detach(dev);
89367087Swpaul
89449610Swpaul	return(error);
89541502Swpaul}
89641502Swpaul
897113609Snjl/*
898113609Snjl * Shutdown hardware and free up resources. This can be called any
899113609Snjl * time after the mutex has been initialized. It is called in both
900113609Snjl * the error case in attach and the normal detach case so it needs
901113609Snjl * to be careful about only freeing resources that have actually been
902113609Snjl * allocated.
903113609Snjl */
904102336Salfredstatic int
905102336Salfredvr_detach(dev)
90649610Swpaul	device_t		dev;
90749610Swpaul{
90849610Swpaul	struct vr_softc		*sc;
90949610Swpaul	struct ifnet		*ifp;
91049610Swpaul
91149610Swpaul	sc = device_get_softc(dev);
912112880Sjhb	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
91367087Swpaul	VR_LOCK(sc);
91449610Swpaul	ifp = &sc->arpcom.ac_if;
91549610Swpaul
916113609Snjl	/* These should only be active if attach succeeded */
917113812Simp	if (device_is_attached(dev)) {
918113609Snjl		vr_stop(sc);
919112872Snjl		ether_ifdetach(ifp);
920113609Snjl	}
921113609Snjl	if (sc->vr_miibus)
922112872Snjl		device_delete_child(dev, sc->vr_miibus);
923113609Snjl	bus_generic_detach(dev);
92449610Swpaul
925112872Snjl	if (sc->vr_intrhand)
926112872Snjl		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
927112872Snjl	if (sc->vr_irq)
928112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
929112872Snjl	if (sc->vr_res)
930112872Snjl		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
93151432Swpaul
932112872Snjl	if (sc->vr_ldata)
933112872Snjl		contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
93449610Swpaul
93567087Swpaul	VR_UNLOCK(sc);
93667087Swpaul	mtx_destroy(&sc->vr_mtx);
93749610Swpaul
93849610Swpaul	return(0);
93949610Swpaul}
94049610Swpaul
94141502Swpaul/*
94241502Swpaul * Initialize the transmit descriptors.
94341502Swpaul */
944102336Salfredstatic int
945102336Salfredvr_list_tx_init(sc)
94641502Swpaul	struct vr_softc		*sc;
94741502Swpaul{
94841502Swpaul	struct vr_chain_data	*cd;
94941502Swpaul	struct vr_list_data	*ld;
95041502Swpaul	int			i;
95141502Swpaul
95241502Swpaul	cd = &sc->vr_cdata;
95341502Swpaul	ld = sc->vr_ldata;
95441502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
95541502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
95641502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
95741502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
95841502Swpaul				&cd->vr_tx_chain[0];
95941502Swpaul		else
96041502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
96141502Swpaul				&cd->vr_tx_chain[i + 1];
96241502Swpaul	}
96341502Swpaul
96441502Swpaul	cd->vr_tx_free = &cd->vr_tx_chain[0];
96541502Swpaul	cd->vr_tx_tail = cd->vr_tx_head = NULL;
96641502Swpaul
96741502Swpaul	return(0);
96841502Swpaul}
96941502Swpaul
97041502Swpaul
97141502Swpaul/*
97241502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
97341502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
97441502Swpaul * points back to the first.
97541502Swpaul */
976102336Salfredstatic int
977102336Salfredvr_list_rx_init(sc)
97841502Swpaul	struct vr_softc		*sc;
97941502Swpaul{
98041502Swpaul	struct vr_chain_data	*cd;
98141502Swpaul	struct vr_list_data	*ld;
98241502Swpaul	int			i;
98341502Swpaul
98441502Swpaul	cd = &sc->vr_cdata;
98541502Swpaul	ld = sc->vr_ldata;
98641502Swpaul
98741502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
98841502Swpaul		cd->vr_rx_chain[i].vr_ptr =
98941502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
99049610Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
99141502Swpaul			return(ENOBUFS);
99241502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
99341502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
99441502Swpaul					&cd->vr_rx_chain[0];
99541502Swpaul			ld->vr_rx_list[i].vr_next =
99641502Swpaul					vtophys(&ld->vr_rx_list[0]);
99741502Swpaul		} else {
99841502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
99941502Swpaul					&cd->vr_rx_chain[i + 1];
100041502Swpaul			ld->vr_rx_list[i].vr_next =
100141502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
100241502Swpaul		}
100341502Swpaul	}
100441502Swpaul
100541502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
100641502Swpaul
100741502Swpaul	return(0);
100841502Swpaul}
100941502Swpaul
101041502Swpaul/*
101141502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
101241502Swpaul * Note: the length fields are only 11 bits wide, which means the
101341502Swpaul * largest size we can specify is 2047. This is important because
101441502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
101541502Swpaul * overflow the field and make a mess.
101641502Swpaul */
1017102336Salfredstatic int
1018102336Salfredvr_newbuf(sc, c, m)
101941502Swpaul	struct vr_softc		*sc;
102041502Swpaul	struct vr_chain_onefrag	*c;
102149610Swpaul	struct mbuf		*m;
102241502Swpaul{
102341502Swpaul	struct mbuf		*m_new = NULL;
102441502Swpaul
102549610Swpaul	if (m == NULL) {
1026111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
102787846Sluigi		if (m_new == NULL)
102849610Swpaul			return(ENOBUFS);
102941502Swpaul
1030111119Simp		MCLGET(m_new, M_DONTWAIT);
103149610Swpaul		if (!(m_new->m_flags & M_EXT)) {
103249610Swpaul			m_freem(m_new);
103349610Swpaul			return(ENOBUFS);
103449610Swpaul		}
103549610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
103649610Swpaul	} else {
103749610Swpaul		m_new = m;
103849610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
103949610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
104041502Swpaul	}
104141502Swpaul
104249610Swpaul	m_adj(m_new, sizeof(u_int64_t));
104349610Swpaul
104441502Swpaul	c->vr_mbuf = m_new;
104541502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
104641502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
104742491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
104841502Swpaul
104941502Swpaul	return(0);
105041502Swpaul}
105141502Swpaul
105241502Swpaul/*
105341502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
105441502Swpaul * the higher level protocols.
105541502Swpaul */
1056102336Salfredstatic void
1057102336Salfredvr_rxeof(sc)
105841502Swpaul	struct vr_softc		*sc;
105941502Swpaul{
106041502Swpaul        struct mbuf		*m;
106141502Swpaul        struct ifnet		*ifp;
106241502Swpaul	struct vr_chain_onefrag	*cur_rx;
106341502Swpaul	int			total_len = 0;
106441502Swpaul	u_int32_t		rxstat;
106541502Swpaul
106641502Swpaul	ifp = &sc->arpcom.ac_if;
106741502Swpaul
106841502Swpaul	while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
106941502Swpaul							VR_RXSTAT_OWN)) {
107049610Swpaul		struct mbuf		*m0 = NULL;
107149610Swpaul
107241502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
107341502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
107449610Swpaul		m = cur_rx->vr_mbuf;
107541502Swpaul
107641502Swpaul		/*
107741502Swpaul		 * If an error occurs, update stats, clear the
107841502Swpaul		 * status word and leave the mbuf cluster in place:
107941502Swpaul		 * it should simply get re-used next time this descriptor
108041502Swpaul	 	 * comes up in the ring.
108141502Swpaul		 */
108241502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
108341502Swpaul			ifp->if_ierrors++;
1084110131Ssilby			printf("vr%d: rx error (%02x):",
1085110131Ssilby			       sc->vr_unit, rxstat & 0x000000ff);
1086110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
1087110131Ssilby				printf(" crc error");
1088110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
1089110131Ssilby				printf(" frame alignment error\n");
1090110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
1091110131Ssilby				printf(" FIFO overflow");
1092110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
1093110131Ssilby				printf(" received giant packet");
1094110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
1095110131Ssilby				printf(" received runt packet");
1096110131Ssilby			if (rxstat & VR_RXSTAT_BUSERR)
1097110131Ssilby				printf(" system bus error");
1098110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
1099110131Ssilby				printf("rx buffer error");
1100110131Ssilby			printf("\n");
110149610Swpaul			vr_newbuf(sc, cur_rx, m);
110241502Swpaul			continue;
110341502Swpaul		}
110441502Swpaul
110541502Swpaul		/* No errors; receive the packet. */
110641502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
110741502Swpaul
110841502Swpaul		/*
110942048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
111042048Swpaul		 * received frame, and there's no way to turn this
111142048Swpaul		 * behavior off (at least, I can't find anything in
111242048Swpaul	 	 * the manual that explains how to do it) so we have
111342048Swpaul		 * to trim off the CRC manually.
111442048Swpaul		 */
111542048Swpaul		total_len -= ETHER_CRC_LEN;
111642048Swpaul
111778508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
111878508Sbmilekic		    NULL);
111949610Swpaul		vr_newbuf(sc, cur_rx, m);
112049610Swpaul		if (m0 == NULL) {
112141502Swpaul			ifp->if_ierrors++;
112241502Swpaul			continue;
112341502Swpaul		}
112449610Swpaul		m = m0;
112541502Swpaul
112641502Swpaul		ifp->if_ipackets++;
1127106936Ssam		(*ifp->if_input)(ifp, m);
112841502Swpaul	}
112941502Swpaul
113041502Swpaul	return;
113141502Swpaul}
113241502Swpaul
1133105221Sphkstatic void
1134102336Salfredvr_rxeoc(sc)
113541502Swpaul	struct vr_softc		*sc;
113641502Swpaul{
1137110131Ssilby	struct ifnet		*ifp;
1138110131Ssilby	int			i;
113941502Swpaul
1140110131Ssilby	ifp = &sc->arpcom.ac_if;
1141110131Ssilby
1142110131Ssilby	ifp->if_ierrors++;
1143110131Ssilby
1144110131Ssilby	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
1145110131Ssilby        DELAY(10000);
1146110131Ssilby
1147110131Ssilby	for (i = 0x400;
1148110131Ssilby	     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON);
1149110131Ssilby	     i--)
1150110131Ssilby		;	/* Wait for receiver to stop */
1151110131Ssilby
1152110131Ssilby	if (!i) {
1153110131Ssilby		printf("vr%d: rx shutdown error!\n", sc->vr_unit);
1154110131Ssilby		sc->vr_flags |= VR_F_RESTART;
1155110131Ssilby		return;
1156110131Ssilby		}
1157110131Ssilby
115841502Swpaul	vr_rxeof(sc);
1159110131Ssilby
116041502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
116141502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
116241502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
116341502Swpaul
116441502Swpaul	return;
116541502Swpaul}
116641502Swpaul
116741502Swpaul/*
116841502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
116941502Swpaul * the list buffers.
117041502Swpaul */
117141502Swpaul
1172102336Salfredstatic void
1173102336Salfredvr_txeof(sc)
117441502Swpaul	struct vr_softc		*sc;
117541502Swpaul{
117641502Swpaul	struct vr_chain		*cur_tx;
117741502Swpaul	struct ifnet		*ifp;
117841502Swpaul
117941502Swpaul	ifp = &sc->arpcom.ac_if;
118041502Swpaul
118196677Ssilby	/* Reset the timeout timer; if_txeoc will clear it. */
118296677Ssilby	ifp->if_timer = 5;
118341502Swpaul
118441502Swpaul	/* Sanity check. */
118541502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
118641502Swpaul		return;
118741502Swpaul
118841502Swpaul	/*
118941502Swpaul	 * Go through our tx list and free mbufs for those
119041502Swpaul	 * frames that have been transmitted.
119141502Swpaul	 */
119241502Swpaul	while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) {
119341502Swpaul		u_int32_t		txstat;
1194110131Ssilby		int			i;
119541502Swpaul
119641502Swpaul		cur_tx = sc->vr_cdata.vr_tx_head;
119741502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
119841502Swpaul
1199101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
1200101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
1201110131Ssilby			for (i = 0x400;
1202110131Ssilby			     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON);
1203110131Ssilby			     i--)
1204101896Ssilby				;	/* Wait for chip to shutdown */
1205110131Ssilby			if (!i) {
1206110131Ssilby				printf("vr%d: tx shutdown timeout\n", sc->vr_unit);
1207110131Ssilby				sc->vr_flags |= VR_F_RESTART;
1208110131Ssilby				break;
1209110131Ssilby			}
1210101896Ssilby			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
1211101896Ssilby			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr));
1212101896Ssilby			break;
1213101896Ssilby		}
1214101896Ssilby
121542491Swpaul		if (txstat & VR_TXSTAT_OWN)
121641502Swpaul			break;
121741502Swpaul
121841502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
121941502Swpaul			ifp->if_oerrors++;
122041502Swpaul			if (txstat & VR_TXSTAT_DEFER)
122141502Swpaul				ifp->if_collisions++;
122241502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
122341502Swpaul				ifp->if_collisions++;
122441502Swpaul		}
122541502Swpaul
122641502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
122741502Swpaul
122841502Swpaul		ifp->if_opackets++;
122951432Swpaul		if (cur_tx->vr_mbuf != NULL) {
123051432Swpaul			m_freem(cur_tx->vr_mbuf);
123151432Swpaul			cur_tx->vr_mbuf = NULL;
123251432Swpaul		}
123341502Swpaul
123441502Swpaul		if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {
123541502Swpaul			sc->vr_cdata.vr_tx_head = NULL;
123641502Swpaul			sc->vr_cdata.vr_tx_tail = NULL;
123741502Swpaul			break;
123841502Swpaul		}
123941502Swpaul
124041502Swpaul		sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc;
124141502Swpaul	}
124241502Swpaul
124341502Swpaul	return;
124441502Swpaul}
124541502Swpaul
124641502Swpaul/*
124741502Swpaul * TX 'end of channel' interrupt handler.
124841502Swpaul */
1249102336Salfredstatic void
1250102336Salfredvr_txeoc(sc)
125141502Swpaul	struct vr_softc		*sc;
125241502Swpaul{
125341502Swpaul	struct ifnet		*ifp;
125441502Swpaul
125541502Swpaul	ifp = &sc->arpcom.ac_if;
125641502Swpaul
125741502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL) {
125841502Swpaul		ifp->if_flags &= ~IFF_OACTIVE;
125941502Swpaul		sc->vr_cdata.vr_tx_tail = NULL;
126096677Ssilby		ifp->if_timer = 0;
126141502Swpaul	}
126241502Swpaul
126341502Swpaul	return;
126441502Swpaul}
126541502Swpaul
1266102336Salfredstatic void
1267102336Salfredvr_tick(xsc)
126851432Swpaul	void			*xsc;
126951432Swpaul{
127051432Swpaul	struct vr_softc		*sc;
127151432Swpaul	struct mii_data		*mii;
127251432Swpaul
127351432Swpaul	sc = xsc;
127467087Swpaul	VR_LOCK(sc);
1275110131Ssilby	if (sc->vr_flags & VR_F_RESTART) {
1276110131Ssilby		printf("vr%d: restarting\n", sc->vr_unit);
1277110131Ssilby		vr_stop(sc);
1278110131Ssilby		vr_reset(sc);
1279110131Ssilby		vr_init(sc);
1280110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1281110131Ssilby	}
1282110131Ssilby
128351432Swpaul	mii = device_get_softc(sc->vr_miibus);
128451432Swpaul	mii_tick(mii);
128551432Swpaul
128651432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
128751432Swpaul
128867087Swpaul	VR_UNLOCK(sc);
128951432Swpaul
129051432Swpaul	return;
129151432Swpaul}
129251432Swpaul
1293102336Salfredstatic void
1294102336Salfredvr_intr(arg)
129541502Swpaul	void			*arg;
129641502Swpaul{
129741502Swpaul	struct vr_softc		*sc;
129841502Swpaul	struct ifnet		*ifp;
129941502Swpaul	u_int16_t		status;
130041502Swpaul
130141502Swpaul	sc = arg;
130267087Swpaul	VR_LOCK(sc);
130341502Swpaul	ifp = &sc->arpcom.ac_if;
130441502Swpaul
130541502Swpaul	/* Supress unwanted interrupts. */
130641502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
130741502Swpaul		vr_stop(sc);
130867087Swpaul		VR_UNLOCK(sc);
130941502Swpaul		return;
131041502Swpaul	}
131141502Swpaul
131241502Swpaul	/* Disable interrupts. */
131341502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
131441502Swpaul
131541502Swpaul	for (;;) {
131641502Swpaul
131741502Swpaul		status = CSR_READ_2(sc, VR_ISR);
131841502Swpaul		if (status)
131941502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
132041502Swpaul
132141502Swpaul		if ((status & VR_INTRS) == 0)
132241502Swpaul			break;
132341502Swpaul
132441502Swpaul		if (status & VR_ISR_RX_OK)
132541502Swpaul			vr_rxeof(sc);
132641502Swpaul
1327110131Ssilby		if (status & VR_ISR_RX_DROPPED) {
1328110131Ssilby			printf("vr%d: rx packet lost\n", sc->vr_unit);
1329110131Ssilby			ifp->if_ierrors++;
1330110131Ssilby			}
1331110131Ssilby
133241502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1333110131Ssilby		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1334110131Ssilby			printf("vr%d: receive error (%04x)",
1335110131Ssilby			       sc->vr_unit, status);
1336110131Ssilby			if (status & VR_ISR_RX_NOBUF)
1337110131Ssilby				printf(" no buffers");
1338110131Ssilby			if (status & VR_ISR_RX_OFLOW)
1339110131Ssilby				printf(" overflow");
1340110131Ssilby			if (status & VR_ISR_RX_DROPPED)
1341110131Ssilby				printf(" packet lost");
1342110131Ssilby			printf("\n");
134341502Swpaul			vr_rxeoc(sc);
134441502Swpaul		}
134541502Swpaul
1346101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1347101896Ssilby			vr_reset(sc);
1348101896Ssilby			vr_init(sc);
1349101896Ssilby			break;
135041502Swpaul		}
135141502Swpaul
1352101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1353101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
135441502Swpaul			vr_txeof(sc);
1355101896Ssilby			if ((status & VR_ISR_UDFI) ||
1356101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1357101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1358101896Ssilby				ifp->if_oerrors++;
1359101896Ssilby				if (sc->vr_cdata.vr_tx_head != NULL) {
1360101896Ssilby					VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1361101896Ssilby					VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1362101896Ssilby				}
1363101896Ssilby			} else
1364101896Ssilby				vr_txeoc(sc);
136541502Swpaul		}
136641502Swpaul
136741502Swpaul	}
136841502Swpaul
136941502Swpaul	/* Re-enable interrupts. */
137041502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
137141502Swpaul
137241502Swpaul	if (ifp->if_snd.ifq_head != NULL) {
137341502Swpaul		vr_start(ifp);
137441502Swpaul	}
137541502Swpaul
137667087Swpaul	VR_UNLOCK(sc);
137767087Swpaul
137841502Swpaul	return;
137941502Swpaul}
138041502Swpaul
138141502Swpaul/*
138241502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
138341502Swpaul * pointers to the fragment pointers.
138441502Swpaul */
1385102336Salfredstatic int
1386102336Salfredvr_encap(sc, c, m_head)
138741502Swpaul	struct vr_softc		*sc;
138841502Swpaul	struct vr_chain		*c;
138941502Swpaul	struct mbuf		*m_head;
139041502Swpaul{
139141502Swpaul	int			frag = 0;
139241502Swpaul	struct vr_desc		*f = NULL;
139341502Swpaul	int			total_len;
139441502Swpaul	struct mbuf		*m;
139541502Swpaul
139641502Swpaul	m = m_head;
139741502Swpaul	total_len = 0;
139841502Swpaul
139941502Swpaul	/*
140041502Swpaul	 * The VIA Rhine wants packet buffers to be longword
140141502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
140241502Swpaul	 * waste time trying to decide when to copy and when not
140341502Swpaul	 * to copy, just do it all the time.
140441502Swpaul	 */
140541502Swpaul	if (m != NULL) {
140641502Swpaul		struct mbuf		*m_new = NULL;
140741502Swpaul
1408112821Ssilby		m_new = m_defrag(m_head, M_DONTWAIT);
140941502Swpaul		if (m_new == NULL) {
141041502Swpaul			return(1);
141141502Swpaul		}
1412112821Ssilby
141341502Swpaul		m_head = m_new;
141441502Swpaul		/*
141541502Swpaul		 * The Rhine chip doesn't auto-pad, so we have to make
141641502Swpaul		 * sure to pad short frames out to the minimum frame length
141741502Swpaul		 * ourselves.
141841502Swpaul		 */
141941502Swpaul		if (m_head->m_len < VR_MIN_FRAMELEN) {
142041502Swpaul			m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
142141502Swpaul			m_new->m_len = m_new->m_pkthdr.len;
142241502Swpaul		}
142341502Swpaul		f = c->vr_ptr;
142441502Swpaul		f->vr_data = vtophys(mtod(m_new, caddr_t));
142541502Swpaul		f->vr_ctl = total_len = m_new->m_len;
142641502Swpaul		f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
142741502Swpaul		f->vr_status = 0;
142841502Swpaul		frag = 1;
142941502Swpaul	}
143041502Swpaul
143141502Swpaul	c->vr_mbuf = m_head;
143242491Swpaul	c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
143341502Swpaul	c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
143441502Swpaul
143541502Swpaul	return(0);
143641502Swpaul}
143741502Swpaul
143841502Swpaul/*
143941502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
144041502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
144141502Swpaul * copy of the pointers since the transmit list fragment pointers are
144241502Swpaul * physical addresses.
144341502Swpaul */
144441502Swpaul
1445102336Salfredstatic void
1446102336Salfredvr_start(ifp)
144741502Swpaul	struct ifnet		*ifp;
144841502Swpaul{
144941502Swpaul	struct vr_softc		*sc;
145041502Swpaul	struct mbuf		*m_head = NULL;
1451113274Ssilby	struct vr_chain		*cur_tx = NULL, *start_tx, *prev_tx;
145241502Swpaul
145341502Swpaul	sc = ifp->if_softc;
145441502Swpaul
145567087Swpaul	VR_LOCK(sc);
145641502Swpaul
145741502Swpaul	/*
145841502Swpaul	 * Check for an available queue slot. If there are none,
145941502Swpaul	 * punt.
146041502Swpaul	 */
146141502Swpaul	if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) {
1462113274Ssilby		VR_UNLOCK(sc);
146341502Swpaul		return;
146441502Swpaul	}
146541502Swpaul
146641502Swpaul	start_tx = sc->vr_cdata.vr_tx_free;
146741502Swpaul
146841502Swpaul	while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) {
146941502Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
147041502Swpaul		if (m_head == NULL)
147141502Swpaul			break;
147241502Swpaul
147341502Swpaul		/* Pick a descriptor off the free list. */
1474113274Ssilby		prev_tx = cur_tx;
147541502Swpaul		cur_tx = sc->vr_cdata.vr_tx_free;
147641502Swpaul		sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc;
147741502Swpaul
147841502Swpaul		/* Pack the data into the descriptor. */
147971271Swpaul		if (vr_encap(sc, cur_tx, m_head)) {
1480113274Ssilby			/* Rollback, send what we were able to encap. */
148171271Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
1482113274Ssilby			sc->vr_cdata.vr_tx_free = cur_tx;
1483113274Ssilby			cur_tx = prev_tx;
148471271Swpaul			break;
148571271Swpaul		}
148641502Swpaul
148741502Swpaul		if (cur_tx != start_tx)
148841502Swpaul			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
148941502Swpaul
149041502Swpaul		/*
149141502Swpaul		 * If there's a BPF listener, bounce a copy of this frame
149241502Swpaul		 * to him.
149341502Swpaul		 */
1494106936Ssam		BPF_MTAP(ifp, cur_tx->vr_mbuf);
149551583Swpaul
149642491Swpaul		VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
149741502Swpaul	}
149841502Swpaul
149941502Swpaul	/*
150041526Swpaul	 * If there are no frames queued, bail.
150141526Swpaul	 */
150267087Swpaul	if (cur_tx == NULL) {
150367087Swpaul		VR_UNLOCK(sc);
150441526Swpaul		return;
150567087Swpaul	}
150641526Swpaul
150741502Swpaul	sc->vr_cdata.vr_tx_tail = cur_tx;
150841502Swpaul
150942491Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
151041502Swpaul		sc->vr_cdata.vr_tx_head = start_tx;
1511113274Ssilby
1512113274Ssilby	/* Tell the chip to start transmitting. */
1513113274Ssilby	VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO);
151441502Swpaul
151541502Swpaul	/*
151641502Swpaul	 * Set a timeout in case the chip goes out to lunch.
151741502Swpaul	 */
151841502Swpaul	ifp->if_timer = 5;
151967087Swpaul	VR_UNLOCK(sc);
152041502Swpaul
152141502Swpaul	return;
152241502Swpaul}
152341502Swpaul
1524102336Salfredstatic void
1525102336Salfredvr_init(xsc)
152641502Swpaul	void			*xsc;
152741502Swpaul{
152841502Swpaul	struct vr_softc		*sc = xsc;
152941502Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
153051432Swpaul	struct mii_data		*mii;
153173963Swpaul	int			i;
153241502Swpaul
153367087Swpaul	VR_LOCK(sc);
153441502Swpaul
153551432Swpaul	mii = device_get_softc(sc->vr_miibus);
153641502Swpaul
153741502Swpaul	/*
153841502Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
153941502Swpaul	 */
154041502Swpaul	vr_stop(sc);
154141502Swpaul	vr_reset(sc);
154241502Swpaul
154373963Swpaul	/*
154473963Swpaul	 * Set our station address.
154573963Swpaul	 */
154673963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
154773963Swpaul		CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]);
1548101375Ssilby
1549101375Ssilby	/* Set DMA size */
1550101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1551101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
155273963Swpaul
1553101375Ssilby	/*
1554101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1555101108Ssilby	 * so we must set both.
1556101108Ssilby	 */
1557101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1558110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
1559101108Ssilby
1560101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1561101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1562101108Ssilby
156341502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
1564110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
156541502Swpaul
156641502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
156741502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
156841502Swpaul
156941502Swpaul	/* Init circular RX list. */
157041502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
157141502Swpaul		printf("vr%d: initialization failed: no "
157241502Swpaul			"memory for rx buffers\n", sc->vr_unit);
157341502Swpaul		vr_stop(sc);
157467087Swpaul		VR_UNLOCK(sc);
157541502Swpaul		return;
157641502Swpaul	}
157741502Swpaul
157841502Swpaul	/*
157941502Swpaul	 * Init tx descriptors.
158041502Swpaul	 */
158141502Swpaul	vr_list_tx_init(sc);
158241502Swpaul
158341502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
158441502Swpaul	if (ifp->if_flags & IFF_PROMISC)
158541502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
158641502Swpaul	else
158741502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
158841502Swpaul
158941502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
159041502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
159141502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
159241502Swpaul	else
159341502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
159441502Swpaul
159541502Swpaul	/*
159641502Swpaul	 * Program the multicast filter, if necessary.
159741502Swpaul	 */
159841502Swpaul	vr_setmulti(sc);
159941502Swpaul
160041502Swpaul	/*
160141502Swpaul	 * Load the address of the RX list.
160241502Swpaul	 */
160341502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
160441502Swpaul
160541502Swpaul	/* Enable receiver and transmitter. */
160641502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
160741502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
160841502Swpaul				    VR_CMD_RX_GO);
160941502Swpaul
161041502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
161141502Swpaul
161241502Swpaul	/*
161341502Swpaul	 * Enable interrupts.
161441502Swpaul	 */
161541502Swpaul	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
161641502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
161741502Swpaul
161851432Swpaul	mii_mediachg(mii);
161941502Swpaul
162041502Swpaul	ifp->if_flags |= IFF_RUNNING;
162141502Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
162241502Swpaul
162351432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
162451432Swpaul
162567087Swpaul	VR_UNLOCK(sc);
162667087Swpaul
162741502Swpaul	return;
162841502Swpaul}
162941502Swpaul
163041502Swpaul/*
163141502Swpaul * Set media options.
163241502Swpaul */
1633102336Salfredstatic int
1634102336Salfredvr_ifmedia_upd(ifp)
163541502Swpaul	struct ifnet		*ifp;
163641502Swpaul{
163741502Swpaul	struct vr_softc		*sc;
163841502Swpaul
163941502Swpaul	sc = ifp->if_softc;
164041502Swpaul
164151432Swpaul	if (ifp->if_flags & IFF_UP)
164251432Swpaul		vr_init(sc);
164341502Swpaul
164441502Swpaul	return(0);
164541502Swpaul}
164641502Swpaul
164741502Swpaul/*
164841502Swpaul * Report current media status.
164941502Swpaul */
1650102336Salfredstatic void
1651102336Salfredvr_ifmedia_sts(ifp, ifmr)
165241502Swpaul	struct ifnet		*ifp;
165341502Swpaul	struct ifmediareq	*ifmr;
165441502Swpaul{
165541502Swpaul	struct vr_softc		*sc;
165651432Swpaul	struct mii_data		*mii;
165741502Swpaul
165841502Swpaul	sc = ifp->if_softc;
165951432Swpaul	mii = device_get_softc(sc->vr_miibus);
166051432Swpaul	mii_pollstat(mii);
166151432Swpaul	ifmr->ifm_active = mii->mii_media_active;
166251432Swpaul	ifmr->ifm_status = mii->mii_media_status;
166341502Swpaul
166441502Swpaul	return;
166541502Swpaul}
166641502Swpaul
1667102336Salfredstatic int
1668102336Salfredvr_ioctl(ifp, command, data)
166941502Swpaul	struct ifnet		*ifp;
167041502Swpaul	u_long			command;
167141502Swpaul	caddr_t			data;
167241502Swpaul{
167341502Swpaul	struct vr_softc		*sc = ifp->if_softc;
167441502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
167551432Swpaul	struct mii_data		*mii;
167667087Swpaul	int			error = 0;
167741502Swpaul
167867087Swpaul	VR_LOCK(sc);
167941502Swpaul
168041502Swpaul	switch(command) {
168141502Swpaul	case SIOCSIFFLAGS:
168241502Swpaul		if (ifp->if_flags & IFF_UP) {
168341502Swpaul			vr_init(sc);
168441502Swpaul		} else {
168541502Swpaul			if (ifp->if_flags & IFF_RUNNING)
168641502Swpaul				vr_stop(sc);
168741502Swpaul		}
168841502Swpaul		error = 0;
168941502Swpaul		break;
169041502Swpaul	case SIOCADDMULTI:
169141502Swpaul	case SIOCDELMULTI:
169241502Swpaul		vr_setmulti(sc);
169341502Swpaul		error = 0;
169441502Swpaul		break;
169541502Swpaul	case SIOCGIFMEDIA:
169641502Swpaul	case SIOCSIFMEDIA:
169751432Swpaul		mii = device_get_softc(sc->vr_miibus);
169851432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
169941502Swpaul		break;
170041502Swpaul	default:
1701106936Ssam		error = ether_ioctl(ifp, command, data);
170241502Swpaul		break;
170341502Swpaul	}
170441502Swpaul
170567087Swpaul	VR_UNLOCK(sc);
170641502Swpaul
170741502Swpaul	return(error);
170841502Swpaul}
170941502Swpaul
1710102336Salfredstatic void
1711102336Salfredvr_watchdog(ifp)
171241502Swpaul	struct ifnet		*ifp;
171341502Swpaul{
171441502Swpaul	struct vr_softc		*sc;
171541502Swpaul
171641502Swpaul	sc = ifp->if_softc;
171741502Swpaul
171867087Swpaul	VR_LOCK(sc);
171941502Swpaul	ifp->if_oerrors++;
172041502Swpaul	printf("vr%d: watchdog timeout\n", sc->vr_unit);
172141502Swpaul
172241502Swpaul	vr_stop(sc);
172341502Swpaul	vr_reset(sc);
172441502Swpaul	vr_init(sc);
172541502Swpaul
172641502Swpaul	if (ifp->if_snd.ifq_head != NULL)
172741502Swpaul		vr_start(ifp);
172841502Swpaul
172967087Swpaul	VR_UNLOCK(sc);
173067087Swpaul
173141502Swpaul	return;
173241502Swpaul}
173341502Swpaul
173441502Swpaul/*
173541502Swpaul * Stop the adapter and free any mbufs allocated to the
173641502Swpaul * RX and TX lists.
173741502Swpaul */
1738102336Salfredstatic void
1739102336Salfredvr_stop(sc)
174041502Swpaul	struct vr_softc		*sc;
174141502Swpaul{
174241502Swpaul	register int		i;
174341502Swpaul	struct ifnet		*ifp;
174441502Swpaul
174567087Swpaul	VR_LOCK(sc);
174667087Swpaul
174741502Swpaul	ifp = &sc->arpcom.ac_if;
174841502Swpaul	ifp->if_timer = 0;
174941502Swpaul
175051432Swpaul	untimeout(vr_tick, sc, sc->vr_stat_ch);
175151432Swpaul
175241502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
175341502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
175441502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
175541502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
175641502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
175741502Swpaul
175841502Swpaul	/*
175941502Swpaul	 * Free data in the RX lists.
176041502Swpaul	 */
176141502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
176241502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
176341502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
176441502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
176541502Swpaul		}
176641502Swpaul	}
176741502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
176841502Swpaul		sizeof(sc->vr_ldata->vr_rx_list));
176941502Swpaul
177041502Swpaul	/*
177141502Swpaul	 * Free the TX list buffers.
177241502Swpaul	 */
177341502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
177441502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
177541502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
177641502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
177741502Swpaul		}
177841502Swpaul	}
177941502Swpaul
178041502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
178141502Swpaul		sizeof(sc->vr_ldata->vr_tx_list));
178241502Swpaul
178341502Swpaul	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
178467087Swpaul	VR_UNLOCK(sc);
178541502Swpaul
178641502Swpaul	return;
178741502Swpaul}
178841502Swpaul
178941502Swpaul/*
179041502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
179141502Swpaul * get confused by errant DMAs when rebooting.
179241502Swpaul */
1793102336Salfredstatic void
1794102336Salfredvr_shutdown(dev)
179549610Swpaul	device_t		dev;
179641502Swpaul{
179749610Swpaul	struct vr_softc		*sc;
179841502Swpaul
179949610Swpaul	sc = device_get_softc(dev);
180049610Swpaul
180141502Swpaul	vr_stop(sc);
180241502Swpaul
180341502Swpaul	return;
180441502Swpaul}
1805