if_vr.c revision 105221
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 105221 2002-10-16 09:14:59Z phk $
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
6241502Swpaul#include <sys/param.h>
6341502Swpaul#include <sys/systm.h>
6441502Swpaul#include <sys/sockio.h>
6541502Swpaul#include <sys/mbuf.h>
6641502Swpaul#include <sys/malloc.h>
6741502Swpaul#include <sys/kernel.h>
6841502Swpaul#include <sys/socket.h>
6941502Swpaul
7041502Swpaul#include <net/if.h>
7141502Swpaul#include <net/if_arp.h>
7241502Swpaul#include <net/ethernet.h>
7341502Swpaul#include <net/if_dl.h>
7441502Swpaul#include <net/if_media.h>
7541502Swpaul
7641502Swpaul#include <net/bpf.h>
7741502Swpaul
7841502Swpaul#include <vm/vm.h>              /* for vtophys */
7941502Swpaul#include <vm/pmap.h>            /* for vtophys */
8041502Swpaul#include <machine/bus_pio.h>
8141502Swpaul#include <machine/bus_memio.h>
8241502Swpaul#include <machine/bus.h>
8349610Swpaul#include <machine/resource.h>
8449610Swpaul#include <sys/bus.h>
8549610Swpaul#include <sys/rman.h>
8641502Swpaul
8751432Swpaul#include <dev/mii/mii.h>
8851432Swpaul#include <dev/mii/miivar.h>
8951432Swpaul
9041502Swpaul#include <pci/pcireg.h>
9141502Swpaul#include <pci/pcivar.h>
9241502Swpaul
9341502Swpaul#define VR_USEIOSPACE
9441502Swpaul
9541502Swpaul#include <pci/if_vrreg.h>
9641502Swpaul
9759758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
9859758Speter
9951432Swpaul/* "controller miibus0" required.  See GENERIC if you get errors here. */
10051432Swpaul#include "miibus_if.h"
10151432Swpaul
10241502Swpaul#ifndef lint
10341591Sarchiestatic const char rcsid[] =
10450477Speter  "$FreeBSD: head/sys/dev/vr/if_vr.c 105221 2002-10-16 09:14:59Z phk $";
10541502Swpaul#endif
10641502Swpaul
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" },
11744238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
11844238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
11944238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
12044238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
12141502Swpaul	{ 0, 0, NULL }
12241502Swpaul};
12341502Swpaul
12492739Salfredstatic int vr_probe		(device_t);
12592739Salfredstatic int vr_attach		(device_t);
12692739Salfredstatic int vr_detach		(device_t);
12741502Swpaul
12892739Salfredstatic int vr_newbuf		(struct vr_softc *,
12949610Swpaul					struct vr_chain_onefrag *,
13092739Salfred					struct mbuf *);
13192739Salfredstatic int vr_encap		(struct vr_softc *, struct vr_chain *,
13292739Salfred						struct mbuf * );
13341502Swpaul
13492739Salfredstatic void vr_rxeof		(struct vr_softc *);
13592739Salfredstatic void vr_rxeoc		(struct vr_softc *);
13692739Salfredstatic void vr_txeof		(struct vr_softc *);
13792739Salfredstatic void vr_txeoc		(struct vr_softc *);
13892739Salfredstatic void vr_tick		(void *);
13992739Salfredstatic void vr_intr		(void *);
14092739Salfredstatic void vr_start		(struct ifnet *);
14192739Salfredstatic int vr_ioctl		(struct ifnet *, u_long, caddr_t);
14292739Salfredstatic void vr_init		(void *);
14392739Salfredstatic void vr_stop		(struct vr_softc *);
14492739Salfredstatic void vr_watchdog		(struct ifnet *);
14592739Salfredstatic void vr_shutdown		(device_t);
14692739Salfredstatic int vr_ifmedia_upd	(struct ifnet *);
14792739Salfredstatic void vr_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
14841502Swpaul
14992739Salfredstatic void vr_mii_sync		(struct vr_softc *);
15092739Salfredstatic void vr_mii_send		(struct vr_softc *, u_int32_t, int);
15192739Salfredstatic int vr_mii_readreg	(struct vr_softc *, struct vr_mii_frame *);
15292739Salfredstatic int vr_mii_writereg	(struct vr_softc *, struct vr_mii_frame *);
15392739Salfredstatic int vr_miibus_readreg	(device_t, int, int);
15492739Salfredstatic int vr_miibus_writereg	(device_t, int, int, int);
15592739Salfredstatic void vr_miibus_statchg	(device_t);
15641502Swpaul
15792739Salfredstatic void vr_setcfg		(struct vr_softc *, int);
15892739Salfredstatic u_int8_t vr_calchash	(u_int8_t *);
15992739Salfredstatic void vr_setmulti		(struct vr_softc *);
16092739Salfredstatic void vr_reset		(struct vr_softc *);
16192739Salfredstatic int vr_list_rx_init	(struct vr_softc *);
16292739Salfredstatic int vr_list_tx_init	(struct vr_softc *);
16341502Swpaul
16449610Swpaul#ifdef VR_USEIOSPACE
16549610Swpaul#define VR_RES			SYS_RES_IOPORT
16649610Swpaul#define VR_RID			VR_PCI_LOIO
16749610Swpaul#else
16849610Swpaul#define VR_RES			SYS_RES_MEMORY
16949610Swpaul#define VR_RID			VR_PCI_LOMEM
17049610Swpaul#endif
17149610Swpaul
17249610Swpaulstatic device_method_t vr_methods[] = {
17349610Swpaul	/* Device interface */
17449610Swpaul	DEVMETHOD(device_probe,		vr_probe),
17549610Swpaul	DEVMETHOD(device_attach,	vr_attach),
17649610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
17749610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
17851432Swpaul
17951432Swpaul	/* bus interface */
18051432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18151432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
18251432Swpaul
18351432Swpaul	/* MII interface */
18451432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
18551432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
18651432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
18751432Swpaul
18849610Swpaul	{ 0, 0 }
18949610Swpaul};
19049610Swpaul
19149610Swpaulstatic driver_t vr_driver = {
19251455Swpaul	"vr",
19349610Swpaul	vr_methods,
19449610Swpaul	sizeof(struct vr_softc)
19549610Swpaul};
19649610Swpaul
19749610Swpaulstatic devclass_t vr_devclass;
19849610Swpaul
19951533SwpaulDRIVER_MODULE(if_vr, pci, vr_driver, vr_devclass, 0, 0);
20051473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
20149610Swpaul
20241502Swpaul#define VR_SETBIT(sc, reg, x)				\
20341502Swpaul	CSR_WRITE_1(sc, reg,				\
204105221Sphk		CSR_READ_1(sc, reg) | (x))
20541502Swpaul
20641502Swpaul#define VR_CLRBIT(sc, reg, x)				\
20741502Swpaul	CSR_WRITE_1(sc, reg,				\
208105221Sphk		CSR_READ_1(sc, reg) & ~(x))
20941502Swpaul
21041502Swpaul#define VR_SETBIT16(sc, reg, x)				\
21141502Swpaul	CSR_WRITE_2(sc, reg,				\
212105221Sphk		CSR_READ_2(sc, reg) | (x))
21341502Swpaul
21441502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
21541502Swpaul	CSR_WRITE_2(sc, reg,				\
216105221Sphk		CSR_READ_2(sc, reg) & ~(x))
21741502Swpaul
21841502Swpaul#define VR_SETBIT32(sc, reg, x)				\
21941502Swpaul	CSR_WRITE_4(sc, reg,				\
220105221Sphk		CSR_READ_4(sc, reg) | (x))
22141502Swpaul
22241502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
22341502Swpaul	CSR_WRITE_4(sc, reg,				\
224105221Sphk		CSR_READ_4(sc, reg) & ~(x))
22541502Swpaul
22641502Swpaul#define SIO_SET(x)					\
22741502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
228105221Sphk		CSR_READ_1(sc, VR_MIICMD) | (x))
22941502Swpaul
23041502Swpaul#define SIO_CLR(x)					\
23141502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
232105221Sphk		CSR_READ_1(sc, VR_MIICMD) & ~(x))
23341502Swpaul
23441502Swpaul/*
23541502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
23641502Swpaul */
237102336Salfredstatic void
238102336Salfredvr_mii_sync(sc)
23941502Swpaul	struct vr_softc		*sc;
24041502Swpaul{
24141502Swpaul	register int		i;
24241502Swpaul
24341502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
24441502Swpaul
24541502Swpaul	for (i = 0; i < 32; i++) {
24641502Swpaul		SIO_SET(VR_MIICMD_CLK);
24741502Swpaul		DELAY(1);
24841502Swpaul		SIO_CLR(VR_MIICMD_CLK);
24941502Swpaul		DELAY(1);
25041502Swpaul	}
25141502Swpaul
25241502Swpaul	return;
25341502Swpaul}
25441502Swpaul
25541502Swpaul/*
25641502Swpaul * Clock a series of bits through the MII.
25741502Swpaul */
258102336Salfredstatic void
259102336Salfredvr_mii_send(sc, bits, cnt)
26041502Swpaul	struct vr_softc		*sc;
26141502Swpaul	u_int32_t		bits;
26241502Swpaul	int			cnt;
26341502Swpaul{
26441502Swpaul	int			i;
26541502Swpaul
26641502Swpaul	SIO_CLR(VR_MIICMD_CLK);
26741502Swpaul
26841502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
26941502Swpaul                if (bits & i) {
27041502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
27141502Swpaul                } else {
27241502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
27341502Swpaul                }
27441502Swpaul		DELAY(1);
27541502Swpaul		SIO_CLR(VR_MIICMD_CLK);
27641502Swpaul		DELAY(1);
27741502Swpaul		SIO_SET(VR_MIICMD_CLK);
27841502Swpaul	}
27941502Swpaul}
28041502Swpaul
28141502Swpaul/*
28241502Swpaul * Read an PHY register through the MII.
28341502Swpaul */
284102336Salfredstatic int
285102336Salfredvr_mii_readreg(sc, frame)
28641502Swpaul	struct vr_softc		*sc;
28741502Swpaul	struct vr_mii_frame	*frame;
28841502Swpaul
28941502Swpaul{
29067087Swpaul	int			i, ack;
29141502Swpaul
29267087Swpaul	VR_LOCK(sc);
29341502Swpaul
29441502Swpaul	/*
29541502Swpaul	 * Set up frame for RX.
29641502Swpaul	 */
29741502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
29841502Swpaul	frame->mii_opcode = VR_MII_READOP;
29941502Swpaul	frame->mii_turnaround = 0;
30041502Swpaul	frame->mii_data = 0;
30141502Swpaul
30241502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
30341502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
30441502Swpaul
30541502Swpaul	/*
30641502Swpaul 	 * Turn on data xmit.
30741502Swpaul	 */
30841502Swpaul	SIO_SET(VR_MIICMD_DIR);
30941502Swpaul
31041502Swpaul	vr_mii_sync(sc);
31141502Swpaul
31241502Swpaul	/*
31341502Swpaul	 * Send command/address info.
31441502Swpaul	 */
31541502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
31641502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
31741502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
31841502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
31941502Swpaul
32041502Swpaul	/* Idle bit */
32141502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
32241502Swpaul	DELAY(1);
32341502Swpaul	SIO_SET(VR_MIICMD_CLK);
32441502Swpaul	DELAY(1);
32541502Swpaul
32641502Swpaul	/* Turn off xmit. */
32741502Swpaul	SIO_CLR(VR_MIICMD_DIR);
32841502Swpaul
32941502Swpaul	/* Check for ack */
33041502Swpaul	SIO_CLR(VR_MIICMD_CLK);
33141502Swpaul	DELAY(1);
33241502Swpaul	SIO_SET(VR_MIICMD_CLK);
33341502Swpaul	DELAY(1);
33441502Swpaul	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
33541502Swpaul
33641502Swpaul	/*
33741502Swpaul	 * Now try reading data bits. If the ack failed, we still
33841502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
33941502Swpaul	 */
34041502Swpaul	if (ack) {
34141502Swpaul		for(i = 0; i < 16; i++) {
34241502Swpaul			SIO_CLR(VR_MIICMD_CLK);
34341502Swpaul			DELAY(1);
34441502Swpaul			SIO_SET(VR_MIICMD_CLK);
34541502Swpaul			DELAY(1);
34641502Swpaul		}
34741502Swpaul		goto fail;
34841502Swpaul	}
34941502Swpaul
35041502Swpaul	for (i = 0x8000; i; i >>= 1) {
35141502Swpaul		SIO_CLR(VR_MIICMD_CLK);
35241502Swpaul		DELAY(1);
35341502Swpaul		if (!ack) {
35441502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
35541502Swpaul				frame->mii_data |= i;
35641502Swpaul			DELAY(1);
35741502Swpaul		}
35841502Swpaul		SIO_SET(VR_MIICMD_CLK);
35941502Swpaul		DELAY(1);
36041502Swpaul	}
36141502Swpaul
36241502Swpaulfail:
36341502Swpaul
36441502Swpaul	SIO_CLR(VR_MIICMD_CLK);
36541502Swpaul	DELAY(1);
36641502Swpaul	SIO_SET(VR_MIICMD_CLK);
36741502Swpaul	DELAY(1);
36841502Swpaul
36967087Swpaul	VR_UNLOCK(sc);
37041502Swpaul
37141502Swpaul	if (ack)
37241502Swpaul		return(1);
37341502Swpaul	return(0);
37441502Swpaul}
37541502Swpaul
37641502Swpaul/*
37741502Swpaul * Write to a PHY register through the MII.
37841502Swpaul */
379102336Salfredstatic int
380102336Salfredvr_mii_writereg(sc, frame)
38141502Swpaul	struct vr_softc		*sc;
38241502Swpaul	struct vr_mii_frame	*frame;
38341502Swpaul
38441502Swpaul{
38567087Swpaul	VR_LOCK(sc);
38641502Swpaul
38741502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
38841502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
38941502Swpaul
39041502Swpaul	/*
39141502Swpaul	 * Set up frame for TX.
39241502Swpaul	 */
39341502Swpaul
39441502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
39541502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
39641502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
39741502Swpaul
39841502Swpaul	/*
39941502Swpaul 	 * Turn on data output.
40041502Swpaul	 */
40141502Swpaul	SIO_SET(VR_MIICMD_DIR);
40241502Swpaul
40341502Swpaul	vr_mii_sync(sc);
40441502Swpaul
40541502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
40641502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
40741502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
40841502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
40941502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
41041502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
41141502Swpaul
41241502Swpaul	/* Idle bit. */
41341502Swpaul	SIO_SET(VR_MIICMD_CLK);
41441502Swpaul	DELAY(1);
41541502Swpaul	SIO_CLR(VR_MIICMD_CLK);
41641502Swpaul	DELAY(1);
41741502Swpaul
41841502Swpaul	/*
41941502Swpaul	 * Turn off xmit.
42041502Swpaul	 */
42141502Swpaul	SIO_CLR(VR_MIICMD_DIR);
42241502Swpaul
42367087Swpaul	VR_UNLOCK(sc);
42441502Swpaul
42541502Swpaul	return(0);
42641502Swpaul}
42741502Swpaul
428102336Salfredstatic int
429102336Salfredvr_miibus_readreg(dev, phy, reg)
43051432Swpaul	device_t		dev;
43151432Swpaul	int			phy, reg;
43251432Swpaul{
43341502Swpaul	struct vr_softc		*sc;
43441502Swpaul	struct vr_mii_frame	frame;
43541502Swpaul
43651432Swpaul	sc = device_get_softc(dev);
43741502Swpaul	bzero((char *)&frame, sizeof(frame));
43841502Swpaul
43951432Swpaul	frame.mii_phyaddr = phy;
44041502Swpaul	frame.mii_regaddr = reg;
44141502Swpaul	vr_mii_readreg(sc, &frame);
44241502Swpaul
44341502Swpaul	return(frame.mii_data);
44441502Swpaul}
44541502Swpaul
446102336Salfredstatic int
447102336Salfredvr_miibus_writereg(dev, phy, reg, data)
44851432Swpaul	device_t		dev;
44951432Swpaul	u_int16_t		phy, reg, data;
45051432Swpaul{
45141502Swpaul	struct vr_softc		*sc;
45241502Swpaul	struct vr_mii_frame	frame;
45341502Swpaul
45451432Swpaul	sc = device_get_softc(dev);
45541502Swpaul	bzero((char *)&frame, sizeof(frame));
45641502Swpaul
45751432Swpaul	frame.mii_phyaddr = phy;
45841502Swpaul	frame.mii_regaddr = reg;
45941502Swpaul	frame.mii_data = data;
46041502Swpaul
46141502Swpaul	vr_mii_writereg(sc, &frame);
46241502Swpaul
46351432Swpaul	return(0);
46451432Swpaul}
46551432Swpaul
466102336Salfredstatic void
467102336Salfredvr_miibus_statchg(dev)
46851432Swpaul	device_t		dev;
46951432Swpaul{
47051432Swpaul	struct vr_softc		*sc;
47151432Swpaul	struct mii_data		*mii;
47251432Swpaul
47351432Swpaul	sc = device_get_softc(dev);
47467087Swpaul	VR_LOCK(sc);
47551432Swpaul	mii = device_get_softc(sc->vr_miibus);
47651432Swpaul	vr_setcfg(sc, mii->mii_media_active);
47767087Swpaul	VR_UNLOCK(sc);
47851432Swpaul
47941502Swpaul	return;
48041502Swpaul}
48141502Swpaul
48241502Swpaul/*
48341502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits.
48441502Swpaul */
48541502Swpaulstatic u_int8_t vr_calchash(addr)
48641502Swpaul	u_int8_t		*addr;
48741502Swpaul{
48841502Swpaul	u_int32_t		crc, carry;
48941502Swpaul	int			i, j;
49041502Swpaul	u_int8_t		c;
49141502Swpaul
49241502Swpaul	/* Compute CRC for the address value. */
49341502Swpaul	crc = 0xFFFFFFFF; /* initial value */
49441502Swpaul
49541502Swpaul	for (i = 0; i < 6; i++) {
49641502Swpaul		c = *(addr + i);
49741502Swpaul		for (j = 0; j < 8; j++) {
49841502Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
49941502Swpaul			crc <<= 1;
50041502Swpaul			c >>= 1;
50141502Swpaul			if (carry)
50241502Swpaul				crc = (crc ^ 0x04c11db6) | carry;
50341502Swpaul		}
50441502Swpaul	}
50541502Swpaul
50641502Swpaul	/* return the filter bit position */
50741502Swpaul	return((crc >> 26) & 0x0000003F);
50841502Swpaul}
50941502Swpaul
51041502Swpaul/*
51141502Swpaul * Program the 64-bit multicast hash filter.
51241502Swpaul */
513102336Salfredstatic void
514102336Salfredvr_setmulti(sc)
51541502Swpaul	struct vr_softc		*sc;
51641502Swpaul{
51741502Swpaul	struct ifnet		*ifp;
51841502Swpaul	int			h = 0;
51941502Swpaul	u_int32_t		hashes[2] = { 0, 0 };
52041502Swpaul	struct ifmultiaddr	*ifma;
52141502Swpaul	u_int8_t		rxfilt;
52241502Swpaul	int			mcnt = 0;
52341502Swpaul
52441502Swpaul	ifp = &sc->arpcom.ac_if;
52541502Swpaul
52641502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
52741502Swpaul
52841502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
52941502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
53041502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
53141502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
53241502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
53341502Swpaul		return;
53441502Swpaul	}
53541502Swpaul
53641502Swpaul	/* first, zot all the existing hash bits */
53741502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
53841502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
53941502Swpaul
54041502Swpaul	/* now program new ones */
54172084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
54241502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
54341502Swpaul			continue;
54441502Swpaul		h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
54541502Swpaul		if (h < 32)
54641502Swpaul			hashes[0] |= (1 << h);
54741502Swpaul		else
54841502Swpaul			hashes[1] |= (1 << (h - 32));
54941502Swpaul		mcnt++;
55041502Swpaul	}
55141502Swpaul
55241502Swpaul	if (mcnt)
55341502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
55441502Swpaul	else
55541502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
55641502Swpaul
55741502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
55841502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
55941502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
56041502Swpaul
56141502Swpaul	return;
56241502Swpaul}
56341502Swpaul
56441502Swpaul/*
56541502Swpaul * In order to fiddle with the
56641502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
56741502Swpaul * first have to put the transmit and/or receive logic in the idle state.
56841502Swpaul */
569102336Salfredstatic void
570102336Salfredvr_setcfg(sc, media)
57141502Swpaul	struct vr_softc		*sc;
57251432Swpaul	int			media;
57341502Swpaul{
57441502Swpaul	int			restart = 0;
57541502Swpaul
57641502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
57741502Swpaul		restart = 1;
57841502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
57941502Swpaul	}
58041502Swpaul
58151432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
58241502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58341502Swpaul	else
58441502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58541502Swpaul
58641502Swpaul	if (restart)
58741502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
58841502Swpaul
58941502Swpaul	return;
59041502Swpaul}
59141502Swpaul
592102336Salfredstatic void
593102336Salfredvr_reset(sc)
59441502Swpaul	struct vr_softc		*sc;
59541502Swpaul{
59641502Swpaul	register int		i;
59741502Swpaul
59841502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
59941502Swpaul
60041502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
60141502Swpaul		DELAY(10);
60241502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
60341502Swpaul			break;
60441502Swpaul	}
60541502Swpaul	if (i == VR_TIMEOUT)
60641502Swpaul		printf("vr%d: reset never completed!\n", sc->vr_unit);
60741502Swpaul
60841502Swpaul	/* Wait a little while for the chip to get its brains in order. */
60941502Swpaul	DELAY(1000);
61041502Swpaul
61141502Swpaul        return;
61241502Swpaul}
61341502Swpaul
61441502Swpaul/*
61541502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
61641502Swpaul * IDs against our list and return a device name if we find a match.
61741502Swpaul */
618102336Salfredstatic int
619102336Salfredvr_probe(dev)
62049610Swpaul	device_t		dev;
62141502Swpaul{
62241502Swpaul	struct vr_type		*t;
62341502Swpaul
62441502Swpaul	t = vr_devs;
62541502Swpaul
62641502Swpaul	while(t->vr_name != NULL) {
62749610Swpaul		if ((pci_get_vendor(dev) == t->vr_vid) &&
62849610Swpaul		    (pci_get_device(dev) == t->vr_did)) {
62949610Swpaul			device_set_desc(dev, t->vr_name);
63049610Swpaul			return(0);
63141502Swpaul		}
63241502Swpaul		t++;
63341502Swpaul	}
63441502Swpaul
63549610Swpaul	return(ENXIO);
63641502Swpaul}
63741502Swpaul
63841502Swpaul/*
63941502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
64041502Swpaul * setup and ethernet/BPF attach.
64141502Swpaul */
642102336Salfredstatic int
643102336Salfredvr_attach(dev)
64449610Swpaul	device_t		dev;
64541502Swpaul{
64667087Swpaul	int			i;
64741502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
64841502Swpaul	u_int32_t		command;
64941502Swpaul	struct vr_softc		*sc;
65041502Swpaul	struct ifnet		*ifp;
65149610Swpaul	int			unit, error = 0, rid;
65241502Swpaul
65349610Swpaul	sc = device_get_softc(dev);
65449610Swpaul	unit = device_get_unit(dev);
65549610Swpaul	bzero(sc, sizeof(struct vr_softc *));
65641502Swpaul
65793818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
65893818Sjhb	    MTX_DEF | MTX_RECURSE);
65969583Swpaul	VR_LOCK(sc);
66069583Swpaul
66141502Swpaul	/*
66241502Swpaul	 * Handle power management nonsense.
66341502Swpaul	 */
66472813Swpaul	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
66572813Swpaul		u_int32_t		iobase, membase, irq;
66641502Swpaul
66772813Swpaul		/* Save important PCI config data. */
66872813Swpaul		iobase = pci_read_config(dev, VR_PCI_LOIO, 4);
66972813Swpaul		membase = pci_read_config(dev, VR_PCI_LOMEM, 4);
67072813Swpaul		irq = pci_read_config(dev, VR_PCI_INTLINE, 4);
67141502Swpaul
67272813Swpaul		/* Reset the power state. */
67372813Swpaul		printf("vr%d: chip is in D%d power mode "
67472813Swpaul		    "-- setting to D0\n", unit,
67572813Swpaul		    pci_get_powerstate(dev));
67672813Swpaul		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
67741502Swpaul
67841502Swpaul			/* Restore PCI config data. */
67972813Swpaul		pci_write_config(dev, VR_PCI_LOIO, iobase, 4);
68072813Swpaul		pci_write_config(dev, VR_PCI_LOMEM, membase, 4);
68172813Swpaul		pci_write_config(dev, VR_PCI_INTLINE, irq, 4);
68241502Swpaul	}
68341502Swpaul
68441502Swpaul	/*
68541502Swpaul	 * Map control/status registers.
68641502Swpaul	 */
68772813Swpaul	pci_enable_busmaster(dev);
68879472Swpaul	pci_enable_io(dev, SYS_RES_IOPORT);
68979472Swpaul	pci_enable_io(dev, SYS_RES_MEMORY);
69061041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
69141502Swpaul
69241502Swpaul#ifdef VR_USEIOSPACE
69341502Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
69441502Swpaul		printf("vr%d: failed to enable I/O ports!\n", unit);
69541502Swpaul		free(sc, M_DEVBUF);
69641502Swpaul		goto fail;
69741502Swpaul	}
69841502Swpaul#else
69941502Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
70041502Swpaul		printf("vr%d: failed to enable memory mapping!\n", unit);
70141502Swpaul		goto fail;
70241502Swpaul	}
70349610Swpaul#endif
70441502Swpaul
70549610Swpaul	rid = VR_RID;
70649610Swpaul	sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid,
70749610Swpaul	    0, ~0, 1, RF_ACTIVE);
70849610Swpaul
70949610Swpaul	if (sc->vr_res == NULL) {
71049610Swpaul		printf("vr%d: couldn't map ports/memory\n", unit);
71149610Swpaul		error = ENXIO;
71241502Swpaul		goto fail;
71341502Swpaul	}
71441502Swpaul
71549610Swpaul	sc->vr_btag = rman_get_bustag(sc->vr_res);
71649610Swpaul	sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
71741502Swpaul
71841502Swpaul	/* Allocate interrupt */
71949610Swpaul	rid = 0;
72049610Swpaul	sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
72149610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
72249610Swpaul
72349610Swpaul	if (sc->vr_irq == NULL) {
72441502Swpaul		printf("vr%d: couldn't map interrupt\n", unit);
72549610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
72649610Swpaul		error = ENXIO;
72741502Swpaul		goto fail;
72841502Swpaul	}
72941502Swpaul
73049610Swpaul	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET,
73149610Swpaul	    vr_intr, sc, &sc->vr_intrhand);
73249610Swpaul
73349610Swpaul	if (error) {
73449610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
73549610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
73649610Swpaul		printf("vr%d: couldn't set up irq\n", unit);
73749610Swpaul		goto fail;
73849610Swpaul	}
73949610Swpaul
74076586Swpaul	/*
74176586Swpaul	 * Windows may put the chip in suspend mode when it
74276586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
74376586Swpaul	 * up again.
74476586Swpaul	 */
74576586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
74676586Swpaul
74741502Swpaul	/* Reset the adapter. */
74841502Swpaul	vr_reset(sc);
74941502Swpaul
75041502Swpaul	/*
75141502Swpaul	 * Get station address. The way the Rhine chips work,
75241502Swpaul	 * you're not allowed to directly access the EEPROM once
75341502Swpaul	 * they've been programmed a special way. Consequently,
75441502Swpaul	 * we need to read the node address from the PAR0 and PAR1
75541502Swpaul	 * registers.
75641502Swpaul	 */
75741502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
75841502Swpaul	DELAY(200);
75941502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
76041502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
76141502Swpaul
76241502Swpaul	/*
76341502Swpaul	 * A Rhine chip was detected. Inform the world.
76441502Swpaul	 */
76541502Swpaul	printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":");
76641502Swpaul
76741502Swpaul	sc->vr_unit = unit;
76841502Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
76941502Swpaul
77051432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
77151657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
77251432Swpaul
77351432Swpaul	if (sc->vr_ldata == NULL) {
77441502Swpaul		printf("vr%d: no memory for list buffers!\n", unit);
77549610Swpaul		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
77649610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
77749610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
77849610Swpaul		error = ENXIO;
77949610Swpaul		goto fail;
78041502Swpaul	}
78141502Swpaul
78241502Swpaul	bzero(sc->vr_ldata, sizeof(struct vr_list_data));
78341502Swpaul
78441502Swpaul	ifp = &sc->arpcom.ac_if;
78541502Swpaul	ifp->if_softc = sc;
78641502Swpaul	ifp->if_unit = unit;
78741502Swpaul	ifp->if_name = "vr";
78841502Swpaul	ifp->if_mtu = ETHERMTU;
78941502Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
79041502Swpaul	ifp->if_ioctl = vr_ioctl;
79141502Swpaul	ifp->if_output = ether_output;
79241502Swpaul	ifp->if_start = vr_start;
79341502Swpaul	ifp->if_watchdog = vr_watchdog;
79441502Swpaul	ifp->if_init = vr_init;
79541502Swpaul	ifp->if_baudrate = 10000000;
79643515Swpaul	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
79741502Swpaul
79851432Swpaul	/*
79951432Swpaul	 * Do MII setup.
80051432Swpaul	 */
80151432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
80251432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
80341502Swpaul		printf("vr%d: MII without any phy!\n", sc->vr_unit);
80449610Swpaul		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
80549610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
80649610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
80751432Swpaul		contigfree(sc->vr_ldata,
80851432Swpaul		    sizeof(struct vr_list_data), M_DEVBUF);
80949610Swpaul		error = ENXIO;
81041502Swpaul		goto fail;
81141502Swpaul	}
81241502Swpaul
81351432Swpaul	callout_handle_init(&sc->vr_stat_ch);
81441502Swpaul
81541502Swpaul	/*
81663090Sarchie	 * Call MI attach routine.
81741502Swpaul	 */
81863090Sarchie	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
81967087Swpaul	VR_UNLOCK(sc);
82067087Swpaul	return(0);
82141502Swpaul
82241502Swpaulfail:
82367087Swpaul	VR_UNLOCK(sc);
82467087Swpaul	mtx_destroy(&sc->vr_mtx);
82567087Swpaul
82649610Swpaul	return(error);
82741502Swpaul}
82841502Swpaul
829102336Salfredstatic int
830102336Salfredvr_detach(dev)
83149610Swpaul	device_t		dev;
83249610Swpaul{
83349610Swpaul	struct vr_softc		*sc;
83449610Swpaul	struct ifnet		*ifp;
83549610Swpaul
83649610Swpaul	sc = device_get_softc(dev);
83767087Swpaul	VR_LOCK(sc);
83849610Swpaul	ifp = &sc->arpcom.ac_if;
83949610Swpaul
84049610Swpaul	vr_stop(sc);
84163090Sarchie	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
84249610Swpaul
84351432Swpaul	bus_generic_detach(dev);
84451432Swpaul	device_delete_child(dev, sc->vr_miibus);
84551432Swpaul
84649610Swpaul	bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
84749610Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
84849610Swpaul	bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
84949610Swpaul
85051432Swpaul	contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
85149610Swpaul
85267087Swpaul	VR_UNLOCK(sc);
85367087Swpaul	mtx_destroy(&sc->vr_mtx);
85449610Swpaul
85549610Swpaul	return(0);
85649610Swpaul}
85749610Swpaul
85841502Swpaul/*
85941502Swpaul * Initialize the transmit descriptors.
86041502Swpaul */
861102336Salfredstatic int
862102336Salfredvr_list_tx_init(sc)
86341502Swpaul	struct vr_softc		*sc;
86441502Swpaul{
86541502Swpaul	struct vr_chain_data	*cd;
86641502Swpaul	struct vr_list_data	*ld;
86741502Swpaul	int			i;
86841502Swpaul
86941502Swpaul	cd = &sc->vr_cdata;
87041502Swpaul	ld = sc->vr_ldata;
87141502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
87241502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
87341502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
87441502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
87541502Swpaul				&cd->vr_tx_chain[0];
87641502Swpaul		else
87741502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
87841502Swpaul				&cd->vr_tx_chain[i + 1];
87941502Swpaul	}
88041502Swpaul
88141502Swpaul	cd->vr_tx_free = &cd->vr_tx_chain[0];
88241502Swpaul	cd->vr_tx_tail = cd->vr_tx_head = NULL;
88341502Swpaul
88441502Swpaul	return(0);
88541502Swpaul}
88641502Swpaul
88741502Swpaul
88841502Swpaul/*
88941502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
89041502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
89141502Swpaul * points back to the first.
89241502Swpaul */
893102336Salfredstatic int
894102336Salfredvr_list_rx_init(sc)
89541502Swpaul	struct vr_softc		*sc;
89641502Swpaul{
89741502Swpaul	struct vr_chain_data	*cd;
89841502Swpaul	struct vr_list_data	*ld;
89941502Swpaul	int			i;
90041502Swpaul
90141502Swpaul	cd = &sc->vr_cdata;
90241502Swpaul	ld = sc->vr_ldata;
90341502Swpaul
90441502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
90541502Swpaul		cd->vr_rx_chain[i].vr_ptr =
90641502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
90749610Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
90841502Swpaul			return(ENOBUFS);
90941502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
91041502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
91141502Swpaul					&cd->vr_rx_chain[0];
91241502Swpaul			ld->vr_rx_list[i].vr_next =
91341502Swpaul					vtophys(&ld->vr_rx_list[0]);
91441502Swpaul		} else {
91541502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
91641502Swpaul					&cd->vr_rx_chain[i + 1];
91741502Swpaul			ld->vr_rx_list[i].vr_next =
91841502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
91941502Swpaul		}
92041502Swpaul	}
92141502Swpaul
92241502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
92341502Swpaul
92441502Swpaul	return(0);
92541502Swpaul}
92641502Swpaul
92741502Swpaul/*
92841502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
92941502Swpaul * Note: the length fields are only 11 bits wide, which means the
93041502Swpaul * largest size we can specify is 2047. This is important because
93141502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
93241502Swpaul * overflow the field and make a mess.
93341502Swpaul */
934102336Salfredstatic int
935102336Salfredvr_newbuf(sc, c, m)
93641502Swpaul	struct vr_softc		*sc;
93741502Swpaul	struct vr_chain_onefrag	*c;
93849610Swpaul	struct mbuf		*m;
93941502Swpaul{
94041502Swpaul	struct mbuf		*m_new = NULL;
94141502Swpaul
94249610Swpaul	if (m == NULL) {
94349610Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
94487846Sluigi		if (m_new == NULL)
94549610Swpaul			return(ENOBUFS);
94641502Swpaul
94749610Swpaul		MCLGET(m_new, M_DONTWAIT);
94849610Swpaul		if (!(m_new->m_flags & M_EXT)) {
94949610Swpaul			m_freem(m_new);
95049610Swpaul			return(ENOBUFS);
95149610Swpaul		}
95249610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
95349610Swpaul	} else {
95449610Swpaul		m_new = m;
95549610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
95649610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
95741502Swpaul	}
95841502Swpaul
95949610Swpaul	m_adj(m_new, sizeof(u_int64_t));
96049610Swpaul
96141502Swpaul	c->vr_mbuf = m_new;
96241502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
96341502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
96442491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
96541502Swpaul
96641502Swpaul	return(0);
96741502Swpaul}
96841502Swpaul
96941502Swpaul/*
97041502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
97141502Swpaul * the higher level protocols.
97241502Swpaul */
973102336Salfredstatic void
974102336Salfredvr_rxeof(sc)
97541502Swpaul	struct vr_softc		*sc;
97641502Swpaul{
97741502Swpaul        struct ether_header	*eh;
97841502Swpaul        struct mbuf		*m;
97941502Swpaul        struct ifnet		*ifp;
98041502Swpaul	struct vr_chain_onefrag	*cur_rx;
98141502Swpaul	int			total_len = 0;
98241502Swpaul	u_int32_t		rxstat;
98341502Swpaul
98441502Swpaul	ifp = &sc->arpcom.ac_if;
98541502Swpaul
98641502Swpaul	while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
98741502Swpaul							VR_RXSTAT_OWN)) {
98849610Swpaul		struct mbuf		*m0 = NULL;
98949610Swpaul
99041502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
99141502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
99249610Swpaul		m = cur_rx->vr_mbuf;
99341502Swpaul
99441502Swpaul		/*
99541502Swpaul		 * If an error occurs, update stats, clear the
99641502Swpaul		 * status word and leave the mbuf cluster in place:
99741502Swpaul		 * it should simply get re-used next time this descriptor
99841502Swpaul	 	 * comes up in the ring.
99941502Swpaul		 */
100041502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
100141502Swpaul			ifp->if_ierrors++;
100241502Swpaul			printf("vr%d: rx error: ", sc->vr_unit);
100341502Swpaul			switch(rxstat & 0x000000FF) {
100441502Swpaul			case VR_RXSTAT_CRCERR:
100541502Swpaul				printf("crc error\n");
100641502Swpaul				break;
100741502Swpaul			case VR_RXSTAT_FRAMEALIGNERR:
100841502Swpaul				printf("frame alignment error\n");
100941502Swpaul				break;
101041502Swpaul			case VR_RXSTAT_FIFOOFLOW:
101141502Swpaul				printf("FIFO overflow\n");
101241502Swpaul				break;
101341502Swpaul			case VR_RXSTAT_GIANT:
101441502Swpaul				printf("received giant packet\n");
101541502Swpaul				break;
101641502Swpaul			case VR_RXSTAT_RUNT:
101741502Swpaul				printf("received runt packet\n");
101841502Swpaul				break;
101941502Swpaul			case VR_RXSTAT_BUSERR:
102041502Swpaul				printf("system bus error\n");
102141502Swpaul				break;
102241502Swpaul			case VR_RXSTAT_BUFFERR:
102341502Swpaul				printf("rx buffer error\n");
102441502Swpaul				break;
102541502Swpaul			default:
102641502Swpaul				printf("unknown rx error\n");
102741502Swpaul				break;
102841502Swpaul			}
102949610Swpaul			vr_newbuf(sc, cur_rx, m);
103041502Swpaul			continue;
103141502Swpaul		}
103241502Swpaul
103341502Swpaul		/* No errors; receive the packet. */
103441502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
103541502Swpaul
103641502Swpaul		/*
103742048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
103842048Swpaul		 * received frame, and there's no way to turn this
103942048Swpaul		 * behavior off (at least, I can't find anything in
104042048Swpaul	 	 * the manual that explains how to do it) so we have
104142048Swpaul		 * to trim off the CRC manually.
104242048Swpaul		 */
104342048Swpaul		total_len -= ETHER_CRC_LEN;
104442048Swpaul
104578508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
104678508Sbmilekic		    NULL);
104749610Swpaul		vr_newbuf(sc, cur_rx, m);
104849610Swpaul		if (m0 == NULL) {
104941502Swpaul			ifp->if_ierrors++;
105041502Swpaul			continue;
105141502Swpaul		}
105249610Swpaul		m = m0;
105341502Swpaul
105441502Swpaul		ifp->if_ipackets++;
105541502Swpaul		eh = mtod(m, struct ether_header *);
105649610Swpaul
105741502Swpaul		/* Remove header from mbuf and pass it on. */
105841502Swpaul		m_adj(m, sizeof(struct ether_header));
105941502Swpaul		ether_input(ifp, eh, m);
106041502Swpaul	}
106141502Swpaul
106241502Swpaul	return;
106341502Swpaul}
106441502Swpaul
1065105221Sphkstatic void
1066102336Salfredvr_rxeoc(sc)
106741502Swpaul	struct vr_softc		*sc;
106841502Swpaul{
106941502Swpaul
107041502Swpaul	vr_rxeof(sc);
107141502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
107241502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
107341502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
107441502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
107541502Swpaul
107641502Swpaul	return;
107741502Swpaul}
107841502Swpaul
107941502Swpaul/*
108041502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
108141502Swpaul * the list buffers.
108241502Swpaul */
108341502Swpaul
1084102336Salfredstatic void
1085102336Salfredvr_txeof(sc)
108641502Swpaul	struct vr_softc		*sc;
108741502Swpaul{
108841502Swpaul	struct vr_chain		*cur_tx;
108941502Swpaul	struct ifnet		*ifp;
109041502Swpaul
109141502Swpaul	ifp = &sc->arpcom.ac_if;
109241502Swpaul
109396677Ssilby	/* Reset the timeout timer; if_txeoc will clear it. */
109496677Ssilby	ifp->if_timer = 5;
109541502Swpaul
109641502Swpaul	/* Sanity check. */
109741502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
109841502Swpaul		return;
109941502Swpaul
110041502Swpaul	/*
110141502Swpaul	 * Go through our tx list and free mbufs for those
110241502Swpaul	 * frames that have been transmitted.
110341502Swpaul	 */
110441502Swpaul	while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) {
110541502Swpaul		u_int32_t		txstat;
110641502Swpaul
110741502Swpaul		cur_tx = sc->vr_cdata.vr_tx_head;
110841502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
110941502Swpaul
1110101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
1111101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
1112101896Ssilby			while (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON)
1113101896Ssilby				;	/* Wait for chip to shutdown */
1114101896Ssilby			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
1115101896Ssilby			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr));
1116101896Ssilby			break;
1117101896Ssilby		}
1118101896Ssilby
111942491Swpaul		if (txstat & VR_TXSTAT_OWN)
112041502Swpaul			break;
112141502Swpaul
112241502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
112341502Swpaul			ifp->if_oerrors++;
112441502Swpaul			if (txstat & VR_TXSTAT_DEFER)
112541502Swpaul				ifp->if_collisions++;
112641502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
112741502Swpaul				ifp->if_collisions++;
112841502Swpaul		}
112941502Swpaul
113041502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
113141502Swpaul
113241502Swpaul		ifp->if_opackets++;
113351432Swpaul		if (cur_tx->vr_mbuf != NULL) {
113451432Swpaul			m_freem(cur_tx->vr_mbuf);
113551432Swpaul			cur_tx->vr_mbuf = NULL;
113651432Swpaul		}
113741502Swpaul
113841502Swpaul		if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {
113941502Swpaul			sc->vr_cdata.vr_tx_head = NULL;
114041502Swpaul			sc->vr_cdata.vr_tx_tail = NULL;
114141502Swpaul			break;
114241502Swpaul		}
114341502Swpaul
114441502Swpaul		sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc;
114541502Swpaul	}
114641502Swpaul
114741502Swpaul	return;
114841502Swpaul}
114941502Swpaul
115041502Swpaul/*
115141502Swpaul * TX 'end of channel' interrupt handler.
115241502Swpaul */
1153102336Salfredstatic void
1154102336Salfredvr_txeoc(sc)
115541502Swpaul	struct vr_softc		*sc;
115641502Swpaul{
115741502Swpaul	struct ifnet		*ifp;
115841502Swpaul
115941502Swpaul	ifp = &sc->arpcom.ac_if;
116041502Swpaul
116141502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL) {
116241502Swpaul		ifp->if_flags &= ~IFF_OACTIVE;
116341502Swpaul		sc->vr_cdata.vr_tx_tail = NULL;
116496677Ssilby		ifp->if_timer = 0;
116541502Swpaul	}
116641502Swpaul
116741502Swpaul	return;
116841502Swpaul}
116941502Swpaul
1170102336Salfredstatic void
1171102336Salfredvr_tick(xsc)
117251432Swpaul	void			*xsc;
117351432Swpaul{
117451432Swpaul	struct vr_softc		*sc;
117551432Swpaul	struct mii_data		*mii;
117651432Swpaul
117751432Swpaul	sc = xsc;
117867087Swpaul	VR_LOCK(sc);
117951432Swpaul	mii = device_get_softc(sc->vr_miibus);
118051432Swpaul	mii_tick(mii);
118151432Swpaul
118251432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
118351432Swpaul
118467087Swpaul	VR_UNLOCK(sc);
118551432Swpaul
118651432Swpaul	return;
118751432Swpaul}
118851432Swpaul
1189102336Salfredstatic void
1190102336Salfredvr_intr(arg)
119141502Swpaul	void			*arg;
119241502Swpaul{
119341502Swpaul	struct vr_softc		*sc;
119441502Swpaul	struct ifnet		*ifp;
119541502Swpaul	u_int16_t		status;
119641502Swpaul
119741502Swpaul	sc = arg;
119867087Swpaul	VR_LOCK(sc);
119941502Swpaul	ifp = &sc->arpcom.ac_if;
120041502Swpaul
120141502Swpaul	/* Supress unwanted interrupts. */
120241502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
120341502Swpaul		vr_stop(sc);
120467087Swpaul		VR_UNLOCK(sc);
120541502Swpaul		return;
120641502Swpaul	}
120741502Swpaul
120841502Swpaul	/* Disable interrupts. */
120941502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
121041502Swpaul
121141502Swpaul	for (;;) {
121241502Swpaul
121341502Swpaul		status = CSR_READ_2(sc, VR_ISR);
121441502Swpaul		if (status)
121541502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
121641502Swpaul
121741502Swpaul		if ((status & VR_INTRS) == 0)
121841502Swpaul			break;
121941502Swpaul
122041502Swpaul		if (status & VR_ISR_RX_OK)
122141502Swpaul			vr_rxeof(sc);
122241502Swpaul
122341502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
122441502Swpaul		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) ||
122541502Swpaul		    (status & VR_ISR_RX_DROPPED)) {
122641502Swpaul			vr_rxeof(sc);
122741502Swpaul			vr_rxeoc(sc);
122841502Swpaul		}
122941502Swpaul
1230101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1231101896Ssilby			vr_reset(sc);
1232101896Ssilby			vr_init(sc);
1233101896Ssilby			break;
123441502Swpaul		}
123541502Swpaul
1236101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1237101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
123841502Swpaul			vr_txeof(sc);
1239101896Ssilby			if ((status & VR_ISR_UDFI) ||
1240101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1241101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1242101896Ssilby				ifp->if_oerrors++;
1243101896Ssilby				if (sc->vr_cdata.vr_tx_head != NULL) {
1244101896Ssilby					VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1245101896Ssilby					VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1246101896Ssilby				}
1247101896Ssilby			} else
1248101896Ssilby				vr_txeoc(sc);
124941502Swpaul		}
125041502Swpaul
125141502Swpaul	}
125241502Swpaul
125341502Swpaul	/* Re-enable interrupts. */
125441502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
125541502Swpaul
125641502Swpaul	if (ifp->if_snd.ifq_head != NULL) {
125741502Swpaul		vr_start(ifp);
125841502Swpaul	}
125941502Swpaul
126067087Swpaul	VR_UNLOCK(sc);
126167087Swpaul
126241502Swpaul	return;
126341502Swpaul}
126441502Swpaul
126541502Swpaul/*
126641502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
126741502Swpaul * pointers to the fragment pointers.
126841502Swpaul */
1269102336Salfredstatic int
1270102336Salfredvr_encap(sc, c, m_head)
127141502Swpaul	struct vr_softc		*sc;
127241502Swpaul	struct vr_chain		*c;
127341502Swpaul	struct mbuf		*m_head;
127441502Swpaul{
127541502Swpaul	int			frag = 0;
127641502Swpaul	struct vr_desc		*f = NULL;
127741502Swpaul	int			total_len;
127841502Swpaul	struct mbuf		*m;
127941502Swpaul
128041502Swpaul	m = m_head;
128141502Swpaul	total_len = 0;
128241502Swpaul
128341502Swpaul	/*
128441502Swpaul	 * The VIA Rhine wants packet buffers to be longword
128541502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
128641502Swpaul	 * waste time trying to decide when to copy and when not
128741502Swpaul	 * to copy, just do it all the time.
128841502Swpaul	 */
128941502Swpaul	if (m != NULL) {
129041502Swpaul		struct mbuf		*m_new = NULL;
129141502Swpaul
129241502Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
129341502Swpaul		if (m_new == NULL) {
129471271Swpaul			printf("vr%d: no memory for tx list\n", sc->vr_unit);
129541502Swpaul			return(1);
129641502Swpaul		}
129741502Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
129841502Swpaul			MCLGET(m_new, M_DONTWAIT);
129941502Swpaul			if (!(m_new->m_flags & M_EXT)) {
130041502Swpaul				m_freem(m_new);
130171271Swpaul				printf("vr%d: no memory for tx list\n",
130241502Swpaul						sc->vr_unit);
130341502Swpaul				return(1);
130441502Swpaul			}
130541502Swpaul		}
130641502Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
130741502Swpaul					mtod(m_new, caddr_t));
130841502Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
130941502Swpaul		m_freem(m_head);
131041502Swpaul		m_head = m_new;
131141502Swpaul		/*
131241502Swpaul		 * The Rhine chip doesn't auto-pad, so we have to make
131341502Swpaul		 * sure to pad short frames out to the minimum frame length
131441502Swpaul		 * ourselves.
131541502Swpaul		 */
131641502Swpaul		if (m_head->m_len < VR_MIN_FRAMELEN) {
131741502Swpaul			m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
131841502Swpaul			m_new->m_len = m_new->m_pkthdr.len;
131941502Swpaul		}
132041502Swpaul		f = c->vr_ptr;
132141502Swpaul		f->vr_data = vtophys(mtod(m_new, caddr_t));
132241502Swpaul		f->vr_ctl = total_len = m_new->m_len;
132341502Swpaul		f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
132441502Swpaul		f->vr_status = 0;
132541502Swpaul		frag = 1;
132641502Swpaul	}
132741502Swpaul
132841502Swpaul	c->vr_mbuf = m_head;
132942491Swpaul	c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
133041502Swpaul	c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
133141502Swpaul
133241502Swpaul	return(0);
133341502Swpaul}
133441502Swpaul
133541502Swpaul/*
133641502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
133741502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
133841502Swpaul * copy of the pointers since the transmit list fragment pointers are
133941502Swpaul * physical addresses.
134041502Swpaul */
134141502Swpaul
1342102336Salfredstatic void
1343102336Salfredvr_start(ifp)
134441502Swpaul	struct ifnet		*ifp;
134541502Swpaul{
134641502Swpaul	struct vr_softc		*sc;
134741502Swpaul	struct mbuf		*m_head = NULL;
134841502Swpaul	struct vr_chain		*cur_tx = NULL, *start_tx;
134941502Swpaul
135041502Swpaul	sc = ifp->if_softc;
135141502Swpaul
135267087Swpaul	VR_LOCK(sc);
135367087Swpaul	if (ifp->if_flags & IFF_OACTIVE) {
135467087Swpaul		VR_UNLOCK(sc);
135541502Swpaul		return;
135667087Swpaul	}
135741502Swpaul
135841502Swpaul	/*
135941502Swpaul	 * Check for an available queue slot. If there are none,
136041502Swpaul	 * punt.
136141502Swpaul	 */
136241502Swpaul	if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) {
136341502Swpaul		ifp->if_flags |= IFF_OACTIVE;
136441502Swpaul		return;
136541502Swpaul	}
136641502Swpaul
136741502Swpaul	start_tx = sc->vr_cdata.vr_tx_free;
136841502Swpaul
136941502Swpaul	while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) {
137041502Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
137141502Swpaul		if (m_head == NULL)
137241502Swpaul			break;
137341502Swpaul
137441502Swpaul		/* Pick a descriptor off the free list. */
137541502Swpaul		cur_tx = sc->vr_cdata.vr_tx_free;
137641502Swpaul		sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc;
137741502Swpaul
137841502Swpaul		/* Pack the data into the descriptor. */
137971271Swpaul		if (vr_encap(sc, cur_tx, m_head)) {
138071271Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
138171275Swpaul			ifp->if_flags |= IFF_OACTIVE;
138271271Swpaul			cur_tx = NULL;
138371271Swpaul			break;
138471271Swpaul		}
138541502Swpaul
138641502Swpaul		if (cur_tx != start_tx)
138741502Swpaul			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
138841502Swpaul
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);
139551583Swpaul
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	 */
140367087Swpaul	if (cur_tx == NULL) {
140467087Swpaul		VR_UNLOCK(sc);
140541526Swpaul		return;
140667087Swpaul	}
140741526Swpaul
140841502Swpaul	sc->vr_cdata.vr_tx_tail = cur_tx;
140941502Swpaul
141042491Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
141141502Swpaul		sc->vr_cdata.vr_tx_head = start_tx;
141241502Swpaul
141341502Swpaul	/*
141441502Swpaul	 * Set a timeout in case the chip goes out to lunch.
141541502Swpaul	 */
141641502Swpaul	ifp->if_timer = 5;
141767087Swpaul	VR_UNLOCK(sc);
141841502Swpaul
141941502Swpaul	return;
142041502Swpaul}
142141502Swpaul
1422102336Salfredstatic void
1423102336Salfredvr_init(xsc)
142441502Swpaul	void			*xsc;
142541502Swpaul{
142641502Swpaul	struct vr_softc		*sc = xsc;
142741502Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
142851432Swpaul	struct mii_data		*mii;
142973963Swpaul	int			i;
143041502Swpaul
143167087Swpaul	VR_LOCK(sc);
143241502Swpaul
143351432Swpaul	mii = device_get_softc(sc->vr_miibus);
143441502Swpaul
143541502Swpaul	/*
143641502Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
143741502Swpaul	 */
143841502Swpaul	vr_stop(sc);
143941502Swpaul	vr_reset(sc);
144041502Swpaul
144173963Swpaul	/*
144273963Swpaul	 * Set our station address.
144373963Swpaul	 */
144473963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
144573963Swpaul		CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]);
1446101375Ssilby
1447101375Ssilby	/* Set DMA size */
1448101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1449101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
145073963Swpaul
1451101375Ssilby	/*
1452101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1453101108Ssilby	 * so we must set both.
1454101108Ssilby	 */
1455101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1456101108Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESHSTORENFWD);
1457101108Ssilby
1458101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1459101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1460101108Ssilby
146141502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
146241502Swpaul	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD);
146341502Swpaul
146441502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
146541502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
146641502Swpaul
146741502Swpaul	/* Init circular RX list. */
146841502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
146941502Swpaul		printf("vr%d: initialization failed: no "
147041502Swpaul			"memory for rx buffers\n", sc->vr_unit);
147141502Swpaul		vr_stop(sc);
147267087Swpaul		VR_UNLOCK(sc);
147341502Swpaul		return;
147441502Swpaul	}
147541502Swpaul
147641502Swpaul	/*
147741502Swpaul	 * Init tx descriptors.
147841502Swpaul	 */
147941502Swpaul	vr_list_tx_init(sc);
148041502Swpaul
148141502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
148241502Swpaul	if (ifp->if_flags & IFF_PROMISC)
148341502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
148441502Swpaul	else
148541502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
148641502Swpaul
148741502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
148841502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
148941502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
149041502Swpaul	else
149141502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
149241502Swpaul
149341502Swpaul	/*
149441502Swpaul	 * Program the multicast filter, if necessary.
149541502Swpaul	 */
149641502Swpaul	vr_setmulti(sc);
149741502Swpaul
149841502Swpaul	/*
149941502Swpaul	 * Load the address of the RX list.
150041502Swpaul	 */
150141502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
150241502Swpaul
150341502Swpaul	/* Enable receiver and transmitter. */
150441502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
150541502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
150641502Swpaul				    VR_CMD_RX_GO);
150741502Swpaul
150841502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
150941502Swpaul
151041502Swpaul	/*
151141502Swpaul	 * Enable interrupts.
151241502Swpaul	 */
151341502Swpaul	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
151441502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
151541502Swpaul
151651432Swpaul	mii_mediachg(mii);
151741502Swpaul
151841502Swpaul	ifp->if_flags |= IFF_RUNNING;
151941502Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
152041502Swpaul
152151432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
152251432Swpaul
152367087Swpaul	VR_UNLOCK(sc);
152467087Swpaul
152541502Swpaul	return;
152641502Swpaul}
152741502Swpaul
152841502Swpaul/*
152941502Swpaul * Set media options.
153041502Swpaul */
1531102336Salfredstatic int
1532102336Salfredvr_ifmedia_upd(ifp)
153341502Swpaul	struct ifnet		*ifp;
153441502Swpaul{
153541502Swpaul	struct vr_softc		*sc;
153641502Swpaul
153741502Swpaul	sc = ifp->if_softc;
153841502Swpaul
153951432Swpaul	if (ifp->if_flags & IFF_UP)
154051432Swpaul		vr_init(sc);
154141502Swpaul
154241502Swpaul	return(0);
154341502Swpaul}
154441502Swpaul
154541502Swpaul/*
154641502Swpaul * Report current media status.
154741502Swpaul */
1548102336Salfredstatic void
1549102336Salfredvr_ifmedia_sts(ifp, ifmr)
155041502Swpaul	struct ifnet		*ifp;
155141502Swpaul	struct ifmediareq	*ifmr;
155241502Swpaul{
155341502Swpaul	struct vr_softc		*sc;
155451432Swpaul	struct mii_data		*mii;
155541502Swpaul
155641502Swpaul	sc = ifp->if_softc;
155751432Swpaul	mii = device_get_softc(sc->vr_miibus);
155851432Swpaul	mii_pollstat(mii);
155951432Swpaul	ifmr->ifm_active = mii->mii_media_active;
156051432Swpaul	ifmr->ifm_status = mii->mii_media_status;
156141502Swpaul
156241502Swpaul	return;
156341502Swpaul}
156441502Swpaul
1565102336Salfredstatic int
1566102336Salfredvr_ioctl(ifp, command, data)
156741502Swpaul	struct ifnet		*ifp;
156841502Swpaul	u_long			command;
156941502Swpaul	caddr_t			data;
157041502Swpaul{
157141502Swpaul	struct vr_softc		*sc = ifp->if_softc;
157241502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
157351432Swpaul	struct mii_data		*mii;
157467087Swpaul	int			error = 0;
157541502Swpaul
157667087Swpaul	VR_LOCK(sc);
157741502Swpaul
157841502Swpaul	switch(command) {
157941502Swpaul	case SIOCSIFADDR:
158041502Swpaul	case SIOCGIFADDR:
158141502Swpaul	case SIOCSIFMTU:
158241502Swpaul		error = ether_ioctl(ifp, command, data);
158341502Swpaul		break;
158441502Swpaul	case SIOCSIFFLAGS:
158541502Swpaul		if (ifp->if_flags & IFF_UP) {
158641502Swpaul			vr_init(sc);
158741502Swpaul		} else {
158841502Swpaul			if (ifp->if_flags & IFF_RUNNING)
158941502Swpaul				vr_stop(sc);
159041502Swpaul		}
159141502Swpaul		error = 0;
159241502Swpaul		break;
159341502Swpaul	case SIOCADDMULTI:
159441502Swpaul	case SIOCDELMULTI:
159541502Swpaul		vr_setmulti(sc);
159641502Swpaul		error = 0;
159741502Swpaul		break;
159841502Swpaul	case SIOCGIFMEDIA:
159941502Swpaul	case SIOCSIFMEDIA:
160051432Swpaul		mii = device_get_softc(sc->vr_miibus);
160151432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
160241502Swpaul		break;
160341502Swpaul	default:
160441502Swpaul		error = EINVAL;
160541502Swpaul		break;
160641502Swpaul	}
160741502Swpaul
160867087Swpaul	VR_UNLOCK(sc);
160941502Swpaul
161041502Swpaul	return(error);
161141502Swpaul}
161241502Swpaul
1613102336Salfredstatic void
1614102336Salfredvr_watchdog(ifp)
161541502Swpaul	struct ifnet		*ifp;
161641502Swpaul{
161741502Swpaul	struct vr_softc		*sc;
161841502Swpaul
161941502Swpaul	sc = ifp->if_softc;
162041502Swpaul
162167087Swpaul	VR_LOCK(sc);
162241502Swpaul	ifp->if_oerrors++;
162341502Swpaul	printf("vr%d: watchdog timeout\n", sc->vr_unit);
162441502Swpaul
162541502Swpaul	vr_stop(sc);
162641502Swpaul	vr_reset(sc);
162741502Swpaul	vr_init(sc);
162841502Swpaul
162941502Swpaul	if (ifp->if_snd.ifq_head != NULL)
163041502Swpaul		vr_start(ifp);
163141502Swpaul
163267087Swpaul	VR_UNLOCK(sc);
163367087Swpaul
163441502Swpaul	return;
163541502Swpaul}
163641502Swpaul
163741502Swpaul/*
163841502Swpaul * Stop the adapter and free any mbufs allocated to the
163941502Swpaul * RX and TX lists.
164041502Swpaul */
1641102336Salfredstatic void
1642102336Salfredvr_stop(sc)
164341502Swpaul	struct vr_softc		*sc;
164441502Swpaul{
164541502Swpaul	register int		i;
164641502Swpaul	struct ifnet		*ifp;
164741502Swpaul
164867087Swpaul	VR_LOCK(sc);
164967087Swpaul
165041502Swpaul	ifp = &sc->arpcom.ac_if;
165141502Swpaul	ifp->if_timer = 0;
165241502Swpaul
165351432Swpaul	untimeout(vr_tick, sc, sc->vr_stat_ch);
165451432Swpaul
165541502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
165641502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
165741502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
165841502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
165941502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
166041502Swpaul
166141502Swpaul	/*
166241502Swpaul	 * Free data in the RX lists.
166341502Swpaul	 */
166441502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
166541502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
166641502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
166741502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
166841502Swpaul		}
166941502Swpaul	}
167041502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
167141502Swpaul		sizeof(sc->vr_ldata->vr_rx_list));
167241502Swpaul
167341502Swpaul	/*
167441502Swpaul	 * Free the TX list buffers.
167541502Swpaul	 */
167641502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
167741502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
167841502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
167941502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
168041502Swpaul		}
168141502Swpaul	}
168241502Swpaul
168341502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
168441502Swpaul		sizeof(sc->vr_ldata->vr_tx_list));
168541502Swpaul
168641502Swpaul	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
168767087Swpaul	VR_UNLOCK(sc);
168841502Swpaul
168941502Swpaul	return;
169041502Swpaul}
169141502Swpaul
169241502Swpaul/*
169341502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
169441502Swpaul * get confused by errant DMAs when rebooting.
169541502Swpaul */
1696102336Salfredstatic void
1697102336Salfredvr_shutdown(dev)
169849610Swpaul	device_t		dev;
169941502Swpaul{
170049610Swpaul	struct vr_softc		*sc;
170141502Swpaul
170249610Swpaul	sc = device_get_softc(dev);
170349610Swpaul
170441502Swpaul	vr_stop(sc);
170541502Swpaul
170641502Swpaul	return;
170741502Swpaul}
1708