if_vr.c revision 168950
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 168950 2007-04-22 15:09:03Z phk $");
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/ethernet.h>
7841502Swpaul#include <net/if_dl.h>
7941502Swpaul#include <net/if_media.h>
80147256Sbrooks#include <net/if_types.h>
8141502Swpaul
8241502Swpaul#include <net/bpf.h>
8341502Swpaul
84131503Sbms#include <vm/vm.h>		/* for vtophys */
85131503Sbms#include <vm/pmap.h>		/* for vtophys */
8641502Swpaul#include <machine/bus.h>
8749610Swpaul#include <machine/resource.h>
8849610Swpaul#include <sys/bus.h>
8949610Swpaul#include <sys/rman.h>
9041502Swpaul
9151432Swpaul#include <dev/mii/miivar.h>
9251432Swpaul
93119288Simp#include <dev/pci/pcivar.h>
9441502Swpaul
9541502Swpaul#define VR_USEIOSPACE
9641502Swpaul
9741502Swpaul#include <pci/if_vrreg.h>
9841502Swpaul
99113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1);
100113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1);
10159758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
10259758Speter
103151545Simp/* "device miibus" required.  See GENERIC if you get errors here. */
10451432Swpaul#include "miibus_if.h"
10551432Swpaul
106110168Ssilby#undef VR_USESWSHIFT
107110168Ssilby
10841502Swpaul/*
10941502Swpaul * Various supported device vendors/types and their names.
11041502Swpaul */
11141502Swpaulstatic struct vr_type vr_devs[] = {
112168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
113168827Sphk	    VR_Q_NEEDALIGN,
114168827Sphk	    "VIA VT3043 Rhine I 10/100BaseTX" },
115168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
116168827Sphk	    VR_Q_NEEDALIGN,
117168827Sphk	    "VIA VT86C100A Rhine II 10/100BaseTX" },
118168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
119168827Sphk	    0,
120168827Sphk	    "VIA VT6102 Rhine II 10/100BaseTX" },
121168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III,
122168827Sphk	    0,
123168827Sphk	    "VIA VT6105 Rhine III 10/100BaseTX" },
124168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
125168827Sphk	    VR_Q_CSUM,
126168827Sphk	    "VIA VT6105M Rhine III 10/100BaseTX" },
127168827Sphk	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
128168827Sphk	    VR_Q_NEEDALIGN,
129168827Sphk	    "Delta Electronics Rhine II 10/100BaseTX" },
130168827Sphk	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
131168827Sphk	    VR_Q_NEEDALIGN,
132168827Sphk	    "Addtron Technology Rhine II 10/100BaseTX" },
133168813Sphk	{ 0, 0, 0, NULL }
13441502Swpaul};
13541502Swpaul
136168946Sphk
137168946Sphkstruct vr_softc {
138168946Sphk	struct ifnet		*vr_ifp;	/* interface info */
139168946Sphk	device_t		vr_dev;
140168946Sphk	struct resource		*vr_res;
141168946Sphk	struct resource		*vr_irq;
142168946Sphk	void			*vr_intrhand;
143168946Sphk	device_t		vr_miibus;
144168946Sphk	u_int8_t		vr_revid;	/* Rhine chip revision */
145168946Sphk	u_int8_t                vr_flags;       /* See VR_F_* below */
146168946Sphk	struct vr_list_data	*vr_ldata;
147168946Sphk	struct vr_chain_data	vr_cdata;
148168946Sphk	struct callout		vr_stat_callout;
149168946Sphk	struct mtx		vr_mtx;
150168948Sphk	int			vr_suspended;	/* if 1, sleeping/detaching */
151168946Sphk	int			vr_quirks;
152168946Sphk#ifdef DEVICE_POLLING
153168946Sphk	int			rxcycles;
154168946Sphk#endif
155168946Sphk};
156168946Sphk
157142407Simpstatic int vr_probe(device_t);
158142407Simpstatic int vr_attach(device_t);
159142407Simpstatic int vr_detach(device_t);
16041502Swpaul
161168948Sphkstatic int vr_newbuf(struct vr_chain *, struct mbuf *);
16241502Swpaul
163142407Simpstatic void vr_rxeof(struct vr_softc *);
164142407Simpstatic void vr_rxeoc(struct vr_softc *);
165142407Simpstatic void vr_txeof(struct vr_softc *);
166142407Simpstatic void vr_tick(void *);
167142407Simpstatic void vr_intr(void *);
168142407Simpstatic void vr_start(struct ifnet *);
169142407Simpstatic void vr_start_locked(struct ifnet *);
170142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t);
171142407Simpstatic void vr_init(void *);
172142407Simpstatic void vr_init_locked(struct vr_softc *);
173142407Simpstatic void vr_stop(struct vr_softc *);
174142407Simpstatic void vr_watchdog(struct ifnet *);
175142407Simpstatic void vr_shutdown(device_t);
176142407Simpstatic int vr_ifmedia_upd(struct ifnet *);
177142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
17841502Swpaul
179110168Ssilby#ifdef VR_USESWSHIFT
180142407Simpstatic void vr_mii_sync(struct vr_softc *);
181142407Simpstatic void vr_mii_send(struct vr_softc *, uint32_t, int);
182110168Ssilby#endif
183168946Sphkstatic int vr_mii_readreg(const struct vr_softc *, struct vr_mii_frame *);
184168946Sphkstatic int vr_mii_writereg(const struct vr_softc *, const struct vr_mii_frame *);
185142407Simpstatic int vr_miibus_readreg(device_t, uint16_t, uint16_t);
186142407Simpstatic int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t);
187142407Simpstatic void vr_miibus_statchg(device_t);
18841502Swpaul
189142407Simpstatic void vr_setcfg(struct vr_softc *, int);
190142407Simpstatic void vr_setmulti(struct vr_softc *);
191168946Sphkstatic void vr_reset(const struct vr_softc *);
192142407Simpstatic int vr_list_rx_init(struct vr_softc *);
193142407Simpstatic int vr_list_tx_init(struct vr_softc *);
19441502Swpaul
19549610Swpaul#ifdef VR_USEIOSPACE
19649610Swpaul#define VR_RES			SYS_RES_IOPORT
19749610Swpaul#define VR_RID			VR_PCI_LOIO
19849610Swpaul#else
19949610Swpaul#define VR_RES			SYS_RES_MEMORY
20049610Swpaul#define VR_RID			VR_PCI_LOMEM
20149610Swpaul#endif
20249610Swpaul
20349610Swpaulstatic device_method_t vr_methods[] = {
20449610Swpaul	/* Device interface */
20549610Swpaul	DEVMETHOD(device_probe,		vr_probe),
20649610Swpaul	DEVMETHOD(device_attach,	vr_attach),
20749610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
20849610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
20951432Swpaul
21051432Swpaul	/* bus interface */
21151432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
21251432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
21351432Swpaul
21451432Swpaul	/* MII interface */
21551432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
21651432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
21751432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
21851432Swpaul
21949610Swpaul	{ 0, 0 }
22049610Swpaul};
22149610Swpaul
22249610Swpaulstatic driver_t vr_driver = {
22351455Swpaul	"vr",
22449610Swpaul	vr_methods,
22549610Swpaul	sizeof(struct vr_softc)
22649610Swpaul};
22749610Swpaul
22849610Swpaulstatic devclass_t vr_devclass;
22949610Swpaul
230113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0);
23151473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
232168946Sphk#define VR_F_RESTART		0x01		/* Restart unit on next tick */
23349610Swpaul
234168946Sphk#define	VR_LOCK(_sc)		mtx_lock(&(_sc)->vr_mtx)
235168946Sphk#define	VR_UNLOCK(_sc)		mtx_unlock(&(_sc)->vr_mtx)
236168946Sphk#define	VR_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->vr_mtx, MA_OWNED)
23741502Swpaul
238168946Sphk/*
239168946Sphk * register space access macros
240168946Sphk */
241168946Sphk#define CSR_WRITE_4(sc, reg, val)	bus_write_4(sc->vr_res, reg, val)
242168946Sphk#define CSR_WRITE_2(sc, reg, val)	bus_write_2(sc->vr_res, reg, val)
243168946Sphk#define CSR_WRITE_1(sc, reg, val)	bus_write_1(sc->vr_res, reg, val)
24441502Swpaul
245168946Sphk#define CSR_READ_2(sc, reg)		bus_read_2(sc->vr_res, reg)
246168946Sphk#define CSR_READ_1(sc, reg)		bus_read_1(sc->vr_res, reg)
24741502Swpaul
248168946Sphk#define VR_SETBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | (x))
249168946Sphk#define VR_CLRBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~(x))
25041502Swpaul
251168946Sphk#define VR_SETBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | (x))
252168946Sphk#define VR_CLRBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~(x))
25341502Swpaul
254168946Sphk#ifdef VR_USESWSHIFT
25541502Swpaul
256168946Sphk#define CSR_READ_4(sc, reg)		bus_read_4(sc->vr_res, reg)
257168946Sphk#define SIO_SET(x) CSR_WRITE_1(sc, VR_MIICMD, CSR_READ_1(sc, VR_MIICMD) | (x))
258168946Sphk#define SIO_CLR(x) CSR_WRITE_1(sc, VR_MIICMD, CSR_READ_1(sc, VR_MIICMD) & ~(x))
25941502Swpaul
26041502Swpaul/*
26141502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
26241502Swpaul */
263102336Salfredstatic void
264131503Sbmsvr_mii_sync(struct vr_softc *sc)
26541502Swpaul{
266131503Sbms	register int	i;
26741502Swpaul
26841502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
26941502Swpaul
27041502Swpaul	for (i = 0; i < 32; i++) {
27141502Swpaul		SIO_SET(VR_MIICMD_CLK);
27241502Swpaul		DELAY(1);
27341502Swpaul		SIO_CLR(VR_MIICMD_CLK);
27441502Swpaul		DELAY(1);
27541502Swpaul	}
27641502Swpaul}
27741502Swpaul
27841502Swpaul/*
27941502Swpaul * Clock a series of bits through the MII.
28041502Swpaul */
281102336Salfredstatic void
282131503Sbmsvr_mii_send(struct vr_softc *sc, uint32_t bits, int cnt)
28341502Swpaul{
284131503Sbms	int	i;
28541502Swpaul
28641502Swpaul	SIO_CLR(VR_MIICMD_CLK);
28741502Swpaul
28841502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
289131503Sbms		if (bits & i) {
29041502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
291131503Sbms		} else {
29241502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
293131503Sbms		}
29441502Swpaul		DELAY(1);
29541502Swpaul		SIO_CLR(VR_MIICMD_CLK);
29641502Swpaul		DELAY(1);
29741502Swpaul		SIO_SET(VR_MIICMD_CLK);
29841502Swpaul	}
29941502Swpaul}
300110168Ssilby#endif
30141502Swpaul
30241502Swpaul/*
30341502Swpaul * Read an PHY register through the MII.
30441502Swpaul */
305102336Salfredstatic int
306168946Sphkvr_mii_readreg(const struct vr_softc *sc, struct vr_mii_frame *frame)
307131503Sbms#ifdef VR_USESWSHIFT
30841502Swpaul{
309131503Sbms	int	i, ack;
31041502Swpaul
311131503Sbms	/* Set up frame for RX. */
31241502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
31341502Swpaul	frame->mii_opcode = VR_MII_READOP;
31441502Swpaul	frame->mii_turnaround = 0;
31541502Swpaul	frame->mii_data = 0;
316131503Sbms
31741502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
31841502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
31941502Swpaul
320131503Sbms	/* Turn on data xmit. */
32141502Swpaul	SIO_SET(VR_MIICMD_DIR);
32241502Swpaul
32341502Swpaul	vr_mii_sync(sc);
32441502Swpaul
325131503Sbms	/* Send command/address info. */
32641502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
32741502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
32841502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
32941502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
33041502Swpaul
331131503Sbms	/* Idle bit. */
33241502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
33341502Swpaul	DELAY(1);
33441502Swpaul	SIO_SET(VR_MIICMD_CLK);
33541502Swpaul	DELAY(1);
33641502Swpaul
33741502Swpaul	/* Turn off xmit. */
33841502Swpaul	SIO_CLR(VR_MIICMD_DIR);
33941502Swpaul
34041502Swpaul	/* Check for ack */
34141502Swpaul	SIO_CLR(VR_MIICMD_CLK);
34241502Swpaul	DELAY(1);
343109058Smbr	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
34441502Swpaul	SIO_SET(VR_MIICMD_CLK);
34541502Swpaul	DELAY(1);
34641502Swpaul
34741502Swpaul	/*
34841502Swpaul	 * Now try reading data bits. If the ack failed, we still
34941502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
35041502Swpaul	 */
35141502Swpaul	if (ack) {
35241502Swpaul		for(i = 0; i < 16; i++) {
35341502Swpaul			SIO_CLR(VR_MIICMD_CLK);
35441502Swpaul			DELAY(1);
35541502Swpaul			SIO_SET(VR_MIICMD_CLK);
35641502Swpaul			DELAY(1);
35741502Swpaul		}
35841502Swpaul		goto fail;
35941502Swpaul	}
36041502Swpaul
36141502Swpaul	for (i = 0x8000; i; i >>= 1) {
36241502Swpaul		SIO_CLR(VR_MIICMD_CLK);
36341502Swpaul		DELAY(1);
36441502Swpaul		if (!ack) {
36541502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
36641502Swpaul				frame->mii_data |= i;
36741502Swpaul			DELAY(1);
36841502Swpaul		}
36941502Swpaul		SIO_SET(VR_MIICMD_CLK);
37041502Swpaul		DELAY(1);
37141502Swpaul	}
37241502Swpaul
37341502Swpaulfail:
37441502Swpaul	SIO_CLR(VR_MIICMD_CLK);
37541502Swpaul	DELAY(1);
37641502Swpaul	SIO_SET(VR_MIICMD_CLK);
37741502Swpaul	DELAY(1);
37841502Swpaul
37941502Swpaul	if (ack)
380131503Sbms		return (1);
381131503Sbms	return (0);
38241502Swpaul}
383110168Ssilby#else
384110168Ssilby{
385131518Sbms	int	i;
38641502Swpaul
387131503Sbms	/* Set the PHY address. */
388110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
389110168Ssilby	    frame->mii_phyaddr);
390110168Ssilby
391131503Sbms	/* Set the register address. */
392110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
393110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
394131503Sbms
395110168Ssilby	for (i = 0; i < 10000; i++) {
396110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
397110168Ssilby			break;
398110168Ssilby		DELAY(1);
399110168Ssilby	}
400110168Ssilby	frame->mii_data = CSR_READ_2(sc, VR_MIIDATA);
401110168Ssilby
402131503Sbms	return (0);
403110168Ssilby}
404110168Ssilby#endif
405110168Ssilby
406110168Ssilby
40741502Swpaul/*
40841502Swpaul * Write to a PHY register through the MII.
40941502Swpaul */
410102336Salfredstatic int
411168946Sphkvr_mii_writereg(const struct vr_softc *sc, const struct vr_mii_frame *frame)
412131503Sbms#ifdef VR_USESWSHIFT
41341502Swpaul{
41441502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
41541502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
41641502Swpaul
417131503Sbms	/* Set up frame for TX. */
41841502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
41941502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
42041502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
421131503Sbms
422131503Sbms	/* Turn on data output. */
42341502Swpaul	SIO_SET(VR_MIICMD_DIR);
42441502Swpaul
42541502Swpaul	vr_mii_sync(sc);
42641502Swpaul
42741502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
42841502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
42941502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
43041502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
43141502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
43241502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
43341502Swpaul
43441502Swpaul	/* Idle bit. */
43541502Swpaul	SIO_SET(VR_MIICMD_CLK);
43641502Swpaul	DELAY(1);
43741502Swpaul	SIO_CLR(VR_MIICMD_CLK);
43841502Swpaul	DELAY(1);
43941502Swpaul
440131503Sbms	/* Turn off xmit. */
44141502Swpaul	SIO_CLR(VR_MIICMD_DIR);
44241502Swpaul
443131503Sbms	return (0);
44441502Swpaul}
445110168Ssilby#else
446110168Ssilby{
447131518Sbms	int	i;
44841502Swpaul
449131503Sbms	/* Set the PHY address. */
450110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
451131503Sbms	    frame->mii_phyaddr);
452110168Ssilby
453131503Sbms	/* Set the register address and data to write. */
454110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
455110168Ssilby	CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data);
456110168Ssilby
457110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
458110168Ssilby
459110168Ssilby	for (i = 0; i < 10000; i++) {
460110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
461110168Ssilby			break;
462110168Ssilby		DELAY(1);
463110168Ssilby	}
464110168Ssilby
465131503Sbms	return (0);
466110168Ssilby}
467110168Ssilby#endif
468110168Ssilby
469102336Salfredstatic int
470131517Sbmsvr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg)
47151432Swpaul{
47241502Swpaul	struct vr_mii_frame	frame;
473131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
47441502Swpaul
475168946Sphk	if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1)
476168946Sphk		return (0);
477110168Ssilby
47841502Swpaul	bzero((char *)&frame, sizeof(frame));
47951432Swpaul	frame.mii_phyaddr = phy;
48041502Swpaul	frame.mii_regaddr = reg;
48141502Swpaul	vr_mii_readreg(sc, &frame);
482131503Sbms	return (frame.mii_data);
48341502Swpaul}
48441502Swpaul
485102336Salfredstatic int
486131503Sbmsvr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data)
48751432Swpaul{
48841502Swpaul	struct vr_mii_frame	frame;
489131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
49041502Swpaul
491168946Sphk	if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1)
492168946Sphk		return (0);
493110168Ssilby
49441502Swpaul	bzero((char *)&frame, sizeof(frame));
49551432Swpaul	frame.mii_phyaddr = phy;
49641502Swpaul	frame.mii_regaddr = reg;
49741502Swpaul	frame.mii_data = data;
49841502Swpaul	vr_mii_writereg(sc, &frame);
49941502Swpaul
500131503Sbms	return (0);
50151432Swpaul}
50251432Swpaul
503102336Salfredstatic void
504131503Sbmsvr_miibus_statchg(device_t dev)
50551432Swpaul{
50651432Swpaul	struct mii_data		*mii;
507131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
50851432Swpaul
50951432Swpaul	mii = device_get_softc(sc->vr_miibus);
51051432Swpaul	vr_setcfg(sc, mii->mii_media_active);
51141502Swpaul}
51241502Swpaul
51341502Swpaul/*
51441502Swpaul * Program the 64-bit multicast hash filter.
51541502Swpaul */
516102336Salfredstatic void
517131503Sbmsvr_setmulti(struct vr_softc *sc)
51841502Swpaul{
519147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
52041502Swpaul	int			h = 0;
521131503Sbms	uint32_t		hashes[2] = { 0, 0 };
52241502Swpaul	struct ifmultiaddr	*ifma;
523131503Sbms	uint8_t			rxfilt;
52441502Swpaul	int			mcnt = 0;
52541502Swpaul
526131518Sbms	VR_LOCK_ASSERT(sc);
52741502Swpaul
52841502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
52941502Swpaul
53041502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
53141502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
53241502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
53341502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
53441502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
53541502Swpaul		return;
53641502Swpaul	}
53741502Swpaul
538131503Sbms	/* First, zero out all the existing hash bits. */
53941502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
54041502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
54141502Swpaul
542131503Sbms	/* Now program new ones. */
543148654Srwatson	IF_ADDR_LOCK(ifp);
54472084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
54541502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
54641502Swpaul			continue;
547130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
548130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
54941502Swpaul		if (h < 32)
55041502Swpaul			hashes[0] |= (1 << h);
55141502Swpaul		else
55241502Swpaul			hashes[1] |= (1 << (h - 32));
55341502Swpaul		mcnt++;
55441502Swpaul	}
555148654Srwatson	IF_ADDR_UNLOCK(ifp);
55641502Swpaul
55741502Swpaul	if (mcnt)
55841502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
55941502Swpaul	else
56041502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
56141502Swpaul
56241502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
56341502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
56441502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
56541502Swpaul}
56641502Swpaul
56741502Swpaul/*
56841502Swpaul * In order to fiddle with the
56941502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
57041502Swpaul * first have to put the transmit and/or receive logic in the idle state.
57141502Swpaul */
572102336Salfredstatic void
573131503Sbmsvr_setcfg(struct vr_softc *sc, int media)
57441502Swpaul{
575131517Sbms	int	restart = 0;
57641502Swpaul
577131518Sbms	VR_LOCK_ASSERT(sc);
578131518Sbms
57941502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
58041502Swpaul		restart = 1;
58141502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
58241502Swpaul	}
58341502Swpaul
58451432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
58541502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58641502Swpaul	else
58741502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
58841502Swpaul
58941502Swpaul	if (restart)
59041502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
59141502Swpaul}
59241502Swpaul
593102336Salfredstatic void
594168946Sphkvr_reset(const struct vr_softc *sc)
59541502Swpaul{
596131517Sbms	register int	i;
59741502Swpaul
598151773Sjhb	/*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during attach w/o lock. */
599131518Sbms
60041502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
60141502Swpaul
60241502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
60341502Swpaul		DELAY(10);
60441502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
60541502Swpaul			break;
60641502Swpaul	}
607107220Ssilby	if (i == VR_TIMEOUT) {
608107220Ssilby		if (sc->vr_revid < REV_ID_VT3065_A)
609162315Sglebius			device_printf(sc->vr_dev, "reset never completed!\n");
610107220Ssilby		else {
611107220Ssilby			/* Use newer force reset command */
612162315Sglebius			device_printf(sc->vr_dev, "Using force reset command.\n");
613107220Ssilby			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
614107220Ssilby		}
615107220Ssilby	}
61641502Swpaul
61741502Swpaul	/* Wait a little while for the chip to get its brains in order. */
61841502Swpaul	DELAY(1000);
61941502Swpaul}
62041502Swpaul
62141502Swpaul/*
62241502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
623168813Sphk * IDs against our list and return a match or NULL
624168813Sphk */
625168813Sphkstatic struct vr_type *
626168813Sphkvr_match(device_t dev)
627168813Sphk{
628168813Sphk	struct vr_type	*t = vr_devs;
629168813Sphk
630168813Sphk	for (t = vr_devs; t->vr_name != NULL; t++)
631168813Sphk		if ((pci_get_vendor(dev) == t->vr_vid) &&
632168813Sphk		    (pci_get_device(dev) == t->vr_did))
633168813Sphk			return (t);
634168813Sphk	return (NULL);
635168813Sphk}
636168813Sphk
637168813Sphk/*
638168813Sphk * Probe for a VIA Rhine chip. Check the PCI vendor and device
63941502Swpaul * IDs against our list and return a device name if we find a match.
64041502Swpaul */
641102336Salfredstatic int
642131503Sbmsvr_probe(device_t dev)
64341502Swpaul{
644168813Sphk	struct vr_type	*t;
64541502Swpaul
646168813Sphk	t = vr_match(dev);
647168813Sphk	if (t != NULL) {
648168813Sphk		device_set_desc(dev, t->vr_name);
649168813Sphk		return (BUS_PROBE_DEFAULT);
65041502Swpaul	}
651131503Sbms	return (ENXIO);
65241502Swpaul}
65341502Swpaul
65441502Swpaul/*
65541502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
65641502Swpaul * setup and ethernet/BPF attach.
65741502Swpaul */
658102336Salfredstatic int
659168946Sphkvr_attach(device_t dev)
66041502Swpaul{
66167087Swpaul	int			i;
66241502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
66341502Swpaul	struct vr_softc		*sc;
66441502Swpaul	struct ifnet		*ifp;
665168946Sphk	int			error = 0, rid;
666168813Sphk	struct vr_type		*t;
66741502Swpaul
66849610Swpaul	sc = device_get_softc(dev);
669162315Sglebius	sc->vr_dev = dev;
670168813Sphk	t = vr_match(dev);
671168813Sphk	KASSERT(t != NULL, ("Lost if_vr device match"));
672168813Sphk	sc->vr_quirks = t->vr_quirks;
673168813Sphk	device_printf(dev, "Quirks: 0x%x\n", sc->vr_quirks);
67441502Swpaul
67593818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
676131518Sbms	    MTX_DEF);
677151911Sjhb	callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0);
678151911Sjhb
67941502Swpaul	/*
68041502Swpaul	 * Map control/status registers.
68141502Swpaul	 */
68272813Swpaul	pci_enable_busmaster(dev);
683107220Ssilby	sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF;
68441502Swpaul
68549610Swpaul	rid = VR_RID;
686127135Snjl	sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE);
68749610Swpaul
68849610Swpaul	if (sc->vr_res == NULL) {
689151773Sjhb		device_printf(dev, "couldn't map ports/memory\n");
69049610Swpaul		error = ENXIO;
69141502Swpaul		goto fail;
69241502Swpaul	}
69341502Swpaul
69441502Swpaul	/* Allocate interrupt */
69549610Swpaul	rid = 0;
696127135Snjl	sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
69749610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
69849610Swpaul
69949610Swpaul	if (sc->vr_irq == NULL) {
700151773Sjhb		device_printf(dev, "couldn't map interrupt\n");
70149610Swpaul		error = ENXIO;
70241502Swpaul		goto fail;
70341502Swpaul	}
70441502Swpaul
705151773Sjhb	/* Allocate ifnet structure. */
706151773Sjhb	ifp = sc->vr_ifp = if_alloc(IFT_ETHER);
707151773Sjhb	if (ifp == NULL) {
708151773Sjhb		device_printf(dev, "can not if_alloc()\n");
709151773Sjhb		error = ENOSPC;
710151773Sjhb		goto fail;
711151773Sjhb	}
712151773Sjhb	ifp->if_softc = sc;
713151773Sjhb	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
714151773Sjhb	ifp->if_mtu = ETHERMTU;
715151773Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
716151773Sjhb	ifp->if_ioctl = vr_ioctl;
717151773Sjhb	ifp->if_start = vr_start;
718151773Sjhb	ifp->if_watchdog = vr_watchdog;
719151773Sjhb	ifp->if_init = vr_init;
720151773Sjhb	IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1);
721151773Sjhb	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
722151773Sjhb	IFQ_SET_READY(&ifp->if_snd);
723168827Sphk
724168827Sphk	if (sc->vr_quirks & VR_Q_CSUM) {
725168827Sphk		ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
726168827Sphk		ifp->if_capabilities |= IFCAP_HWCSUM;
727168827Sphk	}
728168827Sphk
729151773Sjhb	ifp->if_capenable = ifp->if_capabilities;
730168827Sphk	if (ifp->if_capenable & IFCAP_TXCSUM)
731168827Sphk		ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
732168827Sphk	else
733168827Sphk		ifp->if_hwassist = 0;
734168827Sphk
735151773Sjhb#ifdef DEVICE_POLLING
736151773Sjhb	ifp->if_capabilities |= IFCAP_POLLING;
737151773Sjhb#endif
738151773Sjhb
73976586Swpaul	/*
74076586Swpaul	 * Windows may put the chip in suspend mode when it
74176586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
74276586Swpaul	 * up again.
74376586Swpaul	 */
74476586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
74576586Swpaul
74641502Swpaul	/* Reset the adapter. */
74741502Swpaul	vr_reset(sc);
74841502Swpaul
749131503Sbms	/*
750110168Ssilby	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
751110168Ssilby	 * initialization and disable AUTOPOLL.
752110168Ssilby	 */
753131503Sbms	pci_write_config(dev, VR_PCI_MODE,
754110168Ssilby	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
755110168Ssilby	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
756110168Ssilby
75741502Swpaul	/*
75841502Swpaul	 * Get station address. The way the Rhine chips work,
75941502Swpaul	 * you're not allowed to directly access the EEPROM once
76041502Swpaul	 * they've been programmed a special way. Consequently,
76141502Swpaul	 * we need to read the node address from the PAR0 and PAR1
76241502Swpaul	 * registers.
76341502Swpaul	 */
76441502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
76541502Swpaul	DELAY(200);
76641502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
76741502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
76841502Swpaul
76951432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
770151773Sjhb	    M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
77151432Swpaul
77251432Swpaul	if (sc->vr_ldata == NULL) {
773151773Sjhb		device_printf(dev, "no memory for list buffers!\n");
77449610Swpaul		error = ENXIO;
77549610Swpaul		goto fail;
77641502Swpaul	}
77741502Swpaul
778131503Sbms	/* Do MII setup. */
77951432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
78051432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
781151773Sjhb		device_printf(dev, "MII without any phy!\n");
78249610Swpaul		error = ENXIO;
78341502Swpaul		goto fail;
78441502Swpaul	}
78541502Swpaul
786131503Sbms	/* Call MI attach routine. */
787106936Ssam	ether_ifattach(ifp, eaddr);
78841502Swpaul
789168948Sphk	sc->vr_suspended = 0;
790131844Sbms
791113609Snjl	/* Hook interrupt last to avoid having to lock softc */
792131518Sbms	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE,
793166901Spiso	    NULL, vr_intr, sc, &sc->vr_intrhand);
794112872Snjl
795112872Snjl	if (error) {
796151773Sjhb		device_printf(dev, "couldn't set up irq\n");
797113609Snjl		ether_ifdetach(ifp);
798112872Snjl		goto fail;
799112872Snjl	}
800112872Snjl
80141502Swpaulfail:
802112872Snjl	if (error)
803112872Snjl		vr_detach(dev);
80467087Swpaul
805131503Sbms	return (error);
80641502Swpaul}
80741502Swpaul
808113609Snjl/*
809113609Snjl * Shutdown hardware and free up resources. This can be called any
810113609Snjl * time after the mutex has been initialized. It is called in both
811113609Snjl * the error case in attach and the normal detach case so it needs
812113609Snjl * to be careful about only freeing resources that have actually been
813113609Snjl * allocated.
814113609Snjl */
815102336Salfredstatic int
816131503Sbmsvr_detach(device_t dev)
81749610Swpaul{
818131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
819147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
82049610Swpaul
821112880Sjhb	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
822131518Sbms
823150789Sglebius#ifdef DEVICE_POLLING
824150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
825150789Sglebius		ether_poll_deregister(ifp);
826150789Sglebius#endif
827150789Sglebius
828113609Snjl	/* These should only be active if attach succeeded */
829113812Simp	if (device_is_attached(dev)) {
830151911Sjhb		VR_LOCK(sc);
831168948Sphk		sc->vr_suspended = 1;
832113609Snjl		vr_stop(sc);
833151911Sjhb		VR_UNLOCK(sc);
834151911Sjhb		callout_drain(&sc->vr_stat_callout);
835112872Snjl		ether_ifdetach(ifp);
836113609Snjl	}
837113609Snjl	if (sc->vr_miibus)
838112872Snjl		device_delete_child(dev, sc->vr_miibus);
839113609Snjl	bus_generic_detach(dev);
84049610Swpaul
841112872Snjl	if (sc->vr_intrhand)
842112872Snjl		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
843112872Snjl	if (sc->vr_irq)
844112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
845112872Snjl	if (sc->vr_res)
846112872Snjl		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
84751432Swpaul
848151297Sru	if (ifp)
849151297Sru		if_free(ifp);
850151297Sru
851112872Snjl	if (sc->vr_ldata)
852112872Snjl		contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
85349610Swpaul
85467087Swpaul	mtx_destroy(&sc->vr_mtx);
85549610Swpaul
856131503Sbms	return (0);
85749610Swpaul}
85849610Swpaul
85941502Swpaul/*
86041502Swpaul * Initialize the transmit descriptors.
86141502Swpaul */
862102336Salfredstatic int
863131503Sbmsvr_list_tx_init(struct vr_softc *sc)
86441502Swpaul{
86541502Swpaul	struct vr_chain_data	*cd;
86641502Swpaul	struct vr_list_data	*ld;
86741502Swpaul	int			i;
86841502Swpaul
86941502Swpaul	cd = &sc->vr_cdata;
87041502Swpaul	ld = sc->vr_ldata;
87141502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
87241502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
873168950Sphk		if (i == (VR_TX_LIST_CNT - 1)) {
874131503Sbms			cd->vr_tx_chain[i].vr_nextdesc =
875168950Sphk			    &cd->vr_tx_chain[0];
876168950Sphk			ld->vr_tx_list[i].vr_nextphys =
877168950Sphk			    vtophys(&ld->vr_tx_list[0]);
878168950Sphk		} else {
87941502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
88041502Swpaul				&cd->vr_tx_chain[i + 1];
881168950Sphk			ld->vr_tx_list[i].vr_nextphys =
882168950Sphk			    vtophys(&ld->vr_tx_list[i + 1]);
883168950Sphk		}
88441502Swpaul	}
885127901Sru	cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0];
88641502Swpaul
887131503Sbms	return (0);
88841502Swpaul}
88941502Swpaul
89041502Swpaul
89141502Swpaul/*
89241502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
89341502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
89441502Swpaul * points back to the first.
89541502Swpaul */
896102336Salfredstatic int
897131503Sbmsvr_list_rx_init(struct vr_softc *sc)
89841502Swpaul{
89941502Swpaul	struct vr_chain_data	*cd;
90041502Swpaul	struct vr_list_data	*ld;
90141502Swpaul	int			i;
90241502Swpaul
903131518Sbms	VR_LOCK_ASSERT(sc);
904131518Sbms
90541502Swpaul	cd = &sc->vr_cdata;
90641502Swpaul	ld = sc->vr_ldata;
90741502Swpaul
90841502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
909168948Sphk		cd->vr_rx_chain[i].vr_ptr = &ld->vr_rx_list[i];
910168946Sphk		if (vr_newbuf(&cd->vr_rx_chain[i], NULL) == ENOBUFS)
911131503Sbms			return (ENOBUFS);
91241502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
91341502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
91441502Swpaul					&cd->vr_rx_chain[0];
915168948Sphk			ld->vr_rx_list[i].vr_nextphys =
91641502Swpaul					vtophys(&ld->vr_rx_list[0]);
91741502Swpaul		} else {
91841502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
91941502Swpaul					&cd->vr_rx_chain[i + 1];
920168948Sphk			ld->vr_rx_list[i].vr_nextphys =
92141502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
92241502Swpaul		}
92341502Swpaul	}
92441502Swpaul
92541502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
92641502Swpaul
927131503Sbms	return (0);
92841502Swpaul}
92941502Swpaul
93041502Swpaul/*
93141502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
93241502Swpaul * Note: the length fields are only 11 bits wide, which means the
93341502Swpaul * largest size we can specify is 2047. This is important because
93441502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
93541502Swpaul * overflow the field and make a mess.
93641502Swpaul */
937102336Salfredstatic int
938168948Sphkvr_newbuf(struct vr_chain *c, struct mbuf *m)
93941502Swpaul{
94041502Swpaul	struct mbuf		*m_new = NULL;
94141502Swpaul
94249610Swpaul	if (m == NULL) {
943111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
94487846Sluigi		if (m_new == NULL)
945131503Sbms			return (ENOBUFS);
94641502Swpaul
947111119Simp		MCLGET(m_new, M_DONTWAIT);
94849610Swpaul		if (!(m_new->m_flags & M_EXT)) {
94949610Swpaul			m_freem(m_new);
950131503Sbms			return (ENOBUFS);
95149610Swpaul		}
95249610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
95349610Swpaul	} else {
95449610Swpaul		m_new = m;
95549610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
95649610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
95741502Swpaul	}
95841502Swpaul
959131503Sbms	m_adj(m_new, sizeof(uint64_t));
96049610Swpaul
96141502Swpaul	c->vr_mbuf = m_new;
96241502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
96341502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
96442491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
96541502Swpaul
966131503Sbms	return (0);
96741502Swpaul}
96841502Swpaul
96941502Swpaul/*
97041502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
97141502Swpaul * the higher level protocols.
97241502Swpaul */
973102336Salfredstatic void
974131503Sbmsvr_rxeof(struct vr_softc *sc)
97541502Swpaul{
976131503Sbms	struct mbuf		*m, *m0;
977131503Sbms	struct ifnet		*ifp;
978168948Sphk	struct vr_chain		*cur_rx;
97941502Swpaul	int			total_len = 0;
980168827Sphk	uint32_t		rxstat, rxctl;
98141502Swpaul
982122689Ssam	VR_LOCK_ASSERT(sc);
983147256Sbrooks	ifp = sc->vr_ifp;
98441502Swpaul
985131503Sbms	while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
986131503Sbms	    VR_RXSTAT_OWN)) {
987127901Sru#ifdef DEVICE_POLLING
988150789Sglebius		if (ifp->if_capenable & IFCAP_POLLING) {
989127901Sru			if (sc->rxcycles <= 0)
990127901Sru				break;
991127901Sru			sc->rxcycles--;
992127901Sru		}
993150789Sglebius#endif
994127901Sru		m0 = NULL;
99541502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
99641502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
99749610Swpaul		m = cur_rx->vr_mbuf;
99841502Swpaul
99941502Swpaul		/*
100041502Swpaul		 * If an error occurs, update stats, clear the
100141502Swpaul		 * status word and leave the mbuf cluster in place:
100241502Swpaul		 * it should simply get re-used next time this descriptor
1003131503Sbms		 * comes up in the ring.
100441502Swpaul		 */
100541502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
100641502Swpaul			ifp->if_ierrors++;
1007162315Sglebius			device_printf(sc->vr_dev,
1008162315Sglebius			    "rx error (%02x):", rxstat & 0x000000ff);
1009110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
1010110131Ssilby				printf(" crc error");
1011110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
1012110131Ssilby				printf(" frame alignment error\n");
1013110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
1014110131Ssilby				printf(" FIFO overflow");
1015110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
1016110131Ssilby				printf(" received giant packet");
1017110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
1018110131Ssilby				printf(" received runt packet");
1019110131Ssilby			if (rxstat & VR_RXSTAT_BUSERR)
1020110131Ssilby				printf(" system bus error");
1021110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
1022110131Ssilby				printf("rx buffer error");
1023110131Ssilby			printf("\n");
1024168946Sphk			vr_newbuf(cur_rx, m);
102541502Swpaul			continue;
102641502Swpaul		}
102741502Swpaul
1028131503Sbms		/* No errors; receive the packet. */
102941502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
1030168827Sphk		if (ifp->if_capenable & IFCAP_RXCSUM) {
1031168827Sphk			rxctl = cur_rx->vr_ptr->vr_ctl;
1032168827Sphk			if ((rxctl & VR_RXCTL_GOODIP) == VR_RXCTL_GOODIP)
1033168827Sphk				m->m_pkthdr.csum_flags |=
1034168827Sphk				    CSUM_IP_CHECKED | CSUM_IP_VALID;
1035168827Sphk			if ((rxctl & VR_RXCTL_GOODTCPUDP)) {
1036168827Sphk				m->m_pkthdr.csum_flags |=
1037168827Sphk				    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
1038168827Sphk				m->m_pkthdr.csum_data = 0xffff;
1039168827Sphk			}
1040168827Sphk		}
104141502Swpaul
104241502Swpaul		/*
104342048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
104442048Swpaul		 * received frame, and there's no way to turn this
104542048Swpaul		 * behavior off (at least, I can't find anything in
1046131503Sbms		 * the manual that explains how to do it) so we have
104742048Swpaul		 * to trim off the CRC manually.
104842048Swpaul		 */
104942048Swpaul		total_len -= ETHER_CRC_LEN;
105042048Swpaul
105178508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
105278508Sbmilekic		    NULL);
1053168946Sphk		vr_newbuf(cur_rx, m);
105449610Swpaul		if (m0 == NULL) {
105541502Swpaul			ifp->if_ierrors++;
105641502Swpaul			continue;
105741502Swpaul		}
105849610Swpaul		m = m0;
105941502Swpaul
106041502Swpaul		ifp->if_ipackets++;
1061122689Ssam		VR_UNLOCK(sc);
1062106936Ssam		(*ifp->if_input)(ifp, m);
1063122689Ssam		VR_LOCK(sc);
106441502Swpaul	}
106541502Swpaul}
106641502Swpaul
1067105221Sphkstatic void
1068131503Sbmsvr_rxeoc(struct vr_softc *sc)
106941502Swpaul{
1070147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
1071110131Ssilby	int			i;
107241502Swpaul
1073131518Sbms	VR_LOCK_ASSERT(sc);
1074131518Sbms
1075110131Ssilby	ifp->if_ierrors++;
1076110131Ssilby
1077131503Sbms	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
1078131503Sbms	DELAY(10000);
1079110131Ssilby
1080131503Sbms	/* Wait for receiver to stop */
1081110131Ssilby	for (i = 0x400;
1082110131Ssilby	     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON);
1083131503Sbms	     i--) {
1084131503Sbms		;
1085131503Sbms	}
1086110131Ssilby
1087110131Ssilby	if (!i) {
1088162315Sglebius		device_printf(sc->vr_dev, "rx shutdown error!\n");
1089110131Ssilby		sc->vr_flags |= VR_F_RESTART;
1090110131Ssilby		return;
1091131503Sbms	}
1092110131Ssilby
109341502Swpaul	vr_rxeof(sc);
1094110131Ssilby
109541502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
109641502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
109741502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
109841502Swpaul}
109941502Swpaul
110041502Swpaul/*
110141502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
110241502Swpaul * the list buffers.
110341502Swpaul */
1104102336Salfredstatic void
1105131503Sbmsvr_txeof(struct vr_softc *sc)
110641502Swpaul{
110741502Swpaul	struct vr_chain		*cur_tx;
1108147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
110941502Swpaul
1110131518Sbms	VR_LOCK_ASSERT(sc);
111141502Swpaul
111241502Swpaul	/*
111341502Swpaul	 * Go through our tx list and free mbufs for those
111441502Swpaul	 * frames that have been transmitted.
111541502Swpaul	 */
1116127901Sru	cur_tx = sc->vr_cdata.vr_tx_cons;
1117168813Sphk	while (cur_tx != sc->vr_cdata.vr_tx_prod) {
1118131503Sbms		uint32_t		txstat;
1119110131Ssilby		int			i;
112041502Swpaul
112141502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
112241502Swpaul
1123101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
1124101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
1125110131Ssilby			for (i = 0x400;
1126110131Ssilby			     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON);
1127110131Ssilby			     i--)
1128101896Ssilby				;	/* Wait for chip to shutdown */
1129110131Ssilby			if (!i) {
1130162315Sglebius				device_printf(sc->vr_dev, "tx shutdown timeout\n");
1131110131Ssilby				sc->vr_flags |= VR_F_RESTART;
1132110131Ssilby				break;
1133110131Ssilby			}
1134168813Sphk			atomic_set_acq_32(&VR_TXOWN(cur_tx), VR_TXSTAT_OWN);
1135101896Ssilby			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr));
1136101896Ssilby			break;
1137101896Ssilby		}
1138101896Ssilby
113942491Swpaul		if (txstat & VR_TXSTAT_OWN)
114041502Swpaul			break;
114141502Swpaul
114241502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
114341502Swpaul			ifp->if_oerrors++;
114441502Swpaul			if (txstat & VR_TXSTAT_DEFER)
114541502Swpaul				ifp->if_collisions++;
114641502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
114741502Swpaul				ifp->if_collisions++;
114841502Swpaul		}
114941502Swpaul
115041502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
115141502Swpaul
115241502Swpaul		ifp->if_opackets++;
1153168813Sphk		if (cur_tx->vr_mbuf != NULL)
1154168813Sphk			m_freem(cur_tx->vr_mbuf);
1155127901Sru		cur_tx->vr_mbuf = NULL;
1156148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
115741502Swpaul
1158127901Sru		cur_tx = cur_tx->vr_nextdesc;
115941502Swpaul	}
1160127901Sru	sc->vr_cdata.vr_tx_cons = cur_tx;
1161127901Sru	if (cur_tx->vr_mbuf == NULL)
116296677Ssilby		ifp->if_timer = 0;
116341502Swpaul}
116441502Swpaul
1165102336Salfredstatic void
1166131503Sbmsvr_tick(void *xsc)
116751432Swpaul{
1168131503Sbms	struct vr_softc		*sc = xsc;
116951432Swpaul	struct mii_data		*mii;
117051432Swpaul
1171151911Sjhb	VR_LOCK_ASSERT(sc);
1172131517Sbms
1173110131Ssilby	if (sc->vr_flags & VR_F_RESTART) {
1174162315Sglebius		device_printf(sc->vr_dev, "restarting\n");
1175110131Ssilby		vr_stop(sc);
1176110131Ssilby		vr_reset(sc);
1177131844Sbms		vr_init_locked(sc);
1178110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1179110131Ssilby	}
1180110131Ssilby
118151432Swpaul	mii = device_get_softc(sc->vr_miibus);
118251432Swpaul	mii_tick(mii);
1183151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
118451432Swpaul}
118551432Swpaul
1186127901Sru#ifdef DEVICE_POLLING
1187127901Srustatic poll_handler_t vr_poll;
1188131844Sbmsstatic poll_handler_t vr_poll_locked;
1189127901Sru
1190102336Salfredstatic void
1191127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1192127901Sru{
1193127901Sru	struct vr_softc *sc = ifp->if_softc;
1194127901Sru
1195127901Sru	VR_LOCK(sc);
1196150789Sglebius	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1197150789Sglebius		vr_poll_locked(ifp, cmd, count);
1198131844Sbms	VR_UNLOCK(sc);
1199131844Sbms}
1200131517Sbms
1201131844Sbmsstatic void
1202131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
1203131844Sbms{
1204131844Sbms	struct vr_softc *sc = ifp->if_softc;
1205131844Sbms
1206131844Sbms	VR_LOCK_ASSERT(sc);
1207131844Sbms
1208127901Sru	sc->rxcycles = count;
1209127901Sru	vr_rxeof(sc);
1210127901Sru	vr_txeof(sc);
1211133006Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1212131844Sbms		vr_start_locked(ifp);
1213127901Sru
1214131503Sbms	if (cmd == POLL_AND_CHECK_STATUS) {
1215131503Sbms		uint16_t status;
1216127901Sru
1217131503Sbms		/* Also check status register. */
1218127901Sru		status = CSR_READ_2(sc, VR_ISR);
1219127901Sru		if (status)
1220127901Sru			CSR_WRITE_2(sc, VR_ISR, status);
1221127901Sru
1222127901Sru		if ((status & VR_INTRS) == 0)
1223131844Sbms			return;
1224127901Sru
1225127901Sru		if (status & VR_ISR_RX_DROPPED) {
1226151773Sjhb			if_printf(ifp, "rx packet lost\n");
1227127901Sru			ifp->if_ierrors++;
1228127901Sru		}
1229127901Sru
1230127901Sru		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1231127901Sru		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1232151773Sjhb			if_printf(ifp, "receive error (%04x)", status);
1233127901Sru			if (status & VR_ISR_RX_NOBUF)
1234127901Sru				printf(" no buffers");
1235127901Sru			if (status & VR_ISR_RX_OFLOW)
1236127901Sru				printf(" overflow");
1237127901Sru			if (status & VR_ISR_RX_DROPPED)
1238127901Sru				printf(" packet lost");
1239127901Sru			printf("\n");
1240127901Sru			vr_rxeoc(sc);
1241127901Sru		}
1242127901Sru
1243131503Sbms		if ((status & VR_ISR_BUSERR) ||
1244131503Sbms		    (status & VR_ISR_TX_UNDERRUN)) {
1245127901Sru			vr_reset(sc);
1246131844Sbms			vr_init_locked(sc);
1247131518Sbms			return;
1248127901Sru		}
1249127901Sru
1250127901Sru		if ((status & VR_ISR_UDFI) ||
1251127901Sru		    (status & VR_ISR_TX_ABRT2) ||
1252127901Sru		    (status & VR_ISR_TX_ABRT)) {
1253127901Sru			ifp->if_oerrors++;
1254127901Sru			if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) {
1255127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1256127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1257127901Sru			}
1258127901Sru		}
1259127901Sru	}
1260127901Sru}
1261127901Sru#endif /* DEVICE_POLLING */
1262127901Sru
1263127901Srustatic void
1264131503Sbmsvr_intr(void *arg)
126541502Swpaul{
1266131503Sbms	struct vr_softc		*sc = arg;
1267147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
1268131503Sbms	uint16_t		status;
126941502Swpaul
127067087Swpaul	VR_LOCK(sc);
1271131844Sbms
1272168948Sphk	if (sc->vr_suspended) {
1273136997Sbms		/*
1274136997Sbms		 * Forcibly disable interrupts.
1275136997Sbms		 * XXX: Mobile VIA based platforms may need
1276136997Sbms		 * interrupt re-enable on resume.
1277136997Sbms		 */
1278136997Sbms		CSR_WRITE_2(sc, VR_IMR, 0x0000);
1279131844Sbms		goto done_locked;
1280136997Sbms	}
1281131844Sbms
1282127901Sru#ifdef DEVICE_POLLING
1283150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1284131844Sbms		goto done_locked;
1285150789Sglebius#endif
1286131844Sbms
1287131844Sbms	/* Suppress unwanted interrupts. */
128841502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
128941502Swpaul		vr_stop(sc);
1290131844Sbms		goto done_locked;
129141502Swpaul	}
129241502Swpaul
129341502Swpaul	/* Disable interrupts. */
129441502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
129541502Swpaul
129641502Swpaul	for (;;) {
129741502Swpaul		status = CSR_READ_2(sc, VR_ISR);
1298168813Sphk
129941502Swpaul		if (status)
130041502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
130141502Swpaul
130241502Swpaul		if ((status & VR_INTRS) == 0)
130341502Swpaul			break;
130441502Swpaul
130541502Swpaul		if (status & VR_ISR_RX_OK)
130641502Swpaul			vr_rxeof(sc);
130741502Swpaul
1308110131Ssilby		if (status & VR_ISR_RX_DROPPED) {
1309162315Sglebius			device_printf(sc->vr_dev, "rx packet lost\n");
1310110131Ssilby			ifp->if_ierrors++;
1311131503Sbms		}
1312110131Ssilby
131341502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1314110131Ssilby		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1315162315Sglebius			device_printf(sc->vr_dev, "receive error (%04x)", status);
1316110131Ssilby			if (status & VR_ISR_RX_NOBUF)
1317110131Ssilby				printf(" no buffers");
1318110131Ssilby			if (status & VR_ISR_RX_OFLOW)
1319110131Ssilby				printf(" overflow");
1320110131Ssilby			if (status & VR_ISR_RX_DROPPED)
1321110131Ssilby				printf(" packet lost");
1322110131Ssilby			printf("\n");
132341502Swpaul			vr_rxeoc(sc);
132441502Swpaul		}
132541502Swpaul
1326101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1327101896Ssilby			vr_reset(sc);
1328131844Sbms			vr_init_locked(sc);
1329101896Ssilby			break;
133041502Swpaul		}
133141502Swpaul
1332101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1333101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
133441502Swpaul			vr_txeof(sc);
1335101896Ssilby			if ((status & VR_ISR_UDFI) ||
1336101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1337101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1338101896Ssilby				ifp->if_oerrors++;
1339127901Sru				if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) {
1340131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1341131503Sbms					    VR_CMD_TX_ON);
1342131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1343131503Sbms					    VR_CMD_TX_GO);
1344101896Ssilby				}
1345127901Sru			}
134641502Swpaul		}
134741502Swpaul	}
134841502Swpaul
134941502Swpaul	/* Re-enable interrupts. */
135041502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
135141502Swpaul
1352132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1353131844Sbms		vr_start_locked(ifp);
1354131844Sbms
1355131844Sbmsdone_locked:
1356131844Sbms	VR_UNLOCK(sc);
135741502Swpaul}
135841502Swpaul
135941502Swpaul/*
136041502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
136141502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
136241502Swpaul * copy of the pointers since the transmit list fragment pointers are
136341502Swpaul * physical addresses.
136441502Swpaul */
136541502Swpaul
1366102336Salfredstatic void
1367131503Sbmsvr_start(struct ifnet *ifp)
136841502Swpaul{
1369131518Sbms	struct vr_softc		*sc = ifp->if_softc;
1370131844Sbms
1371131844Sbms	VR_LOCK(sc);
1372131844Sbms	vr_start_locked(ifp);
1373131844Sbms	VR_UNLOCK(sc);
1374131844Sbms}
1375131844Sbms
1376131844Sbmsstatic void
1377131844Sbmsvr_start_locked(struct ifnet *ifp)
1378131844Sbms{
1379131844Sbms	struct vr_softc		*sc = ifp->if_softc;
1380168813Sphk	struct mbuf		*m, *m_head;
1381168813Sphk	struct vr_chain		*cur_tx, *n_tx;
1382168813Sphk	struct vr_desc		*f = NULL;
1383168813Sphk	uint32_t		cval;
138441502Swpaul
1385148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
1386127901Sru		return;
1387127901Sru
1388168813Sphk	for (cur_tx = sc->vr_cdata.vr_tx_prod;
1389168813Sphk	    cur_tx->vr_nextdesc != sc->vr_cdata.vr_tx_cons; ) {
1390132986Smlaier       	        IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
139141502Swpaul		if (m_head == NULL)
139241502Swpaul			break;
139341502Swpaul
1394168813Sphk		VR_LOCK_ASSERT(sc);
1395168813Sphk		/*
1396168813Sphk		 * Some VIA Rhine wants packet buffers to be longword
1397168813Sphk		 * aligned, but very often our mbufs aren't. Rather than
1398168813Sphk		 * waste time trying to decide when to copy and when not
1399168813Sphk		 * to copy, just do it all the time.
1400168813Sphk		 */
1401168827Sphk		if (sc->vr_quirks & VR_Q_NEEDALIGN) {
1402168813Sphk			m = m_defrag(m_head, M_DONTWAIT);
1403168813Sphk			if (m == NULL) {
1404168813Sphk				/* Rollback, send what we were able to encap. */
1405168813Sphk				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1406168813Sphk				break;
1407168813Sphk			}
1408168813Sphk			m_head = m;
1409168813Sphk		}
141041502Swpaul
141141502Swpaul		/*
1412168813Sphk		 * The Rhine chip doesn't auto-pad, so we have to make
1413168813Sphk		 * sure to pad short frames out to the minimum frame length
1414168813Sphk		 * ourselves.
141541502Swpaul		 */
1416168813Sphk		if (m_head->m_pkthdr.len < VR_MIN_FRAMELEN) {
1417168813Sphk			if (m_head->m_next != NULL)
1418168813Sphk				m_head = m_defrag(m_head, M_DONTWAIT);
1419168813Sphk			m_head->m_pkthdr.len += VR_MIN_FRAMELEN - m_head->m_len;
1420168813Sphk			m_head->m_len = m_head->m_pkthdr.len;
1421168813Sphk			/* XXX: bzero the padding bytes */
1422168813Sphk		}
142351583Swpaul
1424168813Sphk		n_tx = cur_tx;
1425168813Sphk		for (m = m_head; m != NULL; m = m->m_next) {
1426168813Sphk			if (m->m_len == 0)
1427168813Sphk				continue;
1428168813Sphk			if (n_tx->vr_nextdesc == sc->vr_cdata.vr_tx_cons) {
1429168813Sphk				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1430168813Sphk				sc->vr_cdata.vr_tx_prod = cur_tx;
1431168813Sphk				return;
1432168813Sphk			}
1433168813Sphk			KASSERT(n_tx->vr_mbuf == NULL, ("if_vr_tx overrun"));
1434168813Sphk
1435168813Sphk			f = n_tx->vr_ptr;
1436168813Sphk			f->vr_data = vtophys(mtod(m, caddr_t));
1437168813Sphk			cval = m->m_len;
1438168813Sphk			cval |= VR_TXCTL_TLINK;
1439168827Sphk
1440168827Sphk			if ((ifp->if_capenable & IFCAP_TXCSUM) &&
1441168827Sphk			    m_head->m_pkthdr.csum_flags) {
1442168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_IP)
1443168827Sphk					cval |= VR_TXCTL_IPCSUM;
1444168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_TCP)
1445168827Sphk					cval |= VR_TXCTL_TCPCSUM;
1446168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_UDP)
1447168827Sphk					cval |= VR_TXCTL_UDPCSUM;
1448168827Sphk			}
1449168827Sphk
1450168813Sphk			if (m == m_head)
1451168813Sphk				cval |= VR_TXCTL_FIRSTFRAG;
1452168813Sphk			f->vr_ctl = cval;
1453168813Sphk			f->vr_status = 0;
1454168813Sphk			n_tx = n_tx->vr_nextdesc;
1455168813Sphk		}
145641502Swpaul
1457168946Sphk		KASSERT(f != NULL, ("if_vr: no packet processed"));
1458168813Sphk		f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
1459168813Sphk		cur_tx->vr_mbuf = m_head;
1460168813Sphk		atomic_set_acq_32(&VR_TXOWN(cur_tx), VR_TXSTAT_OWN);
1461168813Sphk
1462127901Sru		/* Tell the chip to start transmitting. */
1463131517Sbms		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO);
146441526Swpaul
1465168813Sphk		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1466127901Sru		ifp->if_timer = 5;
146741502Swpaul
1468168813Sphk		/*
1469168813Sphk		 * If there's a BPF listener, bounce a copy of this frame
1470168813Sphk		 * to him.
1471168813Sphk		 */
1472168813Sphk		BPF_MTAP(ifp, m_head);
1473168813Sphk		cur_tx = n_tx;
1474127901Sru	}
1475168813Sphk	sc->vr_cdata.vr_tx_prod = cur_tx;
1476131844Sbms}
147741502Swpaul
1478131844Sbmsstatic void
1479131844Sbmsvr_init(void *xsc)
1480131844Sbms{
1481131844Sbms	struct vr_softc		*sc = xsc;
1482131844Sbms
1483131844Sbms	VR_LOCK(sc);
1484131844Sbms	vr_init_locked(sc);
148567087Swpaul	VR_UNLOCK(sc);
148641502Swpaul}
148741502Swpaul
1488102336Salfredstatic void
1489131844Sbmsvr_init_locked(struct vr_softc *sc)
149041502Swpaul{
1491147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
149251432Swpaul	struct mii_data		*mii;
149373963Swpaul	int			i;
149441502Swpaul
1495131844Sbms	VR_LOCK_ASSERT(sc);
149641502Swpaul
149751432Swpaul	mii = device_get_softc(sc->vr_miibus);
149841502Swpaul
1499131503Sbms	/* Cancel pending I/O and free all RX/TX buffers. */
150041502Swpaul	vr_stop(sc);
150141502Swpaul	vr_reset(sc);
150241502Swpaul
1503131503Sbms	/* Set our station address. */
150473963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
1505152315Sru		CSR_WRITE_1(sc, VR_PAR0 + i, IF_LLADDR(sc->vr_ifp)[i]);
1506131503Sbms
1507131503Sbms	/* Set DMA size. */
1508101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1509101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
151073963Swpaul
1511131503Sbms	/*
1512101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1513101108Ssilby	 * so we must set both.
1514101108Ssilby	 */
1515101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1516110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
1517101108Ssilby
1518101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1519101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1520101108Ssilby
152141502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
1522110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
152341502Swpaul
152441502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
152541502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
152641502Swpaul
152741502Swpaul	/* Init circular RX list. */
152841502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
1529162315Sglebius		device_printf(sc->vr_dev,
1530151773Sjhb		    "initialization failed: no memory for rx buffers\n");
153141502Swpaul		vr_stop(sc);
153241502Swpaul		return;
153341502Swpaul	}
153441502Swpaul
1535131503Sbms	/* Init tx descriptors. */
153641502Swpaul	vr_list_tx_init(sc);
153741502Swpaul
153841502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
153941502Swpaul	if (ifp->if_flags & IFF_PROMISC)
154041502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
154141502Swpaul	else
154241502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
154341502Swpaul
154441502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
154541502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
154641502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
154741502Swpaul	else
154841502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
154941502Swpaul
155041502Swpaul	/*
155141502Swpaul	 * Program the multicast filter, if necessary.
155241502Swpaul	 */
155341502Swpaul	vr_setmulti(sc);
155441502Swpaul
155541502Swpaul	/*
155641502Swpaul	 * Load the address of the RX list.
155741502Swpaul	 */
155841502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
155941502Swpaul
156041502Swpaul	/* Enable receiver and transmitter. */
156141502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
156241502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
156341502Swpaul				    VR_CMD_RX_GO);
156441502Swpaul
156541502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
156641502Swpaul
1567127901Sru	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
1568127901Sru#ifdef DEVICE_POLLING
156941502Swpaul	/*
1570127901Sru	 * Disable interrupts if we are polling.
1571127901Sru	 */
1572150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1573127901Sru		CSR_WRITE_2(sc, VR_IMR, 0);
1574131503Sbms	else
1575150789Sglebius#endif
1576127901Sru	/*
157741502Swpaul	 * Enable interrupts.
157841502Swpaul	 */
157941502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
158041502Swpaul
158151432Swpaul	mii_mediachg(mii);
158241502Swpaul
1583148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1584148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
158541502Swpaul
1586151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
158741502Swpaul}
158841502Swpaul
158941502Swpaul/*
159041502Swpaul * Set media options.
159141502Swpaul */
1592102336Salfredstatic int
1593131503Sbmsvr_ifmedia_upd(struct ifnet *ifp)
159441502Swpaul{
1595131503Sbms	struct vr_softc		*sc = ifp->if_softc;
159641502Swpaul
159751432Swpaul	if (ifp->if_flags & IFF_UP)
159851432Swpaul		vr_init(sc);
159941502Swpaul
1600131503Sbms	return (0);
160141502Swpaul}
160241502Swpaul
160341502Swpaul/*
160441502Swpaul * Report current media status.
160541502Swpaul */
1606102336Salfredstatic void
1607131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
160841502Swpaul{
1609131518Sbms	struct vr_softc		*sc = ifp->if_softc;
161051432Swpaul	struct mii_data		*mii;
161141502Swpaul
161251432Swpaul	mii = device_get_softc(sc->vr_miibus);
1613133468Sscottl	VR_LOCK(sc);
161451432Swpaul	mii_pollstat(mii);
1615133468Sscottl	VR_UNLOCK(sc);
161651432Swpaul	ifmr->ifm_active = mii->mii_media_active;
161751432Swpaul	ifmr->ifm_status = mii->mii_media_status;
161841502Swpaul}
161941502Swpaul
1620102336Salfredstatic int
1621131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
162241502Swpaul{
162341502Swpaul	struct vr_softc		*sc = ifp->if_softc;
162441502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
162551432Swpaul	struct mii_data		*mii;
162667087Swpaul	int			error = 0;
162741502Swpaul
1628131503Sbms	switch (command) {
162941502Swpaul	case SIOCSIFFLAGS:
1630131844Sbms		VR_LOCK(sc);
163141502Swpaul		if (ifp->if_flags & IFF_UP) {
1632131844Sbms			vr_init_locked(sc);
163341502Swpaul		} else {
1634148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
163541502Swpaul				vr_stop(sc);
163641502Swpaul		}
1637131844Sbms		VR_UNLOCK(sc);
163841502Swpaul		error = 0;
163941502Swpaul		break;
164041502Swpaul	case SIOCADDMULTI:
164141502Swpaul	case SIOCDELMULTI:
1642131518Sbms		VR_LOCK(sc);
164341502Swpaul		vr_setmulti(sc);
1644131518Sbms		VR_UNLOCK(sc);
164541502Swpaul		error = 0;
164641502Swpaul		break;
164741502Swpaul	case SIOCGIFMEDIA:
164841502Swpaul	case SIOCSIFMEDIA:
164951432Swpaul		mii = device_get_softc(sc->vr_miibus);
165051432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
165141502Swpaul		break;
1652128118Sru	case SIOCSIFCAP:
1653150789Sglebius#ifdef DEVICE_POLLING
1654150789Sglebius		if (ifr->ifr_reqcap & IFCAP_POLLING &&
1655150789Sglebius		    !(ifp->if_capenable & IFCAP_POLLING)) {
1656150789Sglebius			error = ether_poll_register(vr_poll, ifp);
1657150789Sglebius			if (error)
1658150789Sglebius				return(error);
1659150789Sglebius			VR_LOCK(sc);
1660150789Sglebius			/* Disable interrupts */
1661150789Sglebius			CSR_WRITE_2(sc, VR_IMR, 0x0000);
1662150789Sglebius			ifp->if_capenable |= IFCAP_POLLING;
1663150789Sglebius			VR_UNLOCK(sc);
1664150789Sglebius			return (error);
1665150789Sglebius
1666150789Sglebius		}
1667150789Sglebius		if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
1668150789Sglebius		    ifp->if_capenable & IFCAP_POLLING) {
1669150789Sglebius			error = ether_poll_deregister(ifp);
1670150789Sglebius			/* Enable interrupts. */
1671150789Sglebius			VR_LOCK(sc);
1672150789Sglebius			CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
1673150789Sglebius			ifp->if_capenable &= ~IFCAP_POLLING;
1674150789Sglebius			VR_UNLOCK(sc);
1675150789Sglebius			return (error);
1676150789Sglebius		}
1677150789Sglebius#endif /* DEVICE_POLLING */
1678168827Sphk		ifp->if_capenable = ifr->ifr_reqcap;
1679168827Sphk		if (ifp->if_capenable & IFCAP_TXCSUM)
1680168827Sphk			ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
1681168827Sphk		else
1682168827Sphk			ifp->if_hwassist = 0;
1683128118Sru		break;
168441502Swpaul	default:
1685106936Ssam		error = ether_ioctl(ifp, command, data);
168641502Swpaul		break;
168741502Swpaul	}
168841502Swpaul
1689131503Sbms	return (error);
169041502Swpaul}
169141502Swpaul
1692102336Salfredstatic void
1693131503Sbmsvr_watchdog(struct ifnet *ifp)
169441502Swpaul{
1695131518Sbms	struct vr_softc		*sc = ifp->if_softc;
169641502Swpaul
169767087Swpaul	VR_LOCK(sc);
1698131844Sbms
169941502Swpaul	ifp->if_oerrors++;
1700151773Sjhb	if_printf(ifp, "watchdog timeout\n");
170141502Swpaul
170241502Swpaul	vr_stop(sc);
170341502Swpaul	vr_reset(sc);
1704131844Sbms	vr_init_locked(sc);
1705131518Sbms
1706132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1707131844Sbms		vr_start_locked(ifp);
1708131844Sbms
1709131844Sbms	VR_UNLOCK(sc);
171041502Swpaul}
171141502Swpaul
171241502Swpaul/*
171341502Swpaul * Stop the adapter and free any mbufs allocated to the
171441502Swpaul * RX and TX lists.
171541502Swpaul */
1716102336Salfredstatic void
1717131503Sbmsvr_stop(struct vr_softc *sc)
171841502Swpaul{
1719131503Sbms	register int	i;
1720131503Sbms	struct ifnet	*ifp;
172141502Swpaul
1722131518Sbms	VR_LOCK_ASSERT(sc);
172367087Swpaul
1724147256Sbrooks	ifp = sc->vr_ifp;
172541502Swpaul	ifp->if_timer = 0;
172641502Swpaul
1727151911Sjhb	callout_stop(&sc->vr_stat_callout);
1728148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
172951432Swpaul
173041502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
173141502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
173241502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
173341502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
173441502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
173541502Swpaul
173641502Swpaul	/*
173741502Swpaul	 * Free data in the RX lists.
173841502Swpaul	 */
173941502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
174041502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
174141502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
174241502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
174341502Swpaul		}
174441502Swpaul	}
174541502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
1746131517Sbms	    sizeof(sc->vr_ldata->vr_rx_list));
174741502Swpaul
174841502Swpaul	/*
174941502Swpaul	 * Free the TX list buffers.
175041502Swpaul	 */
175141502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
175241502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
175341502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
175441502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
175541502Swpaul		}
175641502Swpaul	}
175741502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
1758131517Sbms	    sizeof(sc->vr_ldata->vr_tx_list));
175941502Swpaul}
176041502Swpaul
176141502Swpaul/*
176241502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
176341502Swpaul * get confused by errant DMAs when rebooting.
176441502Swpaul */
1765102336Salfredstatic void
1766131503Sbmsvr_shutdown(device_t dev)
176741502Swpaul{
176841502Swpaul
1769136696Sbms	vr_detach(dev);
177041502Swpaul}
1771