if_vr.c revision 44238
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 *
3244238Swpaul *	$Id: if_vr.c,v 1.18 1999/02/23 06:47:52 wpaul Exp $
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 "bpfilter.h"
6341502Swpaul
6441502Swpaul#include <sys/param.h>
6541502Swpaul#include <sys/systm.h>
6641502Swpaul#include <sys/sockio.h>
6741502Swpaul#include <sys/mbuf.h>
6841502Swpaul#include <sys/malloc.h>
6941502Swpaul#include <sys/kernel.h>
7041502Swpaul#include <sys/socket.h>
7141502Swpaul
7241502Swpaul#include <net/if.h>
7341502Swpaul#include <net/if_arp.h>
7441502Swpaul#include <net/ethernet.h>
7541502Swpaul#include <net/if_dl.h>
7641502Swpaul#include <net/if_media.h>
7741502Swpaul
7841502Swpaul#if NBPFILTER > 0
7941502Swpaul#include <net/bpf.h>
8041502Swpaul#endif
8141502Swpaul
8241502Swpaul#include <vm/vm.h>              /* for vtophys */
8341502Swpaul#include <vm/pmap.h>            /* for vtophys */
8441502Swpaul#include <machine/clock.h>      /* for DELAY */
8541502Swpaul#include <machine/bus_pio.h>
8641502Swpaul#include <machine/bus_memio.h>
8741502Swpaul#include <machine/bus.h>
8841502Swpaul
8941502Swpaul#include <pci/pcireg.h>
9041502Swpaul#include <pci/pcivar.h>
9141502Swpaul
9241502Swpaul#define VR_USEIOSPACE
9341502Swpaul
9441502Swpaul/* #define VR_BACKGROUND_AUTONEG */
9541502Swpaul
9641502Swpaul#include <pci/if_vrreg.h>
9741502Swpaul
9841502Swpaul#ifndef lint
9941591Sarchiestatic const char rcsid[] =
10044238Swpaul	"$Id: if_vr.c,v 1.18 1999/02/23 06:47:52 wpaul Exp $";
10141502Swpaul#endif
10241502Swpaul
10341502Swpaul/*
10441502Swpaul * Various supported device vendors/types and their names.
10541502Swpaul */
10641502Swpaulstatic struct vr_type vr_devs[] = {
10741502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
10841502Swpaul		"VIA VT3043 Rhine I 10/100BaseTX" },
10941502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
11041502Swpaul		"VIA VT86C100A Rhine II 10/100BaseTX" },
11144238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
11244238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
11344238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
11444238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
11541502Swpaul	{ 0, 0, NULL }
11641502Swpaul};
11741502Swpaul
11841502Swpaul/*
11941502Swpaul * Various supported PHY vendors/types and their names. Note that
12041502Swpaul * this driver will work with pretty much any MII-compliant PHY,
12141502Swpaul * so failure to positively identify the chip is not a fatal error.
12241502Swpaul */
12341502Swpaul
12441502Swpaulstatic struct vr_type vr_phys[] = {
12541502Swpaul	{ TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" },
12641502Swpaul	{ TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" },
12741502Swpaul	{ NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"},
12841502Swpaul	{ LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" },
12941502Swpaul	{ INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" },
13041502Swpaul	{ SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" },
13141502Swpaul	{ 0, 0, "<MII-compliant physical interface>" }
13241502Swpaul};
13341502Swpaul
13441502Swpaulstatic unsigned long vr_count = 0;
13541771Sdillonstatic const char *vr_probe	__P((pcici_t, pcidi_t));
13641502Swpaulstatic void vr_attach		__P((pcici_t, int));
13741502Swpaul
13841502Swpaulstatic int vr_newbuf		__P((struct vr_softc *,
13941502Swpaul						struct vr_chain_onefrag *));
14041502Swpaulstatic int vr_encap		__P((struct vr_softc *, struct vr_chain *,
14141502Swpaul						struct mbuf * ));
14241502Swpaul
14341502Swpaulstatic void vr_rxeof		__P((struct vr_softc *));
14441502Swpaulstatic void vr_rxeoc		__P((struct vr_softc *));
14541502Swpaulstatic void vr_txeof		__P((struct vr_softc *));
14641502Swpaulstatic void vr_txeoc		__P((struct vr_softc *));
14741502Swpaulstatic void vr_intr		__P((void *));
14841502Swpaulstatic void vr_start		__P((struct ifnet *));
14941502Swpaulstatic int vr_ioctl		__P((struct ifnet *, u_long, caddr_t));
15041502Swpaulstatic void vr_init		__P((void *));
15141502Swpaulstatic void vr_stop		__P((struct vr_softc *));
15241502Swpaulstatic void vr_watchdog		__P((struct ifnet *));
15341502Swpaulstatic void vr_shutdown		__P((int, void *));
15441502Swpaulstatic int vr_ifmedia_upd	__P((struct ifnet *));
15541502Swpaulstatic void vr_ifmedia_sts	__P((struct ifnet *, struct ifmediareq *));
15641502Swpaul
15741502Swpaulstatic void vr_mii_sync		__P((struct vr_softc *));
15841502Swpaulstatic void vr_mii_send		__P((struct vr_softc *, u_int32_t, int));
15941502Swpaulstatic int vr_mii_readreg	__P((struct vr_softc *, struct vr_mii_frame *));
16041502Swpaulstatic int vr_mii_writereg	__P((struct vr_softc *, struct vr_mii_frame *));
16141502Swpaulstatic u_int16_t vr_phy_readreg	__P((struct vr_softc *, int));
16241502Swpaulstatic void vr_phy_writereg	__P((struct vr_softc *, u_int16_t, u_int16_t));
16341502Swpaul
16441502Swpaulstatic void vr_autoneg_xmit	__P((struct vr_softc *));
16541502Swpaulstatic void vr_autoneg_mii	__P((struct vr_softc *, int, int));
16641502Swpaulstatic void vr_setmode_mii	__P((struct vr_softc *, int));
16741502Swpaulstatic void vr_getmode_mii	__P((struct vr_softc *));
16841502Swpaulstatic void vr_setcfg		__P((struct vr_softc *, u_int16_t));
16941502Swpaulstatic u_int8_t vr_calchash	__P((u_int8_t *));
17041502Swpaulstatic void vr_setmulti		__P((struct vr_softc *));
17141502Swpaulstatic void vr_reset		__P((struct vr_softc *));
17241502Swpaulstatic int vr_list_rx_init	__P((struct vr_softc *));
17341502Swpaulstatic int vr_list_tx_init	__P((struct vr_softc *));
17441502Swpaul
17541502Swpaul#define VR_SETBIT(sc, reg, x)				\
17641502Swpaul	CSR_WRITE_1(sc, reg,				\
17741502Swpaul		CSR_READ_1(sc, reg) | x)
17841502Swpaul
17941502Swpaul#define VR_CLRBIT(sc, reg, x)				\
18041502Swpaul	CSR_WRITE_1(sc, reg,				\
18141502Swpaul		CSR_READ_1(sc, reg) & ~x)
18241502Swpaul
18341502Swpaul#define VR_SETBIT16(sc, reg, x)				\
18441502Swpaul	CSR_WRITE_2(sc, reg,				\
18541502Swpaul		CSR_READ_2(sc, reg) | x)
18641502Swpaul
18741502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
18841502Swpaul	CSR_WRITE_2(sc, reg,				\
18941502Swpaul		CSR_READ_2(sc, reg) & ~x)
19041502Swpaul
19141502Swpaul#define VR_SETBIT32(sc, reg, x)				\
19241502Swpaul	CSR_WRITE_4(sc, reg,				\
19341502Swpaul		CSR_READ_4(sc, reg) | x)
19441502Swpaul
19541502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
19641502Swpaul	CSR_WRITE_4(sc, reg,				\
19741502Swpaul		CSR_READ_4(sc, reg) & ~x)
19841502Swpaul
19941502Swpaul#define SIO_SET(x)					\
20041502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
20141502Swpaul		CSR_READ_1(sc, VR_MIICMD) | x)
20241502Swpaul
20341502Swpaul#define SIO_CLR(x)					\
20441502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
20541502Swpaul		CSR_READ_1(sc, VR_MIICMD) & ~x)
20641502Swpaul
20741502Swpaul/*
20841502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
20941502Swpaul */
21041502Swpaulstatic void vr_mii_sync(sc)
21141502Swpaul	struct vr_softc		*sc;
21241502Swpaul{
21341502Swpaul	register int		i;
21441502Swpaul
21541502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
21641502Swpaul
21741502Swpaul	for (i = 0; i < 32; i++) {
21841502Swpaul		SIO_SET(VR_MIICMD_CLK);
21941502Swpaul		DELAY(1);
22041502Swpaul		SIO_CLR(VR_MIICMD_CLK);
22141502Swpaul		DELAY(1);
22241502Swpaul	}
22341502Swpaul
22441502Swpaul	return;
22541502Swpaul}
22641502Swpaul
22741502Swpaul/*
22841502Swpaul * Clock a series of bits through the MII.
22941502Swpaul */
23041502Swpaulstatic void vr_mii_send(sc, bits, cnt)
23141502Swpaul	struct vr_softc		*sc;
23241502Swpaul	u_int32_t		bits;
23341502Swpaul	int			cnt;
23441502Swpaul{
23541502Swpaul	int			i;
23641502Swpaul
23741502Swpaul	SIO_CLR(VR_MIICMD_CLK);
23841502Swpaul
23941502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
24041502Swpaul                if (bits & i) {
24141502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
24241502Swpaul                } else {
24341502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
24441502Swpaul                }
24541502Swpaul		DELAY(1);
24641502Swpaul		SIO_CLR(VR_MIICMD_CLK);
24741502Swpaul		DELAY(1);
24841502Swpaul		SIO_SET(VR_MIICMD_CLK);
24941502Swpaul	}
25041502Swpaul}
25141502Swpaul
25241502Swpaul/*
25341502Swpaul * Read an PHY register through the MII.
25441502Swpaul */
25541502Swpaulstatic int vr_mii_readreg(sc, frame)
25641502Swpaul	struct vr_softc		*sc;
25741502Swpaul	struct vr_mii_frame	*frame;
25841502Swpaul
25941502Swpaul{
26041502Swpaul	int			i, ack, s;
26141502Swpaul
26241502Swpaul	s = splimp();
26341502Swpaul
26441502Swpaul	/*
26541502Swpaul	 * Set up frame for RX.
26641502Swpaul	 */
26741502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
26841502Swpaul	frame->mii_opcode = VR_MII_READOP;
26941502Swpaul	frame->mii_turnaround = 0;
27041502Swpaul	frame->mii_data = 0;
27141502Swpaul
27241502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
27341502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
27441502Swpaul
27541502Swpaul	/*
27641502Swpaul 	 * Turn on data xmit.
27741502Swpaul	 */
27841502Swpaul	SIO_SET(VR_MIICMD_DIR);
27941502Swpaul
28041502Swpaul	vr_mii_sync(sc);
28141502Swpaul
28241502Swpaul	/*
28341502Swpaul	 * Send command/address info.
28441502Swpaul	 */
28541502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
28641502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
28741502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
28841502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
28941502Swpaul
29041502Swpaul	/* Idle bit */
29141502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
29241502Swpaul	DELAY(1);
29341502Swpaul	SIO_SET(VR_MIICMD_CLK);
29441502Swpaul	DELAY(1);
29541502Swpaul
29641502Swpaul	/* Turn off xmit. */
29741502Swpaul	SIO_CLR(VR_MIICMD_DIR);
29841502Swpaul
29941502Swpaul	/* Check for ack */
30041502Swpaul	SIO_CLR(VR_MIICMD_CLK);
30141502Swpaul	DELAY(1);
30241502Swpaul	SIO_SET(VR_MIICMD_CLK);
30341502Swpaul	DELAY(1);
30441502Swpaul	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
30541502Swpaul
30641502Swpaul	/*
30741502Swpaul	 * Now try reading data bits. If the ack failed, we still
30841502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
30941502Swpaul	 */
31041502Swpaul	if (ack) {
31141502Swpaul		for(i = 0; i < 16; i++) {
31241502Swpaul			SIO_CLR(VR_MIICMD_CLK);
31341502Swpaul			DELAY(1);
31441502Swpaul			SIO_SET(VR_MIICMD_CLK);
31541502Swpaul			DELAY(1);
31641502Swpaul		}
31741502Swpaul		goto fail;
31841502Swpaul	}
31941502Swpaul
32041502Swpaul	for (i = 0x8000; i; i >>= 1) {
32141502Swpaul		SIO_CLR(VR_MIICMD_CLK);
32241502Swpaul		DELAY(1);
32341502Swpaul		if (!ack) {
32441502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
32541502Swpaul				frame->mii_data |= i;
32641502Swpaul			DELAY(1);
32741502Swpaul		}
32841502Swpaul		SIO_SET(VR_MIICMD_CLK);
32941502Swpaul		DELAY(1);
33041502Swpaul	}
33141502Swpaul
33241502Swpaulfail:
33341502Swpaul
33441502Swpaul	SIO_CLR(VR_MIICMD_CLK);
33541502Swpaul	DELAY(1);
33641502Swpaul	SIO_SET(VR_MIICMD_CLK);
33741502Swpaul	DELAY(1);
33841502Swpaul
33941502Swpaul	splx(s);
34041502Swpaul
34141502Swpaul	if (ack)
34241502Swpaul		return(1);
34341502Swpaul	return(0);
34441502Swpaul}
34541502Swpaul
34641502Swpaul/*
34741502Swpaul * Write to a PHY register through the MII.
34841502Swpaul */
34941502Swpaulstatic int vr_mii_writereg(sc, frame)
35041502Swpaul	struct vr_softc		*sc;
35141502Swpaul	struct vr_mii_frame	*frame;
35241502Swpaul
35341502Swpaul{
35441502Swpaul	int			s;
35541502Swpaul
35641502Swpaul	s = splimp();
35741502Swpaul
35841502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
35941502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
36041502Swpaul
36141502Swpaul	/*
36241502Swpaul	 * Set up frame for TX.
36341502Swpaul	 */
36441502Swpaul
36541502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
36641502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
36741502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
36841502Swpaul
36941502Swpaul	/*
37041502Swpaul 	 * Turn on data output.
37141502Swpaul	 */
37241502Swpaul	SIO_SET(VR_MIICMD_DIR);
37341502Swpaul
37441502Swpaul	vr_mii_sync(sc);
37541502Swpaul
37641502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
37741502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
37841502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
37941502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
38041502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
38141502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
38241502Swpaul
38341502Swpaul	/* Idle bit. */
38441502Swpaul	SIO_SET(VR_MIICMD_CLK);
38541502Swpaul	DELAY(1);
38641502Swpaul	SIO_CLR(VR_MIICMD_CLK);
38741502Swpaul	DELAY(1);
38841502Swpaul
38941502Swpaul	/*
39041502Swpaul	 * Turn off xmit.
39141502Swpaul	 */
39241502Swpaul	SIO_CLR(VR_MIICMD_DIR);
39341502Swpaul
39441502Swpaul	splx(s);
39541502Swpaul
39641502Swpaul	return(0);
39741502Swpaul}
39841502Swpaul
39941502Swpaulstatic u_int16_t vr_phy_readreg(sc, reg)
40041502Swpaul	struct vr_softc		*sc;
40141502Swpaul	int			reg;
40241502Swpaul{
40341502Swpaul	struct vr_mii_frame	frame;
40441502Swpaul
40541502Swpaul	bzero((char *)&frame, sizeof(frame));
40641502Swpaul
40741502Swpaul	frame.mii_phyaddr = sc->vr_phy_addr;
40841502Swpaul	frame.mii_regaddr = reg;
40941502Swpaul	vr_mii_readreg(sc, &frame);
41041502Swpaul
41141502Swpaul	return(frame.mii_data);
41241502Swpaul}
41341502Swpaul
41441502Swpaulstatic void vr_phy_writereg(sc, reg, data)
41541502Swpaul	struct vr_softc		*sc;
41641502Swpaul	u_int16_t		reg;
41741502Swpaul	u_int16_t		data;
41841502Swpaul{
41941502Swpaul	struct vr_mii_frame	frame;
42041502Swpaul
42141502Swpaul	bzero((char *)&frame, sizeof(frame));
42241502Swpaul
42341502Swpaul	frame.mii_phyaddr = sc->vr_phy_addr;
42441502Swpaul	frame.mii_regaddr = reg;
42541502Swpaul	frame.mii_data = data;
42641502Swpaul
42741502Swpaul	vr_mii_writereg(sc, &frame);
42841502Swpaul
42941502Swpaul	return;
43041502Swpaul}
43141502Swpaul
43241502Swpaul/*
43341502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits.
43441502Swpaul */
43541502Swpaulstatic u_int8_t vr_calchash(addr)
43641502Swpaul	u_int8_t		*addr;
43741502Swpaul{
43841502Swpaul	u_int32_t		crc, carry;
43941502Swpaul	int			i, j;
44041502Swpaul	u_int8_t		c;
44141502Swpaul
44241502Swpaul	/* Compute CRC for the address value. */
44341502Swpaul	crc = 0xFFFFFFFF; /* initial value */
44441502Swpaul
44541502Swpaul	for (i = 0; i < 6; i++) {
44641502Swpaul		c = *(addr + i);
44741502Swpaul		for (j = 0; j < 8; j++) {
44841502Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
44941502Swpaul			crc <<= 1;
45041502Swpaul			c >>= 1;
45141502Swpaul			if (carry)
45241502Swpaul				crc = (crc ^ 0x04c11db6) | carry;
45341502Swpaul		}
45441502Swpaul	}
45541502Swpaul
45641502Swpaul	/* return the filter bit position */
45741502Swpaul	return((crc >> 26) & 0x0000003F);
45841502Swpaul}
45941502Swpaul
46041502Swpaul/*
46141502Swpaul * Program the 64-bit multicast hash filter.
46241502Swpaul */
46341502Swpaulstatic void vr_setmulti(sc)
46441502Swpaul	struct vr_softc		*sc;
46541502Swpaul{
46641502Swpaul	struct ifnet		*ifp;
46741502Swpaul	int			h = 0;
46841502Swpaul	u_int32_t		hashes[2] = { 0, 0 };
46941502Swpaul	struct ifmultiaddr	*ifma;
47041502Swpaul	u_int8_t		rxfilt;
47141502Swpaul	int			mcnt = 0;
47241502Swpaul
47341502Swpaul	ifp = &sc->arpcom.ac_if;
47441502Swpaul
47541502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
47641502Swpaul
47741502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
47841502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
47941502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
48041502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
48141502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
48241502Swpaul		return;
48341502Swpaul	}
48441502Swpaul
48541502Swpaul	/* first, zot all the existing hash bits */
48641502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
48741502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
48841502Swpaul
48941502Swpaul	/* now program new ones */
49041502Swpaul	for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
49141502Swpaul				ifma = ifma->ifma_link.le_next) {
49241502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
49341502Swpaul			continue;
49441502Swpaul		h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
49541502Swpaul		if (h < 32)
49641502Swpaul			hashes[0] |= (1 << h);
49741502Swpaul		else
49841502Swpaul			hashes[1] |= (1 << (h - 32));
49941502Swpaul		mcnt++;
50041502Swpaul	}
50141502Swpaul
50241502Swpaul	if (mcnt)
50341502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
50441502Swpaul	else
50541502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
50641502Swpaul
50741502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
50841502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
50941502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
51041502Swpaul
51141502Swpaul	return;
51241502Swpaul}
51341502Swpaul
51441502Swpaul/*
51541502Swpaul * Initiate an autonegotiation session.
51641502Swpaul */
51741502Swpaulstatic void vr_autoneg_xmit(sc)
51841502Swpaul	struct vr_softc		*sc;
51941502Swpaul{
52041502Swpaul	u_int16_t		phy_sts;
52141502Swpaul
52241502Swpaul	vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
52341502Swpaul	DELAY(500);
52441502Swpaul	while(vr_phy_readreg(sc, PHY_BMCR)
52541502Swpaul			& PHY_BMCR_RESET);
52641502Swpaul
52741502Swpaul	phy_sts = vr_phy_readreg(sc, PHY_BMCR);
52841502Swpaul	phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR;
52941502Swpaul	vr_phy_writereg(sc, PHY_BMCR, phy_sts);
53041502Swpaul
53141502Swpaul	return;
53241502Swpaul}
53341502Swpaul
53441502Swpaul/*
53541502Swpaul * Invoke autonegotiation on a PHY.
53641502Swpaul */
53741502Swpaulstatic void vr_autoneg_mii(sc, flag, verbose)
53841502Swpaul	struct vr_softc		*sc;
53941502Swpaul	int			flag;
54041502Swpaul	int			verbose;
54141502Swpaul{
54241502Swpaul	u_int16_t		phy_sts = 0, media, advert, ability;
54341502Swpaul	struct ifnet		*ifp;
54441502Swpaul	struct ifmedia		*ifm;
54541502Swpaul
54641502Swpaul	ifm = &sc->ifmedia;
54741502Swpaul	ifp = &sc->arpcom.ac_if;
54841502Swpaul
54941502Swpaul	ifm->ifm_media = IFM_ETHER | IFM_AUTO;
55041502Swpaul
55141502Swpaul	/*
55241502Swpaul	 * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported'
55341502Swpaul	 * bit cleared in the status register, but has the 'autoneg enabled'
55441502Swpaul	 * bit set in the control register. This is a contradiction, and
55541502Swpaul	 * I'm not sure how to handle it. If you want to force an attempt
55641502Swpaul	 * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR
55741502Swpaul	 * and see what happens.
55841502Swpaul	 */
55941502Swpaul#ifndef FORCE_AUTONEG_TFOUR
56041502Swpaul	/*
56141502Swpaul	 * First, see if autoneg is supported. If not, there's
56241502Swpaul	 * no point in continuing.
56341502Swpaul	 */
56441502Swpaul	phy_sts = vr_phy_readreg(sc, PHY_BMSR);
56541502Swpaul	if (!(phy_sts & PHY_BMSR_CANAUTONEG)) {
56641502Swpaul		if (verbose)
56741502Swpaul			printf("vr%d: autonegotiation not supported\n",
56841502Swpaul							sc->vr_unit);
56941502Swpaul		ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
57041502Swpaul		return;
57141502Swpaul	}
57241502Swpaul#endif
57341502Swpaul
57441502Swpaul	switch (flag) {
57541502Swpaul	case VR_FLAG_FORCEDELAY:
57641502Swpaul		/*
57741502Swpaul	 	 * XXX Never use this option anywhere but in the probe
57841502Swpaul	 	 * routine: making the kernel stop dead in its tracks
57941502Swpaul 		 * for three whole seconds after we've gone multi-user
58041502Swpaul		 * is really bad manners.
58141502Swpaul	 	 */
58241502Swpaul		vr_autoneg_xmit(sc);
58341502Swpaul		DELAY(5000000);
58441502Swpaul		break;
58541502Swpaul	case VR_FLAG_SCHEDDELAY:
58641502Swpaul		/*
58741502Swpaul		 * Wait for the transmitter to go idle before starting
58841502Swpaul		 * an autoneg session, otherwise vr_start() may clobber
58941502Swpaul	 	 * our timeout, and we don't want to allow transmission
59041502Swpaul		 * during an autoneg session since that can screw it up.
59141502Swpaul	 	 */
59241502Swpaul		if (sc->vr_cdata.vr_tx_head != NULL) {
59341502Swpaul			sc->vr_want_auto = 1;
59441502Swpaul			return;
59541502Swpaul		}
59641502Swpaul		vr_autoneg_xmit(sc);
59741502Swpaul		ifp->if_timer = 5;
59841502Swpaul		sc->vr_autoneg = 1;
59941502Swpaul		sc->vr_want_auto = 0;
60041502Swpaul		return;
60141502Swpaul		break;
60241502Swpaul	case VR_FLAG_DELAYTIMEO:
60341502Swpaul		ifp->if_timer = 0;
60441502Swpaul		sc->vr_autoneg = 0;
60541502Swpaul		break;
60641502Swpaul	default:
60741502Swpaul		printf("vr%d: invalid autoneg flag: %d\n", sc->vr_unit, flag);
60841502Swpaul		return;
60941502Swpaul	}
61041502Swpaul
61141502Swpaul	if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) {
61241502Swpaul		if (verbose)
61341502Swpaul			printf("vr%d: autoneg complete, ", sc->vr_unit);
61441502Swpaul		phy_sts = vr_phy_readreg(sc, PHY_BMSR);
61541502Swpaul	} else {
61641502Swpaul		if (verbose)
61741502Swpaul			printf("vr%d: autoneg not complete, ", sc->vr_unit);
61841502Swpaul	}
61941502Swpaul
62041502Swpaul	media = vr_phy_readreg(sc, PHY_BMCR);
62141502Swpaul
62241502Swpaul	/* Link is good. Report modes and set duplex mode. */
62341502Swpaul	if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) {
62441502Swpaul		if (verbose)
62541502Swpaul			printf("link status good ");
62641502Swpaul		advert = vr_phy_readreg(sc, PHY_ANAR);
62741502Swpaul		ability = vr_phy_readreg(sc, PHY_LPAR);
62841502Swpaul
62941502Swpaul		if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) {
63041502Swpaul			ifm->ifm_media = IFM_ETHER|IFM_100_T4;
63141502Swpaul			media |= PHY_BMCR_SPEEDSEL;
63241502Swpaul			media &= ~PHY_BMCR_DUPLEX;
63341502Swpaul			printf("(100baseT4)\n");
63441502Swpaul		} else if (advert & PHY_ANAR_100BTXFULL &&
63541502Swpaul			ability & PHY_ANAR_100BTXFULL) {
63641502Swpaul			ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
63741502Swpaul			media |= PHY_BMCR_SPEEDSEL;
63841502Swpaul			media |= PHY_BMCR_DUPLEX;
63941502Swpaul			printf("(full-duplex, 100Mbps)\n");
64041502Swpaul		} else if (advert & PHY_ANAR_100BTXHALF &&
64141502Swpaul			ability & PHY_ANAR_100BTXHALF) {
64241502Swpaul			ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
64341502Swpaul			media |= PHY_BMCR_SPEEDSEL;
64441502Swpaul			media &= ~PHY_BMCR_DUPLEX;
64541502Swpaul			printf("(half-duplex, 100Mbps)\n");
64641502Swpaul		} else if (advert & PHY_ANAR_10BTFULL &&
64741502Swpaul			ability & PHY_ANAR_10BTFULL) {
64841502Swpaul			ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
64941502Swpaul			media &= ~PHY_BMCR_SPEEDSEL;
65041502Swpaul			media |= PHY_BMCR_DUPLEX;
65141502Swpaul			printf("(full-duplex, 10Mbps)\n");
65241502Swpaul		} else {
65341502Swpaul			ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
65441502Swpaul			media &= ~PHY_BMCR_SPEEDSEL;
65541502Swpaul			media &= ~PHY_BMCR_DUPLEX;
65641502Swpaul			printf("(half-duplex, 10Mbps)\n");
65741502Swpaul		}
65841502Swpaul
65941502Swpaul		media &= ~PHY_BMCR_AUTONEGENBL;
66041502Swpaul
66141502Swpaul		/* Set ASIC's duplex mode to match the PHY. */
66241502Swpaul		vr_setcfg(sc, media);
66341502Swpaul		vr_phy_writereg(sc, PHY_BMCR, media);
66441502Swpaul	} else {
66541502Swpaul		if (verbose)
66641502Swpaul			printf("no carrier\n");
66741502Swpaul	}
66841502Swpaul
66941502Swpaul	vr_init(sc);
67041502Swpaul
67141502Swpaul	if (sc->vr_tx_pend) {
67241502Swpaul		sc->vr_autoneg = 0;
67341502Swpaul		sc->vr_tx_pend = 0;
67441502Swpaul		vr_start(ifp);
67541502Swpaul	}
67641502Swpaul
67741502Swpaul	return;
67841502Swpaul}
67941502Swpaul
68041502Swpaulstatic void vr_getmode_mii(sc)
68141502Swpaul	struct vr_softc		*sc;
68241502Swpaul{
68341502Swpaul	u_int16_t		bmsr;
68441502Swpaul	struct ifnet		*ifp;
68541502Swpaul
68641502Swpaul	ifp = &sc->arpcom.ac_if;
68741502Swpaul
68841502Swpaul	bmsr = vr_phy_readreg(sc, PHY_BMSR);
68941502Swpaul	if (bootverbose)
69041502Swpaul		printf("vr%d: PHY status word: %x\n", sc->vr_unit, bmsr);
69141502Swpaul
69241502Swpaul	/* fallback */
69341502Swpaul	sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX;
69441502Swpaul
69541502Swpaul	if (bmsr & PHY_BMSR_10BTHALF) {
69641502Swpaul		if (bootverbose)
69741502Swpaul			printf("vr%d: 10Mbps half-duplex mode supported\n",
69841502Swpaul								sc->vr_unit);
69941502Swpaul		ifmedia_add(&sc->ifmedia,
70041502Swpaul			IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
70141502Swpaul		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
70241502Swpaul	}
70341502Swpaul
70441502Swpaul	if (bmsr & PHY_BMSR_10BTFULL) {
70541502Swpaul		if (bootverbose)
70641502Swpaul			printf("vr%d: 10Mbps full-duplex mode supported\n",
70741502Swpaul								sc->vr_unit);
70841502Swpaul		ifmedia_add(&sc->ifmedia,
70941502Swpaul			IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
71041502Swpaul		sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX;
71141502Swpaul	}
71241502Swpaul
71341502Swpaul	if (bmsr & PHY_BMSR_100BTXHALF) {
71441502Swpaul		if (bootverbose)
71541502Swpaul			printf("vr%d: 100Mbps half-duplex mode supported\n",
71641502Swpaul								sc->vr_unit);
71741502Swpaul		ifp->if_baudrate = 100000000;
71841502Swpaul		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
71941502Swpaul		ifmedia_add(&sc->ifmedia,
72041502Swpaul			IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
72141502Swpaul		sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX;
72241502Swpaul	}
72341502Swpaul
72441502Swpaul	if (bmsr & PHY_BMSR_100BTXFULL) {
72541502Swpaul		if (bootverbose)
72641502Swpaul			printf("vr%d: 100Mbps full-duplex mode supported\n",
72741502Swpaul								sc->vr_unit);
72841502Swpaul		ifp->if_baudrate = 100000000;
72941502Swpaul		ifmedia_add(&sc->ifmedia,
73041502Swpaul			IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
73141502Swpaul		sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX;
73241502Swpaul	}
73341502Swpaul
73441502Swpaul	/* Some also support 100BaseT4. */
73541502Swpaul	if (bmsr & PHY_BMSR_100BT4) {
73641502Swpaul		if (bootverbose)
73741502Swpaul			printf("vr%d: 100baseT4 mode supported\n", sc->vr_unit);
73841502Swpaul		ifp->if_baudrate = 100000000;
73941502Swpaul		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL);
74041502Swpaul		sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4;
74141502Swpaul#ifdef FORCE_AUTONEG_TFOUR
74241502Swpaul		if (bootverbose)
74341502Swpaul			printf("vr%d: forcing on autoneg support for BT4\n",
74441502Swpaul							 sc->vr_unit);
74541502Swpaul		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL):
74641502Swpaul		sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;
74741502Swpaul#endif
74841502Swpaul	}
74941502Swpaul
75041502Swpaul	if (bmsr & PHY_BMSR_CANAUTONEG) {
75141502Swpaul		if (bootverbose)
75241502Swpaul			printf("vr%d: autoneg supported\n", sc->vr_unit);
75341502Swpaul		ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
75441502Swpaul		sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO;
75541502Swpaul	}
75641502Swpaul
75741502Swpaul	return;
75841502Swpaul}
75941502Swpaul
76041502Swpaul/*
76141502Swpaul * Set speed and duplex mode.
76241502Swpaul */
76341502Swpaulstatic void vr_setmode_mii(sc, media)
76441502Swpaul	struct vr_softc		*sc;
76541502Swpaul	int			media;
76641502Swpaul{
76741502Swpaul	u_int16_t		bmcr;
76841502Swpaul	struct ifnet		*ifp;
76941502Swpaul
77041502Swpaul	ifp = &sc->arpcom.ac_if;
77141502Swpaul
77241502Swpaul	/*
77341502Swpaul	 * If an autoneg session is in progress, stop it.
77441502Swpaul	 */
77541502Swpaul	if (sc->vr_autoneg) {
77641502Swpaul		printf("vr%d: canceling autoneg session\n", sc->vr_unit);
77741502Swpaul		ifp->if_timer = sc->vr_autoneg = sc->vr_want_auto = 0;
77841502Swpaul		bmcr = vr_phy_readreg(sc, PHY_BMCR);
77941502Swpaul		bmcr &= ~PHY_BMCR_AUTONEGENBL;
78041502Swpaul		vr_phy_writereg(sc, PHY_BMCR, bmcr);
78141502Swpaul	}
78241502Swpaul
78341502Swpaul	printf("vr%d: selecting MII, ", sc->vr_unit);
78441502Swpaul
78541502Swpaul	bmcr = vr_phy_readreg(sc, PHY_BMCR);
78641502Swpaul
78741502Swpaul	bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL|
78841502Swpaul			PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK);
78941502Swpaul
79041502Swpaul	if (IFM_SUBTYPE(media) == IFM_100_T4) {
79141502Swpaul		printf("100Mbps/T4, half-duplex\n");
79241502Swpaul		bmcr |= PHY_BMCR_SPEEDSEL;
79341502Swpaul		bmcr &= ~PHY_BMCR_DUPLEX;
79441502Swpaul	}
79541502Swpaul
79641502Swpaul	if (IFM_SUBTYPE(media) == IFM_100_TX) {
79741502Swpaul		printf("100Mbps, ");
79841502Swpaul		bmcr |= PHY_BMCR_SPEEDSEL;
79941502Swpaul	}
80041502Swpaul
80141502Swpaul	if (IFM_SUBTYPE(media) == IFM_10_T) {
80241502Swpaul		printf("10Mbps, ");
80341502Swpaul		bmcr &= ~PHY_BMCR_SPEEDSEL;
80441502Swpaul	}
80541502Swpaul
80641502Swpaul	if ((media & IFM_GMASK) == IFM_FDX) {
80741502Swpaul		printf("full duplex\n");
80841502Swpaul		bmcr |= PHY_BMCR_DUPLEX;
80941502Swpaul	} else {
81041502Swpaul		printf("half duplex\n");
81141502Swpaul		bmcr &= ~PHY_BMCR_DUPLEX;
81241502Swpaul	}
81341502Swpaul
81441502Swpaul	vr_setcfg(sc, bmcr);
81541502Swpaul	vr_phy_writereg(sc, PHY_BMCR, bmcr);
81641502Swpaul
81741502Swpaul	return;
81841502Swpaul}
81941502Swpaul
82041502Swpaul/*
82141502Swpaul * In order to fiddle with the
82241502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
82341502Swpaul * first have to put the transmit and/or receive logic in the idle state.
82441502Swpaul */
82541502Swpaulstatic void vr_setcfg(sc, bmcr)
82641502Swpaul	struct vr_softc		*sc;
82741502Swpaul	u_int16_t		bmcr;
82841502Swpaul{
82941502Swpaul	int			restart = 0;
83041502Swpaul
83141502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
83241502Swpaul		restart = 1;
83341502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
83441502Swpaul	}
83541502Swpaul
83641502Swpaul	if (bmcr & PHY_BMCR_DUPLEX)
83741502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
83841502Swpaul	else
83941502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
84041502Swpaul
84141502Swpaul	if (restart)
84241502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
84341502Swpaul
84441502Swpaul	return;
84541502Swpaul}
84641502Swpaul
84741502Swpaulstatic void vr_reset(sc)
84841502Swpaul	struct vr_softc		*sc;
84941502Swpaul{
85041502Swpaul	register int		i;
85141502Swpaul
85241502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
85341502Swpaul
85441502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
85541502Swpaul		DELAY(10);
85641502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
85741502Swpaul			break;
85841502Swpaul	}
85941502Swpaul	if (i == VR_TIMEOUT)
86041502Swpaul		printf("vr%d: reset never completed!\n", sc->vr_unit);
86141502Swpaul
86241502Swpaul	/* Wait a little while for the chip to get its brains in order. */
86341502Swpaul	DELAY(1000);
86441502Swpaul
86541502Swpaul        return;
86641502Swpaul}
86741502Swpaul
86841502Swpaul/*
86941502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
87041502Swpaul * IDs against our list and return a device name if we find a match.
87141502Swpaul */
87241771Sdillonstatic const char *
87341502Swpaulvr_probe(config_id, device_id)
87441502Swpaul	pcici_t			config_id;
87541502Swpaul	pcidi_t			device_id;
87641502Swpaul{
87741502Swpaul	struct vr_type		*t;
87841502Swpaul
87941502Swpaul	t = vr_devs;
88041502Swpaul
88141502Swpaul	while(t->vr_name != NULL) {
88241502Swpaul		if ((device_id & 0xFFFF) == t->vr_vid &&
88341502Swpaul		    ((device_id >> 16) & 0xFFFF) == t->vr_did) {
88441502Swpaul			return(t->vr_name);
88541502Swpaul		}
88641502Swpaul		t++;
88741502Swpaul	}
88841502Swpaul
88941502Swpaul	return(NULL);
89041502Swpaul}
89141502Swpaul
89241502Swpaul/*
89341502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
89441502Swpaul * setup and ethernet/BPF attach.
89541502Swpaul */
89641502Swpaulstatic void
89741502Swpaulvr_attach(config_id, unit)
89841502Swpaul	pcici_t			config_id;
89941502Swpaul	int			unit;
90041502Swpaul{
90141502Swpaul	int			s, i;
90241502Swpaul#ifndef VR_USEIOSPACE
90341502Swpaul	vm_offset_t		pbase, vbase;
90441502Swpaul#endif
90541502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
90641502Swpaul	u_int32_t		command;
90741502Swpaul	struct vr_softc		*sc;
90841502Swpaul	struct ifnet		*ifp;
90941502Swpaul	int			media = IFM_ETHER|IFM_100_TX|IFM_FDX;
91041502Swpaul	unsigned int		round;
91141502Swpaul	caddr_t			roundptr;
91241502Swpaul	struct vr_type		*p;
91341502Swpaul	u_int16_t		phy_vid, phy_did, phy_sts;
91441502Swpaul
91541502Swpaul	s = splimp();
91641502Swpaul
91741502Swpaul	sc = malloc(sizeof(struct vr_softc), M_DEVBUF, M_NOWAIT);
91841502Swpaul	if (sc == NULL) {
91941502Swpaul		printf("vr%d: no memory for softc struct!\n", unit);
92041502Swpaul		return;
92141502Swpaul	}
92241502Swpaul	bzero(sc, sizeof(struct vr_softc));
92341502Swpaul
92441502Swpaul	/*
92541502Swpaul	 * Handle power management nonsense.
92641502Swpaul	 */
92741502Swpaul
92841502Swpaul	command = pci_conf_read(config_id, VR_PCI_CAPID) & 0x000000FF;
92941502Swpaul	if (command == 0x01) {
93041502Swpaul
93141502Swpaul		command = pci_conf_read(config_id, VR_PCI_PWRMGMTCTRL);
93241502Swpaul		if (command & VR_PSTATE_MASK) {
93341502Swpaul			u_int32_t		iobase, membase, irq;
93441502Swpaul
93541502Swpaul			/* Save important PCI config data. */
93641502Swpaul			iobase = pci_conf_read(config_id, VR_PCI_LOIO);
93741502Swpaul			membase = pci_conf_read(config_id, VR_PCI_LOMEM);
93841502Swpaul			irq = pci_conf_read(config_id, VR_PCI_INTLINE);
93941502Swpaul
94041502Swpaul			/* Reset the power state. */
94141502Swpaul			printf("vr%d: chip is in D%d power mode "
94241502Swpaul			"-- setting to D0\n", unit, command & VR_PSTATE_MASK);
94341502Swpaul			command &= 0xFFFFFFFC;
94441502Swpaul			pci_conf_write(config_id, VR_PCI_PWRMGMTCTRL, command);
94541502Swpaul
94641502Swpaul			/* Restore PCI config data. */
94741502Swpaul			pci_conf_write(config_id, VR_PCI_LOIO, iobase);
94841502Swpaul			pci_conf_write(config_id, VR_PCI_LOMEM, membase);
94941502Swpaul			pci_conf_write(config_id, VR_PCI_INTLINE, irq);
95041502Swpaul		}
95141502Swpaul	}
95241502Swpaul
95341502Swpaul	/*
95441502Swpaul	 * Map control/status registers.
95541502Swpaul	 */
95641502Swpaul	command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
95741502Swpaul	command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
95841502Swpaul	pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command);
95941502Swpaul	command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
96041502Swpaul
96141502Swpaul#ifdef VR_USEIOSPACE
96241502Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
96341502Swpaul		printf("vr%d: failed to enable I/O ports!\n", unit);
96441502Swpaul		free(sc, M_DEVBUF);
96541502Swpaul		goto fail;
96641502Swpaul	}
96741502Swpaul
96841502Swpaul	if (!pci_map_port(config_id, VR_PCI_LOIO,
96941502Swpaul					(u_int16_t *)(&sc->vr_bhandle))) {
97041502Swpaul		printf ("vr%d: couldn't map ports\n", unit);
97141502Swpaul		goto fail;
97241502Swpaul	}
97341502Swpaul	sc->vr_btag = I386_BUS_SPACE_IO;
97441502Swpaul#else
97541502Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
97641502Swpaul		printf("vr%d: failed to enable memory mapping!\n", unit);
97741502Swpaul		goto fail;
97841502Swpaul	}
97941502Swpaul
98041502Swpaul	if (!pci_map_mem(config_id, VR_PCI_LOMEM, &vbase, &pbase)) {
98141502Swpaul		printf ("vr%d: couldn't map memory\n", unit);
98241502Swpaul		goto fail;
98341502Swpaul	}
98441502Swpaul
98541502Swpaul	sc->vr_bhandle = vbase;
98641502Swpaul	sc->vr_btag = I386_BUS_SPACE_MEM;
98741502Swpaul#endif
98841502Swpaul
98941502Swpaul	/* Allocate interrupt */
99041502Swpaul	if (!pci_map_int(config_id, vr_intr, sc, &net_imask)) {
99141502Swpaul		printf("vr%d: couldn't map interrupt\n", unit);
99241502Swpaul		goto fail;
99341502Swpaul	}
99441502Swpaul
99541502Swpaul	/* Reset the adapter. */
99641502Swpaul	vr_reset(sc);
99741502Swpaul
99841502Swpaul	/*
99941502Swpaul	 * Get station address. The way the Rhine chips work,
100041502Swpaul	 * you're not allowed to directly access the EEPROM once
100141502Swpaul	 * they've been programmed a special way. Consequently,
100241502Swpaul	 * we need to read the node address from the PAR0 and PAR1
100341502Swpaul	 * registers.
100441502Swpaul	 */
100541502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
100641502Swpaul	DELAY(200);
100741502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
100841502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
100941502Swpaul
101041502Swpaul	/*
101141502Swpaul	 * A Rhine chip was detected. Inform the world.
101241502Swpaul	 */
101341502Swpaul	printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":");
101441502Swpaul
101541502Swpaul	sc->vr_unit = unit;
101641502Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
101741502Swpaul
101841502Swpaul	sc->vr_ldata_ptr = malloc(sizeof(struct vr_list_data) + 8,
101941502Swpaul				M_DEVBUF, M_NOWAIT);
102041502Swpaul	if (sc->vr_ldata_ptr == NULL) {
102141502Swpaul		free(sc, M_DEVBUF);
102241502Swpaul		printf("vr%d: no memory for list buffers!\n", unit);
102341502Swpaul		return;
102441502Swpaul	}
102541502Swpaul
102641502Swpaul	sc->vr_ldata = (struct vr_list_data *)sc->vr_ldata_ptr;
102741502Swpaul	round = (unsigned int)sc->vr_ldata_ptr & 0xF;
102841502Swpaul	roundptr = sc->vr_ldata_ptr;
102941502Swpaul	for (i = 0; i < 8; i++) {
103041502Swpaul		if (round % 8) {
103141502Swpaul			round++;
103241502Swpaul			roundptr++;
103341502Swpaul		} else
103441502Swpaul			break;
103541502Swpaul	}
103641502Swpaul	sc->vr_ldata = (struct vr_list_data *)roundptr;
103741502Swpaul	bzero(sc->vr_ldata, sizeof(struct vr_list_data));
103841502Swpaul
103941502Swpaul	ifp = &sc->arpcom.ac_if;
104041502Swpaul	ifp->if_softc = sc;
104141502Swpaul	ifp->if_unit = unit;
104241502Swpaul	ifp->if_name = "vr";
104341502Swpaul	ifp->if_mtu = ETHERMTU;
104441502Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
104541502Swpaul	ifp->if_ioctl = vr_ioctl;
104641502Swpaul	ifp->if_output = ether_output;
104741502Swpaul	ifp->if_start = vr_start;
104841502Swpaul	ifp->if_watchdog = vr_watchdog;
104941502Swpaul	ifp->if_init = vr_init;
105041502Swpaul	ifp->if_baudrate = 10000000;
105143515Swpaul	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
105241502Swpaul
105341502Swpaul	if (bootverbose)
105441502Swpaul		printf("vr%d: probing for a PHY\n", sc->vr_unit);
105541502Swpaul	for (i = VR_PHYADDR_MIN; i < VR_PHYADDR_MAX + 1; i++) {
105641502Swpaul		if (bootverbose)
105741502Swpaul			printf("vr%d: checking address: %d\n",
105841502Swpaul						sc->vr_unit, i);
105941502Swpaul		sc->vr_phy_addr = i;
106041502Swpaul		vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
106141502Swpaul		DELAY(500);
106241502Swpaul		while(vr_phy_readreg(sc, PHY_BMCR)
106341502Swpaul				& PHY_BMCR_RESET);
106441502Swpaul		if ((phy_sts = vr_phy_readreg(sc, PHY_BMSR)))
106541502Swpaul			break;
106641502Swpaul	}
106741502Swpaul	if (phy_sts) {
106841502Swpaul		phy_vid = vr_phy_readreg(sc, PHY_VENID);
106941502Swpaul		phy_did = vr_phy_readreg(sc, PHY_DEVID);
107041502Swpaul		if (bootverbose)
107141502Swpaul			printf("vr%d: found PHY at address %d, ",
107241502Swpaul					sc->vr_unit, sc->vr_phy_addr);
107341502Swpaul		if (bootverbose)
107441502Swpaul			printf("vendor id: %x device id: %x\n",
107541502Swpaul				phy_vid, phy_did);
107641502Swpaul		p = vr_phys;
107741502Swpaul		while(p->vr_vid) {
107841502Swpaul			if (phy_vid == p->vr_vid &&
107941502Swpaul				(phy_did | 0x000F) == p->vr_did) {
108041502Swpaul				sc->vr_pinfo = p;
108141502Swpaul				break;
108241502Swpaul			}
108341502Swpaul			p++;
108441502Swpaul		}
108541502Swpaul		if (sc->vr_pinfo == NULL)
108641502Swpaul			sc->vr_pinfo = &vr_phys[PHY_UNKNOWN];
108741502Swpaul		if (bootverbose)
108841502Swpaul			printf("vr%d: PHY type: %s\n",
108941502Swpaul				sc->vr_unit, sc->vr_pinfo->vr_name);
109041502Swpaul	} else {
109141502Swpaul		printf("vr%d: MII without any phy!\n", sc->vr_unit);
109241502Swpaul		goto fail;
109341502Swpaul	}
109441502Swpaul
109541502Swpaul	/*
109641502Swpaul	 * Do ifmedia setup.
109741502Swpaul	 */
109841502Swpaul	ifmedia_init(&sc->ifmedia, 0, vr_ifmedia_upd, vr_ifmedia_sts);
109941502Swpaul
110041502Swpaul	vr_getmode_mii(sc);
110141502Swpaul	vr_autoneg_mii(sc, VR_FLAG_FORCEDELAY, 1);
110241502Swpaul	media = sc->ifmedia.ifm_media;
110341502Swpaul	vr_stop(sc);
110441502Swpaul
110541502Swpaul	ifmedia_set(&sc->ifmedia, media);
110641502Swpaul
110741502Swpaul	/*
110841502Swpaul	 * Call MI attach routines.
110941502Swpaul	 */
111041502Swpaul	if_attach(ifp);
111141502Swpaul	ether_ifattach(ifp);
111241502Swpaul
111341502Swpaul#if NBPFILTER > 0
111441502Swpaul	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
111541502Swpaul#endif
111641502Swpaul
111741502Swpaul	at_shutdown(vr_shutdown, sc, SHUTDOWN_POST_SYNC);
111841502Swpaul
111941502Swpaulfail:
112041502Swpaul	splx(s);
112141502Swpaul	return;
112241502Swpaul}
112341502Swpaul
112441502Swpaul/*
112541502Swpaul * Initialize the transmit descriptors.
112641502Swpaul */
112741502Swpaulstatic int vr_list_tx_init(sc)
112841502Swpaul	struct vr_softc		*sc;
112941502Swpaul{
113041502Swpaul	struct vr_chain_data	*cd;
113141502Swpaul	struct vr_list_data	*ld;
113241502Swpaul	int			i;
113341502Swpaul
113441502Swpaul	cd = &sc->vr_cdata;
113541502Swpaul	ld = sc->vr_ldata;
113641502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
113741502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
113841502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
113941502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
114041502Swpaul				&cd->vr_tx_chain[0];
114141502Swpaul		else
114241502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
114341502Swpaul				&cd->vr_tx_chain[i + 1];
114441502Swpaul	}
114541502Swpaul
114641502Swpaul	cd->vr_tx_free = &cd->vr_tx_chain[0];
114741502Swpaul	cd->vr_tx_tail = cd->vr_tx_head = NULL;
114841502Swpaul
114941502Swpaul	return(0);
115041502Swpaul}
115141502Swpaul
115241502Swpaul
115341502Swpaul/*
115441502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
115541502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
115641502Swpaul * points back to the first.
115741502Swpaul */
115841502Swpaulstatic int vr_list_rx_init(sc)
115941502Swpaul	struct vr_softc		*sc;
116041502Swpaul{
116141502Swpaul	struct vr_chain_data	*cd;
116241502Swpaul	struct vr_list_data	*ld;
116341502Swpaul	int			i;
116441502Swpaul
116541502Swpaul	cd = &sc->vr_cdata;
116641502Swpaul	ld = sc->vr_ldata;
116741502Swpaul
116841502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
116941502Swpaul		cd->vr_rx_chain[i].vr_ptr =
117041502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
117141502Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i]) == ENOBUFS)
117241502Swpaul			return(ENOBUFS);
117341502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
117441502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
117541502Swpaul					&cd->vr_rx_chain[0];
117641502Swpaul			ld->vr_rx_list[i].vr_next =
117741502Swpaul					vtophys(&ld->vr_rx_list[0]);
117841502Swpaul		} else {
117941502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
118041502Swpaul					&cd->vr_rx_chain[i + 1];
118141502Swpaul			ld->vr_rx_list[i].vr_next =
118241502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
118341502Swpaul		}
118441502Swpaul	}
118541502Swpaul
118641502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
118741502Swpaul
118841502Swpaul	return(0);
118941502Swpaul}
119041502Swpaul
119141502Swpaul/*
119241502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
119341502Swpaul * Note: the length fields are only 11 bits wide, which means the
119441502Swpaul * largest size we can specify is 2047. This is important because
119541502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
119641502Swpaul * overflow the field and make a mess.
119741502Swpaul */
119841502Swpaulstatic int vr_newbuf(sc, c)
119941502Swpaul	struct vr_softc		*sc;
120041502Swpaul	struct vr_chain_onefrag	*c;
120141502Swpaul{
120241502Swpaul	struct mbuf		*m_new = NULL;
120341502Swpaul
120441502Swpaul	MGETHDR(m_new, M_DONTWAIT, MT_DATA);
120541502Swpaul	if (m_new == NULL) {
120641502Swpaul		printf("vr%d: no memory for rx list -- packet dropped!\n",
120741502Swpaul								sc->vr_unit);
120841502Swpaul		return(ENOBUFS);
120941502Swpaul	}
121041502Swpaul
121141502Swpaul	MCLGET(m_new, M_DONTWAIT);
121241502Swpaul	if (!(m_new->m_flags & M_EXT)) {
121341502Swpaul		printf("vr%d: no memory for rx list -- packet dropped!\n",
121441502Swpaul								sc->vr_unit);
121541502Swpaul		m_freem(m_new);
121641502Swpaul		return(ENOBUFS);
121741502Swpaul	}
121841502Swpaul
121941502Swpaul	c->vr_mbuf = m_new;
122041502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
122141502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
122242491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
122341502Swpaul
122441502Swpaul	return(0);
122541502Swpaul}
122641502Swpaul
122741502Swpaul/*
122841502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
122941502Swpaul * the higher level protocols.
123041502Swpaul */
123141502Swpaulstatic void vr_rxeof(sc)
123241502Swpaul	struct vr_softc		*sc;
123341502Swpaul{
123441502Swpaul        struct ether_header	*eh;
123541502Swpaul        struct mbuf		*m;
123641502Swpaul        struct ifnet		*ifp;
123741502Swpaul	struct vr_chain_onefrag	*cur_rx;
123841502Swpaul	int			total_len = 0;
123941502Swpaul	u_int32_t		rxstat;
124041502Swpaul
124141502Swpaul	ifp = &sc->arpcom.ac_if;
124241502Swpaul
124341502Swpaul	while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
124441502Swpaul							VR_RXSTAT_OWN)) {
124541502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
124641502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
124741502Swpaul
124841502Swpaul		/*
124941502Swpaul		 * If an error occurs, update stats, clear the
125041502Swpaul		 * status word and leave the mbuf cluster in place:
125141502Swpaul		 * it should simply get re-used next time this descriptor
125241502Swpaul	 	 * comes up in the ring.
125341502Swpaul		 */
125441502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
125541502Swpaul			ifp->if_ierrors++;
125641502Swpaul			printf("vr%d: rx error: ", sc->vr_unit);
125741502Swpaul			switch(rxstat & 0x000000FF) {
125841502Swpaul			case VR_RXSTAT_CRCERR:
125941502Swpaul				printf("crc error\n");
126041502Swpaul				break;
126141502Swpaul			case VR_RXSTAT_FRAMEALIGNERR:
126241502Swpaul				printf("frame alignment error\n");
126341502Swpaul				break;
126441502Swpaul			case VR_RXSTAT_FIFOOFLOW:
126541502Swpaul				printf("FIFO overflow\n");
126641502Swpaul				break;
126741502Swpaul			case VR_RXSTAT_GIANT:
126841502Swpaul				printf("received giant packet\n");
126941502Swpaul				break;
127041502Swpaul			case VR_RXSTAT_RUNT:
127141502Swpaul				printf("received runt packet\n");
127241502Swpaul				break;
127341502Swpaul			case VR_RXSTAT_BUSERR:
127441502Swpaul				printf("system bus error\n");
127541502Swpaul				break;
127641502Swpaul			case VR_RXSTAT_BUFFERR:
127741502Swpaul				printf("rx buffer error\n");
127841502Swpaul				break;
127941502Swpaul			default:
128041502Swpaul				printf("unknown rx error\n");
128141502Swpaul				break;
128241502Swpaul			}
128341502Swpaul			cur_rx->vr_ptr->vr_status = VR_RXSTAT;
128442491Swpaul			cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN;
128541502Swpaul			continue;
128641502Swpaul		}
128741502Swpaul
128841502Swpaul		/* No errors; receive the packet. */
128941502Swpaul		m = cur_rx->vr_mbuf;
129041502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
129141502Swpaul
129241502Swpaul		/*
129342048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
129442048Swpaul		 * received frame, and there's no way to turn this
129542048Swpaul		 * behavior off (at least, I can't find anything in
129642048Swpaul	 	 * the manual that explains how to do it) so we have
129742048Swpaul		 * to trim off the CRC manually.
129842048Swpaul		 */
129942048Swpaul		total_len -= ETHER_CRC_LEN;
130042048Swpaul
130142048Swpaul		/*
130241502Swpaul		 * Try to conjure up a new mbuf cluster. If that
130341502Swpaul		 * fails, it means we have an out of memory condition and
130441502Swpaul		 * should leave the buffer in place and continue. This will
130541502Swpaul		 * result in a lost packet, but there's little else we
130641502Swpaul		 * can do in this situation.
130741502Swpaul		 */
130841502Swpaul		if (vr_newbuf(sc, cur_rx) == ENOBUFS) {
130941502Swpaul			ifp->if_ierrors++;
131042260Swpaul			cur_rx->vr_ptr->vr_status = VR_RXSTAT;
131142491Swpaul			cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN;
131241502Swpaul			continue;
131341502Swpaul		}
131441502Swpaul
131541502Swpaul		ifp->if_ipackets++;
131641502Swpaul		eh = mtod(m, struct ether_header *);
131741502Swpaul		m->m_pkthdr.rcvif = ifp;
131841502Swpaul		m->m_pkthdr.len = m->m_len = total_len;
131941502Swpaul#if NBPFILTER > 0
132041502Swpaul		/*
132141502Swpaul		 * Handle BPF listeners. Let the BPF user see the packet, but
132241502Swpaul		 * don't pass it up to the ether_input() layer unless it's
132341502Swpaul		 * a broadcast packet, multicast packet, matches our ethernet
132441502Swpaul		 * address or the interface is in promiscuous mode.
132541502Swpaul		 */
132641502Swpaul		if (ifp->if_bpf) {
132741502Swpaul			bpf_mtap(ifp, m);
132841502Swpaul			if (ifp->if_flags & IFF_PROMISC &&
132941502Swpaul				(bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
133041502Swpaul						ETHER_ADDR_LEN) &&
133141502Swpaul					(eh->ether_dhost[0] & 1) == 0)) {
133241502Swpaul				m_freem(m);
133341502Swpaul				continue;
133441502Swpaul			}
133541502Swpaul		}
133641502Swpaul#endif
133741502Swpaul		/* Remove header from mbuf and pass it on. */
133841502Swpaul		m_adj(m, sizeof(struct ether_header));
133941502Swpaul		ether_input(ifp, eh, m);
134041502Swpaul	}
134141502Swpaul
134241502Swpaul	return;
134341502Swpaul}
134441502Swpaul
134541502Swpaulvoid vr_rxeoc(sc)
134641502Swpaul	struct vr_softc		*sc;
134741502Swpaul{
134841502Swpaul
134941502Swpaul	vr_rxeof(sc);
135041502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
135141502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
135241502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
135341502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
135441502Swpaul
135541502Swpaul	return;
135641502Swpaul}
135741502Swpaul
135841502Swpaul/*
135941502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
136041502Swpaul * the list buffers.
136141502Swpaul */
136241502Swpaul
136341502Swpaulstatic void vr_txeof(sc)
136441502Swpaul	struct vr_softc		*sc;
136541502Swpaul{
136641502Swpaul	struct vr_chain		*cur_tx;
136741502Swpaul	struct ifnet		*ifp;
136841502Swpaul	register struct mbuf	*n;
136941502Swpaul
137041502Swpaul	ifp = &sc->arpcom.ac_if;
137141502Swpaul
137241502Swpaul	/* Clear the timeout timer. */
137341502Swpaul	ifp->if_timer = 0;
137441502Swpaul
137541502Swpaul	/* Sanity check. */
137641502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
137741502Swpaul		return;
137841502Swpaul
137941502Swpaul	/*
138041502Swpaul	 * Go through our tx list and free mbufs for those
138141502Swpaul	 * frames that have been transmitted.
138241502Swpaul	 */
138341502Swpaul	while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) {
138441502Swpaul		u_int32_t		txstat;
138541502Swpaul
138641502Swpaul		cur_tx = sc->vr_cdata.vr_tx_head;
138741502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
138841502Swpaul
138942491Swpaul		if (txstat & VR_TXSTAT_OWN)
139041502Swpaul			break;
139141502Swpaul
139241502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
139341502Swpaul			ifp->if_oerrors++;
139441502Swpaul			if (txstat & VR_TXSTAT_DEFER)
139541502Swpaul				ifp->if_collisions++;
139641502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
139741502Swpaul				ifp->if_collisions++;
139841502Swpaul		}
139941502Swpaul
140041502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
140141502Swpaul
140241502Swpaul		ifp->if_opackets++;
140341502Swpaul        	MFREE(cur_tx->vr_mbuf, n);
140441502Swpaul		cur_tx->vr_mbuf = NULL;
140541502Swpaul
140641502Swpaul		if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {
140741502Swpaul			sc->vr_cdata.vr_tx_head = NULL;
140841502Swpaul			sc->vr_cdata.vr_tx_tail = NULL;
140941502Swpaul			break;
141041502Swpaul		}
141141502Swpaul
141241502Swpaul		sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc;
141341502Swpaul	}
141441502Swpaul
141541502Swpaul	return;
141641502Swpaul}
141741502Swpaul
141841502Swpaul/*
141941502Swpaul * TX 'end of channel' interrupt handler.
142041502Swpaul */
142141502Swpaulstatic void vr_txeoc(sc)
142241502Swpaul	struct vr_softc		*sc;
142341502Swpaul{
142441502Swpaul	struct ifnet		*ifp;
142541502Swpaul
142641502Swpaul	ifp = &sc->arpcom.ac_if;
142741502Swpaul
142841502Swpaul	ifp->if_timer = 0;
142941502Swpaul
143041502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL) {
143141502Swpaul		ifp->if_flags &= ~IFF_OACTIVE;
143241502Swpaul		sc->vr_cdata.vr_tx_tail = NULL;
143341502Swpaul		if (sc->vr_want_auto)
143441502Swpaul			vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1);
143541502Swpaul	}
143641502Swpaul
143741502Swpaul	return;
143841502Swpaul}
143941502Swpaul
144041502Swpaulstatic void vr_intr(arg)
144141502Swpaul	void			*arg;
144241502Swpaul{
144341502Swpaul	struct vr_softc		*sc;
144441502Swpaul	struct ifnet		*ifp;
144541502Swpaul	u_int16_t		status;
144641502Swpaul
144741502Swpaul	sc = arg;
144841502Swpaul	ifp = &sc->arpcom.ac_if;
144941502Swpaul
145041502Swpaul	/* Supress unwanted interrupts. */
145141502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
145241502Swpaul		vr_stop(sc);
145341502Swpaul		return;
145441502Swpaul	}
145541502Swpaul
145641502Swpaul	/* Disable interrupts. */
145741502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
145841502Swpaul
145941502Swpaul	for (;;) {
146041502Swpaul
146141502Swpaul		status = CSR_READ_2(sc, VR_ISR);
146241502Swpaul		if (status)
146341502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
146441502Swpaul
146541502Swpaul		if ((status & VR_INTRS) == 0)
146641502Swpaul			break;
146741502Swpaul
146841502Swpaul		if (status & VR_ISR_RX_OK)
146941502Swpaul			vr_rxeof(sc);
147041502Swpaul
147141502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
147241502Swpaul		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) ||
147341502Swpaul		    (status & VR_ISR_RX_DROPPED)) {
147441502Swpaul			vr_rxeof(sc);
147541502Swpaul			vr_rxeoc(sc);
147641502Swpaul		}
147741502Swpaul
147841502Swpaul		if (status & VR_ISR_TX_OK) {
147941502Swpaul			vr_txeof(sc);
148041502Swpaul			vr_txeoc(sc);
148141502Swpaul		}
148241502Swpaul
148341502Swpaul		if ((status & VR_ISR_TX_UNDERRUN)||(status & VR_ISR_TX_ABRT)){
148441502Swpaul			ifp->if_oerrors++;
148541502Swpaul			vr_txeof(sc);
148641502Swpaul			if (sc->vr_cdata.vr_tx_head != NULL) {
148741502Swpaul				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
148841502Swpaul				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
148941502Swpaul			}
149041502Swpaul		}
149141502Swpaul
149241502Swpaul		if (status & VR_ISR_BUSERR) {
149341502Swpaul			vr_reset(sc);
149441502Swpaul			vr_init(sc);
149541502Swpaul		}
149641502Swpaul	}
149741502Swpaul
149841502Swpaul	/* Re-enable interrupts. */
149941502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
150041502Swpaul
150141502Swpaul	if (ifp->if_snd.ifq_head != NULL) {
150241502Swpaul		vr_start(ifp);
150341502Swpaul	}
150441502Swpaul
150541502Swpaul	return;
150641502Swpaul}
150741502Swpaul
150841502Swpaul/*
150941502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
151041502Swpaul * pointers to the fragment pointers.
151141502Swpaul */
151241502Swpaulstatic int vr_encap(sc, c, m_head)
151341502Swpaul	struct vr_softc		*sc;
151441502Swpaul	struct vr_chain		*c;
151541502Swpaul	struct mbuf		*m_head;
151641502Swpaul{
151741502Swpaul	int			frag = 0;
151841502Swpaul	struct vr_desc		*f = NULL;
151941502Swpaul	int			total_len;
152041502Swpaul	struct mbuf		*m;
152141502Swpaul
152241502Swpaul	m = m_head;
152341502Swpaul	total_len = 0;
152441502Swpaul
152541502Swpaul	/*
152641502Swpaul	 * The VIA Rhine wants packet buffers to be longword
152741502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
152841502Swpaul	 * waste time trying to decide when to copy and when not
152941502Swpaul	 * to copy, just do it all the time.
153041502Swpaul	 */
153141502Swpaul	if (m != NULL) {
153241502Swpaul		struct mbuf		*m_new = NULL;
153341502Swpaul
153441502Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
153541502Swpaul		if (m_new == NULL) {
153641502Swpaul			printf("vr%d: no memory for tx list", sc->vr_unit);
153741502Swpaul			return(1);
153841502Swpaul		}
153941502Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
154041502Swpaul			MCLGET(m_new, M_DONTWAIT);
154141502Swpaul			if (!(m_new->m_flags & M_EXT)) {
154241502Swpaul				m_freem(m_new);
154341502Swpaul				printf("vr%d: no memory for tx list",
154441502Swpaul						sc->vr_unit);
154541502Swpaul				return(1);
154641502Swpaul			}
154741502Swpaul		}
154841502Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
154941502Swpaul					mtod(m_new, caddr_t));
155041502Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
155141502Swpaul		m_freem(m_head);
155241502Swpaul		m_head = m_new;
155341502Swpaul		/*
155441502Swpaul		 * The Rhine chip doesn't auto-pad, so we have to make
155541502Swpaul		 * sure to pad short frames out to the minimum frame length
155641502Swpaul		 * ourselves.
155741502Swpaul		 */
155841502Swpaul		if (m_head->m_len < VR_MIN_FRAMELEN) {
155941502Swpaul			m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
156041502Swpaul			m_new->m_len = m_new->m_pkthdr.len;
156141502Swpaul		}
156241502Swpaul		f = c->vr_ptr;
156341502Swpaul		f->vr_data = vtophys(mtod(m_new, caddr_t));
156441502Swpaul		f->vr_ctl = total_len = m_new->m_len;
156541502Swpaul		f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
156641502Swpaul		f->vr_status = 0;
156741502Swpaul		frag = 1;
156841502Swpaul	}
156941502Swpaul
157041502Swpaul	c->vr_mbuf = m_head;
157142491Swpaul	c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
157241502Swpaul	c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
157341502Swpaul
157441502Swpaul	return(0);
157541502Swpaul}
157641502Swpaul
157741502Swpaul/*
157841502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
157941502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
158041502Swpaul * copy of the pointers since the transmit list fragment pointers are
158141502Swpaul * physical addresses.
158241502Swpaul */
158341502Swpaul
158441502Swpaulstatic void vr_start(ifp)
158541502Swpaul	struct ifnet		*ifp;
158641502Swpaul{
158741502Swpaul	struct vr_softc		*sc;
158841502Swpaul	struct mbuf		*m_head = NULL;
158941502Swpaul	struct vr_chain		*cur_tx = NULL, *start_tx;
159041502Swpaul
159141502Swpaul	sc = ifp->if_softc;
159241502Swpaul
159341502Swpaul	if (sc->vr_autoneg) {
159441502Swpaul		sc->vr_tx_pend = 1;
159541502Swpaul		return;
159641502Swpaul	}
159741502Swpaul
159841502Swpaul	/*
159941502Swpaul	 * Check for an available queue slot. If there are none,
160041502Swpaul	 * punt.
160141502Swpaul	 */
160241502Swpaul	if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) {
160341502Swpaul		ifp->if_flags |= IFF_OACTIVE;
160441502Swpaul		return;
160541502Swpaul	}
160641502Swpaul
160741502Swpaul	start_tx = sc->vr_cdata.vr_tx_free;
160841502Swpaul
160941502Swpaul	while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) {
161041502Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
161141502Swpaul		if (m_head == NULL)
161241502Swpaul			break;
161341502Swpaul
161441502Swpaul		/* Pick a descriptor off the free list. */
161541502Swpaul		cur_tx = sc->vr_cdata.vr_tx_free;
161641502Swpaul		sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc;
161741502Swpaul
161841502Swpaul		/* Pack the data into the descriptor. */
161941502Swpaul		vr_encap(sc, cur_tx, m_head);
162041502Swpaul
162141502Swpaul		if (cur_tx != start_tx)
162241502Swpaul			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
162341502Swpaul
162441502Swpaul#if NBPFILTER > 0
162541502Swpaul		/*
162641502Swpaul		 * If there's a BPF listener, bounce a copy of this frame
162741502Swpaul		 * to him.
162841502Swpaul		 */
162941502Swpaul		if (ifp->if_bpf)
163041502Swpaul			bpf_mtap(ifp, cur_tx->vr_mbuf);
163141502Swpaul#endif
163242491Swpaul		VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
163342491Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_TX_GO);
163441502Swpaul	}
163541502Swpaul
163641502Swpaul	/*
163741526Swpaul	 * If there are no frames queued, bail.
163841526Swpaul	 */
163941526Swpaul	if (cur_tx == NULL)
164041526Swpaul		return;
164141526Swpaul
164241502Swpaul	sc->vr_cdata.vr_tx_tail = cur_tx;
164341502Swpaul
164442491Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
164541502Swpaul		sc->vr_cdata.vr_tx_head = start_tx;
164641502Swpaul
164741502Swpaul	/*
164841502Swpaul	 * Set a timeout in case the chip goes out to lunch.
164941502Swpaul	 */
165041502Swpaul	ifp->if_timer = 5;
165141502Swpaul
165241502Swpaul	return;
165341502Swpaul}
165441502Swpaul
165541502Swpaulstatic void vr_init(xsc)
165641502Swpaul	void			*xsc;
165741502Swpaul{
165841502Swpaul	struct vr_softc		*sc = xsc;
165941502Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
166041502Swpaul	u_int16_t		phy_bmcr = 0;
166141502Swpaul	int			s;
166241502Swpaul
166341502Swpaul	if (sc->vr_autoneg)
166441502Swpaul		return;
166541502Swpaul
166641502Swpaul	s = splimp();
166741502Swpaul
166841502Swpaul	if (sc->vr_pinfo != NULL)
166941502Swpaul		phy_bmcr = vr_phy_readreg(sc, PHY_BMCR);
167041502Swpaul
167141502Swpaul	/*
167241502Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
167341502Swpaul	 */
167441502Swpaul	vr_stop(sc);
167541502Swpaul	vr_reset(sc);
167641502Swpaul
167741502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
167841502Swpaul	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD);
167941502Swpaul
168041502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
168141502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
168241502Swpaul
168341502Swpaul	/* Init circular RX list. */
168441502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
168541502Swpaul		printf("vr%d: initialization failed: no "
168641502Swpaul			"memory for rx buffers\n", sc->vr_unit);
168741502Swpaul		vr_stop(sc);
168841502Swpaul		(void)splx(s);
168941502Swpaul		return;
169041502Swpaul	}
169141502Swpaul
169241502Swpaul	/*
169341502Swpaul	 * Init tx descriptors.
169441502Swpaul	 */
169541502Swpaul	vr_list_tx_init(sc);
169641502Swpaul
169741502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
169841502Swpaul	if (ifp->if_flags & IFF_PROMISC)
169941502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
170041502Swpaul	else
170141502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
170241502Swpaul
170341502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
170441502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
170541502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
170641502Swpaul	else
170741502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
170841502Swpaul
170941502Swpaul	/*
171041502Swpaul	 * Program the multicast filter, if necessary.
171141502Swpaul	 */
171241502Swpaul	vr_setmulti(sc);
171341502Swpaul
171441502Swpaul	/*
171541502Swpaul	 * Load the address of the RX list.
171641502Swpaul	 */
171741502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
171841502Swpaul
171941502Swpaul	/* Enable receiver and transmitter. */
172041502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
172141502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
172241502Swpaul				    VR_CMD_RX_GO);
172341502Swpaul
172441502Swpaul	vr_setcfg(sc, vr_phy_readreg(sc, PHY_BMCR));
172541502Swpaul
172641502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
172741502Swpaul
172841502Swpaul	/*
172941502Swpaul	 * Enable interrupts.
173041502Swpaul	 */
173141502Swpaul	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
173241502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
173341502Swpaul
173441502Swpaul	/* Restore state of BMCR */
173541502Swpaul	if (sc->vr_pinfo != NULL)
173641502Swpaul		vr_phy_writereg(sc, PHY_BMCR, phy_bmcr);
173741502Swpaul
173841502Swpaul	ifp->if_flags |= IFF_RUNNING;
173941502Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
174041502Swpaul
174141502Swpaul	(void)splx(s);
174241502Swpaul
174341502Swpaul	return;
174441502Swpaul}
174541502Swpaul
174641502Swpaul/*
174741502Swpaul * Set media options.
174841502Swpaul */
174941502Swpaulstatic int vr_ifmedia_upd(ifp)
175041502Swpaul	struct ifnet		*ifp;
175141502Swpaul{
175241502Swpaul	struct vr_softc		*sc;
175341502Swpaul	struct ifmedia		*ifm;
175441502Swpaul
175541502Swpaul	sc = ifp->if_softc;
175641502Swpaul	ifm = &sc->ifmedia;
175741502Swpaul
175841502Swpaul	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
175941502Swpaul		return(EINVAL);
176041502Swpaul
176141502Swpaul	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO)
176241502Swpaul		vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1);
176341502Swpaul	else
176441502Swpaul		vr_setmode_mii(sc, ifm->ifm_media);
176541502Swpaul
176641502Swpaul	return(0);
176741502Swpaul}
176841502Swpaul
176941502Swpaul/*
177041502Swpaul * Report current media status.
177141502Swpaul */
177241502Swpaulstatic void vr_ifmedia_sts(ifp, ifmr)
177341502Swpaul	struct ifnet		*ifp;
177441502Swpaul	struct ifmediareq	*ifmr;
177541502Swpaul{
177641502Swpaul	struct vr_softc		*sc;
177741502Swpaul	u_int16_t		advert = 0, ability = 0;
177841502Swpaul
177941502Swpaul	sc = ifp->if_softc;
178041502Swpaul
178141502Swpaul	ifmr->ifm_active = IFM_ETHER;
178241502Swpaul
178341502Swpaul	if (!(vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) {
178441502Swpaul		if (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL)
178541502Swpaul			ifmr->ifm_active = IFM_ETHER|IFM_100_TX;
178641502Swpaul		else
178741502Swpaul			ifmr->ifm_active = IFM_ETHER|IFM_10_T;
178841502Swpaul		if (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX)
178941502Swpaul			ifmr->ifm_active |= IFM_FDX;
179041502Swpaul		else
179141502Swpaul			ifmr->ifm_active |= IFM_HDX;
179241502Swpaul		return;
179341502Swpaul	}
179441502Swpaul
179541502Swpaul	ability = vr_phy_readreg(sc, PHY_LPAR);
179641502Swpaul	advert = vr_phy_readreg(sc, PHY_ANAR);
179741502Swpaul	if (advert & PHY_ANAR_100BT4 &&
179841502Swpaul		ability & PHY_ANAR_100BT4) {
179941502Swpaul		ifmr->ifm_active = IFM_ETHER|IFM_100_T4;
180041502Swpaul	} else if (advert & PHY_ANAR_100BTXFULL &&
180141502Swpaul		ability & PHY_ANAR_100BTXFULL) {
180241502Swpaul		ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX;
180341502Swpaul	} else if (advert & PHY_ANAR_100BTXHALF &&
180441502Swpaul		ability & PHY_ANAR_100BTXHALF) {
180541502Swpaul		ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX;
180641502Swpaul	} else if (advert & PHY_ANAR_10BTFULL &&
180741502Swpaul		ability & PHY_ANAR_10BTFULL) {
180841502Swpaul		ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX;
180941502Swpaul	} else if (advert & PHY_ANAR_10BTHALF &&
181041502Swpaul		ability & PHY_ANAR_10BTHALF) {
181141502Swpaul		ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX;
181241502Swpaul	}
181341502Swpaul
181441502Swpaul	return;
181541502Swpaul}
181641502Swpaul
181741502Swpaulstatic int vr_ioctl(ifp, command, data)
181841502Swpaul	struct ifnet		*ifp;
181941502Swpaul	u_long			command;
182041502Swpaul	caddr_t			data;
182141502Swpaul{
182241502Swpaul	struct vr_softc		*sc = ifp->if_softc;
182341502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
182441502Swpaul	int			s, error = 0;
182541502Swpaul
182641502Swpaul	s = splimp();
182741502Swpaul
182841502Swpaul	switch(command) {
182941502Swpaul	case SIOCSIFADDR:
183041502Swpaul	case SIOCGIFADDR:
183141502Swpaul	case SIOCSIFMTU:
183241502Swpaul		error = ether_ioctl(ifp, command, data);
183341502Swpaul		break;
183441502Swpaul	case SIOCSIFFLAGS:
183541502Swpaul		if (ifp->if_flags & IFF_UP) {
183641502Swpaul			vr_init(sc);
183741502Swpaul		} else {
183841502Swpaul			if (ifp->if_flags & IFF_RUNNING)
183941502Swpaul				vr_stop(sc);
184041502Swpaul		}
184141502Swpaul		error = 0;
184241502Swpaul		break;
184341502Swpaul	case SIOCADDMULTI:
184441502Swpaul	case SIOCDELMULTI:
184541502Swpaul		vr_setmulti(sc);
184641502Swpaul		error = 0;
184741502Swpaul		break;
184841502Swpaul	case SIOCGIFMEDIA:
184941502Swpaul	case SIOCSIFMEDIA:
185041502Swpaul		error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
185141502Swpaul		break;
185241502Swpaul	default:
185341502Swpaul		error = EINVAL;
185441502Swpaul		break;
185541502Swpaul	}
185641502Swpaul
185741502Swpaul	(void)splx(s);
185841502Swpaul
185941502Swpaul	return(error);
186041502Swpaul}
186141502Swpaul
186241502Swpaulstatic void vr_watchdog(ifp)
186341502Swpaul	struct ifnet		*ifp;
186441502Swpaul{
186541502Swpaul	struct vr_softc		*sc;
186641502Swpaul
186741502Swpaul	sc = ifp->if_softc;
186841502Swpaul
186941502Swpaul	if (sc->vr_autoneg) {
187041502Swpaul		vr_autoneg_mii(sc, VR_FLAG_DELAYTIMEO, 1);
187141502Swpaul		return;
187241502Swpaul	}
187341502Swpaul
187441502Swpaul	ifp->if_oerrors++;
187541502Swpaul	printf("vr%d: watchdog timeout\n", sc->vr_unit);
187641502Swpaul
187741502Swpaul	if (!(vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
187841502Swpaul		printf("vr%d: no carrier - transceiver cable problem?\n",
187941502Swpaul								sc->vr_unit);
188041502Swpaul
188141502Swpaul	vr_stop(sc);
188241502Swpaul	vr_reset(sc);
188341502Swpaul	vr_init(sc);
188441502Swpaul
188541502Swpaul	if (ifp->if_snd.ifq_head != NULL)
188641502Swpaul		vr_start(ifp);
188741502Swpaul
188841502Swpaul	return;
188941502Swpaul}
189041502Swpaul
189141502Swpaul/*
189241502Swpaul * Stop the adapter and free any mbufs allocated to the
189341502Swpaul * RX and TX lists.
189441502Swpaul */
189541502Swpaulstatic void vr_stop(sc)
189641502Swpaul	struct vr_softc		*sc;
189741502Swpaul{
189841502Swpaul	register int		i;
189941502Swpaul	struct ifnet		*ifp;
190041502Swpaul
190141502Swpaul	ifp = &sc->arpcom.ac_if;
190241502Swpaul	ifp->if_timer = 0;
190341502Swpaul
190441502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
190541502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
190641502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
190741502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
190841502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
190941502Swpaul
191041502Swpaul	/*
191141502Swpaul	 * Free data in the RX lists.
191241502Swpaul	 */
191341502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
191441502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
191541502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
191641502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
191741502Swpaul		}
191841502Swpaul	}
191941502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
192041502Swpaul		sizeof(sc->vr_ldata->vr_rx_list));
192141502Swpaul
192241502Swpaul	/*
192341502Swpaul	 * Free the TX list buffers.
192441502Swpaul	 */
192541502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
192641502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
192741502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
192841502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
192941502Swpaul		}
193041502Swpaul	}
193141502Swpaul
193241502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
193341502Swpaul		sizeof(sc->vr_ldata->vr_tx_list));
193441502Swpaul
193541502Swpaul	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
193641502Swpaul
193741502Swpaul	return;
193841502Swpaul}
193941502Swpaul
194041502Swpaul/*
194141502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
194241502Swpaul * get confused by errant DMAs when rebooting.
194341502Swpaul */
194441502Swpaulstatic void vr_shutdown(howto, arg)
194541502Swpaul	int			howto;
194641502Swpaul	void			*arg;
194741502Swpaul{
194841502Swpaul	struct vr_softc		*sc = (struct vr_softc *)arg;
194941502Swpaul
195041502Swpaul	vr_stop(sc);
195141502Swpaul
195241502Swpaul	return;
195341502Swpaul}
195441502Swpaul
195541502Swpaulstatic struct pci_device vr_device = {
195641502Swpaul	"vr",
195741502Swpaul	vr_probe,
195841502Swpaul	vr_attach,
195941502Swpaul	&vr_count,
196041502Swpaul	NULL
196141502Swpaul};
196241502SwpaulDATA_SET(pcidevice_set, vr_device);
1963