if_vr.c revision 148887
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 148887 2005-08-09 10:20:02Z rwatson $");
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
6341502Swpaul#include <sys/param.h>
6441502Swpaul#include <sys/systm.h>
6541502Swpaul#include <sys/sockio.h>
6641502Swpaul#include <sys/mbuf.h>
6741502Swpaul#include <sys/malloc.h>
6841502Swpaul#include <sys/kernel.h>
69129878Sphk#include <sys/module.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>
77147256Sbrooks#include <net/if_types.h>
7841502Swpaul
7941502Swpaul#include <net/bpf.h>
8041502Swpaul
81131503Sbms#include <vm/vm.h>		/* for vtophys */
82131503Sbms#include <vm/pmap.h>		/* for vtophys */
8341502Swpaul#include <machine/bus.h>
8449610Swpaul#include <machine/resource.h>
8549610Swpaul#include <sys/bus.h>
8649610Swpaul#include <sys/rman.h>
8741502Swpaul
8851432Swpaul#include <dev/mii/mii.h>
8951432Swpaul#include <dev/mii/miivar.h>
9051432Swpaul
91119288Simp#include <dev/pci/pcireg.h>
92119288Simp#include <dev/pci/pcivar.h>
9341502Swpaul
9441502Swpaul#define VR_USEIOSPACE
9541502Swpaul
9641502Swpaul#include <pci/if_vrreg.h>
9741502Swpaul
98113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1);
99113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1);
10059758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
10159758Speter
10251432Swpaul/* "controller miibus0" required.  See GENERIC if you get errors here. */
10351432Swpaul#include "miibus_if.h"
10451432Swpaul
105110168Ssilby#undef VR_USESWSHIFT
106110168Ssilby
10741502Swpaul/*
10841502Swpaul * Various supported device vendors/types and their names.
10941502Swpaul */
11041502Swpaulstatic struct vr_type vr_devs[] = {
11141502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
11241502Swpaul		"VIA VT3043 Rhine I 10/100BaseTX" },
11341502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
11441502Swpaul		"VIA VT86C100A Rhine II 10/100BaseTX" },
11562653Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
11662653Swpaul		"VIA VT6102 Rhine II 10/100BaseTX" },
117110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III,
118110170Ssilby		"VIA VT6105 Rhine III 10/100BaseTX" },
119110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
120110170Ssilby		"VIA VT6105M Rhine III 10/100BaseTX" },
12144238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
12244238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
12344238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
12444238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
12541502Swpaul	{ 0, 0, NULL }
12641502Swpaul};
12741502Swpaul
128142407Simpstatic int vr_probe(device_t);
129142407Simpstatic int vr_attach(device_t);
130142407Simpstatic int vr_detach(device_t);
13141502Swpaul
132142407Simpstatic int vr_newbuf(struct vr_softc *, struct vr_chain_onefrag *,
133142407Simp		struct mbuf *);
134142407Simpstatic int vr_encap(struct vr_softc *, struct vr_chain *, struct mbuf * );
13541502Swpaul
136142407Simpstatic void vr_rxeof(struct vr_softc *);
137142407Simpstatic void vr_rxeoc(struct vr_softc *);
138142407Simpstatic void vr_txeof(struct vr_softc *);
139142407Simpstatic void vr_tick(void *);
140142407Simpstatic void vr_intr(void *);
141142407Simpstatic void vr_start(struct ifnet *);
142142407Simpstatic void vr_start_locked(struct ifnet *);
143142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t);
144142407Simpstatic void vr_init(void *);
145142407Simpstatic void vr_init_locked(struct vr_softc *);
146142407Simpstatic void vr_stop(struct vr_softc *);
147142407Simpstatic void vr_watchdog(struct ifnet *);
148142407Simpstatic void vr_shutdown(device_t);
149142407Simpstatic int vr_ifmedia_upd(struct ifnet *);
150142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
15141502Swpaul
152110168Ssilby#ifdef VR_USESWSHIFT
153142407Simpstatic void vr_mii_sync(struct vr_softc *);
154142407Simpstatic void vr_mii_send(struct vr_softc *, uint32_t, int);
155110168Ssilby#endif
156142407Simpstatic int vr_mii_readreg(struct vr_softc *, struct vr_mii_frame *);
157142407Simpstatic int vr_mii_writereg(struct vr_softc *, struct vr_mii_frame *);
158142407Simpstatic int vr_miibus_readreg(device_t, uint16_t, uint16_t);
159142407Simpstatic int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t);
160142407Simpstatic void vr_miibus_statchg(device_t);
16141502Swpaul
162142407Simpstatic void vr_setcfg(struct vr_softc *, int);
163142407Simpstatic void vr_setmulti(struct vr_softc *);
164142407Simpstatic void vr_reset(struct vr_softc *);
165142407Simpstatic int vr_list_rx_init(struct vr_softc *);
166142407Simpstatic int vr_list_tx_init(struct vr_softc *);
16741502Swpaul
16849610Swpaul#ifdef VR_USEIOSPACE
16949610Swpaul#define VR_RES			SYS_RES_IOPORT
17049610Swpaul#define VR_RID			VR_PCI_LOIO
17149610Swpaul#else
17249610Swpaul#define VR_RES			SYS_RES_MEMORY
17349610Swpaul#define VR_RID			VR_PCI_LOMEM
17449610Swpaul#endif
17549610Swpaul
17649610Swpaulstatic device_method_t vr_methods[] = {
17749610Swpaul	/* Device interface */
17849610Swpaul	DEVMETHOD(device_probe,		vr_probe),
17949610Swpaul	DEVMETHOD(device_attach,	vr_attach),
18049610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
18149610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
18251432Swpaul
18351432Swpaul	/* bus interface */
18451432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18551432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
18651432Swpaul
18751432Swpaul	/* MII interface */
18851432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
18951432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
19051432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
19151432Swpaul
19249610Swpaul	{ 0, 0 }
19349610Swpaul};
19449610Swpaul
19549610Swpaulstatic driver_t vr_driver = {
19651455Swpaul	"vr",
19749610Swpaul	vr_methods,
19849610Swpaul	sizeof(struct vr_softc)
19949610Swpaul};
20049610Swpaul
20149610Swpaulstatic devclass_t vr_devclass;
20249610Swpaul
203113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0);
20451473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
20549610Swpaul
20641502Swpaul#define VR_SETBIT(sc, reg, x)				\
20741502Swpaul	CSR_WRITE_1(sc, reg,				\
208105221Sphk		CSR_READ_1(sc, reg) | (x))
20941502Swpaul
21041502Swpaul#define VR_CLRBIT(sc, reg, x)				\
21141502Swpaul	CSR_WRITE_1(sc, reg,				\
212105221Sphk		CSR_READ_1(sc, reg) & ~(x))
21341502Swpaul
21441502Swpaul#define VR_SETBIT16(sc, reg, x)				\
21541502Swpaul	CSR_WRITE_2(sc, reg,				\
216105221Sphk		CSR_READ_2(sc, reg) | (x))
21741502Swpaul
21841502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
21941502Swpaul	CSR_WRITE_2(sc, reg,				\
220105221Sphk		CSR_READ_2(sc, reg) & ~(x))
22141502Swpaul
22241502Swpaul#define VR_SETBIT32(sc, reg, x)				\
22341502Swpaul	CSR_WRITE_4(sc, reg,				\
224105221Sphk		CSR_READ_4(sc, reg) | (x))
22541502Swpaul
22641502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
22741502Swpaul	CSR_WRITE_4(sc, reg,				\
228105221Sphk		CSR_READ_4(sc, reg) & ~(x))
22941502Swpaul
23041502Swpaul#define SIO_SET(x)					\
23141502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
232105221Sphk		CSR_READ_1(sc, VR_MIICMD) | (x))
23341502Swpaul
23441502Swpaul#define SIO_CLR(x)					\
23541502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
236105221Sphk		CSR_READ_1(sc, VR_MIICMD) & ~(x))
23741502Swpaul
238110168Ssilby#ifdef VR_USESWSHIFT
23941502Swpaul/*
24041502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
24141502Swpaul */
242102336Salfredstatic void
243131503Sbmsvr_mii_sync(struct vr_softc *sc)
24441502Swpaul{
245131503Sbms	register int	i;
24641502Swpaul
24741502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
24841502Swpaul
24941502Swpaul	for (i = 0; i < 32; i++) {
25041502Swpaul		SIO_SET(VR_MIICMD_CLK);
25141502Swpaul		DELAY(1);
25241502Swpaul		SIO_CLR(VR_MIICMD_CLK);
25341502Swpaul		DELAY(1);
25441502Swpaul	}
25541502Swpaul}
25641502Swpaul
25741502Swpaul/*
25841502Swpaul * Clock a series of bits through the MII.
25941502Swpaul */
260102336Salfredstatic void
261131503Sbmsvr_mii_send(struct vr_softc *sc, uint32_t bits, int cnt)
26241502Swpaul{
263131503Sbms	int	i;
26441502Swpaul
26541502Swpaul	SIO_CLR(VR_MIICMD_CLK);
26641502Swpaul
26741502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
268131503Sbms		if (bits & i) {
26941502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
270131503Sbms		} else {
27141502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
272131503Sbms		}
27341502Swpaul		DELAY(1);
27441502Swpaul		SIO_CLR(VR_MIICMD_CLK);
27541502Swpaul		DELAY(1);
27641502Swpaul		SIO_SET(VR_MIICMD_CLK);
27741502Swpaul	}
27841502Swpaul}
279110168Ssilby#endif
28041502Swpaul
28141502Swpaul/*
28241502Swpaul * Read an PHY register through the MII.
28341502Swpaul */
284102336Salfredstatic int
285131503Sbmsvr_mii_readreg(struct vr_softc *sc, struct vr_mii_frame *frame)
286131503Sbms#ifdef VR_USESWSHIFT
28741502Swpaul{
288131503Sbms	int	i, ack;
28941502Swpaul
290131503Sbms	/* Set up frame for RX. */
29141502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
29241502Swpaul	frame->mii_opcode = VR_MII_READOP;
29341502Swpaul	frame->mii_turnaround = 0;
29441502Swpaul	frame->mii_data = 0;
295131503Sbms
29641502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
29741502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
29841502Swpaul
299131503Sbms	/* Turn on data xmit. */
30041502Swpaul	SIO_SET(VR_MIICMD_DIR);
30141502Swpaul
30241502Swpaul	vr_mii_sync(sc);
30341502Swpaul
304131503Sbms	/* Send command/address info. */
30541502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
30641502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
30741502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
30841502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
30941502Swpaul
310131503Sbms	/* Idle bit. */
31141502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
31241502Swpaul	DELAY(1);
31341502Swpaul	SIO_SET(VR_MIICMD_CLK);
31441502Swpaul	DELAY(1);
31541502Swpaul
31641502Swpaul	/* Turn off xmit. */
31741502Swpaul	SIO_CLR(VR_MIICMD_DIR);
31841502Swpaul
31941502Swpaul	/* Check for ack */
32041502Swpaul	SIO_CLR(VR_MIICMD_CLK);
32141502Swpaul	DELAY(1);
322109058Smbr	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
32341502Swpaul	SIO_SET(VR_MIICMD_CLK);
32441502Swpaul	DELAY(1);
32541502Swpaul
32641502Swpaul	/*
32741502Swpaul	 * Now try reading data bits. If the ack failed, we still
32841502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
32941502Swpaul	 */
33041502Swpaul	if (ack) {
33141502Swpaul		for(i = 0; i < 16; i++) {
33241502Swpaul			SIO_CLR(VR_MIICMD_CLK);
33341502Swpaul			DELAY(1);
33441502Swpaul			SIO_SET(VR_MIICMD_CLK);
33541502Swpaul			DELAY(1);
33641502Swpaul		}
33741502Swpaul		goto fail;
33841502Swpaul	}
33941502Swpaul
34041502Swpaul	for (i = 0x8000; i; i >>= 1) {
34141502Swpaul		SIO_CLR(VR_MIICMD_CLK);
34241502Swpaul		DELAY(1);
34341502Swpaul		if (!ack) {
34441502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
34541502Swpaul				frame->mii_data |= i;
34641502Swpaul			DELAY(1);
34741502Swpaul		}
34841502Swpaul		SIO_SET(VR_MIICMD_CLK);
34941502Swpaul		DELAY(1);
35041502Swpaul	}
35141502Swpaul
35241502Swpaulfail:
35341502Swpaul	SIO_CLR(VR_MIICMD_CLK);
35441502Swpaul	DELAY(1);
35541502Swpaul	SIO_SET(VR_MIICMD_CLK);
35641502Swpaul	DELAY(1);
35741502Swpaul
35841502Swpaul	if (ack)
359131503Sbms		return (1);
360131503Sbms	return (0);
36141502Swpaul}
362110168Ssilby#else
363110168Ssilby{
364131518Sbms	int	i;
36541502Swpaul
366131503Sbms	/* Set the PHY address. */
367110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
368110168Ssilby	    frame->mii_phyaddr);
369110168Ssilby
370131503Sbms	/* Set the register address. */
371110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
372110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
373131503Sbms
374110168Ssilby	for (i = 0; i < 10000; i++) {
375110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
376110168Ssilby			break;
377110168Ssilby		DELAY(1);
378110168Ssilby	}
379110168Ssilby	frame->mii_data = CSR_READ_2(sc, VR_MIIDATA);
380110168Ssilby
381131503Sbms	return (0);
382110168Ssilby}
383110168Ssilby#endif
384110168Ssilby
385110168Ssilby
38641502Swpaul/*
38741502Swpaul * Write to a PHY register through the MII.
38841502Swpaul */
389102336Salfredstatic int
390131503Sbmsvr_mii_writereg(struct vr_softc *sc, struct vr_mii_frame *frame)
391131503Sbms#ifdef VR_USESWSHIFT
39241502Swpaul{
39341502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
39441502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
39541502Swpaul
396131503Sbms	/* Set up frame for TX. */
39741502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
39841502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
39941502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
400131503Sbms
401131503Sbms	/* Turn on data output. */
40241502Swpaul	SIO_SET(VR_MIICMD_DIR);
40341502Swpaul
40441502Swpaul	vr_mii_sync(sc);
40541502Swpaul
40641502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
40741502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
40841502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
40941502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
41041502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
41141502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
41241502Swpaul
41341502Swpaul	/* Idle bit. */
41441502Swpaul	SIO_SET(VR_MIICMD_CLK);
41541502Swpaul	DELAY(1);
41641502Swpaul	SIO_CLR(VR_MIICMD_CLK);
41741502Swpaul	DELAY(1);
41841502Swpaul
419131503Sbms	/* Turn off xmit. */
42041502Swpaul	SIO_CLR(VR_MIICMD_DIR);
42141502Swpaul
422131503Sbms	return (0);
42341502Swpaul}
424110168Ssilby#else
425110168Ssilby{
426131518Sbms	int	i;
42741502Swpaul
428131503Sbms	/* Set the PHY address. */
429110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
430131503Sbms	    frame->mii_phyaddr);
431110168Ssilby
432131503Sbms	/* Set the register address and data to write. */
433110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
434110168Ssilby	CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data);
435110168Ssilby
436110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
437110168Ssilby
438110168Ssilby	for (i = 0; i < 10000; i++) {
439110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
440110168Ssilby			break;
441110168Ssilby		DELAY(1);
442110168Ssilby	}
443110168Ssilby
444131503Sbms	return (0);
445110168Ssilby}
446110168Ssilby#endif
447110168Ssilby
448102336Salfredstatic int
449131517Sbmsvr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg)
45051432Swpaul{
45141502Swpaul	struct vr_mii_frame	frame;
452131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
45341502Swpaul
454110168Ssilby	switch (sc->vr_revid) {
455131503Sbms	case REV_ID_VT6102_APOLLO:
456131518Sbms		if (phy != 1) {
457131518Sbms			frame.mii_data = 0;
458131518Sbms			goto out;
459131518Sbms		}
460131503Sbms	default:
461131503Sbms		break;
462131503Sbms	}
463110168Ssilby
46441502Swpaul	bzero((char *)&frame, sizeof(frame));
46551432Swpaul	frame.mii_phyaddr = phy;
46641502Swpaul	frame.mii_regaddr = reg;
46741502Swpaul	vr_mii_readreg(sc, &frame);
46841502Swpaul
469131518Sbmsout:
470131503Sbms	return (frame.mii_data);
47141502Swpaul}
47241502Swpaul
473102336Salfredstatic int
474131503Sbmsvr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data)
47551432Swpaul{
47641502Swpaul	struct vr_mii_frame	frame;
477131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
47841502Swpaul
479110168Ssilby	switch (sc->vr_revid) {
480131503Sbms	case REV_ID_VT6102_APOLLO:
481131503Sbms		if (phy != 1)
482131503Sbms			return (0);
483131503Sbms	default:
484131503Sbms		break;
485131503Sbms	}
486110168Ssilby
48741502Swpaul	bzero((char *)&frame, sizeof(frame));
48851432Swpaul	frame.mii_phyaddr = phy;
48941502Swpaul	frame.mii_regaddr = reg;
49041502Swpaul	frame.mii_data = data;
49141502Swpaul	vr_mii_writereg(sc, &frame);
49241502Swpaul
493131503Sbms	return (0);
49451432Swpaul}
49551432Swpaul
496102336Salfredstatic void
497131503Sbmsvr_miibus_statchg(device_t dev)
49851432Swpaul{
49951432Swpaul	struct mii_data		*mii;
500131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
50151432Swpaul
50251432Swpaul	mii = device_get_softc(sc->vr_miibus);
50351432Swpaul	vr_setcfg(sc, mii->mii_media_active);
50441502Swpaul}
50541502Swpaul
50641502Swpaul/*
50741502Swpaul * Program the 64-bit multicast hash filter.
50841502Swpaul */
509102336Salfredstatic void
510131503Sbmsvr_setmulti(struct vr_softc *sc)
51141502Swpaul{
512147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
51341502Swpaul	int			h = 0;
514131503Sbms	uint32_t		hashes[2] = { 0, 0 };
51541502Swpaul	struct ifmultiaddr	*ifma;
516131503Sbms	uint8_t			rxfilt;
51741502Swpaul	int			mcnt = 0;
51841502Swpaul
519131518Sbms	VR_LOCK_ASSERT(sc);
52041502Swpaul
52141502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
52241502Swpaul
52341502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
52441502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
52541502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
52641502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
52741502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
52841502Swpaul		return;
52941502Swpaul	}
53041502Swpaul
531131503Sbms	/* First, zero out all the existing hash bits. */
53241502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
53341502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
53441502Swpaul
535131503Sbms	/* Now program new ones. */
536148654Srwatson	IF_ADDR_LOCK(ifp);
53772084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
53841502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
53941502Swpaul			continue;
540130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
541130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
54241502Swpaul		if (h < 32)
54341502Swpaul			hashes[0] |= (1 << h);
54441502Swpaul		else
54541502Swpaul			hashes[1] |= (1 << (h - 32));
54641502Swpaul		mcnt++;
54741502Swpaul	}
548148654Srwatson	IF_ADDR_UNLOCK(ifp);
54941502Swpaul
55041502Swpaul	if (mcnt)
55141502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
55241502Swpaul	else
55341502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
55441502Swpaul
55541502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
55641502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
55741502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
55841502Swpaul}
55941502Swpaul
56041502Swpaul/*
56141502Swpaul * In order to fiddle with the
56241502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
56341502Swpaul * first have to put the transmit and/or receive logic in the idle state.
56441502Swpaul */
565102336Salfredstatic void
566131503Sbmsvr_setcfg(struct vr_softc *sc, int media)
56741502Swpaul{
568131517Sbms	int	restart = 0;
56941502Swpaul
570131518Sbms	VR_LOCK_ASSERT(sc);
571131518Sbms
57241502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
57341502Swpaul		restart = 1;
57441502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
57541502Swpaul	}
57641502Swpaul
57751432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
57841502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
57941502Swpaul	else
58041502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58141502Swpaul
58241502Swpaul	if (restart)
58341502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
58441502Swpaul}
58541502Swpaul
586102336Salfredstatic void
587131503Sbmsvr_reset(struct vr_softc *sc)
58841502Swpaul{
589131517Sbms	register int	i;
59041502Swpaul
591131844Sbms	/*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during detach w/o lock. */
592131518Sbms
59341502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
59441502Swpaul
59541502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
59641502Swpaul		DELAY(10);
59741502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
59841502Swpaul			break;
59941502Swpaul	}
600107220Ssilby	if (i == VR_TIMEOUT) {
601107220Ssilby		if (sc->vr_revid < REV_ID_VT3065_A)
602107220Ssilby			printf("vr%d: reset never completed!\n", sc->vr_unit);
603107220Ssilby		else {
604107220Ssilby			/* Use newer force reset command */
605131503Sbms			printf("vr%d: Using force reset command.\n",
606131503Sbms			    sc->vr_unit);
607107220Ssilby			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
608107220Ssilby		}
609107220Ssilby	}
61041502Swpaul
61141502Swpaul	/* Wait a little while for the chip to get its brains in order. */
61241502Swpaul	DELAY(1000);
61341502Swpaul}
61441502Swpaul
61541502Swpaul/*
61641502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
61741502Swpaul * IDs against our list and return a device name if we find a match.
61841502Swpaul */
619102336Salfredstatic int
620131503Sbmsvr_probe(device_t dev)
62141502Swpaul{
622131503Sbms	struct vr_type	*t = vr_devs;
62341502Swpaul
624131503Sbms	while (t->vr_name != NULL) {
62549610Swpaul		if ((pci_get_vendor(dev) == t->vr_vid) &&
62649610Swpaul		    (pci_get_device(dev) == t->vr_did)) {
62749610Swpaul			device_set_desc(dev, t->vr_name);
628142398Simp			return (BUS_PROBE_DEFAULT);
62941502Swpaul		}
63041502Swpaul		t++;
63141502Swpaul	}
63241502Swpaul
633131503Sbms	return (ENXIO);
63441502Swpaul}
63541502Swpaul
63641502Swpaul/*
63741502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
63841502Swpaul * setup and ethernet/BPF attach.
63941502Swpaul */
640102336Salfredstatic int
641102336Salfredvr_attach(dev)
64249610Swpaul	device_t		dev;
64341502Swpaul{
64467087Swpaul	int			i;
64541502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
64641502Swpaul	struct vr_softc		*sc;
64741502Swpaul	struct ifnet		*ifp;
64849610Swpaul	int			unit, error = 0, rid;
64941502Swpaul
65049610Swpaul	sc = device_get_softc(dev);
65149610Swpaul	unit = device_get_unit(dev);
65241502Swpaul
65393818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
654131518Sbms	    MTX_DEF);
65541502Swpaul	/*
65641502Swpaul	 * Map control/status registers.
65741502Swpaul	 */
65872813Swpaul	pci_enable_busmaster(dev);
659107220Ssilby	sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF;
66041502Swpaul
66149610Swpaul	rid = VR_RID;
662127135Snjl	sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE);
66349610Swpaul
66449610Swpaul	if (sc->vr_res == NULL) {
66549610Swpaul		printf("vr%d: couldn't map ports/memory\n", unit);
66649610Swpaul		error = ENXIO;
66741502Swpaul		goto fail;
66841502Swpaul	}
66941502Swpaul
67049610Swpaul	sc->vr_btag = rman_get_bustag(sc->vr_res);
67149610Swpaul	sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
67241502Swpaul
67341502Swpaul	/* Allocate interrupt */
67449610Swpaul	rid = 0;
675127135Snjl	sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
67649610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
67749610Swpaul
67849610Swpaul	if (sc->vr_irq == NULL) {
67941502Swpaul		printf("vr%d: couldn't map interrupt\n", unit);
68049610Swpaul		error = ENXIO;
68141502Swpaul		goto fail;
68241502Swpaul	}
68341502Swpaul
68476586Swpaul	/*
68576586Swpaul	 * Windows may put the chip in suspend mode when it
68676586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
68776586Swpaul	 * up again.
68876586Swpaul	 */
68976586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
69076586Swpaul
69141502Swpaul	/* Reset the adapter. */
69241502Swpaul	vr_reset(sc);
69341502Swpaul
694131503Sbms	/*
695110168Ssilby	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
696110168Ssilby	 * initialization and disable AUTOPOLL.
697110168Ssilby	 */
698131503Sbms	pci_write_config(dev, VR_PCI_MODE,
699110168Ssilby	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
700110168Ssilby	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
701110168Ssilby
70241502Swpaul	/*
70341502Swpaul	 * Get station address. The way the Rhine chips work,
70441502Swpaul	 * you're not allowed to directly access the EEPROM once
70541502Swpaul	 * they've been programmed a special way. Consequently,
70641502Swpaul	 * we need to read the node address from the PAR0 and PAR1
70741502Swpaul	 * registers.
70841502Swpaul	 */
70941502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
71041502Swpaul	DELAY(200);
71141502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
71241502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
71341502Swpaul
71441502Swpaul	sc->vr_unit = unit;
71541502Swpaul
71651432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
71751657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
71851432Swpaul
71951432Swpaul	if (sc->vr_ldata == NULL) {
72041502Swpaul		printf("vr%d: no memory for list buffers!\n", unit);
72149610Swpaul		error = ENXIO;
72249610Swpaul		goto fail;
72341502Swpaul	}
72441502Swpaul
72541502Swpaul	bzero(sc->vr_ldata, sizeof(struct vr_list_data));
72641502Swpaul
727147256Sbrooks	ifp = sc->vr_ifp = if_alloc(IFT_ETHER);
728147256Sbrooks	if (ifp == NULL) {
729147256Sbrooks		printf("vr%d: can not if_alloc()\n", unit);
730147256Sbrooks		error = ENOSPC;
731147256Sbrooks		goto fail;
732147256Sbrooks	}
73341502Swpaul	ifp->if_softc = sc;
734121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
73541502Swpaul	ifp->if_mtu = ETHERMTU;
73641502Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
73741502Swpaul	ifp->if_ioctl = vr_ioctl;
73841502Swpaul	ifp->if_start = vr_start;
73941502Swpaul	ifp->if_watchdog = vr_watchdog;
74041502Swpaul	ifp->if_init = vr_init;
74141502Swpaul	ifp->if_baudrate = 10000000;
742132986Smlaier	IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1);
74343515Swpaul	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
744132986Smlaier	IFQ_SET_READY(&ifp->if_snd);
745128118Sru#ifdef DEVICE_POLLING
746128118Sru	ifp->if_capabilities |= IFCAP_POLLING;
747128118Sru#endif
748128118Sru	ifp->if_capenable = ifp->if_capabilities;
74941502Swpaul
750131503Sbms	/* Do MII setup. */
75151432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
75251432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
75341502Swpaul		printf("vr%d: MII without any phy!\n", sc->vr_unit);
75449610Swpaul		error = ENXIO;
75541502Swpaul		goto fail;
75641502Swpaul	}
75741502Swpaul
75851432Swpaul	callout_handle_init(&sc->vr_stat_ch);
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) {
770112872Snjl		printf("vr%d: couldn't set up irq\n", unit);
771113609Snjl		ether_ifdetach(ifp);
772147256Sbrooks		if_free(ifp);
773112872Snjl		goto fail;
774112872Snjl	}
775112872Snjl
77641502Swpaulfail:
777112872Snjl	if (error)
778112872Snjl		vr_detach(dev);
77967087Swpaul
780131503Sbms	return (error);
78141502Swpaul}
78241502Swpaul
783113609Snjl/*
784113609Snjl * Shutdown hardware and free up resources. This can be called any
785113609Snjl * time after the mutex has been initialized. It is called in both
786113609Snjl * the error case in attach and the normal detach case so it needs
787113609Snjl * to be careful about only freeing resources that have actually been
788113609Snjl * allocated.
789113609Snjl */
790102336Salfredstatic int
791131503Sbmsvr_detach(device_t dev)
79249610Swpaul{
793131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
794147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
79549610Swpaul
796112880Sjhb	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
797131518Sbms
79867087Swpaul	VR_LOCK(sc);
79949610Swpaul
800131844Sbms	sc->suspended = 1;
801131844Sbms
802113609Snjl	/* These should only be active if attach succeeded */
803113812Simp	if (device_is_attached(dev)) {
804113609Snjl		vr_stop(sc);
805136976Sbms		VR_UNLOCK(sc);		/* XXX: Avoid recursive acquire. */
806112872Snjl		ether_ifdetach(ifp);
807147256Sbrooks		if_free(ifp);
808136976Sbms		VR_LOCK(sc);
809113609Snjl	}
810113609Snjl	if (sc->vr_miibus)
811112872Snjl		device_delete_child(dev, sc->vr_miibus);
812113609Snjl	bus_generic_detach(dev);
81349610Swpaul
814112872Snjl	if (sc->vr_intrhand)
815112872Snjl		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
816112872Snjl	if (sc->vr_irq)
817112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
818112872Snjl	if (sc->vr_res)
819112872Snjl		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
82051432Swpaul
821112872Snjl	if (sc->vr_ldata)
822112872Snjl		contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
82349610Swpaul
82467087Swpaul	VR_UNLOCK(sc);
82567087Swpaul	mtx_destroy(&sc->vr_mtx);
82649610Swpaul
827131503Sbms	return (0);
82849610Swpaul}
82949610Swpaul
83041502Swpaul/*
83141502Swpaul * Initialize the transmit descriptors.
83241502Swpaul */
833102336Salfredstatic int
834131503Sbmsvr_list_tx_init(struct vr_softc *sc)
83541502Swpaul{
83641502Swpaul	struct vr_chain_data	*cd;
83741502Swpaul	struct vr_list_data	*ld;
83841502Swpaul	int			i;
83941502Swpaul
84041502Swpaul	cd = &sc->vr_cdata;
84141502Swpaul	ld = sc->vr_ldata;
84241502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
84341502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
84441502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
845131503Sbms			cd->vr_tx_chain[i].vr_nextdesc =
84641502Swpaul				&cd->vr_tx_chain[0];
84741502Swpaul		else
84841502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
84941502Swpaul				&cd->vr_tx_chain[i + 1];
85041502Swpaul	}
851127901Sru	cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0];
85241502Swpaul
853131503Sbms	return (0);
85441502Swpaul}
85541502Swpaul
85641502Swpaul
85741502Swpaul/*
85841502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
85941502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
86041502Swpaul * points back to the first.
86141502Swpaul */
862102336Salfredstatic int
863131503Sbmsvr_list_rx_init(struct vr_softc *sc)
86441502Swpaul{
86541502Swpaul	struct vr_chain_data	*cd;
86641502Swpaul	struct vr_list_data	*ld;
86741502Swpaul	int			i;
86841502Swpaul
869131518Sbms	VR_LOCK_ASSERT(sc);
870131518Sbms
87141502Swpaul	cd = &sc->vr_cdata;
87241502Swpaul	ld = sc->vr_ldata;
87341502Swpaul
87441502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
87541502Swpaul		cd->vr_rx_chain[i].vr_ptr =
87641502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
87749610Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
878131503Sbms			return (ENOBUFS);
87941502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
88041502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
88141502Swpaul					&cd->vr_rx_chain[0];
88241502Swpaul			ld->vr_rx_list[i].vr_next =
88341502Swpaul					vtophys(&ld->vr_rx_list[0]);
88441502Swpaul		} else {
88541502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
88641502Swpaul					&cd->vr_rx_chain[i + 1];
88741502Swpaul			ld->vr_rx_list[i].vr_next =
88841502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
88941502Swpaul		}
89041502Swpaul	}
89141502Swpaul
89241502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
89341502Swpaul
894131503Sbms	return (0);
89541502Swpaul}
89641502Swpaul
89741502Swpaul/*
89841502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
89941502Swpaul * Note: the length fields are only 11 bits wide, which means the
90041502Swpaul * largest size we can specify is 2047. This is important because
90141502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
90241502Swpaul * overflow the field and make a mess.
90341502Swpaul */
904102336Salfredstatic int
905131503Sbmsvr_newbuf(struct vr_softc *sc, struct vr_chain_onefrag *c, struct mbuf *m)
90641502Swpaul{
90741502Swpaul	struct mbuf		*m_new = NULL;
90841502Swpaul
90949610Swpaul	if (m == NULL) {
910111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
91187846Sluigi		if (m_new == NULL)
912131503Sbms			return (ENOBUFS);
91341502Swpaul
914111119Simp		MCLGET(m_new, M_DONTWAIT);
91549610Swpaul		if (!(m_new->m_flags & M_EXT)) {
91649610Swpaul			m_freem(m_new);
917131503Sbms			return (ENOBUFS);
91849610Swpaul		}
91949610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
92049610Swpaul	} else {
92149610Swpaul		m_new = m;
92249610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
92349610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
92441502Swpaul	}
92541502Swpaul
926131503Sbms	m_adj(m_new, sizeof(uint64_t));
92749610Swpaul
92841502Swpaul	c->vr_mbuf = m_new;
92941502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
93041502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
93142491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
93241502Swpaul
933131503Sbms	return (0);
93441502Swpaul}
93541502Swpaul
93641502Swpaul/*
93741502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
93841502Swpaul * the higher level protocols.
93941502Swpaul */
940102336Salfredstatic void
941131503Sbmsvr_rxeof(struct vr_softc *sc)
94241502Swpaul{
943131503Sbms	struct mbuf		*m, *m0;
944131503Sbms	struct ifnet		*ifp;
94541502Swpaul	struct vr_chain_onefrag	*cur_rx;
94641502Swpaul	int			total_len = 0;
947131503Sbms	uint32_t		rxstat;
94841502Swpaul
949122689Ssam	VR_LOCK_ASSERT(sc);
950147256Sbrooks	ifp = sc->vr_ifp;
95141502Swpaul
952131503Sbms	while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
953131503Sbms	    VR_RXSTAT_OWN)) {
954127901Sru#ifdef DEVICE_POLLING
955127901Sru		if (ifp->if_flags & IFF_POLLING) {
956127901Sru			if (sc->rxcycles <= 0)
957127901Sru				break;
958127901Sru			sc->rxcycles--;
959127901Sru		}
960127901Sru#endif /* DEVICE_POLLING */
961127901Sru		m0 = NULL;
96241502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
96341502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
96449610Swpaul		m = cur_rx->vr_mbuf;
96541502Swpaul
96641502Swpaul		/*
96741502Swpaul		 * If an error occurs, update stats, clear the
96841502Swpaul		 * status word and leave the mbuf cluster in place:
96941502Swpaul		 * it should simply get re-used next time this descriptor
970131503Sbms		 * comes up in the ring.
97141502Swpaul		 */
97241502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
97341502Swpaul			ifp->if_ierrors++;
974131503Sbms			printf("vr%d: rx error (%02x):", sc->vr_unit,
975131503Sbms			    rxstat & 0x000000ff);
976110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
977110131Ssilby				printf(" crc error");
978110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
979110131Ssilby				printf(" frame alignment error\n");
980110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
981110131Ssilby				printf(" FIFO overflow");
982110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
983110131Ssilby				printf(" received giant packet");
984110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
985110131Ssilby				printf(" received runt packet");
986110131Ssilby			if (rxstat & VR_RXSTAT_BUSERR)
987110131Ssilby				printf(" system bus error");
988110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
989110131Ssilby				printf("rx buffer error");
990110131Ssilby			printf("\n");
99149610Swpaul			vr_newbuf(sc, cur_rx, m);
99241502Swpaul			continue;
99341502Swpaul		}
99441502Swpaul
995131503Sbms		/* No errors; receive the packet. */
99641502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
99741502Swpaul
99841502Swpaul		/*
99942048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
100042048Swpaul		 * received frame, and there's no way to turn this
100142048Swpaul		 * behavior off (at least, I can't find anything in
1002131503Sbms		 * the manual that explains how to do it) so we have
100342048Swpaul		 * to trim off the CRC manually.
100442048Swpaul		 */
100542048Swpaul		total_len -= ETHER_CRC_LEN;
100642048Swpaul
100778508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
100878508Sbmilekic		    NULL);
100949610Swpaul		vr_newbuf(sc, cur_rx, m);
101049610Swpaul		if (m0 == NULL) {
101141502Swpaul			ifp->if_ierrors++;
101241502Swpaul			continue;
101341502Swpaul		}
101449610Swpaul		m = m0;
101541502Swpaul
101641502Swpaul		ifp->if_ipackets++;
1017122689Ssam		VR_UNLOCK(sc);
1018106936Ssam		(*ifp->if_input)(ifp, m);
1019122689Ssam		VR_LOCK(sc);
102041502Swpaul	}
102141502Swpaul}
102241502Swpaul
1023105221Sphkstatic void
1024131503Sbmsvr_rxeoc(struct vr_softc *sc)
102541502Swpaul{
1026147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
1027110131Ssilby	int			i;
102841502Swpaul
1029131518Sbms	VR_LOCK_ASSERT(sc);
1030131518Sbms
1031110131Ssilby	ifp->if_ierrors++;
1032110131Ssilby
1033131503Sbms	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
1034131503Sbms	DELAY(10000);
1035110131Ssilby
1036131503Sbms	/* Wait for receiver to stop */
1037110131Ssilby	for (i = 0x400;
1038110131Ssilby	     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON);
1039131503Sbms	     i--) {
1040131503Sbms		;
1041131503Sbms	}
1042110131Ssilby
1043110131Ssilby	if (!i) {
1044110131Ssilby		printf("vr%d: rx shutdown error!\n", sc->vr_unit);
1045110131Ssilby		sc->vr_flags |= VR_F_RESTART;
1046110131Ssilby		return;
1047131503Sbms	}
1048110131Ssilby
104941502Swpaul	vr_rxeof(sc);
1050110131Ssilby
105141502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
105241502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
105341502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
105441502Swpaul}
105541502Swpaul
105641502Swpaul/*
105741502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
105841502Swpaul * the list buffers.
105941502Swpaul */
1060102336Salfredstatic void
1061131503Sbmsvr_txeof(struct vr_softc *sc)
106241502Swpaul{
106341502Swpaul	struct vr_chain		*cur_tx;
1064147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
106541502Swpaul
1066131518Sbms	VR_LOCK_ASSERT(sc);
106741502Swpaul
106841502Swpaul	/*
106941502Swpaul	 * Go through our tx list and free mbufs for those
107041502Swpaul	 * frames that have been transmitted.
107141502Swpaul	 */
1072127901Sru	cur_tx = sc->vr_cdata.vr_tx_cons;
1073127901Sru	while (cur_tx->vr_mbuf != NULL) {
1074131503Sbms		uint32_t		txstat;
1075110131Ssilby		int			i;
107641502Swpaul
107741502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
107841502Swpaul
1079101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
1080101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
1081110131Ssilby			for (i = 0x400;
1082110131Ssilby			     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON);
1083110131Ssilby			     i--)
1084101896Ssilby				;	/* Wait for chip to shutdown */
1085110131Ssilby			if (!i) {
1086131503Sbms				printf("vr%d: tx shutdown timeout\n",
1087131503Sbms				    sc->vr_unit);
1088110131Ssilby				sc->vr_flags |= VR_F_RESTART;
1089110131Ssilby				break;
1090110131Ssilby			}
1091101896Ssilby			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
1092101896Ssilby			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr));
1093101896Ssilby			break;
1094101896Ssilby		}
1095101896Ssilby
109642491Swpaul		if (txstat & VR_TXSTAT_OWN)
109741502Swpaul			break;
109841502Swpaul
109941502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
110041502Swpaul			ifp->if_oerrors++;
110141502Swpaul			if (txstat & VR_TXSTAT_DEFER)
110241502Swpaul				ifp->if_collisions++;
110341502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
110441502Swpaul				ifp->if_collisions++;
110541502Swpaul		}
110641502Swpaul
110741502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
110841502Swpaul
110941502Swpaul		ifp->if_opackets++;
1110127901Sru		m_freem(cur_tx->vr_mbuf);
1111127901Sru		cur_tx->vr_mbuf = NULL;
1112148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
111341502Swpaul
1114127901Sru		cur_tx = cur_tx->vr_nextdesc;
111541502Swpaul	}
1116127901Sru	sc->vr_cdata.vr_tx_cons = cur_tx;
1117127901Sru	if (cur_tx->vr_mbuf == NULL)
111896677Ssilby		ifp->if_timer = 0;
111941502Swpaul}
112041502Swpaul
1121102336Salfredstatic void
1122131503Sbmsvr_tick(void *xsc)
112351432Swpaul{
1124131503Sbms	struct vr_softc		*sc = xsc;
112551432Swpaul	struct mii_data		*mii;
112651432Swpaul
112767087Swpaul	VR_LOCK(sc);
1128131517Sbms
1129110131Ssilby	if (sc->vr_flags & VR_F_RESTART) {
1130110131Ssilby		printf("vr%d: restarting\n", sc->vr_unit);
1131110131Ssilby		vr_stop(sc);
1132110131Ssilby		vr_reset(sc);
1133131844Sbms		vr_init_locked(sc);
1134110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1135110131Ssilby	}
1136110131Ssilby
113751432Swpaul	mii = device_get_softc(sc->vr_miibus);
113851432Swpaul	mii_tick(mii);
113951432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
114051432Swpaul
114167087Swpaul	VR_UNLOCK(sc);
114251432Swpaul}
114351432Swpaul
1144127901Sru#ifdef DEVICE_POLLING
1145127901Srustatic poll_handler_t vr_poll;
1146131844Sbmsstatic poll_handler_t vr_poll_locked;
1147127901Sru
1148102336Salfredstatic void
1149127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1150127901Sru{
1151127901Sru	struct vr_softc *sc = ifp->if_softc;
1152127901Sru
1153127901Sru	VR_LOCK(sc);
1154131844Sbms	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
1165128118Sru	if (!(ifp->if_capenable & IFCAP_POLLING)) {
1166128118Sru		ether_poll_deregister(ifp);
1167128118Sru		cmd = POLL_DEREGISTER;
1168128118Sru	}
1169131517Sbms
1170131503Sbms	if (cmd == POLL_DEREGISTER) {
1171131503Sbms		/* Final call, enable interrupts. */
1172127901Sru		CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
1173131844Sbms		return;
1174127901Sru	}
1175127901Sru
1176127901Sru	sc->rxcycles = count;
1177127901Sru	vr_rxeof(sc);
1178127901Sru	vr_txeof(sc);
1179133006Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1180131844Sbms		vr_start_locked(ifp);
1181127901Sru
1182131503Sbms	if (cmd == POLL_AND_CHECK_STATUS) {
1183131503Sbms		uint16_t status;
1184127901Sru
1185131503Sbms		/* Also check status register. */
1186127901Sru		status = CSR_READ_2(sc, VR_ISR);
1187127901Sru		if (status)
1188127901Sru			CSR_WRITE_2(sc, VR_ISR, status);
1189127901Sru
1190127901Sru		if ((status & VR_INTRS) == 0)
1191131844Sbms			return;
1192127901Sru
1193127901Sru		if (status & VR_ISR_RX_DROPPED) {
1194127901Sru			printf("vr%d: rx packet lost\n", sc->vr_unit);
1195127901Sru			ifp->if_ierrors++;
1196127901Sru		}
1197127901Sru
1198127901Sru		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1199127901Sru		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1200127901Sru			printf("vr%d: receive error (%04x)",
1201127901Sru			       sc->vr_unit, status);
1202127901Sru			if (status & VR_ISR_RX_NOBUF)
1203127901Sru				printf(" no buffers");
1204127901Sru			if (status & VR_ISR_RX_OFLOW)
1205127901Sru				printf(" overflow");
1206127901Sru			if (status & VR_ISR_RX_DROPPED)
1207127901Sru				printf(" packet lost");
1208127901Sru			printf("\n");
1209127901Sru			vr_rxeoc(sc);
1210127901Sru		}
1211127901Sru
1212131503Sbms		if ((status & VR_ISR_BUSERR) ||
1213131503Sbms		    (status & VR_ISR_TX_UNDERRUN)) {
1214127901Sru			vr_reset(sc);
1215131844Sbms			vr_init_locked(sc);
1216131518Sbms			return;
1217127901Sru		}
1218127901Sru
1219127901Sru		if ((status & VR_ISR_UDFI) ||
1220127901Sru		    (status & VR_ISR_TX_ABRT2) ||
1221127901Sru		    (status & VR_ISR_TX_ABRT)) {
1222127901Sru			ifp->if_oerrors++;
1223127901Sru			if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) {
1224127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1225127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1226127901Sru			}
1227127901Sru		}
1228127901Sru	}
1229127901Sru}
1230127901Sru#endif /* DEVICE_POLLING */
1231127901Sru
1232127901Srustatic void
1233131503Sbmsvr_intr(void *arg)
123441502Swpaul{
1235131503Sbms	struct vr_softc		*sc = arg;
1236147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
1237131503Sbms	uint16_t		status;
123841502Swpaul
123967087Swpaul	VR_LOCK(sc);
1240131844Sbms
1241136997Sbms	if (sc->suspended) {
1242136997Sbms		/*
1243136997Sbms		 * Forcibly disable interrupts.
1244136997Sbms		 * XXX: Mobile VIA based platforms may need
1245136997Sbms		 * interrupt re-enable on resume.
1246136997Sbms		 */
1247136997Sbms		CSR_WRITE_2(sc, VR_IMR, 0x0000);
1248131844Sbms		goto done_locked;
1249136997Sbms	}
1250131844Sbms
1251127901Sru#ifdef DEVICE_POLLING
1252131844Sbms	if (ifp->if_flags & IFF_POLLING)
1253131844Sbms		goto done_locked;
1254131844Sbms
1255128118Sru	if ((ifp->if_capenable & IFCAP_POLLING) &&
1256131503Sbms	    ether_poll_register(vr_poll, ifp)) {
1257131503Sbms		/* OK, disable interrupts. */
1258127901Sru		CSR_WRITE_2(sc, VR_IMR, 0x0000);
1259131844Sbms		vr_poll_locked(ifp, 0, 1);
1260131844Sbms		goto done_locked;
1261127901Sru	}
1262127901Sru#endif /* DEVICE_POLLING */
1263127901Sru
1264131844Sbms	/* Suppress unwanted interrupts. */
126541502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
126641502Swpaul		vr_stop(sc);
1267131844Sbms		goto done_locked;
126841502Swpaul	}
126941502Swpaul
127041502Swpaul	/* Disable interrupts. */
127141502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
127241502Swpaul
127341502Swpaul	for (;;) {
127441502Swpaul		status = CSR_READ_2(sc, VR_ISR);
127541502Swpaul		if (status)
127641502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
127741502Swpaul
127841502Swpaul		if ((status & VR_INTRS) == 0)
127941502Swpaul			break;
128041502Swpaul
128141502Swpaul		if (status & VR_ISR_RX_OK)
128241502Swpaul			vr_rxeof(sc);
128341502Swpaul
1284110131Ssilby		if (status & VR_ISR_RX_DROPPED) {
1285110131Ssilby			printf("vr%d: rx packet lost\n", sc->vr_unit);
1286110131Ssilby			ifp->if_ierrors++;
1287131503Sbms		}
1288110131Ssilby
128941502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1290110131Ssilby		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1291110131Ssilby			printf("vr%d: receive error (%04x)",
1292110131Ssilby			       sc->vr_unit, status);
1293110131Ssilby			if (status & VR_ISR_RX_NOBUF)
1294110131Ssilby				printf(" no buffers");
1295110131Ssilby			if (status & VR_ISR_RX_OFLOW)
1296110131Ssilby				printf(" overflow");
1297110131Ssilby			if (status & VR_ISR_RX_DROPPED)
1298110131Ssilby				printf(" packet lost");
1299110131Ssilby			printf("\n");
130041502Swpaul			vr_rxeoc(sc);
130141502Swpaul		}
130241502Swpaul
1303101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1304101896Ssilby			vr_reset(sc);
1305131844Sbms			vr_init_locked(sc);
1306101896Ssilby			break;
130741502Swpaul		}
130841502Swpaul
1309101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1310101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
131141502Swpaul			vr_txeof(sc);
1312101896Ssilby			if ((status & VR_ISR_UDFI) ||
1313101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1314101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1315101896Ssilby				ifp->if_oerrors++;
1316127901Sru				if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) {
1317131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1318131503Sbms					    VR_CMD_TX_ON);
1319131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1320131503Sbms					    VR_CMD_TX_GO);
1321101896Ssilby				}
1322127901Sru			}
132341502Swpaul		}
132441502Swpaul	}
132541502Swpaul
132641502Swpaul	/* Re-enable interrupts. */
132741502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
132841502Swpaul
1329132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1330131844Sbms		vr_start_locked(ifp);
1331131844Sbms
1332131844Sbmsdone_locked:
1333131844Sbms	VR_UNLOCK(sc);
133441502Swpaul}
133541502Swpaul
133641502Swpaul/*
133741502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
133841502Swpaul * pointers to the fragment pointers.
133941502Swpaul */
1340102336Salfredstatic int
1341131503Sbmsvr_encap(struct vr_softc *sc, struct vr_chain *c, struct mbuf *m_head)
134241502Swpaul{
134341502Swpaul	struct vr_desc		*f = NULL;
134441502Swpaul	struct mbuf		*m;
134541502Swpaul
1346131518Sbms	VR_LOCK_ASSERT(sc);
134741502Swpaul	/*
134841502Swpaul	 * The VIA Rhine wants packet buffers to be longword
134941502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
135041502Swpaul	 * waste time trying to decide when to copy and when not
135141502Swpaul	 * to copy, just do it all the time.
135241502Swpaul	 */
1353127901Sru	m = m_defrag(m_head, M_DONTWAIT);
1354131503Sbms	if (m == NULL)
1355131503Sbms		return (1);
135641502Swpaul
1357127901Sru	/*
1358127901Sru	 * The Rhine chip doesn't auto-pad, so we have to make
1359127901Sru	 * sure to pad short frames out to the minimum frame length
1360127901Sru	 * ourselves.
1361127901Sru	 */
1362127901Sru	if (m->m_len < VR_MIN_FRAMELEN) {
1363127901Sru		m->m_pkthdr.len += VR_MIN_FRAMELEN - m->m_len;
1364127901Sru		m->m_len = m->m_pkthdr.len;
136541502Swpaul	}
136641502Swpaul
1367127901Sru	c->vr_mbuf = m;
1368127901Sru	f = c->vr_ptr;
1369127901Sru	f->vr_data = vtophys(mtod(m, caddr_t));
1370127901Sru	f->vr_ctl = m->m_len;
1371127901Sru	f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
1372127901Sru	f->vr_status = 0;
1373127901Sru	f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
1374127901Sru	f->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
137541502Swpaul
1376131503Sbms	return (0);
137741502Swpaul}
137841502Swpaul
137941502Swpaul/*
138041502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
138141502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
138241502Swpaul * copy of the pointers since the transmit list fragment pointers are
138341502Swpaul * physical addresses.
138441502Swpaul */
138541502Swpaul
1386102336Salfredstatic void
1387131503Sbmsvr_start(struct ifnet *ifp)
138841502Swpaul{
1389131518Sbms	struct vr_softc		*sc = ifp->if_softc;
1390131844Sbms
1391131844Sbms	VR_LOCK(sc);
1392131844Sbms	vr_start_locked(ifp);
1393131844Sbms	VR_UNLOCK(sc);
1394131844Sbms}
1395131844Sbms
1396131844Sbmsstatic void
1397131844Sbmsvr_start_locked(struct ifnet *ifp)
1398131844Sbms{
1399131844Sbms	struct vr_softc		*sc = ifp->if_softc;
1400127901Sru	struct mbuf		*m_head;
1401127901Sru	struct vr_chain		*cur_tx;
140241502Swpaul
1403148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
1404127901Sru		return;
1405127901Sru
1406127901Sru	cur_tx = sc->vr_cdata.vr_tx_prod;
1407127901Sru	while (cur_tx->vr_mbuf == NULL) {
1408132986Smlaier       	        IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
140941502Swpaul		if (m_head == NULL)
141041502Swpaul			break;
141141502Swpaul
141241502Swpaul		/* Pack the data into the descriptor. */
141371271Swpaul		if (vr_encap(sc, cur_tx, m_head)) {
1414113274Ssilby			/* Rollback, send what we were able to encap. */
1415132986Smlaier               		IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
141671271Swpaul			break;
141771271Swpaul		}
141841502Swpaul
1419127901Sru		VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
142041502Swpaul
142141502Swpaul		/*
142241502Swpaul		 * If there's a BPF listener, bounce a copy of this frame
142341502Swpaul		 * to him.
142441502Swpaul		 */
1425106936Ssam		BPF_MTAP(ifp, cur_tx->vr_mbuf);
142651583Swpaul
1427127901Sru		cur_tx = cur_tx->vr_nextdesc;
142841502Swpaul	}
1429127901Sru	if (cur_tx != sc->vr_cdata.vr_tx_prod || cur_tx->vr_mbuf != NULL) {
1430127901Sru		sc->vr_cdata.vr_tx_prod = cur_tx;
143141502Swpaul
1432127901Sru		/* Tell the chip to start transmitting. */
1433131517Sbms		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO);
143441526Swpaul
1435127901Sru		/* Set a timeout in case the chip goes out to lunch. */
1436127901Sru		ifp->if_timer = 5;
143741502Swpaul
1438127901Sru		if (cur_tx->vr_mbuf != NULL)
1439148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1440127901Sru	}
1441131844Sbms}
144241502Swpaul
1443131844Sbmsstatic void
1444131844Sbmsvr_init(void *xsc)
1445131844Sbms{
1446131844Sbms	struct vr_softc		*sc = xsc;
1447131844Sbms
1448131844Sbms	VR_LOCK(sc);
1449131844Sbms	vr_init_locked(sc);
145067087Swpaul	VR_UNLOCK(sc);
145141502Swpaul}
145241502Swpaul
1453102336Salfredstatic void
1454131844Sbmsvr_init_locked(struct vr_softc *sc)
145541502Swpaul{
1456147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
145751432Swpaul	struct mii_data		*mii;
145873963Swpaul	int			i;
145941502Swpaul
1460131844Sbms	VR_LOCK_ASSERT(sc);
146141502Swpaul
146251432Swpaul	mii = device_get_softc(sc->vr_miibus);
146341502Swpaul
1464131503Sbms	/* Cancel pending I/O and free all RX/TX buffers. */
146541502Swpaul	vr_stop(sc);
146641502Swpaul	vr_reset(sc);
146741502Swpaul
1468131503Sbms	/* Set our station address. */
146973963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
1470147256Sbrooks		CSR_WRITE_1(sc, VR_PAR0 + i, IFP2ENADDR(sc->vr_ifp)[i]);
1471131503Sbms
1472131503Sbms	/* Set DMA size. */
1473101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1474101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
147573963Swpaul
1476131503Sbms	/*
1477101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1478101108Ssilby	 * so we must set both.
1479101108Ssilby	 */
1480101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1481110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
1482101108Ssilby
1483101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1484101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1485101108Ssilby
148641502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
1487110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
148841502Swpaul
148941502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
149041502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
149141502Swpaul
149241502Swpaul	/* Init circular RX list. */
149341502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
1494131503Sbms		printf(
1495131503Sbms"vr%d: initialization failed: no memory for rx buffers\n", sc->vr_unit);
149641502Swpaul		vr_stop(sc);
149741502Swpaul		return;
149841502Swpaul	}
149941502Swpaul
1500131503Sbms	/* Init tx descriptors. */
150141502Swpaul	vr_list_tx_init(sc);
150241502Swpaul
150341502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
150441502Swpaul	if (ifp->if_flags & IFF_PROMISC)
150541502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
150641502Swpaul	else
150741502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
150841502Swpaul
150941502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
151041502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
151141502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
151241502Swpaul	else
151341502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
151441502Swpaul
151541502Swpaul	/*
151641502Swpaul	 * Program the multicast filter, if necessary.
151741502Swpaul	 */
151841502Swpaul	vr_setmulti(sc);
151941502Swpaul
152041502Swpaul	/*
152141502Swpaul	 * Load the address of the RX list.
152241502Swpaul	 */
152341502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
152441502Swpaul
152541502Swpaul	/* Enable receiver and transmitter. */
152641502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
152741502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
152841502Swpaul				    VR_CMD_RX_GO);
152941502Swpaul
153041502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
153141502Swpaul
1532127901Sru	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
1533127901Sru#ifdef DEVICE_POLLING
153441502Swpaul	/*
1535127901Sru	 * Disable interrupts if we are polling.
1536127901Sru	 */
1537127901Sru	if (ifp->if_flags & IFF_POLLING)
1538127901Sru		CSR_WRITE_2(sc, VR_IMR, 0);
1539131503Sbms	else
1540127901Sru#endif /* DEVICE_POLLING */
1541127901Sru	/*
154241502Swpaul	 * Enable interrupts.
154341502Swpaul	 */
154441502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
154541502Swpaul
154651432Swpaul	mii_mediachg(mii);
154741502Swpaul
1548148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1549148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
155041502Swpaul
155151432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
155241502Swpaul}
155341502Swpaul
155441502Swpaul/*
155541502Swpaul * Set media options.
155641502Swpaul */
1557102336Salfredstatic int
1558131503Sbmsvr_ifmedia_upd(struct ifnet *ifp)
155941502Swpaul{
1560131503Sbms	struct vr_softc		*sc = ifp->if_softc;
156141502Swpaul
156251432Swpaul	if (ifp->if_flags & IFF_UP)
156351432Swpaul		vr_init(sc);
156441502Swpaul
1565131503Sbms	return (0);
156641502Swpaul}
156741502Swpaul
156841502Swpaul/*
156941502Swpaul * Report current media status.
157041502Swpaul */
1571102336Salfredstatic void
1572131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
157341502Swpaul{
1574131518Sbms	struct vr_softc		*sc = ifp->if_softc;
157551432Swpaul	struct mii_data		*mii;
157641502Swpaul
157751432Swpaul	mii = device_get_softc(sc->vr_miibus);
1578133468Sscottl	VR_LOCK(sc);
157951432Swpaul	mii_pollstat(mii);
1580133468Sscottl	VR_UNLOCK(sc);
158151432Swpaul	ifmr->ifm_active = mii->mii_media_active;
158251432Swpaul	ifmr->ifm_status = mii->mii_media_status;
158341502Swpaul}
158441502Swpaul
1585102336Salfredstatic int
1586131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
158741502Swpaul{
158841502Swpaul	struct vr_softc		*sc = ifp->if_softc;
158941502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
159051432Swpaul	struct mii_data		*mii;
159167087Swpaul	int			error = 0;
159241502Swpaul
1593131503Sbms	switch (command) {
159441502Swpaul	case SIOCSIFFLAGS:
1595131844Sbms		VR_LOCK(sc);
159641502Swpaul		if (ifp->if_flags & IFF_UP) {
1597131844Sbms			vr_init_locked(sc);
159841502Swpaul		} else {
1599148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
160041502Swpaul				vr_stop(sc);
160141502Swpaul		}
1602131844Sbms		VR_UNLOCK(sc);
160341502Swpaul		error = 0;
160441502Swpaul		break;
160541502Swpaul	case SIOCADDMULTI:
160641502Swpaul	case SIOCDELMULTI:
1607131518Sbms		VR_LOCK(sc);
160841502Swpaul		vr_setmulti(sc);
1609131518Sbms		VR_UNLOCK(sc);
161041502Swpaul		error = 0;
161141502Swpaul		break;
161241502Swpaul	case SIOCGIFMEDIA:
161341502Swpaul	case SIOCSIFMEDIA:
161451432Swpaul		mii = device_get_softc(sc->vr_miibus);
161551432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
161641502Swpaul		break;
1617128118Sru	case SIOCSIFCAP:
1618128118Sru		ifp->if_capenable = ifr->ifr_reqcap;
1619128118Sru		break;
162041502Swpaul	default:
1621106936Ssam		error = ether_ioctl(ifp, command, data);
162241502Swpaul		break;
162341502Swpaul	}
162441502Swpaul
1625131503Sbms	return (error);
162641502Swpaul}
162741502Swpaul
1628102336Salfredstatic void
1629131503Sbmsvr_watchdog(struct ifnet *ifp)
163041502Swpaul{
1631131518Sbms	struct vr_softc		*sc = ifp->if_softc;
163241502Swpaul
163367087Swpaul	VR_LOCK(sc);
1634131844Sbms
163541502Swpaul	ifp->if_oerrors++;
163641502Swpaul	printf("vr%d: watchdog timeout\n", sc->vr_unit);
163741502Swpaul
163841502Swpaul	vr_stop(sc);
163941502Swpaul	vr_reset(sc);
1640131844Sbms	vr_init_locked(sc);
1641131518Sbms
1642132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1643131844Sbms		vr_start_locked(ifp);
1644131844Sbms
1645131844Sbms	VR_UNLOCK(sc);
164641502Swpaul}
164741502Swpaul
164841502Swpaul/*
164941502Swpaul * Stop the adapter and free any mbufs allocated to the
165041502Swpaul * RX and TX lists.
165141502Swpaul */
1652102336Salfredstatic void
1653131503Sbmsvr_stop(struct vr_softc *sc)
165441502Swpaul{
1655131503Sbms	register int	i;
1656131503Sbms	struct ifnet	*ifp;
165741502Swpaul
1658131518Sbms	VR_LOCK_ASSERT(sc);
165967087Swpaul
1660147256Sbrooks	ifp = sc->vr_ifp;
166141502Swpaul	ifp->if_timer = 0;
166241502Swpaul
166351432Swpaul	untimeout(vr_tick, sc, sc->vr_stat_ch);
1664148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1665127901Sru#ifdef DEVICE_POLLING
1666127901Sru	ether_poll_deregister(ifp);
1667127901Sru#endif /* DEVICE_POLLING */
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