if_vr.c revision 151911
1139825Simp/*-
241502Swpaul * Copyright (c) 1997, 1998
341502Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
441502Swpaul *
541502Swpaul * Redistribution and use in source and binary forms, with or without
641502Swpaul * modification, are permitted provided that the following conditions
741502Swpaul * are met:
841502Swpaul * 1. Redistributions of source code must retain the above copyright
941502Swpaul *    notice, this list of conditions and the following disclaimer.
1041502Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1141502Swpaul *    notice, this list of conditions and the following disclaimer in the
1241502Swpaul *    documentation and/or other materials provided with the distribution.
1341502Swpaul * 3. All advertising materials mentioning features or use of this software
1441502Swpaul *    must display the following acknowledgement:
1541502Swpaul *	This product includes software developed by Bill Paul.
1641502Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1741502Swpaul *    may be used to endorse or promote products derived from this software
1841502Swpaul *    without specific prior written permission.
1941502Swpaul *
2041502Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2141502Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2241502Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2341502Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2441502Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2541502Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2641502Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2741502Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2841502Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2941502Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3041502Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3141502Swpaul */
3241502Swpaul
33122678Sobrien#include <sys/cdefs.h>
34122678Sobrien__FBSDID("$FreeBSD: head/sys/dev/vr/if_vr.c 151911 2005-10-31 21:37:27Z jhb $");
35122678Sobrien
3641502Swpaul/*
3741502Swpaul * VIA Rhine fast ethernet PCI NIC driver
3841502Swpaul *
3941502Swpaul * Supports various network adapters based on the VIA Rhine
4041502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX.
4141502Swpaul * Datasheets are available at http://www.via.com.tw.
4241502Swpaul *
4341502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4441502Swpaul * Electrical Engineering Department
4541502Swpaul * Columbia University, New York City
4641502Swpaul */
47131503Sbms
4841502Swpaul/*
4941502Swpaul * The VIA Rhine controllers are similar in some respects to the
5041502Swpaul * the DEC tulip chips, except less complicated. The controller
5141502Swpaul * uses an MII bus and an external physical layer interface. The
5241502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table
5341502Swpaul * multicast filter. Transmit and receive descriptors are similar
5441502Swpaul * to the tulip.
5541502Swpaul *
5641502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism:
5741502Swpaul * transmit buffers must be longword aligned. Unfortunately,
5841502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting
5941502Swpaul * at longword boundaries, so we have to do a buffer copy before
6041502Swpaul * transmission.
6141502Swpaul */
6241502Swpaul
63150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS
64150968Sglebius#include "opt_device_polling.h"
65150968Sglebius#endif
66150968Sglebius
6741502Swpaul#include <sys/param.h>
6841502Swpaul#include <sys/systm.h>
6941502Swpaul#include <sys/sockio.h>
7041502Swpaul#include <sys/mbuf.h>
7141502Swpaul#include <sys/malloc.h>
7241502Swpaul#include <sys/kernel.h>
73129878Sphk#include <sys/module.h>
7441502Swpaul#include <sys/socket.h>
7541502Swpaul
7641502Swpaul#include <net/if.h>
7741502Swpaul#include <net/if_arp.h>
7841502Swpaul#include <net/ethernet.h>
7941502Swpaul#include <net/if_dl.h>
8041502Swpaul#include <net/if_media.h>
81147256Sbrooks#include <net/if_types.h>
8241502Swpaul
8341502Swpaul#include <net/bpf.h>
8441502Swpaul
85131503Sbms#include <vm/vm.h>		/* for vtophys */
86131503Sbms#include <vm/pmap.h>		/* for vtophys */
8741502Swpaul#include <machine/bus.h>
8849610Swpaul#include <machine/resource.h>
8949610Swpaul#include <sys/bus.h>
9049610Swpaul#include <sys/rman.h>
9141502Swpaul
9251432Swpaul#include <dev/mii/mii.h>
9351432Swpaul#include <dev/mii/miivar.h>
9451432Swpaul
95119288Simp#include <dev/pci/pcireg.h>
96119288Simp#include <dev/pci/pcivar.h>
9741502Swpaul
9841502Swpaul#define VR_USEIOSPACE
9941502Swpaul
10041502Swpaul#include <pci/if_vrreg.h>
10141502Swpaul
102113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1);
103113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1);
10459758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
10559758Speter
106151545Simp/* "device miibus" required.  See GENERIC if you get errors here. */
10751432Swpaul#include "miibus_if.h"
10851432Swpaul
109110168Ssilby#undef VR_USESWSHIFT
110110168Ssilby
11141502Swpaul/*
11241502Swpaul * Various supported device vendors/types and their names.
11341502Swpaul */
11441502Swpaulstatic struct vr_type vr_devs[] = {
11541502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
11641502Swpaul		"VIA VT3043 Rhine I 10/100BaseTX" },
11741502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
11841502Swpaul		"VIA VT86C100A Rhine II 10/100BaseTX" },
11962653Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
12062653Swpaul		"VIA VT6102 Rhine II 10/100BaseTX" },
121110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III,
122110170Ssilby		"VIA VT6105 Rhine III 10/100BaseTX" },
123110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
124110170Ssilby		"VIA VT6105M Rhine III 10/100BaseTX" },
12544238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
12644238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
12744238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
12844238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
12941502Swpaul	{ 0, 0, NULL }
13041502Swpaul};
13141502Swpaul
132142407Simpstatic int vr_probe(device_t);
133142407Simpstatic int vr_attach(device_t);
134142407Simpstatic int vr_detach(device_t);
13541502Swpaul
136142407Simpstatic int vr_newbuf(struct vr_softc *, struct vr_chain_onefrag *,
137142407Simp		struct mbuf *);
138142407Simpstatic int vr_encap(struct vr_softc *, struct vr_chain *, struct mbuf * );
13941502Swpaul
140142407Simpstatic void vr_rxeof(struct vr_softc *);
141142407Simpstatic void vr_rxeoc(struct vr_softc *);
142142407Simpstatic void vr_txeof(struct vr_softc *);
143142407Simpstatic void vr_tick(void *);
144142407Simpstatic void vr_intr(void *);
145142407Simpstatic void vr_start(struct ifnet *);
146142407Simpstatic void vr_start_locked(struct ifnet *);
147142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t);
148142407Simpstatic void vr_init(void *);
149142407Simpstatic void vr_init_locked(struct vr_softc *);
150142407Simpstatic void vr_stop(struct vr_softc *);
151142407Simpstatic void vr_watchdog(struct ifnet *);
152142407Simpstatic void vr_shutdown(device_t);
153142407Simpstatic int vr_ifmedia_upd(struct ifnet *);
154142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
15541502Swpaul
156110168Ssilby#ifdef VR_USESWSHIFT
157142407Simpstatic void vr_mii_sync(struct vr_softc *);
158142407Simpstatic void vr_mii_send(struct vr_softc *, uint32_t, int);
159110168Ssilby#endif
160142407Simpstatic int vr_mii_readreg(struct vr_softc *, struct vr_mii_frame *);
161142407Simpstatic int vr_mii_writereg(struct vr_softc *, struct vr_mii_frame *);
162142407Simpstatic int vr_miibus_readreg(device_t, uint16_t, uint16_t);
163142407Simpstatic int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t);
164142407Simpstatic void vr_miibus_statchg(device_t);
16541502Swpaul
166142407Simpstatic void vr_setcfg(struct vr_softc *, int);
167142407Simpstatic void vr_setmulti(struct vr_softc *);
168142407Simpstatic void vr_reset(struct vr_softc *);
169142407Simpstatic int vr_list_rx_init(struct vr_softc *);
170142407Simpstatic int vr_list_tx_init(struct vr_softc *);
17141502Swpaul
17249610Swpaul#ifdef VR_USEIOSPACE
17349610Swpaul#define VR_RES			SYS_RES_IOPORT
17449610Swpaul#define VR_RID			VR_PCI_LOIO
17549610Swpaul#else
17649610Swpaul#define VR_RES			SYS_RES_MEMORY
17749610Swpaul#define VR_RID			VR_PCI_LOMEM
17849610Swpaul#endif
17949610Swpaul
18049610Swpaulstatic device_method_t vr_methods[] = {
18149610Swpaul	/* Device interface */
18249610Swpaul	DEVMETHOD(device_probe,		vr_probe),
18349610Swpaul	DEVMETHOD(device_attach,	vr_attach),
18449610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
18549610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
18651432Swpaul
18751432Swpaul	/* bus interface */
18851432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18951432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
19051432Swpaul
19151432Swpaul	/* MII interface */
19251432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
19351432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
19451432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
19551432Swpaul
19649610Swpaul	{ 0, 0 }
19749610Swpaul};
19849610Swpaul
19949610Swpaulstatic driver_t vr_driver = {
20051455Swpaul	"vr",
20149610Swpaul	vr_methods,
20249610Swpaul	sizeof(struct vr_softc)
20349610Swpaul};
20449610Swpaul
20549610Swpaulstatic devclass_t vr_devclass;
20649610Swpaul
207113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0);
20851473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
20949610Swpaul
21041502Swpaul#define VR_SETBIT(sc, reg, x)				\
21141502Swpaul	CSR_WRITE_1(sc, reg,				\
212105221Sphk		CSR_READ_1(sc, reg) | (x))
21341502Swpaul
21441502Swpaul#define VR_CLRBIT(sc, reg, x)				\
21541502Swpaul	CSR_WRITE_1(sc, reg,				\
216105221Sphk		CSR_READ_1(sc, reg) & ~(x))
21741502Swpaul
21841502Swpaul#define VR_SETBIT16(sc, reg, x)				\
21941502Swpaul	CSR_WRITE_2(sc, reg,				\
220105221Sphk		CSR_READ_2(sc, reg) | (x))
22141502Swpaul
22241502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
22341502Swpaul	CSR_WRITE_2(sc, reg,				\
224105221Sphk		CSR_READ_2(sc, reg) & ~(x))
22541502Swpaul
22641502Swpaul#define VR_SETBIT32(sc, reg, x)				\
22741502Swpaul	CSR_WRITE_4(sc, reg,				\
228105221Sphk		CSR_READ_4(sc, reg) | (x))
22941502Swpaul
23041502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
23141502Swpaul	CSR_WRITE_4(sc, reg,				\
232105221Sphk		CSR_READ_4(sc, reg) & ~(x))
23341502Swpaul
23441502Swpaul#define SIO_SET(x)					\
23541502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
236105221Sphk		CSR_READ_1(sc, VR_MIICMD) | (x))
23741502Swpaul
23841502Swpaul#define SIO_CLR(x)					\
23941502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
240105221Sphk		CSR_READ_1(sc, VR_MIICMD) & ~(x))
24141502Swpaul
242110168Ssilby#ifdef VR_USESWSHIFT
24341502Swpaul/*
24441502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
24541502Swpaul */
246102336Salfredstatic void
247131503Sbmsvr_mii_sync(struct vr_softc *sc)
24841502Swpaul{
249131503Sbms	register int	i;
25041502Swpaul
25141502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
25241502Swpaul
25341502Swpaul	for (i = 0; i < 32; i++) {
25441502Swpaul		SIO_SET(VR_MIICMD_CLK);
25541502Swpaul		DELAY(1);
25641502Swpaul		SIO_CLR(VR_MIICMD_CLK);
25741502Swpaul		DELAY(1);
25841502Swpaul	}
25941502Swpaul}
26041502Swpaul
26141502Swpaul/*
26241502Swpaul * Clock a series of bits through the MII.
26341502Swpaul */
264102336Salfredstatic void
265131503Sbmsvr_mii_send(struct vr_softc *sc, uint32_t bits, int cnt)
26641502Swpaul{
267131503Sbms	int	i;
26841502Swpaul
26941502Swpaul	SIO_CLR(VR_MIICMD_CLK);
27041502Swpaul
27141502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
272131503Sbms		if (bits & i) {
27341502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
274131503Sbms		} else {
27541502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
276131503Sbms		}
27741502Swpaul		DELAY(1);
27841502Swpaul		SIO_CLR(VR_MIICMD_CLK);
27941502Swpaul		DELAY(1);
28041502Swpaul		SIO_SET(VR_MIICMD_CLK);
28141502Swpaul	}
28241502Swpaul}
283110168Ssilby#endif
28441502Swpaul
28541502Swpaul/*
28641502Swpaul * Read an PHY register through the MII.
28741502Swpaul */
288102336Salfredstatic int
289131503Sbmsvr_mii_readreg(struct vr_softc *sc, struct vr_mii_frame *frame)
290131503Sbms#ifdef VR_USESWSHIFT
29141502Swpaul{
292131503Sbms	int	i, ack;
29341502Swpaul
294131503Sbms	/* Set up frame for RX. */
29541502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
29641502Swpaul	frame->mii_opcode = VR_MII_READOP;
29741502Swpaul	frame->mii_turnaround = 0;
29841502Swpaul	frame->mii_data = 0;
299131503Sbms
30041502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
30141502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
30241502Swpaul
303131503Sbms	/* Turn on data xmit. */
30441502Swpaul	SIO_SET(VR_MIICMD_DIR);
30541502Swpaul
30641502Swpaul	vr_mii_sync(sc);
30741502Swpaul
308131503Sbms	/* Send command/address info. */
30941502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
31041502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
31141502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
31241502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
31341502Swpaul
314131503Sbms	/* Idle bit. */
31541502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
31641502Swpaul	DELAY(1);
31741502Swpaul	SIO_SET(VR_MIICMD_CLK);
31841502Swpaul	DELAY(1);
31941502Swpaul
32041502Swpaul	/* Turn off xmit. */
32141502Swpaul	SIO_CLR(VR_MIICMD_DIR);
32241502Swpaul
32341502Swpaul	/* Check for ack */
32441502Swpaul	SIO_CLR(VR_MIICMD_CLK);
32541502Swpaul	DELAY(1);
326109058Smbr	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
32741502Swpaul	SIO_SET(VR_MIICMD_CLK);
32841502Swpaul	DELAY(1);
32941502Swpaul
33041502Swpaul	/*
33141502Swpaul	 * Now try reading data bits. If the ack failed, we still
33241502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
33341502Swpaul	 */
33441502Swpaul	if (ack) {
33541502Swpaul		for(i = 0; i < 16; i++) {
33641502Swpaul			SIO_CLR(VR_MIICMD_CLK);
33741502Swpaul			DELAY(1);
33841502Swpaul			SIO_SET(VR_MIICMD_CLK);
33941502Swpaul			DELAY(1);
34041502Swpaul		}
34141502Swpaul		goto fail;
34241502Swpaul	}
34341502Swpaul
34441502Swpaul	for (i = 0x8000; i; i >>= 1) {
34541502Swpaul		SIO_CLR(VR_MIICMD_CLK);
34641502Swpaul		DELAY(1);
34741502Swpaul		if (!ack) {
34841502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
34941502Swpaul				frame->mii_data |= i;
35041502Swpaul			DELAY(1);
35141502Swpaul		}
35241502Swpaul		SIO_SET(VR_MIICMD_CLK);
35341502Swpaul		DELAY(1);
35441502Swpaul	}
35541502Swpaul
35641502Swpaulfail:
35741502Swpaul	SIO_CLR(VR_MIICMD_CLK);
35841502Swpaul	DELAY(1);
35941502Swpaul	SIO_SET(VR_MIICMD_CLK);
36041502Swpaul	DELAY(1);
36141502Swpaul
36241502Swpaul	if (ack)
363131503Sbms		return (1);
364131503Sbms	return (0);
36541502Swpaul}
366110168Ssilby#else
367110168Ssilby{
368131518Sbms	int	i;
36941502Swpaul
370131503Sbms	/* Set the PHY address. */
371110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
372110168Ssilby	    frame->mii_phyaddr);
373110168Ssilby
374131503Sbms	/* Set the register address. */
375110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
376110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
377131503Sbms
378110168Ssilby	for (i = 0; i < 10000; i++) {
379110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
380110168Ssilby			break;
381110168Ssilby		DELAY(1);
382110168Ssilby	}
383110168Ssilby	frame->mii_data = CSR_READ_2(sc, VR_MIIDATA);
384110168Ssilby
385131503Sbms	return (0);
386110168Ssilby}
387110168Ssilby#endif
388110168Ssilby
389110168Ssilby
39041502Swpaul/*
39141502Swpaul * Write to a PHY register through the MII.
39241502Swpaul */
393102336Salfredstatic int
394131503Sbmsvr_mii_writereg(struct vr_softc *sc, struct vr_mii_frame *frame)
395131503Sbms#ifdef VR_USESWSHIFT
39641502Swpaul{
39741502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
39841502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
39941502Swpaul
400131503Sbms	/* Set up frame for TX. */
40141502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
40241502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
40341502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
404131503Sbms
405131503Sbms	/* Turn on data output. */
40641502Swpaul	SIO_SET(VR_MIICMD_DIR);
40741502Swpaul
40841502Swpaul	vr_mii_sync(sc);
40941502Swpaul
41041502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
41141502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
41241502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
41341502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
41441502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
41541502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
41641502Swpaul
41741502Swpaul	/* Idle bit. */
41841502Swpaul	SIO_SET(VR_MIICMD_CLK);
41941502Swpaul	DELAY(1);
42041502Swpaul	SIO_CLR(VR_MIICMD_CLK);
42141502Swpaul	DELAY(1);
42241502Swpaul
423131503Sbms	/* Turn off xmit. */
42441502Swpaul	SIO_CLR(VR_MIICMD_DIR);
42541502Swpaul
426131503Sbms	return (0);
42741502Swpaul}
428110168Ssilby#else
429110168Ssilby{
430131518Sbms	int	i;
43141502Swpaul
432131503Sbms	/* Set the PHY address. */
433110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
434131503Sbms	    frame->mii_phyaddr);
435110168Ssilby
436131503Sbms	/* Set the register address and data to write. */
437110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
438110168Ssilby	CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data);
439110168Ssilby
440110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
441110168Ssilby
442110168Ssilby	for (i = 0; i < 10000; i++) {
443110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
444110168Ssilby			break;
445110168Ssilby		DELAY(1);
446110168Ssilby	}
447110168Ssilby
448131503Sbms	return (0);
449110168Ssilby}
450110168Ssilby#endif
451110168Ssilby
452102336Salfredstatic int
453131517Sbmsvr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg)
45451432Swpaul{
45541502Swpaul	struct vr_mii_frame	frame;
456131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
45741502Swpaul
458110168Ssilby	switch (sc->vr_revid) {
459131503Sbms	case REV_ID_VT6102_APOLLO:
460131518Sbms		if (phy != 1) {
461131518Sbms			frame.mii_data = 0;
462131518Sbms			goto out;
463131518Sbms		}
464131503Sbms	default:
465131503Sbms		break;
466131503Sbms	}
467110168Ssilby
46841502Swpaul	bzero((char *)&frame, sizeof(frame));
46951432Swpaul	frame.mii_phyaddr = phy;
47041502Swpaul	frame.mii_regaddr = reg;
47141502Swpaul	vr_mii_readreg(sc, &frame);
47241502Swpaul
473131518Sbmsout:
474131503Sbms	return (frame.mii_data);
47541502Swpaul}
47641502Swpaul
477102336Salfredstatic int
478131503Sbmsvr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data)
47951432Swpaul{
48041502Swpaul	struct vr_mii_frame	frame;
481131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
48241502Swpaul
483110168Ssilby	switch (sc->vr_revid) {
484131503Sbms	case REV_ID_VT6102_APOLLO:
485131503Sbms		if (phy != 1)
486131503Sbms			return (0);
487131503Sbms	default:
488131503Sbms		break;
489131503Sbms	}
490110168Ssilby
49141502Swpaul	bzero((char *)&frame, sizeof(frame));
49251432Swpaul	frame.mii_phyaddr = phy;
49341502Swpaul	frame.mii_regaddr = reg;
49441502Swpaul	frame.mii_data = data;
49541502Swpaul	vr_mii_writereg(sc, &frame);
49641502Swpaul
497131503Sbms	return (0);
49851432Swpaul}
49951432Swpaul
500102336Salfredstatic void
501131503Sbmsvr_miibus_statchg(device_t dev)
50251432Swpaul{
50351432Swpaul	struct mii_data		*mii;
504131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
50551432Swpaul
50651432Swpaul	mii = device_get_softc(sc->vr_miibus);
50751432Swpaul	vr_setcfg(sc, mii->mii_media_active);
50841502Swpaul}
50941502Swpaul
51041502Swpaul/*
51141502Swpaul * Program the 64-bit multicast hash filter.
51241502Swpaul */
513102336Salfredstatic void
514131503Sbmsvr_setmulti(struct vr_softc *sc)
51541502Swpaul{
516147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
51741502Swpaul	int			h = 0;
518131503Sbms	uint32_t		hashes[2] = { 0, 0 };
51941502Swpaul	struct ifmultiaddr	*ifma;
520131503Sbms	uint8_t			rxfilt;
52141502Swpaul	int			mcnt = 0;
52241502Swpaul
523131518Sbms	VR_LOCK_ASSERT(sc);
52441502Swpaul
52541502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
52641502Swpaul
52741502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
52841502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
52941502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
53041502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
53141502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
53241502Swpaul		return;
53341502Swpaul	}
53441502Swpaul
535131503Sbms	/* First, zero out all the existing hash bits. */
53641502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
53741502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
53841502Swpaul
539131503Sbms	/* Now program new ones. */
540148654Srwatson	IF_ADDR_LOCK(ifp);
54172084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
54241502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
54341502Swpaul			continue;
544130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
545130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
54641502Swpaul		if (h < 32)
54741502Swpaul			hashes[0] |= (1 << h);
54841502Swpaul		else
54941502Swpaul			hashes[1] |= (1 << (h - 32));
55041502Swpaul		mcnt++;
55141502Swpaul	}
552148654Srwatson	IF_ADDR_UNLOCK(ifp);
55341502Swpaul
55441502Swpaul	if (mcnt)
55541502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
55641502Swpaul	else
55741502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
55841502Swpaul
55941502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
56041502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
56141502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
56241502Swpaul}
56341502Swpaul
56441502Swpaul/*
56541502Swpaul * In order to fiddle with the
56641502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
56741502Swpaul * first have to put the transmit and/or receive logic in the idle state.
56841502Swpaul */
569102336Salfredstatic void
570131503Sbmsvr_setcfg(struct vr_softc *sc, int media)
57141502Swpaul{
572131517Sbms	int	restart = 0;
57341502Swpaul
574131518Sbms	VR_LOCK_ASSERT(sc);
575131518Sbms
57641502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
57741502Swpaul		restart = 1;
57841502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
57941502Swpaul	}
58041502Swpaul
58151432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
58241502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58341502Swpaul	else
58441502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58541502Swpaul
58641502Swpaul	if (restart)
58741502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
58841502Swpaul}
58941502Swpaul
590102336Salfredstatic void
591131503Sbmsvr_reset(struct vr_softc *sc)
59241502Swpaul{
593131517Sbms	register int	i;
59441502Swpaul
595151773Sjhb	/*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during attach w/o lock. */
596131518Sbms
59741502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
59841502Swpaul
59941502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
60041502Swpaul		DELAY(10);
60141502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
60241502Swpaul			break;
60341502Swpaul	}
604107220Ssilby	if (i == VR_TIMEOUT) {
605107220Ssilby		if (sc->vr_revid < REV_ID_VT3065_A)
606151773Sjhb			if_printf(sc->vr_ifp, "reset never completed!\n");
607107220Ssilby		else {
608107220Ssilby			/* Use newer force reset command */
609151773Sjhb			if_printf(sc->vr_ifp, "Using force reset command.\n");
610107220Ssilby			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
611107220Ssilby		}
612107220Ssilby	}
61341502Swpaul
61441502Swpaul	/* Wait a little while for the chip to get its brains in order. */
61541502Swpaul	DELAY(1000);
61641502Swpaul}
61741502Swpaul
61841502Swpaul/*
61941502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
62041502Swpaul * IDs against our list and return a device name if we find a match.
62141502Swpaul */
622102336Salfredstatic int
623131503Sbmsvr_probe(device_t dev)
62441502Swpaul{
625131503Sbms	struct vr_type	*t = vr_devs;
62641502Swpaul
627131503Sbms	while (t->vr_name != NULL) {
62849610Swpaul		if ((pci_get_vendor(dev) == t->vr_vid) &&
62949610Swpaul		    (pci_get_device(dev) == t->vr_did)) {
63049610Swpaul			device_set_desc(dev, t->vr_name);
631142398Simp			return (BUS_PROBE_DEFAULT);
63241502Swpaul		}
63341502Swpaul		t++;
63441502Swpaul	}
63541502Swpaul
636131503Sbms	return (ENXIO);
63741502Swpaul}
63841502Swpaul
63941502Swpaul/*
64041502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
64141502Swpaul * setup and ethernet/BPF attach.
64241502Swpaul */
643102336Salfredstatic int
644102336Salfredvr_attach(dev)
64549610Swpaul	device_t		dev;
64641502Swpaul{
64767087Swpaul	int			i;
64841502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
64941502Swpaul	struct vr_softc		*sc;
65041502Swpaul	struct ifnet		*ifp;
65149610Swpaul	int			unit, error = 0, rid;
65241502Swpaul
65349610Swpaul	sc = device_get_softc(dev);
65449610Swpaul	unit = device_get_unit(dev);
65541502Swpaul
65693818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
657131518Sbms	    MTX_DEF);
658151911Sjhb	callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0);
659151911Sjhb
66041502Swpaul	/*
66141502Swpaul	 * Map control/status registers.
66241502Swpaul	 */
66372813Swpaul	pci_enable_busmaster(dev);
664107220Ssilby	sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF;
66541502Swpaul
66649610Swpaul	rid = VR_RID;
667127135Snjl	sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE);
66849610Swpaul
66949610Swpaul	if (sc->vr_res == NULL) {
670151773Sjhb		device_printf(dev, "couldn't map ports/memory\n");
67149610Swpaul		error = ENXIO;
67241502Swpaul		goto fail;
67341502Swpaul	}
67441502Swpaul
67549610Swpaul	sc->vr_btag = rman_get_bustag(sc->vr_res);
67649610Swpaul	sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
67741502Swpaul
67841502Swpaul	/* Allocate interrupt */
67949610Swpaul	rid = 0;
680127135Snjl	sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
68149610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
68249610Swpaul
68349610Swpaul	if (sc->vr_irq == NULL) {
684151773Sjhb		device_printf(dev, "couldn't map interrupt\n");
68549610Swpaul		error = ENXIO;
68641502Swpaul		goto fail;
68741502Swpaul	}
68841502Swpaul
689151773Sjhb	/* Allocate ifnet structure. */
690151773Sjhb	ifp = sc->vr_ifp = if_alloc(IFT_ETHER);
691151773Sjhb	if (ifp == NULL) {
692151773Sjhb		device_printf(dev, "can not if_alloc()\n");
693151773Sjhb		error = ENOSPC;
694151773Sjhb		goto fail;
695151773Sjhb	}
696151773Sjhb	ifp->if_softc = sc;
697151773Sjhb	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
698151773Sjhb	ifp->if_mtu = ETHERMTU;
699151773Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
700151773Sjhb	ifp->if_ioctl = vr_ioctl;
701151773Sjhb	ifp->if_start = vr_start;
702151773Sjhb	ifp->if_watchdog = vr_watchdog;
703151773Sjhb	ifp->if_init = vr_init;
704151773Sjhb	ifp->if_baudrate = 10000000;
705151773Sjhb	IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1);
706151773Sjhb	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
707151773Sjhb	IFQ_SET_READY(&ifp->if_snd);
708151773Sjhb	ifp->if_capenable = ifp->if_capabilities;
709151773Sjhb#ifdef DEVICE_POLLING
710151773Sjhb	ifp->if_capabilities |= IFCAP_POLLING;
711151773Sjhb#endif
712151773Sjhb
71376586Swpaul	/*
71476586Swpaul	 * Windows may put the chip in suspend mode when it
71576586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
71676586Swpaul	 * up again.
71776586Swpaul	 */
71876586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
71976586Swpaul
72041502Swpaul	/* Reset the adapter. */
72141502Swpaul	vr_reset(sc);
72241502Swpaul
723131503Sbms	/*
724110168Ssilby	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
725110168Ssilby	 * initialization and disable AUTOPOLL.
726110168Ssilby	 */
727131503Sbms	pci_write_config(dev, VR_PCI_MODE,
728110168Ssilby	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
729110168Ssilby	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
730110168Ssilby
73141502Swpaul	/*
73241502Swpaul	 * Get station address. The way the Rhine chips work,
73341502Swpaul	 * you're not allowed to directly access the EEPROM once
73441502Swpaul	 * they've been programmed a special way. Consequently,
73541502Swpaul	 * we need to read the node address from the PAR0 and PAR1
73641502Swpaul	 * registers.
73741502Swpaul	 */
73841502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
73941502Swpaul	DELAY(200);
74041502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
74141502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
74241502Swpaul
74351432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
744151773Sjhb	    M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
74551432Swpaul
74651432Swpaul	if (sc->vr_ldata == NULL) {
747151773Sjhb		device_printf(dev, "no memory for list buffers!\n");
74849610Swpaul		error = ENXIO;
74949610Swpaul		goto fail;
75041502Swpaul	}
75141502Swpaul
752131503Sbms	/* Do MII setup. */
75351432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
75451432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
755151773Sjhb		device_printf(dev, "MII without any phy!\n");
75649610Swpaul		error = ENXIO;
75741502Swpaul		goto fail;
75841502Swpaul	}
75941502Swpaul
760131503Sbms	/* Call MI attach routine. */
761106936Ssam	ether_ifattach(ifp, eaddr);
76241502Swpaul
763131844Sbms	sc->suspended = 0;
764131844Sbms
765113609Snjl	/* Hook interrupt last to avoid having to lock softc */
766131518Sbms	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE,
767112872Snjl	    vr_intr, sc, &sc->vr_intrhand);
768112872Snjl
769112872Snjl	if (error) {
770151773Sjhb		device_printf(dev, "couldn't set up irq\n");
771113609Snjl		ether_ifdetach(ifp);
772112872Snjl		goto fail;
773112872Snjl	}
774112872Snjl
77541502Swpaulfail:
776112872Snjl	if (error)
777112872Snjl		vr_detach(dev);
77867087Swpaul
779131503Sbms	return (error);
78041502Swpaul}
78141502Swpaul
782113609Snjl/*
783113609Snjl * Shutdown hardware and free up resources. This can be called any
784113609Snjl * time after the mutex has been initialized. It is called in both
785113609Snjl * the error case in attach and the normal detach case so it needs
786113609Snjl * to be careful about only freeing resources that have actually been
787113609Snjl * allocated.
788113609Snjl */
789102336Salfredstatic int
790131503Sbmsvr_detach(device_t dev)
79149610Swpaul{
792131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
793147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
79449610Swpaul
795112880Sjhb	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
796131518Sbms
797150789Sglebius#ifdef DEVICE_POLLING
798150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
799150789Sglebius		ether_poll_deregister(ifp);
800150789Sglebius#endif
801150789Sglebius
802113609Snjl	/* These should only be active if attach succeeded */
803113812Simp	if (device_is_attached(dev)) {
804151911Sjhb		VR_LOCK(sc);
805151911Sjhb		sc->suspended = 1;
806113609Snjl		vr_stop(sc);
807151911Sjhb		VR_UNLOCK(sc);
808151911Sjhb		callout_drain(&sc->vr_stat_callout);
809112872Snjl		ether_ifdetach(ifp);
810113609Snjl	}
811113609Snjl	if (sc->vr_miibus)
812112872Snjl		device_delete_child(dev, sc->vr_miibus);
813113609Snjl	bus_generic_detach(dev);
81449610Swpaul
815112872Snjl	if (sc->vr_intrhand)
816112872Snjl		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
817112872Snjl	if (sc->vr_irq)
818112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
819112872Snjl	if (sc->vr_res)
820112872Snjl		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
82151432Swpaul
822151297Sru	if (ifp)
823151297Sru		if_free(ifp);
824151297Sru
825112872Snjl	if (sc->vr_ldata)
826112872Snjl		contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
82749610Swpaul
82867087Swpaul	mtx_destroy(&sc->vr_mtx);
82949610Swpaul
830131503Sbms	return (0);
83149610Swpaul}
83249610Swpaul
83341502Swpaul/*
83441502Swpaul * Initialize the transmit descriptors.
83541502Swpaul */
836102336Salfredstatic int
837131503Sbmsvr_list_tx_init(struct vr_softc *sc)
83841502Swpaul{
83941502Swpaul	struct vr_chain_data	*cd;
84041502Swpaul	struct vr_list_data	*ld;
84141502Swpaul	int			i;
84241502Swpaul
84341502Swpaul	cd = &sc->vr_cdata;
84441502Swpaul	ld = sc->vr_ldata;
84541502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
84641502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
84741502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
848131503Sbms			cd->vr_tx_chain[i].vr_nextdesc =
84941502Swpaul				&cd->vr_tx_chain[0];
85041502Swpaul		else
85141502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
85241502Swpaul				&cd->vr_tx_chain[i + 1];
85341502Swpaul	}
854127901Sru	cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0];
85541502Swpaul
856131503Sbms	return (0);
85741502Swpaul}
85841502Swpaul
85941502Swpaul
86041502Swpaul/*
86141502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
86241502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
86341502Swpaul * points back to the first.
86441502Swpaul */
865102336Salfredstatic int
866131503Sbmsvr_list_rx_init(struct vr_softc *sc)
86741502Swpaul{
86841502Swpaul	struct vr_chain_data	*cd;
86941502Swpaul	struct vr_list_data	*ld;
87041502Swpaul	int			i;
87141502Swpaul
872131518Sbms	VR_LOCK_ASSERT(sc);
873131518Sbms
87441502Swpaul	cd = &sc->vr_cdata;
87541502Swpaul	ld = sc->vr_ldata;
87641502Swpaul
87741502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
87841502Swpaul		cd->vr_rx_chain[i].vr_ptr =
87941502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
88049610Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
881131503Sbms			return (ENOBUFS);
88241502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
88341502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
88441502Swpaul					&cd->vr_rx_chain[0];
88541502Swpaul			ld->vr_rx_list[i].vr_next =
88641502Swpaul					vtophys(&ld->vr_rx_list[0]);
88741502Swpaul		} else {
88841502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
88941502Swpaul					&cd->vr_rx_chain[i + 1];
89041502Swpaul			ld->vr_rx_list[i].vr_next =
89141502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
89241502Swpaul		}
89341502Swpaul	}
89441502Swpaul
89541502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
89641502Swpaul
897131503Sbms	return (0);
89841502Swpaul}
89941502Swpaul
90041502Swpaul/*
90141502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
90241502Swpaul * Note: the length fields are only 11 bits wide, which means the
90341502Swpaul * largest size we can specify is 2047. This is important because
90441502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
90541502Swpaul * overflow the field and make a mess.
90641502Swpaul */
907102336Salfredstatic int
908131503Sbmsvr_newbuf(struct vr_softc *sc, struct vr_chain_onefrag *c, struct mbuf *m)
90941502Swpaul{
91041502Swpaul	struct mbuf		*m_new = NULL;
91141502Swpaul
91249610Swpaul	if (m == NULL) {
913111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
91487846Sluigi		if (m_new == NULL)
915131503Sbms			return (ENOBUFS);
91641502Swpaul
917111119Simp		MCLGET(m_new, M_DONTWAIT);
91849610Swpaul		if (!(m_new->m_flags & M_EXT)) {
91949610Swpaul			m_freem(m_new);
920131503Sbms			return (ENOBUFS);
92149610Swpaul		}
92249610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
92349610Swpaul	} else {
92449610Swpaul		m_new = m;
92549610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
92649610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
92741502Swpaul	}
92841502Swpaul
929131503Sbms	m_adj(m_new, sizeof(uint64_t));
93049610Swpaul
93141502Swpaul	c->vr_mbuf = m_new;
93241502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
93341502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
93442491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
93541502Swpaul
936131503Sbms	return (0);
93741502Swpaul}
93841502Swpaul
93941502Swpaul/*
94041502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
94141502Swpaul * the higher level protocols.
94241502Swpaul */
943102336Salfredstatic void
944131503Sbmsvr_rxeof(struct vr_softc *sc)
94541502Swpaul{
946131503Sbms	struct mbuf		*m, *m0;
947131503Sbms	struct ifnet		*ifp;
94841502Swpaul	struct vr_chain_onefrag	*cur_rx;
94941502Swpaul	int			total_len = 0;
950131503Sbms	uint32_t		rxstat;
95141502Swpaul
952122689Ssam	VR_LOCK_ASSERT(sc);
953147256Sbrooks	ifp = sc->vr_ifp;
95441502Swpaul
955131503Sbms	while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
956131503Sbms	    VR_RXSTAT_OWN)) {
957127901Sru#ifdef DEVICE_POLLING
958150789Sglebius		if (ifp->if_capenable & IFCAP_POLLING) {
959127901Sru			if (sc->rxcycles <= 0)
960127901Sru				break;
961127901Sru			sc->rxcycles--;
962127901Sru		}
963150789Sglebius#endif
964127901Sru		m0 = NULL;
96541502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
96641502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
96749610Swpaul		m = cur_rx->vr_mbuf;
96841502Swpaul
96941502Swpaul		/*
97041502Swpaul		 * If an error occurs, update stats, clear the
97141502Swpaul		 * status word and leave the mbuf cluster in place:
97241502Swpaul		 * it should simply get re-used next time this descriptor
973131503Sbms		 * comes up in the ring.
97441502Swpaul		 */
97541502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
97641502Swpaul			ifp->if_ierrors++;
977151773Sjhb			if_printf(ifp, "rx error (%02x):", rxstat & 0x000000ff);
978110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
979110131Ssilby				printf(" crc error");
980110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
981110131Ssilby				printf(" frame alignment error\n");
982110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
983110131Ssilby				printf(" FIFO overflow");
984110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
985110131Ssilby				printf(" received giant packet");
986110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
987110131Ssilby				printf(" received runt packet");
988110131Ssilby			if (rxstat & VR_RXSTAT_BUSERR)
989110131Ssilby				printf(" system bus error");
990110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
991110131Ssilby				printf("rx buffer error");
992110131Ssilby			printf("\n");
99349610Swpaul			vr_newbuf(sc, cur_rx, m);
99441502Swpaul			continue;
99541502Swpaul		}
99641502Swpaul
997131503Sbms		/* No errors; receive the packet. */
99841502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
99941502Swpaul
100041502Swpaul		/*
100142048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
100242048Swpaul		 * received frame, and there's no way to turn this
100342048Swpaul		 * behavior off (at least, I can't find anything in
1004131503Sbms		 * the manual that explains how to do it) so we have
100542048Swpaul		 * to trim off the CRC manually.
100642048Swpaul		 */
100742048Swpaul		total_len -= ETHER_CRC_LEN;
100842048Swpaul
100978508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
101078508Sbmilekic		    NULL);
101149610Swpaul		vr_newbuf(sc, cur_rx, m);
101249610Swpaul		if (m0 == NULL) {
101341502Swpaul			ifp->if_ierrors++;
101441502Swpaul			continue;
101541502Swpaul		}
101649610Swpaul		m = m0;
101741502Swpaul
101841502Swpaul		ifp->if_ipackets++;
1019122689Ssam		VR_UNLOCK(sc);
1020106936Ssam		(*ifp->if_input)(ifp, m);
1021122689Ssam		VR_LOCK(sc);
102241502Swpaul	}
102341502Swpaul}
102441502Swpaul
1025105221Sphkstatic void
1026131503Sbmsvr_rxeoc(struct vr_softc *sc)
102741502Swpaul{
1028147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
1029110131Ssilby	int			i;
103041502Swpaul
1031131518Sbms	VR_LOCK_ASSERT(sc);
1032131518Sbms
1033110131Ssilby	ifp->if_ierrors++;
1034110131Ssilby
1035131503Sbms	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
1036131503Sbms	DELAY(10000);
1037110131Ssilby
1038131503Sbms	/* Wait for receiver to stop */
1039110131Ssilby	for (i = 0x400;
1040110131Ssilby	     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON);
1041131503Sbms	     i--) {
1042131503Sbms		;
1043131503Sbms	}
1044110131Ssilby
1045110131Ssilby	if (!i) {
1046151773Sjhb		if_printf(ifp, "rx shutdown error!\n");
1047110131Ssilby		sc->vr_flags |= VR_F_RESTART;
1048110131Ssilby		return;
1049131503Sbms	}
1050110131Ssilby
105141502Swpaul	vr_rxeof(sc);
1052110131Ssilby
105341502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
105441502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
105541502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
105641502Swpaul}
105741502Swpaul
105841502Swpaul/*
105941502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
106041502Swpaul * the list buffers.
106141502Swpaul */
1062102336Salfredstatic void
1063131503Sbmsvr_txeof(struct vr_softc *sc)
106441502Swpaul{
106541502Swpaul	struct vr_chain		*cur_tx;
1066147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
106741502Swpaul
1068131518Sbms	VR_LOCK_ASSERT(sc);
106941502Swpaul
107041502Swpaul	/*
107141502Swpaul	 * Go through our tx list and free mbufs for those
107241502Swpaul	 * frames that have been transmitted.
107341502Swpaul	 */
1074127901Sru	cur_tx = sc->vr_cdata.vr_tx_cons;
1075127901Sru	while (cur_tx->vr_mbuf != NULL) {
1076131503Sbms		uint32_t		txstat;
1077110131Ssilby		int			i;
107841502Swpaul
107941502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
108041502Swpaul
1081101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
1082101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
1083110131Ssilby			for (i = 0x400;
1084110131Ssilby			     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON);
1085110131Ssilby			     i--)
1086101896Ssilby				;	/* Wait for chip to shutdown */
1087110131Ssilby			if (!i) {
1088151773Sjhb				if_printf(ifp, "tx shutdown timeout\n");
1089110131Ssilby				sc->vr_flags |= VR_F_RESTART;
1090110131Ssilby				break;
1091110131Ssilby			}
1092101896Ssilby			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
1093101896Ssilby			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr));
1094101896Ssilby			break;
1095101896Ssilby		}
1096101896Ssilby
109742491Swpaul		if (txstat & VR_TXSTAT_OWN)
109841502Swpaul			break;
109941502Swpaul
110041502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
110141502Swpaul			ifp->if_oerrors++;
110241502Swpaul			if (txstat & VR_TXSTAT_DEFER)
110341502Swpaul				ifp->if_collisions++;
110441502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
110541502Swpaul				ifp->if_collisions++;
110641502Swpaul		}
110741502Swpaul
110841502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
110941502Swpaul
111041502Swpaul		ifp->if_opackets++;
1111127901Sru		m_freem(cur_tx->vr_mbuf);
1112127901Sru		cur_tx->vr_mbuf = NULL;
1113148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
111441502Swpaul
1115127901Sru		cur_tx = cur_tx->vr_nextdesc;
111641502Swpaul	}
1117127901Sru	sc->vr_cdata.vr_tx_cons = cur_tx;
1118127901Sru	if (cur_tx->vr_mbuf == NULL)
111996677Ssilby		ifp->if_timer = 0;
112041502Swpaul}
112141502Swpaul
1122102336Salfredstatic void
1123131503Sbmsvr_tick(void *xsc)
112451432Swpaul{
1125131503Sbms	struct vr_softc		*sc = xsc;
112651432Swpaul	struct mii_data		*mii;
112751432Swpaul
1128151911Sjhb	VR_LOCK_ASSERT(sc);
1129131517Sbms
1130110131Ssilby	if (sc->vr_flags & VR_F_RESTART) {
1131151773Sjhb		if_printf(sc->vr_ifp, "restarting\n");
1132110131Ssilby		vr_stop(sc);
1133110131Ssilby		vr_reset(sc);
1134131844Sbms		vr_init_locked(sc);
1135110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1136110131Ssilby	}
1137110131Ssilby
113851432Swpaul	mii = device_get_softc(sc->vr_miibus);
113951432Swpaul	mii_tick(mii);
1140151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
114151432Swpaul}
114251432Swpaul
1143127901Sru#ifdef DEVICE_POLLING
1144127901Srustatic poll_handler_t vr_poll;
1145131844Sbmsstatic poll_handler_t vr_poll_locked;
1146127901Sru
1147102336Salfredstatic void
1148127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1149127901Sru{
1150127901Sru	struct vr_softc *sc = ifp->if_softc;
1151127901Sru
1152127901Sru	VR_LOCK(sc);
1153150789Sglebius	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1154150789Sglebius		vr_poll_locked(ifp, cmd, count);
1155131844Sbms	VR_UNLOCK(sc);
1156131844Sbms}
1157131517Sbms
1158131844Sbmsstatic void
1159131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
1160131844Sbms{
1161131844Sbms	struct vr_softc *sc = ifp->if_softc;
1162131844Sbms
1163131844Sbms	VR_LOCK_ASSERT(sc);
1164131844Sbms
1165127901Sru	sc->rxcycles = count;
1166127901Sru	vr_rxeof(sc);
1167127901Sru	vr_txeof(sc);
1168133006Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1169131844Sbms		vr_start_locked(ifp);
1170127901Sru
1171131503Sbms	if (cmd == POLL_AND_CHECK_STATUS) {
1172131503Sbms		uint16_t status;
1173127901Sru
1174131503Sbms		/* Also check status register. */
1175127901Sru		status = CSR_READ_2(sc, VR_ISR);
1176127901Sru		if (status)
1177127901Sru			CSR_WRITE_2(sc, VR_ISR, status);
1178127901Sru
1179127901Sru		if ((status & VR_INTRS) == 0)
1180131844Sbms			return;
1181127901Sru
1182127901Sru		if (status & VR_ISR_RX_DROPPED) {
1183151773Sjhb			if_printf(ifp, "rx packet lost\n");
1184127901Sru			ifp->if_ierrors++;
1185127901Sru		}
1186127901Sru
1187127901Sru		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1188127901Sru		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1189151773Sjhb			if_printf(ifp, "receive error (%04x)", status);
1190127901Sru			if (status & VR_ISR_RX_NOBUF)
1191127901Sru				printf(" no buffers");
1192127901Sru			if (status & VR_ISR_RX_OFLOW)
1193127901Sru				printf(" overflow");
1194127901Sru			if (status & VR_ISR_RX_DROPPED)
1195127901Sru				printf(" packet lost");
1196127901Sru			printf("\n");
1197127901Sru			vr_rxeoc(sc);
1198127901Sru		}
1199127901Sru
1200131503Sbms		if ((status & VR_ISR_BUSERR) ||
1201131503Sbms		    (status & VR_ISR_TX_UNDERRUN)) {
1202127901Sru			vr_reset(sc);
1203131844Sbms			vr_init_locked(sc);
1204131518Sbms			return;
1205127901Sru		}
1206127901Sru
1207127901Sru		if ((status & VR_ISR_UDFI) ||
1208127901Sru		    (status & VR_ISR_TX_ABRT2) ||
1209127901Sru		    (status & VR_ISR_TX_ABRT)) {
1210127901Sru			ifp->if_oerrors++;
1211127901Sru			if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) {
1212127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1213127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1214127901Sru			}
1215127901Sru		}
1216127901Sru	}
1217127901Sru}
1218127901Sru#endif /* DEVICE_POLLING */
1219127901Sru
1220127901Srustatic void
1221131503Sbmsvr_intr(void *arg)
122241502Swpaul{
1223131503Sbms	struct vr_softc		*sc = arg;
1224147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
1225131503Sbms	uint16_t		status;
122641502Swpaul
122767087Swpaul	VR_LOCK(sc);
1228131844Sbms
1229136997Sbms	if (sc->suspended) {
1230136997Sbms		/*
1231136997Sbms		 * Forcibly disable interrupts.
1232136997Sbms		 * XXX: Mobile VIA based platforms may need
1233136997Sbms		 * interrupt re-enable on resume.
1234136997Sbms		 */
1235136997Sbms		CSR_WRITE_2(sc, VR_IMR, 0x0000);
1236131844Sbms		goto done_locked;
1237136997Sbms	}
1238131844Sbms
1239127901Sru#ifdef DEVICE_POLLING
1240150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1241131844Sbms		goto done_locked;
1242150789Sglebius#endif
1243131844Sbms
1244131844Sbms	/* Suppress unwanted interrupts. */
124541502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
124641502Swpaul		vr_stop(sc);
1247131844Sbms		goto done_locked;
124841502Swpaul	}
124941502Swpaul
125041502Swpaul	/* Disable interrupts. */
125141502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
125241502Swpaul
125341502Swpaul	for (;;) {
125441502Swpaul		status = CSR_READ_2(sc, VR_ISR);
125541502Swpaul		if (status)
125641502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
125741502Swpaul
125841502Swpaul		if ((status & VR_INTRS) == 0)
125941502Swpaul			break;
126041502Swpaul
126141502Swpaul		if (status & VR_ISR_RX_OK)
126241502Swpaul			vr_rxeof(sc);
126341502Swpaul
1264110131Ssilby		if (status & VR_ISR_RX_DROPPED) {
1265151773Sjhb			if_printf(ifp, "rx packet lost\n");
1266110131Ssilby			ifp->if_ierrors++;
1267131503Sbms		}
1268110131Ssilby
126941502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1270110131Ssilby		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1271151773Sjhb			if_printf(ifp, "receive error (%04x)", status);
1272110131Ssilby			if (status & VR_ISR_RX_NOBUF)
1273110131Ssilby				printf(" no buffers");
1274110131Ssilby			if (status & VR_ISR_RX_OFLOW)
1275110131Ssilby				printf(" overflow");
1276110131Ssilby			if (status & VR_ISR_RX_DROPPED)
1277110131Ssilby				printf(" packet lost");
1278110131Ssilby			printf("\n");
127941502Swpaul			vr_rxeoc(sc);
128041502Swpaul		}
128141502Swpaul
1282101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1283101896Ssilby			vr_reset(sc);
1284131844Sbms			vr_init_locked(sc);
1285101896Ssilby			break;
128641502Swpaul		}
128741502Swpaul
1288101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1289101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
129041502Swpaul			vr_txeof(sc);
1291101896Ssilby			if ((status & VR_ISR_UDFI) ||
1292101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1293101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1294101896Ssilby				ifp->if_oerrors++;
1295127901Sru				if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) {
1296131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1297131503Sbms					    VR_CMD_TX_ON);
1298131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1299131503Sbms					    VR_CMD_TX_GO);
1300101896Ssilby				}
1301127901Sru			}
130241502Swpaul		}
130341502Swpaul	}
130441502Swpaul
130541502Swpaul	/* Re-enable interrupts. */
130641502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
130741502Swpaul
1308132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1309131844Sbms		vr_start_locked(ifp);
1310131844Sbms
1311131844Sbmsdone_locked:
1312131844Sbms	VR_UNLOCK(sc);
131341502Swpaul}
131441502Swpaul
131541502Swpaul/*
131641502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
131741502Swpaul * pointers to the fragment pointers.
131841502Swpaul */
1319102336Salfredstatic int
1320131503Sbmsvr_encap(struct vr_softc *sc, struct vr_chain *c, struct mbuf *m_head)
132141502Swpaul{
132241502Swpaul	struct vr_desc		*f = NULL;
132341502Swpaul	struct mbuf		*m;
132441502Swpaul
1325131518Sbms	VR_LOCK_ASSERT(sc);
132641502Swpaul	/*
132741502Swpaul	 * The VIA Rhine wants packet buffers to be longword
132841502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
132941502Swpaul	 * waste time trying to decide when to copy and when not
133041502Swpaul	 * to copy, just do it all the time.
133141502Swpaul	 */
1332127901Sru	m = m_defrag(m_head, M_DONTWAIT);
1333131503Sbms	if (m == NULL)
1334131503Sbms		return (1);
133541502Swpaul
1336127901Sru	/*
1337127901Sru	 * The Rhine chip doesn't auto-pad, so we have to make
1338127901Sru	 * sure to pad short frames out to the minimum frame length
1339127901Sru	 * ourselves.
1340127901Sru	 */
1341127901Sru	if (m->m_len < VR_MIN_FRAMELEN) {
1342127901Sru		m->m_pkthdr.len += VR_MIN_FRAMELEN - m->m_len;
1343127901Sru		m->m_len = m->m_pkthdr.len;
134441502Swpaul	}
134541502Swpaul
1346127901Sru	c->vr_mbuf = m;
1347127901Sru	f = c->vr_ptr;
1348127901Sru	f->vr_data = vtophys(mtod(m, caddr_t));
1349127901Sru	f->vr_ctl = m->m_len;
1350127901Sru	f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
1351127901Sru	f->vr_status = 0;
1352127901Sru	f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
1353127901Sru	f->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
135441502Swpaul
1355131503Sbms	return (0);
135641502Swpaul}
135741502Swpaul
135841502Swpaul/*
135941502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
136041502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
136141502Swpaul * copy of the pointers since the transmit list fragment pointers are
136241502Swpaul * physical addresses.
136341502Swpaul */
136441502Swpaul
1365102336Salfredstatic void
1366131503Sbmsvr_start(struct ifnet *ifp)
136741502Swpaul{
1368131518Sbms	struct vr_softc		*sc = ifp->if_softc;
1369131844Sbms
1370131844Sbms	VR_LOCK(sc);
1371131844Sbms	vr_start_locked(ifp);
1372131844Sbms	VR_UNLOCK(sc);
1373131844Sbms}
1374131844Sbms
1375131844Sbmsstatic void
1376131844Sbmsvr_start_locked(struct ifnet *ifp)
1377131844Sbms{
1378131844Sbms	struct vr_softc		*sc = ifp->if_softc;
1379127901Sru	struct mbuf		*m_head;
1380127901Sru	struct vr_chain		*cur_tx;
138141502Swpaul
1382148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
1383127901Sru		return;
1384127901Sru
1385127901Sru	cur_tx = sc->vr_cdata.vr_tx_prod;
1386127901Sru	while (cur_tx->vr_mbuf == NULL) {
1387132986Smlaier       	        IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
138841502Swpaul		if (m_head == NULL)
138941502Swpaul			break;
139041502Swpaul
139141502Swpaul		/* Pack the data into the descriptor. */
139271271Swpaul		if (vr_encap(sc, cur_tx, m_head)) {
1393113274Ssilby			/* Rollback, send what we were able to encap. */
1394132986Smlaier               		IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
139571271Swpaul			break;
139671271Swpaul		}
139741502Swpaul
1398127901Sru		VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
139941502Swpaul
140041502Swpaul		/*
140141502Swpaul		 * If there's a BPF listener, bounce a copy of this frame
140241502Swpaul		 * to him.
140341502Swpaul		 */
1404106936Ssam		BPF_MTAP(ifp, cur_tx->vr_mbuf);
140551583Swpaul
1406127901Sru		cur_tx = cur_tx->vr_nextdesc;
140741502Swpaul	}
1408127901Sru	if (cur_tx != sc->vr_cdata.vr_tx_prod || cur_tx->vr_mbuf != NULL) {
1409127901Sru		sc->vr_cdata.vr_tx_prod = cur_tx;
141041502Swpaul
1411127901Sru		/* Tell the chip to start transmitting. */
1412131517Sbms		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO);
141341526Swpaul
1414127901Sru		/* Set a timeout in case the chip goes out to lunch. */
1415127901Sru		ifp->if_timer = 5;
141641502Swpaul
1417127901Sru		if (cur_tx->vr_mbuf != NULL)
1418148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1419127901Sru	}
1420131844Sbms}
142141502Swpaul
1422131844Sbmsstatic void
1423131844Sbmsvr_init(void *xsc)
1424131844Sbms{
1425131844Sbms	struct vr_softc		*sc = xsc;
1426131844Sbms
1427131844Sbms	VR_LOCK(sc);
1428131844Sbms	vr_init_locked(sc);
142967087Swpaul	VR_UNLOCK(sc);
143041502Swpaul}
143141502Swpaul
1432102336Salfredstatic void
1433131844Sbmsvr_init_locked(struct vr_softc *sc)
143441502Swpaul{
1435147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
143651432Swpaul	struct mii_data		*mii;
143773963Swpaul	int			i;
143841502Swpaul
1439131844Sbms	VR_LOCK_ASSERT(sc);
144041502Swpaul
144151432Swpaul	mii = device_get_softc(sc->vr_miibus);
144241502Swpaul
1443131503Sbms	/* Cancel pending I/O and free all RX/TX buffers. */
144441502Swpaul	vr_stop(sc);
144541502Swpaul	vr_reset(sc);
144641502Swpaul
1447131503Sbms	/* Set our station address. */
144873963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
1449147256Sbrooks		CSR_WRITE_1(sc, VR_PAR0 + i, IFP2ENADDR(sc->vr_ifp)[i]);
1450131503Sbms
1451131503Sbms	/* Set DMA size. */
1452101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1453101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
145473963Swpaul
1455131503Sbms	/*
1456101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1457101108Ssilby	 * so we must set both.
1458101108Ssilby	 */
1459101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1460110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
1461101108Ssilby
1462101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1463101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1464101108Ssilby
146541502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
1466110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
146741502Swpaul
146841502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
146941502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
147041502Swpaul
147141502Swpaul	/* Init circular RX list. */
147241502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
1473151773Sjhb		if_printf(ifp,
1474151773Sjhb		    "initialization failed: no memory for rx buffers\n");
147541502Swpaul		vr_stop(sc);
147641502Swpaul		return;
147741502Swpaul	}
147841502Swpaul
1479131503Sbms	/* Init tx descriptors. */
148041502Swpaul	vr_list_tx_init(sc);
148141502Swpaul
148241502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
148341502Swpaul	if (ifp->if_flags & IFF_PROMISC)
148441502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
148541502Swpaul	else
148641502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
148741502Swpaul
148841502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
148941502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
149041502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
149141502Swpaul	else
149241502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
149341502Swpaul
149441502Swpaul	/*
149541502Swpaul	 * Program the multicast filter, if necessary.
149641502Swpaul	 */
149741502Swpaul	vr_setmulti(sc);
149841502Swpaul
149941502Swpaul	/*
150041502Swpaul	 * Load the address of the RX list.
150141502Swpaul	 */
150241502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
150341502Swpaul
150441502Swpaul	/* Enable receiver and transmitter. */
150541502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
150641502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
150741502Swpaul				    VR_CMD_RX_GO);
150841502Swpaul
150941502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
151041502Swpaul
1511127901Sru	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
1512127901Sru#ifdef DEVICE_POLLING
151341502Swpaul	/*
1514127901Sru	 * Disable interrupts if we are polling.
1515127901Sru	 */
1516150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1517127901Sru		CSR_WRITE_2(sc, VR_IMR, 0);
1518131503Sbms	else
1519150789Sglebius#endif
1520127901Sru	/*
152141502Swpaul	 * Enable interrupts.
152241502Swpaul	 */
152341502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
152441502Swpaul
152551432Swpaul	mii_mediachg(mii);
152641502Swpaul
1527148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1528148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
152941502Swpaul
1530151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
153141502Swpaul}
153241502Swpaul
153341502Swpaul/*
153441502Swpaul * Set media options.
153541502Swpaul */
1536102336Salfredstatic int
1537131503Sbmsvr_ifmedia_upd(struct ifnet *ifp)
153841502Swpaul{
1539131503Sbms	struct vr_softc		*sc = ifp->if_softc;
154041502Swpaul
154151432Swpaul	if (ifp->if_flags & IFF_UP)
154251432Swpaul		vr_init(sc);
154341502Swpaul
1544131503Sbms	return (0);
154541502Swpaul}
154641502Swpaul
154741502Swpaul/*
154841502Swpaul * Report current media status.
154941502Swpaul */
1550102336Salfredstatic void
1551131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
155241502Swpaul{
1553131518Sbms	struct vr_softc		*sc = ifp->if_softc;
155451432Swpaul	struct mii_data		*mii;
155541502Swpaul
155651432Swpaul	mii = device_get_softc(sc->vr_miibus);
1557133468Sscottl	VR_LOCK(sc);
155851432Swpaul	mii_pollstat(mii);
1559133468Sscottl	VR_UNLOCK(sc);
156051432Swpaul	ifmr->ifm_active = mii->mii_media_active;
156151432Swpaul	ifmr->ifm_status = mii->mii_media_status;
156241502Swpaul}
156341502Swpaul
1564102336Salfredstatic int
1565131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
156641502Swpaul{
156741502Swpaul	struct vr_softc		*sc = ifp->if_softc;
156841502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
156951432Swpaul	struct mii_data		*mii;
157067087Swpaul	int			error = 0;
157141502Swpaul
1572131503Sbms	switch (command) {
157341502Swpaul	case SIOCSIFFLAGS:
1574131844Sbms		VR_LOCK(sc);
157541502Swpaul		if (ifp->if_flags & IFF_UP) {
1576131844Sbms			vr_init_locked(sc);
157741502Swpaul		} else {
1578148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
157941502Swpaul				vr_stop(sc);
158041502Swpaul		}
1581131844Sbms		VR_UNLOCK(sc);
158241502Swpaul		error = 0;
158341502Swpaul		break;
158441502Swpaul	case SIOCADDMULTI:
158541502Swpaul	case SIOCDELMULTI:
1586131518Sbms		VR_LOCK(sc);
158741502Swpaul		vr_setmulti(sc);
1588131518Sbms		VR_UNLOCK(sc);
158941502Swpaul		error = 0;
159041502Swpaul		break;
159141502Swpaul	case SIOCGIFMEDIA:
159241502Swpaul	case SIOCSIFMEDIA:
159351432Swpaul		mii = device_get_softc(sc->vr_miibus);
159451432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
159541502Swpaul		break;
1596128118Sru	case SIOCSIFCAP:
1597150789Sglebius#ifdef DEVICE_POLLING
1598150789Sglebius		if (ifr->ifr_reqcap & IFCAP_POLLING &&
1599150789Sglebius		    !(ifp->if_capenable & IFCAP_POLLING)) {
1600150789Sglebius			error = ether_poll_register(vr_poll, ifp);
1601150789Sglebius			if (error)
1602150789Sglebius				return(error);
1603150789Sglebius			VR_LOCK(sc);
1604150789Sglebius			/* Disable interrupts */
1605150789Sglebius			CSR_WRITE_2(sc, VR_IMR, 0x0000);
1606150789Sglebius			ifp->if_capenable |= IFCAP_POLLING;
1607150789Sglebius			VR_UNLOCK(sc);
1608150789Sglebius			return (error);
1609150789Sglebius
1610150789Sglebius		}
1611150789Sglebius		if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
1612150789Sglebius		    ifp->if_capenable & IFCAP_POLLING) {
1613150789Sglebius			error = ether_poll_deregister(ifp);
1614150789Sglebius			/* Enable interrupts. */
1615150789Sglebius			VR_LOCK(sc);
1616150789Sglebius			CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
1617150789Sglebius			ifp->if_capenable &= ~IFCAP_POLLING;
1618150789Sglebius			VR_UNLOCK(sc);
1619150789Sglebius			return (error);
1620150789Sglebius		}
1621150789Sglebius#endif /* DEVICE_POLLING */
1622128118Sru		break;
162341502Swpaul	default:
1624106936Ssam		error = ether_ioctl(ifp, command, data);
162541502Swpaul		break;
162641502Swpaul	}
162741502Swpaul
1628131503Sbms	return (error);
162941502Swpaul}
163041502Swpaul
1631102336Salfredstatic void
1632131503Sbmsvr_watchdog(struct ifnet *ifp)
163341502Swpaul{
1634131518Sbms	struct vr_softc		*sc = ifp->if_softc;
163541502Swpaul
163667087Swpaul	VR_LOCK(sc);
1637131844Sbms
163841502Swpaul	ifp->if_oerrors++;
1639151773Sjhb	if_printf(ifp, "watchdog timeout\n");
164041502Swpaul
164141502Swpaul	vr_stop(sc);
164241502Swpaul	vr_reset(sc);
1643131844Sbms	vr_init_locked(sc);
1644131518Sbms
1645132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1646131844Sbms		vr_start_locked(ifp);
1647131844Sbms
1648131844Sbms	VR_UNLOCK(sc);
164941502Swpaul}
165041502Swpaul
165141502Swpaul/*
165241502Swpaul * Stop the adapter and free any mbufs allocated to the
165341502Swpaul * RX and TX lists.
165441502Swpaul */
1655102336Salfredstatic void
1656131503Sbmsvr_stop(struct vr_softc *sc)
165741502Swpaul{
1658131503Sbms	register int	i;
1659131503Sbms	struct ifnet	*ifp;
166041502Swpaul
1661131518Sbms	VR_LOCK_ASSERT(sc);
166267087Swpaul
1663147256Sbrooks	ifp = sc->vr_ifp;
166441502Swpaul	ifp->if_timer = 0;
166541502Swpaul
1666151911Sjhb	callout_stop(&sc->vr_stat_callout);
1667148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
166851432Swpaul
166941502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
167041502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
167141502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
167241502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
167341502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
167441502Swpaul
167541502Swpaul	/*
167641502Swpaul	 * Free data in the RX lists.
167741502Swpaul	 */
167841502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
167941502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
168041502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
168141502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
168241502Swpaul		}
168341502Swpaul	}
168441502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
1685131517Sbms	    sizeof(sc->vr_ldata->vr_rx_list));
168641502Swpaul
168741502Swpaul	/*
168841502Swpaul	 * Free the TX list buffers.
168941502Swpaul	 */
169041502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
169141502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
169241502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
169341502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
169441502Swpaul		}
169541502Swpaul	}
169641502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
1697131517Sbms	    sizeof(sc->vr_ldata->vr_tx_list));
169841502Swpaul}
169941502Swpaul
170041502Swpaul/*
170141502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
170241502Swpaul * get confused by errant DMAs when rebooting.
170341502Swpaul */
1704102336Salfredstatic void
1705131503Sbmsvr_shutdown(device_t dev)
170641502Swpaul{
170741502Swpaul
1708136696Sbms	vr_detach(dev);
170941502Swpaul}
1710