if_vr.c revision 62653
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 62653 2000-07-05 21:37:21Z wpaul $
3341502Swpaul */
3441502Swpaul
3541502Swpaul/*
3641502Swpaul * VIA Rhine fast ethernet PCI NIC driver
3741502Swpaul *
3841502Swpaul * Supports various network adapters based on the VIA Rhine
3941502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX.
4041502Swpaul * Datasheets are available at http://www.via.com.tw.
4141502Swpaul *
4241502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4341502Swpaul * Electrical Engineering Department
4441502Swpaul * Columbia University, New York City
4541502Swpaul */
4641502Swpaul
4741502Swpaul/*
4841502Swpaul * The VIA Rhine controllers are similar in some respects to the
4941502Swpaul * the DEC tulip chips, except less complicated. The controller
5041502Swpaul * uses an MII bus and an external physical layer interface. The
5141502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table
5241502Swpaul * multicast filter. Transmit and receive descriptors are similar
5341502Swpaul * to the tulip.
5441502Swpaul *
5541502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism:
5641502Swpaul * transmit buffers must be longword aligned. Unfortunately,
5741502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting
5841502Swpaul * at longword boundaries, so we have to do a buffer copy before
5941502Swpaul * transmission.
6041502Swpaul */
6141502Swpaul
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/clock.h>      /* for DELAY */
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
9141502Swpaul#include <pci/pcireg.h>
9241502Swpaul#include <pci/pcivar.h>
9341502Swpaul
9441502Swpaul#define VR_USEIOSPACE
9541502Swpaul
9641502Swpaul#include <pci/if_vrreg.h>
9741502Swpaul
9859758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
9959758Speter
10051432Swpaul/* "controller miibus0" required.  See GENERIC if you get errors here. */
10151432Swpaul#include "miibus_if.h"
10251432Swpaul
10341502Swpaul#ifndef lint
10441591Sarchiestatic const char rcsid[] =
10550477Speter  "$FreeBSD: head/sys/dev/vr/if_vr.c 62653 2000-07-05 21:37:21Z wpaul $";
10641502Swpaul#endif
10741502Swpaul
10841502Swpaul/*
10941502Swpaul * Various supported device vendors/types and their names.
11041502Swpaul */
11141502Swpaulstatic struct vr_type vr_devs[] = {
11241502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
11341502Swpaul		"VIA VT3043 Rhine I 10/100BaseTX" },
11441502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
11541502Swpaul		"VIA VT86C100A Rhine II 10/100BaseTX" },
11662653Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
11762653Swpaul		"VIA VT6102 Rhine II 10/100BaseTX" },
11844238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
11944238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
12044238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
12144238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
12241502Swpaul	{ 0, 0, NULL }
12341502Swpaul};
12441502Swpaul
12549610Swpaulstatic int vr_probe		__P((device_t));
12649610Swpaulstatic int vr_attach		__P((device_t));
12749610Swpaulstatic int vr_detach		__P((device_t));
12841502Swpaul
12941502Swpaulstatic int vr_newbuf		__P((struct vr_softc *,
13049610Swpaul					struct vr_chain_onefrag *,
13149610Swpaul					struct mbuf *));
13241502Swpaulstatic int vr_encap		__P((struct vr_softc *, struct vr_chain *,
13341502Swpaul						struct mbuf * ));
13441502Swpaul
13541502Swpaulstatic void vr_rxeof		__P((struct vr_softc *));
13641502Swpaulstatic void vr_rxeoc		__P((struct vr_softc *));
13741502Swpaulstatic void vr_txeof		__P((struct vr_softc *));
13841502Swpaulstatic void vr_txeoc		__P((struct vr_softc *));
13951432Swpaulstatic void vr_tick		__P((void *));
14041502Swpaulstatic void vr_intr		__P((void *));
14141502Swpaulstatic void vr_start		__P((struct ifnet *));
14241502Swpaulstatic int vr_ioctl		__P((struct ifnet *, u_long, caddr_t));
14341502Swpaulstatic void vr_init		__P((void *));
14441502Swpaulstatic void vr_stop		__P((struct vr_softc *));
14541502Swpaulstatic void vr_watchdog		__P((struct ifnet *));
14649610Swpaulstatic void vr_shutdown		__P((device_t));
14741502Swpaulstatic int vr_ifmedia_upd	__P((struct ifnet *));
14841502Swpaulstatic void vr_ifmedia_sts	__P((struct ifnet *, struct ifmediareq *));
14941502Swpaul
15041502Swpaulstatic void vr_mii_sync		__P((struct vr_softc *));
15141502Swpaulstatic void vr_mii_send		__P((struct vr_softc *, u_int32_t, int));
15241502Swpaulstatic int vr_mii_readreg	__P((struct vr_softc *, struct vr_mii_frame *));
15341502Swpaulstatic int vr_mii_writereg	__P((struct vr_softc *, struct vr_mii_frame *));
15451432Swpaulstatic int vr_miibus_readreg	__P((device_t, int, int));
15551432Swpaulstatic int vr_miibus_writereg	__P((device_t, int, int, int));
15651432Swpaulstatic void vr_miibus_statchg	__P((device_t));
15741502Swpaul
15851432Swpaulstatic void vr_setcfg		__P((struct vr_softc *, int));
15941502Swpaulstatic u_int8_t vr_calchash	__P((u_int8_t *));
16041502Swpaulstatic void vr_setmulti		__P((struct vr_softc *));
16141502Swpaulstatic void vr_reset		__P((struct vr_softc *));
16241502Swpaulstatic int vr_list_rx_init	__P((struct vr_softc *));
16341502Swpaulstatic int vr_list_tx_init	__P((struct vr_softc *));
16441502Swpaul
16549610Swpaul#ifdef VR_USEIOSPACE
16649610Swpaul#define VR_RES			SYS_RES_IOPORT
16749610Swpaul#define VR_RID			VR_PCI_LOIO
16849610Swpaul#else
16949610Swpaul#define VR_RES			SYS_RES_MEMORY
17049610Swpaul#define VR_RID			VR_PCI_LOMEM
17149610Swpaul#endif
17249610Swpaul
17349610Swpaulstatic device_method_t vr_methods[] = {
17449610Swpaul	/* Device interface */
17549610Swpaul	DEVMETHOD(device_probe,		vr_probe),
17649610Swpaul	DEVMETHOD(device_attach,	vr_attach),
17749610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
17849610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
17951432Swpaul
18051432Swpaul	/* bus interface */
18151432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18251432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
18351432Swpaul
18451432Swpaul	/* MII interface */
18551432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
18651432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
18751432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
18851432Swpaul
18949610Swpaul	{ 0, 0 }
19049610Swpaul};
19149610Swpaul
19249610Swpaulstatic driver_t vr_driver = {
19351455Swpaul	"vr",
19449610Swpaul	vr_methods,
19549610Swpaul	sizeof(struct vr_softc)
19649610Swpaul};
19749610Swpaul
19849610Swpaulstatic devclass_t vr_devclass;
19949610Swpaul
20051533SwpaulDRIVER_MODULE(if_vr, pci, vr_driver, vr_devclass, 0, 0);
20151473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
20249610Swpaul
20341502Swpaul#define VR_SETBIT(sc, reg, x)				\
20441502Swpaul	CSR_WRITE_1(sc, reg,				\
20541502Swpaul		CSR_READ_1(sc, reg) | x)
20641502Swpaul
20741502Swpaul#define VR_CLRBIT(sc, reg, x)				\
20841502Swpaul	CSR_WRITE_1(sc, reg,				\
20941502Swpaul		CSR_READ_1(sc, reg) & ~x)
21041502Swpaul
21141502Swpaul#define VR_SETBIT16(sc, reg, x)				\
21241502Swpaul	CSR_WRITE_2(sc, reg,				\
21341502Swpaul		CSR_READ_2(sc, reg) | x)
21441502Swpaul
21541502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
21641502Swpaul	CSR_WRITE_2(sc, reg,				\
21741502Swpaul		CSR_READ_2(sc, reg) & ~x)
21841502Swpaul
21941502Swpaul#define VR_SETBIT32(sc, reg, x)				\
22041502Swpaul	CSR_WRITE_4(sc, reg,				\
22141502Swpaul		CSR_READ_4(sc, reg) | x)
22241502Swpaul
22341502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
22441502Swpaul	CSR_WRITE_4(sc, reg,				\
22541502Swpaul		CSR_READ_4(sc, reg) & ~x)
22641502Swpaul
22741502Swpaul#define SIO_SET(x)					\
22841502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
22941502Swpaul		CSR_READ_1(sc, VR_MIICMD) | x)
23041502Swpaul
23141502Swpaul#define SIO_CLR(x)					\
23241502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
23341502Swpaul		CSR_READ_1(sc, VR_MIICMD) & ~x)
23441502Swpaul
23541502Swpaul/*
23641502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
23741502Swpaul */
23841502Swpaulstatic void vr_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 */
25841502Swpaulstatic void vr_mii_send(sc, bits, cnt)
25941502Swpaul	struct vr_softc		*sc;
26041502Swpaul	u_int32_t		bits;
26141502Swpaul	int			cnt;
26241502Swpaul{
26341502Swpaul	int			i;
26441502Swpaul
26541502Swpaul	SIO_CLR(VR_MIICMD_CLK);
26641502Swpaul
26741502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
26841502Swpaul                if (bits & i) {
26941502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
27041502Swpaul                } else {
27141502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
27241502Swpaul                }
27341502Swpaul		DELAY(1);
27441502Swpaul		SIO_CLR(VR_MIICMD_CLK);
27541502Swpaul		DELAY(1);
27641502Swpaul		SIO_SET(VR_MIICMD_CLK);
27741502Swpaul	}
27841502Swpaul}
27941502Swpaul
28041502Swpaul/*
28141502Swpaul * Read an PHY register through the MII.
28241502Swpaul */
28341502Swpaulstatic int vr_mii_readreg(sc, frame)
28441502Swpaul	struct vr_softc		*sc;
28541502Swpaul	struct vr_mii_frame	*frame;
28641502Swpaul
28741502Swpaul{
28841502Swpaul	int			i, ack, s;
28941502Swpaul
29041502Swpaul	s = splimp();
29141502Swpaul
29241502Swpaul	/*
29341502Swpaul	 * Set up frame for RX.
29441502Swpaul	 */
29541502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
29641502Swpaul	frame->mii_opcode = VR_MII_READOP;
29741502Swpaul	frame->mii_turnaround = 0;
29841502Swpaul	frame->mii_data = 0;
29941502Swpaul
30041502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
30141502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
30241502Swpaul
30341502Swpaul	/*
30441502Swpaul 	 * Turn on data xmit.
30541502Swpaul	 */
30641502Swpaul	SIO_SET(VR_MIICMD_DIR);
30741502Swpaul
30841502Swpaul	vr_mii_sync(sc);
30941502Swpaul
31041502Swpaul	/*
31141502Swpaul	 * Send command/address info.
31241502Swpaul	 */
31341502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
31441502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
31541502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
31641502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
31741502Swpaul
31841502Swpaul	/* Idle bit */
31941502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
32041502Swpaul	DELAY(1);
32141502Swpaul	SIO_SET(VR_MIICMD_CLK);
32241502Swpaul	DELAY(1);
32341502Swpaul
32441502Swpaul	/* Turn off xmit. */
32541502Swpaul	SIO_CLR(VR_MIICMD_DIR);
32641502Swpaul
32741502Swpaul	/* Check for ack */
32841502Swpaul	SIO_CLR(VR_MIICMD_CLK);
32941502Swpaul	DELAY(1);
33041502Swpaul	SIO_SET(VR_MIICMD_CLK);
33141502Swpaul	DELAY(1);
33241502Swpaul	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
33341502Swpaul
33441502Swpaul	/*
33541502Swpaul	 * Now try reading data bits. If the ack failed, we still
33641502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
33741502Swpaul	 */
33841502Swpaul	if (ack) {
33941502Swpaul		for(i = 0; i < 16; i++) {
34041502Swpaul			SIO_CLR(VR_MIICMD_CLK);
34141502Swpaul			DELAY(1);
34241502Swpaul			SIO_SET(VR_MIICMD_CLK);
34341502Swpaul			DELAY(1);
34441502Swpaul		}
34541502Swpaul		goto fail;
34641502Swpaul	}
34741502Swpaul
34841502Swpaul	for (i = 0x8000; i; i >>= 1) {
34941502Swpaul		SIO_CLR(VR_MIICMD_CLK);
35041502Swpaul		DELAY(1);
35141502Swpaul		if (!ack) {
35241502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
35341502Swpaul				frame->mii_data |= i;
35441502Swpaul			DELAY(1);
35541502Swpaul		}
35641502Swpaul		SIO_SET(VR_MIICMD_CLK);
35741502Swpaul		DELAY(1);
35841502Swpaul	}
35941502Swpaul
36041502Swpaulfail:
36141502Swpaul
36241502Swpaul	SIO_CLR(VR_MIICMD_CLK);
36341502Swpaul	DELAY(1);
36441502Swpaul	SIO_SET(VR_MIICMD_CLK);
36541502Swpaul	DELAY(1);
36641502Swpaul
36741502Swpaul	splx(s);
36841502Swpaul
36941502Swpaul	if (ack)
37041502Swpaul		return(1);
37141502Swpaul	return(0);
37241502Swpaul}
37341502Swpaul
37441502Swpaul/*
37541502Swpaul * Write to a PHY register through the MII.
37641502Swpaul */
37741502Swpaulstatic int vr_mii_writereg(sc, frame)
37841502Swpaul	struct vr_softc		*sc;
37941502Swpaul	struct vr_mii_frame	*frame;
38041502Swpaul
38141502Swpaul{
38241502Swpaul	int			s;
38341502Swpaul
38441502Swpaul	s = splimp();
38541502Swpaul
38641502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
38741502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
38841502Swpaul
38941502Swpaul	/*
39041502Swpaul	 * Set up frame for TX.
39141502Swpaul	 */
39241502Swpaul
39341502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
39441502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
39541502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
39641502Swpaul
39741502Swpaul	/*
39841502Swpaul 	 * Turn on data output.
39941502Swpaul	 */
40041502Swpaul	SIO_SET(VR_MIICMD_DIR);
40141502Swpaul
40241502Swpaul	vr_mii_sync(sc);
40341502Swpaul
40441502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
40541502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
40641502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
40741502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
40841502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
40941502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
41041502Swpaul
41141502Swpaul	/* Idle bit. */
41241502Swpaul	SIO_SET(VR_MIICMD_CLK);
41341502Swpaul	DELAY(1);
41441502Swpaul	SIO_CLR(VR_MIICMD_CLK);
41541502Swpaul	DELAY(1);
41641502Swpaul
41741502Swpaul	/*
41841502Swpaul	 * Turn off xmit.
41941502Swpaul	 */
42041502Swpaul	SIO_CLR(VR_MIICMD_DIR);
42141502Swpaul
42241502Swpaul	splx(s);
42341502Swpaul
42441502Swpaul	return(0);
42541502Swpaul}
42641502Swpaul
42751432Swpaulstatic int vr_miibus_readreg(dev, phy, reg)
42851432Swpaul	device_t		dev;
42951432Swpaul	int			phy, reg;
43051432Swpaul{
43141502Swpaul	struct vr_softc		*sc;
43241502Swpaul	struct vr_mii_frame	frame;
43341502Swpaul
43451432Swpaul	sc = device_get_softc(dev);
43541502Swpaul	bzero((char *)&frame, sizeof(frame));
43641502Swpaul
43751432Swpaul	frame.mii_phyaddr = phy;
43841502Swpaul	frame.mii_regaddr = reg;
43941502Swpaul	vr_mii_readreg(sc, &frame);
44041502Swpaul
44141502Swpaul	return(frame.mii_data);
44241502Swpaul}
44341502Swpaul
44451432Swpaulstatic int vr_miibus_writereg(dev, phy, reg, data)
44551432Swpaul	device_t		dev;
44651432Swpaul	u_int16_t		phy, reg, data;
44751432Swpaul{
44841502Swpaul	struct vr_softc		*sc;
44941502Swpaul	struct vr_mii_frame	frame;
45041502Swpaul
45151432Swpaul	sc = device_get_softc(dev);
45241502Swpaul	bzero((char *)&frame, sizeof(frame));
45341502Swpaul
45451432Swpaul	frame.mii_phyaddr = phy;
45541502Swpaul	frame.mii_regaddr = reg;
45641502Swpaul	frame.mii_data = data;
45741502Swpaul
45841502Swpaul	vr_mii_writereg(sc, &frame);
45941502Swpaul
46051432Swpaul	return(0);
46151432Swpaul}
46251432Swpaul
46351432Swpaulstatic void vr_miibus_statchg(dev)
46451432Swpaul	device_t		dev;
46551432Swpaul{
46651432Swpaul	struct vr_softc		*sc;
46751432Swpaul	struct mii_data		*mii;
46851432Swpaul
46951432Swpaul	sc = device_get_softc(dev);
47051432Swpaul	mii = device_get_softc(sc->vr_miibus);
47151432Swpaul	vr_setcfg(sc, mii->mii_media_active);
47251432Swpaul
47341502Swpaul	return;
47441502Swpaul}
47541502Swpaul
47641502Swpaul/*
47741502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits.
47841502Swpaul */
47941502Swpaulstatic u_int8_t vr_calchash(addr)
48041502Swpaul	u_int8_t		*addr;
48141502Swpaul{
48241502Swpaul	u_int32_t		crc, carry;
48341502Swpaul	int			i, j;
48441502Swpaul	u_int8_t		c;
48541502Swpaul
48641502Swpaul	/* Compute CRC for the address value. */
48741502Swpaul	crc = 0xFFFFFFFF; /* initial value */
48841502Swpaul
48941502Swpaul	for (i = 0; i < 6; i++) {
49041502Swpaul		c = *(addr + i);
49141502Swpaul		for (j = 0; j < 8; j++) {
49241502Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
49341502Swpaul			crc <<= 1;
49441502Swpaul			c >>= 1;
49541502Swpaul			if (carry)
49641502Swpaul				crc = (crc ^ 0x04c11db6) | carry;
49741502Swpaul		}
49841502Swpaul	}
49941502Swpaul
50041502Swpaul	/* return the filter bit position */
50141502Swpaul	return((crc >> 26) & 0x0000003F);
50241502Swpaul}
50341502Swpaul
50441502Swpaul/*
50541502Swpaul * Program the 64-bit multicast hash filter.
50641502Swpaul */
50741502Swpaulstatic void vr_setmulti(sc)
50841502Swpaul	struct vr_softc		*sc;
50941502Swpaul{
51041502Swpaul	struct ifnet		*ifp;
51141502Swpaul	int			h = 0;
51241502Swpaul	u_int32_t		hashes[2] = { 0, 0 };
51341502Swpaul	struct ifmultiaddr	*ifma;
51441502Swpaul	u_int8_t		rxfilt;
51541502Swpaul	int			mcnt = 0;
51641502Swpaul
51741502Swpaul	ifp = &sc->arpcom.ac_if;
51841502Swpaul
51941502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
52041502Swpaul
52141502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
52241502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
52341502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
52441502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
52541502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
52641502Swpaul		return;
52741502Swpaul	}
52841502Swpaul
52941502Swpaul	/* first, zot all the existing hash bits */
53041502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
53141502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
53241502Swpaul
53341502Swpaul	/* now program new ones */
53441502Swpaul	for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
53541502Swpaul				ifma = ifma->ifma_link.le_next) {
53641502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
53741502Swpaul			continue;
53841502Swpaul		h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
53941502Swpaul		if (h < 32)
54041502Swpaul			hashes[0] |= (1 << h);
54141502Swpaul		else
54241502Swpaul			hashes[1] |= (1 << (h - 32));
54341502Swpaul		mcnt++;
54441502Swpaul	}
54541502Swpaul
54641502Swpaul	if (mcnt)
54741502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
54841502Swpaul	else
54941502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
55041502Swpaul
55141502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
55241502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
55341502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
55441502Swpaul
55541502Swpaul	return;
55641502Swpaul}
55741502Swpaul
55841502Swpaul/*
55941502Swpaul * In order to fiddle with the
56041502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
56141502Swpaul * first have to put the transmit and/or receive logic in the idle state.
56241502Swpaul */
56351432Swpaulstatic void vr_setcfg(sc, media)
56441502Swpaul	struct vr_softc		*sc;
56551432Swpaul	int			media;
56641502Swpaul{
56741502Swpaul	int			restart = 0;
56841502Swpaul
56941502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
57041502Swpaul		restart = 1;
57141502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
57241502Swpaul	}
57341502Swpaul
57451432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
57541502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
57641502Swpaul	else
57741502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
57841502Swpaul
57941502Swpaul	if (restart)
58041502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
58141502Swpaul
58241502Swpaul	return;
58341502Swpaul}
58441502Swpaul
58541502Swpaulstatic void vr_reset(sc)
58641502Swpaul	struct vr_softc		*sc;
58741502Swpaul{
58841502Swpaul	register int		i;
58941502Swpaul
59041502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
59141502Swpaul
59241502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
59341502Swpaul		DELAY(10);
59441502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
59541502Swpaul			break;
59641502Swpaul	}
59741502Swpaul	if (i == VR_TIMEOUT)
59841502Swpaul		printf("vr%d: reset never completed!\n", sc->vr_unit);
59941502Swpaul
60041502Swpaul	/* Wait a little while for the chip to get its brains in order. */
60141502Swpaul	DELAY(1000);
60241502Swpaul
60341502Swpaul        return;
60441502Swpaul}
60541502Swpaul
60641502Swpaul/*
60741502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
60841502Swpaul * IDs against our list and return a device name if we find a match.
60941502Swpaul */
61049610Swpaulstatic int vr_probe(dev)
61149610Swpaul	device_t		dev;
61241502Swpaul{
61341502Swpaul	struct vr_type		*t;
61441502Swpaul
61541502Swpaul	t = vr_devs;
61641502Swpaul
61741502Swpaul	while(t->vr_name != NULL) {
61849610Swpaul		if ((pci_get_vendor(dev) == t->vr_vid) &&
61949610Swpaul		    (pci_get_device(dev) == t->vr_did)) {
62049610Swpaul			device_set_desc(dev, t->vr_name);
62149610Swpaul			return(0);
62241502Swpaul		}
62341502Swpaul		t++;
62441502Swpaul	}
62541502Swpaul
62649610Swpaul	return(ENXIO);
62741502Swpaul}
62841502Swpaul
62941502Swpaul/*
63041502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
63141502Swpaul * setup and ethernet/BPF attach.
63241502Swpaul */
63349610Swpaulstatic int vr_attach(dev)
63449610Swpaul	device_t		dev;
63541502Swpaul{
63651432Swpaul	int			i, s;
63741502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
63841502Swpaul	u_int32_t		command;
63941502Swpaul	struct vr_softc		*sc;
64041502Swpaul	struct ifnet		*ifp;
64149610Swpaul	int			unit, error = 0, rid;
64241502Swpaul
64341502Swpaul	s = splimp();
64441502Swpaul
64549610Swpaul	sc = device_get_softc(dev);
64649610Swpaul	unit = device_get_unit(dev);
64749610Swpaul	bzero(sc, sizeof(struct vr_softc *));
64841502Swpaul
64941502Swpaul	/*
65041502Swpaul	 * Handle power management nonsense.
65141502Swpaul	 */
65241502Swpaul
65349610Swpaul	command = pci_read_config(dev, VR_PCI_CAPID, 4) & 0x000000FF;
65441502Swpaul	if (command == 0x01) {
65541502Swpaul
65649610Swpaul		command = pci_read_config(dev, VR_PCI_PWRMGMTCTRL, 4);
65741502Swpaul		if (command & VR_PSTATE_MASK) {
65841502Swpaul			u_int32_t		iobase, membase, irq;
65941502Swpaul
66041502Swpaul			/* Save important PCI config data. */
66149610Swpaul			iobase = pci_read_config(dev, VR_PCI_LOIO, 4);
66249610Swpaul			membase = pci_read_config(dev, VR_PCI_LOMEM, 4);
66349610Swpaul			irq = pci_read_config(dev, VR_PCI_INTLINE, 4);
66441502Swpaul
66541502Swpaul			/* Reset the power state. */
66641502Swpaul			printf("vr%d: chip is in D%d power mode "
66741502Swpaul			"-- setting to D0\n", unit, command & VR_PSTATE_MASK);
66841502Swpaul			command &= 0xFFFFFFFC;
66949610Swpaul			pci_write_config(dev, VR_PCI_PWRMGMTCTRL, command, 4);
67041502Swpaul
67141502Swpaul			/* Restore PCI config data. */
67249610Swpaul			pci_write_config(dev, VR_PCI_LOIO, iobase, 4);
67349610Swpaul			pci_write_config(dev, VR_PCI_LOMEM, membase, 4);
67449610Swpaul			pci_write_config(dev, VR_PCI_INTLINE, irq, 4);
67541502Swpaul		}
67641502Swpaul	}
67741502Swpaul
67841502Swpaul	/*
67941502Swpaul	 * Map control/status registers.
68041502Swpaul	 */
68161041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
68241502Swpaul	command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
68361041Speter	pci_write_config(dev, PCIR_COMMAND, command, 4);
68461041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
68541502Swpaul
68641502Swpaul#ifdef VR_USEIOSPACE
68741502Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
68841502Swpaul		printf("vr%d: failed to enable I/O ports!\n", unit);
68941502Swpaul		free(sc, M_DEVBUF);
69041502Swpaul		goto fail;
69141502Swpaul	}
69241502Swpaul#else
69341502Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
69441502Swpaul		printf("vr%d: failed to enable memory mapping!\n", unit);
69541502Swpaul		goto fail;
69641502Swpaul	}
69749610Swpaul#endif
69841502Swpaul
69949610Swpaul	rid = VR_RID;
70049610Swpaul	sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid,
70149610Swpaul	    0, ~0, 1, RF_ACTIVE);
70249610Swpaul
70349610Swpaul	if (sc->vr_res == NULL) {
70449610Swpaul		printf("vr%d: couldn't map ports/memory\n", unit);
70549610Swpaul		error = ENXIO;
70641502Swpaul		goto fail;
70741502Swpaul	}
70841502Swpaul
70949610Swpaul	sc->vr_btag = rman_get_bustag(sc->vr_res);
71049610Swpaul	sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
71141502Swpaul
71241502Swpaul	/* Allocate interrupt */
71349610Swpaul	rid = 0;
71449610Swpaul	sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
71549610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
71649610Swpaul
71749610Swpaul	if (sc->vr_irq == NULL) {
71841502Swpaul		printf("vr%d: couldn't map interrupt\n", unit);
71949610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
72049610Swpaul		error = ENXIO;
72141502Swpaul		goto fail;
72241502Swpaul	}
72341502Swpaul
72449610Swpaul	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET,
72549610Swpaul	    vr_intr, sc, &sc->vr_intrhand);
72649610Swpaul
72749610Swpaul	if (error) {
72849610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
72949610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
73049610Swpaul		printf("vr%d: couldn't set up irq\n", unit);
73149610Swpaul		goto fail;
73249610Swpaul	}
73349610Swpaul
73441502Swpaul	/* Reset the adapter. */
73541502Swpaul	vr_reset(sc);
73641502Swpaul
73741502Swpaul	/*
73841502Swpaul	 * Get station address. The way the Rhine chips work,
73941502Swpaul	 * you're not allowed to directly access the EEPROM once
74041502Swpaul	 * they've been programmed a special way. Consequently,
74141502Swpaul	 * we need to read the node address from the PAR0 and PAR1
74241502Swpaul	 * registers.
74341502Swpaul	 */
74441502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
74541502Swpaul	DELAY(200);
74641502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
74741502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
74841502Swpaul
74941502Swpaul	/*
75041502Swpaul	 * A Rhine chip was detected. Inform the world.
75141502Swpaul	 */
75241502Swpaul	printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":");
75341502Swpaul
75441502Swpaul	sc->vr_unit = unit;
75541502Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
75641502Swpaul
75751432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
75851657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
75951432Swpaul
76051432Swpaul	if (sc->vr_ldata == NULL) {
76141502Swpaul		printf("vr%d: no memory for list buffers!\n", unit);
76249610Swpaul		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
76349610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
76449610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
76549610Swpaul		error = ENXIO;
76649610Swpaul		goto fail;
76741502Swpaul	}
76841502Swpaul
76941502Swpaul	bzero(sc->vr_ldata, sizeof(struct vr_list_data));
77041502Swpaul
77141502Swpaul	ifp = &sc->arpcom.ac_if;
77241502Swpaul	ifp->if_softc = sc;
77341502Swpaul	ifp->if_unit = unit;
77441502Swpaul	ifp->if_name = "vr";
77541502Swpaul	ifp->if_mtu = ETHERMTU;
77641502Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
77741502Swpaul	ifp->if_ioctl = vr_ioctl;
77841502Swpaul	ifp->if_output = ether_output;
77941502Swpaul	ifp->if_start = vr_start;
78041502Swpaul	ifp->if_watchdog = vr_watchdog;
78141502Swpaul	ifp->if_init = vr_init;
78241502Swpaul	ifp->if_baudrate = 10000000;
78343515Swpaul	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
78441502Swpaul
78551432Swpaul	/*
78651432Swpaul	 * Do MII setup.
78751432Swpaul	 */
78851432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
78951432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
79041502Swpaul		printf("vr%d: MII without any phy!\n", sc->vr_unit);
79149610Swpaul		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
79249610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
79349610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
79451432Swpaul		contigfree(sc->vr_ldata,
79551432Swpaul		    sizeof(struct vr_list_data), M_DEVBUF);
79649610Swpaul		error = ENXIO;
79741502Swpaul		goto fail;
79841502Swpaul	}
79941502Swpaul
80051432Swpaul	callout_handle_init(&sc->vr_stat_ch);
80141502Swpaul
80241502Swpaul	/*
80341502Swpaul	 * Call MI attach routines.
80441502Swpaul	 */
80541502Swpaul	if_attach(ifp);
80641502Swpaul	ether_ifattach(ifp);
80741502Swpaul
80841502Swpaul	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
80941502Swpaul
81041502Swpaulfail:
81141502Swpaul	splx(s);
81249610Swpaul	return(error);
81341502Swpaul}
81441502Swpaul
81549610Swpaulstatic int vr_detach(dev)
81649610Swpaul	device_t		dev;
81749610Swpaul{
81849610Swpaul	struct vr_softc		*sc;
81949610Swpaul	struct ifnet		*ifp;
82049610Swpaul	int			s;
82149610Swpaul
82249610Swpaul	s = splimp();
82349610Swpaul
82449610Swpaul	sc = device_get_softc(dev);
82549610Swpaul	ifp = &sc->arpcom.ac_if;
82649610Swpaul
82749610Swpaul	vr_stop(sc);
82849610Swpaul	if_detach(ifp);
82949610Swpaul
83051432Swpaul	bus_generic_detach(dev);
83151432Swpaul	device_delete_child(dev, sc->vr_miibus);
83251432Swpaul
83349610Swpaul	bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
83449610Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
83549610Swpaul	bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
83649610Swpaul
83751432Swpaul	contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
83849610Swpaul
83949610Swpaul	splx(s);
84049610Swpaul
84149610Swpaul	return(0);
84249610Swpaul}
84349610Swpaul
84441502Swpaul/*
84541502Swpaul * Initialize the transmit descriptors.
84641502Swpaul */
84741502Swpaulstatic int vr_list_tx_init(sc)
84841502Swpaul	struct vr_softc		*sc;
84941502Swpaul{
85041502Swpaul	struct vr_chain_data	*cd;
85141502Swpaul	struct vr_list_data	*ld;
85241502Swpaul	int			i;
85341502Swpaul
85441502Swpaul	cd = &sc->vr_cdata;
85541502Swpaul	ld = sc->vr_ldata;
85641502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
85741502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
85841502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
85941502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
86041502Swpaul				&cd->vr_tx_chain[0];
86141502Swpaul		else
86241502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
86341502Swpaul				&cd->vr_tx_chain[i + 1];
86441502Swpaul	}
86541502Swpaul
86641502Swpaul	cd->vr_tx_free = &cd->vr_tx_chain[0];
86741502Swpaul	cd->vr_tx_tail = cd->vr_tx_head = NULL;
86841502Swpaul
86941502Swpaul	return(0);
87041502Swpaul}
87141502Swpaul
87241502Swpaul
87341502Swpaul/*
87441502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
87541502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
87641502Swpaul * points back to the first.
87741502Swpaul */
87841502Swpaulstatic int vr_list_rx_init(sc)
87941502Swpaul	struct vr_softc		*sc;
88041502Swpaul{
88141502Swpaul	struct vr_chain_data	*cd;
88241502Swpaul	struct vr_list_data	*ld;
88341502Swpaul	int			i;
88441502Swpaul
88541502Swpaul	cd = &sc->vr_cdata;
88641502Swpaul	ld = sc->vr_ldata;
88741502Swpaul
88841502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
88941502Swpaul		cd->vr_rx_chain[i].vr_ptr =
89041502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
89149610Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
89241502Swpaul			return(ENOBUFS);
89341502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
89441502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
89541502Swpaul					&cd->vr_rx_chain[0];
89641502Swpaul			ld->vr_rx_list[i].vr_next =
89741502Swpaul					vtophys(&ld->vr_rx_list[0]);
89841502Swpaul		} else {
89941502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
90041502Swpaul					&cd->vr_rx_chain[i + 1];
90141502Swpaul			ld->vr_rx_list[i].vr_next =
90241502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
90341502Swpaul		}
90441502Swpaul	}
90541502Swpaul
90641502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
90741502Swpaul
90841502Swpaul	return(0);
90941502Swpaul}
91041502Swpaul
91141502Swpaul/*
91241502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
91341502Swpaul * Note: the length fields are only 11 bits wide, which means the
91441502Swpaul * largest size we can specify is 2047. This is important because
91541502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
91641502Swpaul * overflow the field and make a mess.
91741502Swpaul */
91849610Swpaulstatic int vr_newbuf(sc, c, m)
91941502Swpaul	struct vr_softc		*sc;
92041502Swpaul	struct vr_chain_onefrag	*c;
92149610Swpaul	struct mbuf		*m;
92241502Swpaul{
92341502Swpaul	struct mbuf		*m_new = NULL;
92441502Swpaul
92549610Swpaul	if (m == NULL) {
92649610Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
92749610Swpaul		if (m_new == NULL) {
92849610Swpaul			printf("vr%d: no memory for rx list "
92949610Swpaul			    "-- packet dropped!\n", sc->vr_unit);
93049610Swpaul			return(ENOBUFS);
93149610Swpaul		}
93241502Swpaul
93349610Swpaul		MCLGET(m_new, M_DONTWAIT);
93449610Swpaul		if (!(m_new->m_flags & M_EXT)) {
93549610Swpaul			printf("vr%d: no memory for rx list "
93649610Swpaul			    "-- packet dropped!\n", sc->vr_unit);
93749610Swpaul			m_freem(m_new);
93849610Swpaul			return(ENOBUFS);
93949610Swpaul		}
94049610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
94149610Swpaul	} else {
94249610Swpaul		m_new = m;
94349610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
94449610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
94541502Swpaul	}
94641502Swpaul
94749610Swpaul	m_adj(m_new, sizeof(u_int64_t));
94849610Swpaul
94941502Swpaul	c->vr_mbuf = m_new;
95041502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
95141502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
95242491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
95341502Swpaul
95441502Swpaul	return(0);
95541502Swpaul}
95641502Swpaul
95741502Swpaul/*
95841502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
95941502Swpaul * the higher level protocols.
96041502Swpaul */
96141502Swpaulstatic void vr_rxeof(sc)
96241502Swpaul	struct vr_softc		*sc;
96341502Swpaul{
96441502Swpaul        struct ether_header	*eh;
96541502Swpaul        struct mbuf		*m;
96641502Swpaul        struct ifnet		*ifp;
96741502Swpaul	struct vr_chain_onefrag	*cur_rx;
96841502Swpaul	int			total_len = 0;
96941502Swpaul	u_int32_t		rxstat;
97041502Swpaul
97141502Swpaul	ifp = &sc->arpcom.ac_if;
97241502Swpaul
97341502Swpaul	while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
97441502Swpaul							VR_RXSTAT_OWN)) {
97549610Swpaul		struct mbuf		*m0 = NULL;
97649610Swpaul
97741502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
97841502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
97949610Swpaul		m = cur_rx->vr_mbuf;
98041502Swpaul
98141502Swpaul		/*
98241502Swpaul		 * If an error occurs, update stats, clear the
98341502Swpaul		 * status word and leave the mbuf cluster in place:
98441502Swpaul		 * it should simply get re-used next time this descriptor
98541502Swpaul	 	 * comes up in the ring.
98641502Swpaul		 */
98741502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
98841502Swpaul			ifp->if_ierrors++;
98941502Swpaul			printf("vr%d: rx error: ", sc->vr_unit);
99041502Swpaul			switch(rxstat & 0x000000FF) {
99141502Swpaul			case VR_RXSTAT_CRCERR:
99241502Swpaul				printf("crc error\n");
99341502Swpaul				break;
99441502Swpaul			case VR_RXSTAT_FRAMEALIGNERR:
99541502Swpaul				printf("frame alignment error\n");
99641502Swpaul				break;
99741502Swpaul			case VR_RXSTAT_FIFOOFLOW:
99841502Swpaul				printf("FIFO overflow\n");
99941502Swpaul				break;
100041502Swpaul			case VR_RXSTAT_GIANT:
100141502Swpaul				printf("received giant packet\n");
100241502Swpaul				break;
100341502Swpaul			case VR_RXSTAT_RUNT:
100441502Swpaul				printf("received runt packet\n");
100541502Swpaul				break;
100641502Swpaul			case VR_RXSTAT_BUSERR:
100741502Swpaul				printf("system bus error\n");
100841502Swpaul				break;
100941502Swpaul			case VR_RXSTAT_BUFFERR:
101041502Swpaul				printf("rx buffer error\n");
101141502Swpaul				break;
101241502Swpaul			default:
101341502Swpaul				printf("unknown rx error\n");
101441502Swpaul				break;
101541502Swpaul			}
101649610Swpaul			vr_newbuf(sc, cur_rx, m);
101741502Swpaul			continue;
101841502Swpaul		}
101941502Swpaul
102041502Swpaul		/* No errors; receive the packet. */
102141502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
102241502Swpaul
102341502Swpaul		/*
102442048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
102542048Swpaul		 * received frame, and there's no way to turn this
102642048Swpaul		 * behavior off (at least, I can't find anything in
102742048Swpaul	 	 * the manual that explains how to do it) so we have
102842048Swpaul		 * to trim off the CRC manually.
102942048Swpaul		 */
103042048Swpaul		total_len -= ETHER_CRC_LEN;
103142048Swpaul
103249610Swpaul		m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
103349610Swpaul		    total_len + ETHER_ALIGN, 0, ifp, NULL);
103449610Swpaul		vr_newbuf(sc, cur_rx, m);
103549610Swpaul		if (m0 == NULL) {
103641502Swpaul			ifp->if_ierrors++;
103741502Swpaul			continue;
103841502Swpaul		}
103949610Swpaul		m_adj(m0, ETHER_ALIGN);
104049610Swpaul		m = m0;
104141502Swpaul
104241502Swpaul		ifp->if_ipackets++;
104341502Swpaul		eh = mtod(m, struct ether_header *);
104449610Swpaul
104541502Swpaul		/* Remove header from mbuf and pass it on. */
104641502Swpaul		m_adj(m, sizeof(struct ether_header));
104741502Swpaul		ether_input(ifp, eh, m);
104841502Swpaul	}
104941502Swpaul
105041502Swpaul	return;
105141502Swpaul}
105241502Swpaul
105341502Swpaulvoid vr_rxeoc(sc)
105441502Swpaul	struct vr_softc		*sc;
105541502Swpaul{
105641502Swpaul
105741502Swpaul	vr_rxeof(sc);
105841502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
105941502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
106041502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
106141502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
106241502Swpaul
106341502Swpaul	return;
106441502Swpaul}
106541502Swpaul
106641502Swpaul/*
106741502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
106841502Swpaul * the list buffers.
106941502Swpaul */
107041502Swpaul
107141502Swpaulstatic void vr_txeof(sc)
107241502Swpaul	struct vr_softc		*sc;
107341502Swpaul{
107441502Swpaul	struct vr_chain		*cur_tx;
107541502Swpaul	struct ifnet		*ifp;
107641502Swpaul
107741502Swpaul	ifp = &sc->arpcom.ac_if;
107841502Swpaul
107941502Swpaul	/* Clear the timeout timer. */
108041502Swpaul	ifp->if_timer = 0;
108141502Swpaul
108241502Swpaul	/* Sanity check. */
108341502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
108441502Swpaul		return;
108541502Swpaul
108641502Swpaul	/*
108741502Swpaul	 * Go through our tx list and free mbufs for those
108841502Swpaul	 * frames that have been transmitted.
108941502Swpaul	 */
109041502Swpaul	while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) {
109141502Swpaul		u_int32_t		txstat;
109241502Swpaul
109341502Swpaul		cur_tx = sc->vr_cdata.vr_tx_head;
109441502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
109541502Swpaul
109642491Swpaul		if (txstat & VR_TXSTAT_OWN)
109741502Swpaul			break;
109841502Swpaul
109941502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
110041502Swpaul			ifp->if_oerrors++;
110141502Swpaul			if (txstat & VR_TXSTAT_DEFER)
110241502Swpaul				ifp->if_collisions++;
110341502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
110441502Swpaul				ifp->if_collisions++;
110541502Swpaul		}
110641502Swpaul
110741502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
110841502Swpaul
110941502Swpaul		ifp->if_opackets++;
111051432Swpaul		if (cur_tx->vr_mbuf != NULL) {
111151432Swpaul			m_freem(cur_tx->vr_mbuf);
111251432Swpaul			cur_tx->vr_mbuf = NULL;
111351432Swpaul		}
111441502Swpaul
111541502Swpaul		if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {
111641502Swpaul			sc->vr_cdata.vr_tx_head = NULL;
111741502Swpaul			sc->vr_cdata.vr_tx_tail = NULL;
111841502Swpaul			break;
111941502Swpaul		}
112041502Swpaul
112141502Swpaul		sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc;
112241502Swpaul	}
112341502Swpaul
112441502Swpaul	return;
112541502Swpaul}
112641502Swpaul
112741502Swpaul/*
112841502Swpaul * TX 'end of channel' interrupt handler.
112941502Swpaul */
113041502Swpaulstatic void vr_txeoc(sc)
113141502Swpaul	struct vr_softc		*sc;
113241502Swpaul{
113341502Swpaul	struct ifnet		*ifp;
113441502Swpaul
113541502Swpaul	ifp = &sc->arpcom.ac_if;
113641502Swpaul
113741502Swpaul	ifp->if_timer = 0;
113841502Swpaul
113941502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL) {
114041502Swpaul		ifp->if_flags &= ~IFF_OACTIVE;
114141502Swpaul		sc->vr_cdata.vr_tx_tail = NULL;
114241502Swpaul	}
114341502Swpaul
114441502Swpaul	return;
114541502Swpaul}
114641502Swpaul
114751432Swpaulstatic void vr_tick(xsc)
114851432Swpaul	void			*xsc;
114951432Swpaul{
115051432Swpaul	struct vr_softc		*sc;
115151432Swpaul	struct mii_data		*mii;
115251432Swpaul	int			s;
115351432Swpaul
115451432Swpaul	s = splimp();
115551432Swpaul
115651432Swpaul	sc = xsc;
115751432Swpaul	mii = device_get_softc(sc->vr_miibus);
115851432Swpaul	mii_tick(mii);
115951432Swpaul
116051432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
116151432Swpaul
116251432Swpaul	splx(s);
116351432Swpaul
116451432Swpaul	return;
116551432Swpaul}
116651432Swpaul
116741502Swpaulstatic void vr_intr(arg)
116841502Swpaul	void			*arg;
116941502Swpaul{
117041502Swpaul	struct vr_softc		*sc;
117141502Swpaul	struct ifnet		*ifp;
117241502Swpaul	u_int16_t		status;
117341502Swpaul
117441502Swpaul	sc = arg;
117541502Swpaul	ifp = &sc->arpcom.ac_if;
117641502Swpaul
117741502Swpaul	/* Supress unwanted interrupts. */
117841502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
117941502Swpaul		vr_stop(sc);
118041502Swpaul		return;
118141502Swpaul	}
118241502Swpaul
118341502Swpaul	/* Disable interrupts. */
118441502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
118541502Swpaul
118641502Swpaul	for (;;) {
118741502Swpaul
118841502Swpaul		status = CSR_READ_2(sc, VR_ISR);
118941502Swpaul		if (status)
119041502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
119141502Swpaul
119241502Swpaul		if ((status & VR_INTRS) == 0)
119341502Swpaul			break;
119441502Swpaul
119541502Swpaul		if (status & VR_ISR_RX_OK)
119641502Swpaul			vr_rxeof(sc);
119741502Swpaul
119841502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
119941502Swpaul		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) ||
120041502Swpaul		    (status & VR_ISR_RX_DROPPED)) {
120141502Swpaul			vr_rxeof(sc);
120241502Swpaul			vr_rxeoc(sc);
120341502Swpaul		}
120441502Swpaul
120541502Swpaul		if (status & VR_ISR_TX_OK) {
120641502Swpaul			vr_txeof(sc);
120741502Swpaul			vr_txeoc(sc);
120841502Swpaul		}
120941502Swpaul
121041502Swpaul		if ((status & VR_ISR_TX_UNDERRUN)||(status & VR_ISR_TX_ABRT)){
121141502Swpaul			ifp->if_oerrors++;
121241502Swpaul			vr_txeof(sc);
121341502Swpaul			if (sc->vr_cdata.vr_tx_head != NULL) {
121441502Swpaul				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
121541502Swpaul				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
121641502Swpaul			}
121741502Swpaul		}
121841502Swpaul
121941502Swpaul		if (status & VR_ISR_BUSERR) {
122041502Swpaul			vr_reset(sc);
122141502Swpaul			vr_init(sc);
122241502Swpaul		}
122341502Swpaul	}
122441502Swpaul
122541502Swpaul	/* Re-enable interrupts. */
122641502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
122741502Swpaul
122841502Swpaul	if (ifp->if_snd.ifq_head != NULL) {
122941502Swpaul		vr_start(ifp);
123041502Swpaul	}
123141502Swpaul
123241502Swpaul	return;
123341502Swpaul}
123441502Swpaul
123541502Swpaul/*
123641502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
123741502Swpaul * pointers to the fragment pointers.
123841502Swpaul */
123941502Swpaulstatic int vr_encap(sc, c, m_head)
124041502Swpaul	struct vr_softc		*sc;
124141502Swpaul	struct vr_chain		*c;
124241502Swpaul	struct mbuf		*m_head;
124341502Swpaul{
124441502Swpaul	int			frag = 0;
124541502Swpaul	struct vr_desc		*f = NULL;
124641502Swpaul	int			total_len;
124741502Swpaul	struct mbuf		*m;
124841502Swpaul
124941502Swpaul	m = m_head;
125041502Swpaul	total_len = 0;
125141502Swpaul
125241502Swpaul	/*
125341502Swpaul	 * The VIA Rhine wants packet buffers to be longword
125441502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
125541502Swpaul	 * waste time trying to decide when to copy and when not
125641502Swpaul	 * to copy, just do it all the time.
125741502Swpaul	 */
125841502Swpaul	if (m != NULL) {
125941502Swpaul		struct mbuf		*m_new = NULL;
126041502Swpaul
126141502Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
126241502Swpaul		if (m_new == NULL) {
126341502Swpaul			printf("vr%d: no memory for tx list", sc->vr_unit);
126441502Swpaul			return(1);
126541502Swpaul		}
126641502Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
126741502Swpaul			MCLGET(m_new, M_DONTWAIT);
126841502Swpaul			if (!(m_new->m_flags & M_EXT)) {
126941502Swpaul				m_freem(m_new);
127041502Swpaul				printf("vr%d: no memory for tx list",
127141502Swpaul						sc->vr_unit);
127241502Swpaul				return(1);
127341502Swpaul			}
127441502Swpaul		}
127541502Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
127641502Swpaul					mtod(m_new, caddr_t));
127741502Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
127841502Swpaul		m_freem(m_head);
127941502Swpaul		m_head = m_new;
128041502Swpaul		/*
128141502Swpaul		 * The Rhine chip doesn't auto-pad, so we have to make
128241502Swpaul		 * sure to pad short frames out to the minimum frame length
128341502Swpaul		 * ourselves.
128441502Swpaul		 */
128541502Swpaul		if (m_head->m_len < VR_MIN_FRAMELEN) {
128641502Swpaul			m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
128741502Swpaul			m_new->m_len = m_new->m_pkthdr.len;
128841502Swpaul		}
128941502Swpaul		f = c->vr_ptr;
129041502Swpaul		f->vr_data = vtophys(mtod(m_new, caddr_t));
129141502Swpaul		f->vr_ctl = total_len = m_new->m_len;
129241502Swpaul		f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
129341502Swpaul		f->vr_status = 0;
129441502Swpaul		frag = 1;
129541502Swpaul	}
129641502Swpaul
129741502Swpaul	c->vr_mbuf = m_head;
129842491Swpaul	c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
129941502Swpaul	c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
130041502Swpaul
130141502Swpaul	return(0);
130241502Swpaul}
130341502Swpaul
130441502Swpaul/*
130541502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
130641502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
130741502Swpaul * copy of the pointers since the transmit list fragment pointers are
130841502Swpaul * physical addresses.
130941502Swpaul */
131041502Swpaul
131141502Swpaulstatic void vr_start(ifp)
131241502Swpaul	struct ifnet		*ifp;
131341502Swpaul{
131441502Swpaul	struct vr_softc		*sc;
131541502Swpaul	struct mbuf		*m_head = NULL;
131641502Swpaul	struct vr_chain		*cur_tx = NULL, *start_tx;
131741502Swpaul
131841502Swpaul	sc = ifp->if_softc;
131941502Swpaul
132051432Swpaul	if (ifp->if_flags & IFF_OACTIVE)
132141502Swpaul		return;
132241502Swpaul
132341502Swpaul	/*
132441502Swpaul	 * Check for an available queue slot. If there are none,
132541502Swpaul	 * punt.
132641502Swpaul	 */
132741502Swpaul	if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) {
132841502Swpaul		ifp->if_flags |= IFF_OACTIVE;
132941502Swpaul		return;
133041502Swpaul	}
133141502Swpaul
133241502Swpaul	start_tx = sc->vr_cdata.vr_tx_free;
133341502Swpaul
133441502Swpaul	while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) {
133541502Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
133641502Swpaul		if (m_head == NULL)
133741502Swpaul			break;
133841502Swpaul
133941502Swpaul		/* Pick a descriptor off the free list. */
134041502Swpaul		cur_tx = sc->vr_cdata.vr_tx_free;
134141502Swpaul		sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc;
134241502Swpaul
134341502Swpaul		/* Pack the data into the descriptor. */
134441502Swpaul		vr_encap(sc, cur_tx, m_head);
134541502Swpaul
134641502Swpaul		if (cur_tx != start_tx)
134741502Swpaul			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
134841502Swpaul
134941502Swpaul		/*
135041502Swpaul		 * If there's a BPF listener, bounce a copy of this frame
135141502Swpaul		 * to him.
135241502Swpaul		 */
135341502Swpaul		if (ifp->if_bpf)
135441502Swpaul			bpf_mtap(ifp, cur_tx->vr_mbuf);
135551583Swpaul
135642491Swpaul		VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
135751432Swpaul		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO);
135841502Swpaul	}
135941502Swpaul
136041502Swpaul	/*
136141526Swpaul	 * If there are no frames queued, bail.
136241526Swpaul	 */
136341526Swpaul	if (cur_tx == NULL)
136441526Swpaul		return;
136541526Swpaul
136641502Swpaul	sc->vr_cdata.vr_tx_tail = cur_tx;
136741502Swpaul
136842491Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
136941502Swpaul		sc->vr_cdata.vr_tx_head = start_tx;
137041502Swpaul
137141502Swpaul	/*
137241502Swpaul	 * Set a timeout in case the chip goes out to lunch.
137341502Swpaul	 */
137441502Swpaul	ifp->if_timer = 5;
137541502Swpaul
137641502Swpaul	return;
137741502Swpaul}
137841502Swpaul
137941502Swpaulstatic void vr_init(xsc)
138041502Swpaul	void			*xsc;
138141502Swpaul{
138241502Swpaul	struct vr_softc		*sc = xsc;
138341502Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
138451432Swpaul	struct mii_data		*mii;
138541502Swpaul	int			s;
138641502Swpaul
138741502Swpaul	s = splimp();
138841502Swpaul
138951432Swpaul	mii = device_get_softc(sc->vr_miibus);
139041502Swpaul
139141502Swpaul	/*
139241502Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
139341502Swpaul	 */
139441502Swpaul	vr_stop(sc);
139541502Swpaul	vr_reset(sc);
139641502Swpaul
139741502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
139841502Swpaul	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD);
139941502Swpaul
140041502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
140141502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
140241502Swpaul
140341502Swpaul	/* Init circular RX list. */
140441502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
140541502Swpaul		printf("vr%d: initialization failed: no "
140641502Swpaul			"memory for rx buffers\n", sc->vr_unit);
140741502Swpaul		vr_stop(sc);
140841502Swpaul		(void)splx(s);
140941502Swpaul		return;
141041502Swpaul	}
141141502Swpaul
141241502Swpaul	/*
141341502Swpaul	 * Init tx descriptors.
141441502Swpaul	 */
141541502Swpaul	vr_list_tx_init(sc);
141641502Swpaul
141741502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
141841502Swpaul	if (ifp->if_flags & IFF_PROMISC)
141941502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
142041502Swpaul	else
142141502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
142241502Swpaul
142341502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
142441502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
142541502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
142641502Swpaul	else
142741502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
142841502Swpaul
142941502Swpaul	/*
143041502Swpaul	 * Program the multicast filter, if necessary.
143141502Swpaul	 */
143241502Swpaul	vr_setmulti(sc);
143341502Swpaul
143441502Swpaul	/*
143541502Swpaul	 * Load the address of the RX list.
143641502Swpaul	 */
143741502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
143841502Swpaul
143941502Swpaul	/* Enable receiver and transmitter. */
144041502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
144141502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
144241502Swpaul				    VR_CMD_RX_GO);
144341502Swpaul
144441502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
144541502Swpaul
144641502Swpaul	/*
144741502Swpaul	 * Enable interrupts.
144841502Swpaul	 */
144941502Swpaul	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
145041502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
145141502Swpaul
145251432Swpaul	mii_mediachg(mii);
145341502Swpaul
145441502Swpaul	ifp->if_flags |= IFF_RUNNING;
145541502Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
145641502Swpaul
145741502Swpaul	(void)splx(s);
145841502Swpaul
145951432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
146051432Swpaul
146141502Swpaul	return;
146241502Swpaul}
146341502Swpaul
146441502Swpaul/*
146541502Swpaul * Set media options.
146641502Swpaul */
146741502Swpaulstatic int vr_ifmedia_upd(ifp)
146841502Swpaul	struct ifnet		*ifp;
146941502Swpaul{
147041502Swpaul	struct vr_softc		*sc;
147141502Swpaul
147241502Swpaul	sc = ifp->if_softc;
147341502Swpaul
147451432Swpaul	if (ifp->if_flags & IFF_UP)
147551432Swpaul		vr_init(sc);
147641502Swpaul
147741502Swpaul	return(0);
147841502Swpaul}
147941502Swpaul
148041502Swpaul/*
148141502Swpaul * Report current media status.
148241502Swpaul */
148341502Swpaulstatic void vr_ifmedia_sts(ifp, ifmr)
148441502Swpaul	struct ifnet		*ifp;
148541502Swpaul	struct ifmediareq	*ifmr;
148641502Swpaul{
148741502Swpaul	struct vr_softc		*sc;
148851432Swpaul	struct mii_data		*mii;
148941502Swpaul
149041502Swpaul	sc = ifp->if_softc;
149151432Swpaul	mii = device_get_softc(sc->vr_miibus);
149251432Swpaul	mii_pollstat(mii);
149351432Swpaul	ifmr->ifm_active = mii->mii_media_active;
149451432Swpaul	ifmr->ifm_status = mii->mii_media_status;
149541502Swpaul
149641502Swpaul	return;
149741502Swpaul}
149841502Swpaul
149941502Swpaulstatic int vr_ioctl(ifp, command, data)
150041502Swpaul	struct ifnet		*ifp;
150141502Swpaul	u_long			command;
150241502Swpaul	caddr_t			data;
150341502Swpaul{
150441502Swpaul	struct vr_softc		*sc = ifp->if_softc;
150541502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
150651432Swpaul	struct mii_data		*mii;
150741502Swpaul	int			s, error = 0;
150841502Swpaul
150941502Swpaul	s = splimp();
151041502Swpaul
151141502Swpaul	switch(command) {
151241502Swpaul	case SIOCSIFADDR:
151341502Swpaul	case SIOCGIFADDR:
151441502Swpaul	case SIOCSIFMTU:
151541502Swpaul		error = ether_ioctl(ifp, command, data);
151641502Swpaul		break;
151741502Swpaul	case SIOCSIFFLAGS:
151841502Swpaul		if (ifp->if_flags & IFF_UP) {
151941502Swpaul			vr_init(sc);
152041502Swpaul		} else {
152141502Swpaul			if (ifp->if_flags & IFF_RUNNING)
152241502Swpaul				vr_stop(sc);
152341502Swpaul		}
152441502Swpaul		error = 0;
152541502Swpaul		break;
152641502Swpaul	case SIOCADDMULTI:
152741502Swpaul	case SIOCDELMULTI:
152841502Swpaul		vr_setmulti(sc);
152941502Swpaul		error = 0;
153041502Swpaul		break;
153141502Swpaul	case SIOCGIFMEDIA:
153241502Swpaul	case SIOCSIFMEDIA:
153351432Swpaul		mii = device_get_softc(sc->vr_miibus);
153451432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
153541502Swpaul		break;
153641502Swpaul	default:
153741502Swpaul		error = EINVAL;
153841502Swpaul		break;
153941502Swpaul	}
154041502Swpaul
154141502Swpaul	(void)splx(s);
154241502Swpaul
154341502Swpaul	return(error);
154441502Swpaul}
154541502Swpaul
154641502Swpaulstatic void vr_watchdog(ifp)
154741502Swpaul	struct ifnet		*ifp;
154841502Swpaul{
154941502Swpaul	struct vr_softc		*sc;
155041502Swpaul
155141502Swpaul	sc = ifp->if_softc;
155241502Swpaul
155341502Swpaul	ifp->if_oerrors++;
155441502Swpaul	printf("vr%d: watchdog timeout\n", sc->vr_unit);
155541502Swpaul
155641502Swpaul	vr_stop(sc);
155741502Swpaul	vr_reset(sc);
155841502Swpaul	vr_init(sc);
155941502Swpaul
156041502Swpaul	if (ifp->if_snd.ifq_head != NULL)
156141502Swpaul		vr_start(ifp);
156241502Swpaul
156341502Swpaul	return;
156441502Swpaul}
156541502Swpaul
156641502Swpaul/*
156741502Swpaul * Stop the adapter and free any mbufs allocated to the
156841502Swpaul * RX and TX lists.
156941502Swpaul */
157041502Swpaulstatic void vr_stop(sc)
157141502Swpaul	struct vr_softc		*sc;
157241502Swpaul{
157341502Swpaul	register int		i;
157441502Swpaul	struct ifnet		*ifp;
157541502Swpaul
157641502Swpaul	ifp = &sc->arpcom.ac_if;
157741502Swpaul	ifp->if_timer = 0;
157841502Swpaul
157951432Swpaul	untimeout(vr_tick, sc, sc->vr_stat_ch);
158051432Swpaul
158141502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
158241502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
158341502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
158441502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
158541502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
158641502Swpaul
158741502Swpaul	/*
158841502Swpaul	 * Free data in the RX lists.
158941502Swpaul	 */
159041502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
159141502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
159241502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
159341502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
159441502Swpaul		}
159541502Swpaul	}
159641502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
159741502Swpaul		sizeof(sc->vr_ldata->vr_rx_list));
159841502Swpaul
159941502Swpaul	/*
160041502Swpaul	 * Free the TX list buffers.
160141502Swpaul	 */
160241502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
160341502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
160441502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
160541502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
160641502Swpaul		}
160741502Swpaul	}
160841502Swpaul
160941502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
161041502Swpaul		sizeof(sc->vr_ldata->vr_tx_list));
161141502Swpaul
161241502Swpaul	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
161341502Swpaul
161441502Swpaul	return;
161541502Swpaul}
161641502Swpaul
161741502Swpaul/*
161841502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
161941502Swpaul * get confused by errant DMAs when rebooting.
162041502Swpaul */
162149610Swpaulstatic void vr_shutdown(dev)
162249610Swpaul	device_t		dev;
162341502Swpaul{
162449610Swpaul	struct vr_softc		*sc;
162541502Swpaul
162649610Swpaul	sc = device_get_softc(dev);
162749610Swpaul
162841502Swpaul	vr_stop(sc);
162941502Swpaul
163041502Swpaul	return;
163141502Swpaul}
1632