if_vr.c revision 168953
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 168953 2007-04-22 15:58:56Z 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 *
56168953Sphk * Some Rhine chips 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
10641502Swpaul/*
107168952Sphk * Various supported device vendors/types, their names & quirks
10841502Swpaul */
109168952Sphk
110168952Sphk#define VR_Q_NEEDALIGN		(1<<0)
111168952Sphk#define VR_Q_CSUM		(1<<1)
112168952Sphk
113168952Sphkstatic struct vr_type {
114168952Sphk	u_int16_t		vr_vid;
115168952Sphk	u_int16_t		vr_did;
116168952Sphk	int			vr_quirks;
117168952Sphk	char			*vr_name;
118168952Sphk} vr_devs[] = {
119168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
120168827Sphk	    VR_Q_NEEDALIGN,
121168827Sphk	    "VIA VT3043 Rhine I 10/100BaseTX" },
122168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
123168827Sphk	    VR_Q_NEEDALIGN,
124168827Sphk	    "VIA VT86C100A Rhine II 10/100BaseTX" },
125168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
126168827Sphk	    0,
127168827Sphk	    "VIA VT6102 Rhine II 10/100BaseTX" },
128168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III,
129168827Sphk	    0,
130168827Sphk	    "VIA VT6105 Rhine III 10/100BaseTX" },
131168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
132168827Sphk	    VR_Q_CSUM,
133168827Sphk	    "VIA VT6105M Rhine III 10/100BaseTX" },
134168827Sphk	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
135168827Sphk	    VR_Q_NEEDALIGN,
136168827Sphk	    "Delta Electronics Rhine II 10/100BaseTX" },
137168827Sphk	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
138168827Sphk	    VR_Q_NEEDALIGN,
139168827Sphk	    "Addtron Technology Rhine II 10/100BaseTX" },
140168813Sphk	{ 0, 0, 0, NULL }
14141502Swpaul};
14241502Swpaul
143168952Sphkstruct vr_list_data {
144168952Sphk	struct vr_desc		vr_rx_list[VR_RX_LIST_CNT];
145168952Sphk	struct vr_desc		vr_tx_list[VR_TX_LIST_CNT];
146168952Sphk};
147168946Sphk
148168946Sphkstruct vr_softc {
149168946Sphk	struct ifnet		*vr_ifp;	/* interface info */
150168946Sphk	device_t		vr_dev;
151168946Sphk	struct resource		*vr_res;
152168946Sphk	struct resource		*vr_irq;
153168946Sphk	void			*vr_intrhand;
154168946Sphk	device_t		vr_miibus;
155168946Sphk	u_int8_t		vr_revid;	/* Rhine chip revision */
156168946Sphk	u_int8_t                vr_flags;       /* See VR_F_* below */
157168946Sphk	struct vr_list_data	*vr_ldata;
158168946Sphk	struct callout		vr_stat_callout;
159168946Sphk	struct mtx		vr_mtx;
160168948Sphk	int			vr_suspended;	/* if 1, sleeping/detaching */
161168946Sphk	int			vr_quirks;
162168952Sphk	struct vr_desc		*vr_rx_head;
163168952Sphk	struct vr_desc		*vr_tx_cons;
164168952Sphk	struct vr_desc		*vr_tx_prod;
165168946Sphk#ifdef DEVICE_POLLING
166168946Sphk	int			rxcycles;
167168946Sphk#endif
168168946Sphk};
169168946Sphk
170142407Simpstatic int vr_probe(device_t);
171142407Simpstatic int vr_attach(device_t);
172142407Simpstatic int vr_detach(device_t);
17341502Swpaul
174168952Sphkstatic int vr_newbuf(struct vr_desc *, struct mbuf *);
17541502Swpaul
176142407Simpstatic void vr_rxeof(struct vr_softc *);
177142407Simpstatic void vr_rxeoc(struct vr_softc *);
178142407Simpstatic void vr_txeof(struct vr_softc *);
179142407Simpstatic void vr_tick(void *);
180142407Simpstatic void vr_intr(void *);
181142407Simpstatic void vr_start(struct ifnet *);
182142407Simpstatic void vr_start_locked(struct ifnet *);
183142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t);
184142407Simpstatic void vr_init(void *);
185142407Simpstatic void vr_init_locked(struct vr_softc *);
186142407Simpstatic void vr_stop(struct vr_softc *);
187142407Simpstatic void vr_watchdog(struct ifnet *);
188142407Simpstatic void vr_shutdown(device_t);
189142407Simpstatic int vr_ifmedia_upd(struct ifnet *);
190142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
19141502Swpaul
192168946Sphkstatic int vr_mii_readreg(const struct vr_softc *, struct vr_mii_frame *);
193168946Sphkstatic int vr_mii_writereg(const struct vr_softc *, const struct vr_mii_frame *);
194142407Simpstatic int vr_miibus_readreg(device_t, uint16_t, uint16_t);
195142407Simpstatic int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t);
196142407Simpstatic void vr_miibus_statchg(device_t);
19741502Swpaul
198142407Simpstatic void vr_setcfg(struct vr_softc *, int);
199142407Simpstatic void vr_setmulti(struct vr_softc *);
200168946Sphkstatic void vr_reset(const struct vr_softc *);
201142407Simpstatic int vr_list_rx_init(struct vr_softc *);
202142407Simpstatic int vr_list_tx_init(struct vr_softc *);
20341502Swpaul
20449610Swpaul#ifdef VR_USEIOSPACE
20549610Swpaul#define VR_RES			SYS_RES_IOPORT
20649610Swpaul#define VR_RID			VR_PCI_LOIO
20749610Swpaul#else
20849610Swpaul#define VR_RES			SYS_RES_MEMORY
20949610Swpaul#define VR_RID			VR_PCI_LOMEM
21049610Swpaul#endif
21149610Swpaul
21249610Swpaulstatic device_method_t vr_methods[] = {
21349610Swpaul	/* Device interface */
21449610Swpaul	DEVMETHOD(device_probe,		vr_probe),
21549610Swpaul	DEVMETHOD(device_attach,	vr_attach),
21649610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
21749610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
21851432Swpaul
21951432Swpaul	/* bus interface */
22051432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
22151432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
22251432Swpaul
22351432Swpaul	/* MII interface */
22451432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
22551432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
22651432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
22751432Swpaul
22849610Swpaul	{ 0, 0 }
22949610Swpaul};
23049610Swpaul
23149610Swpaulstatic driver_t vr_driver = {
23251455Swpaul	"vr",
23349610Swpaul	vr_methods,
23449610Swpaul	sizeof(struct vr_softc)
23549610Swpaul};
23649610Swpaul
23749610Swpaulstatic devclass_t vr_devclass;
23849610Swpaul
239113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0);
24051473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
241168946Sphk#define VR_F_RESTART		0x01		/* Restart unit on next tick */
24249610Swpaul
243168946Sphk#define	VR_LOCK(_sc)		mtx_lock(&(_sc)->vr_mtx)
244168946Sphk#define	VR_UNLOCK(_sc)		mtx_unlock(&(_sc)->vr_mtx)
245168946Sphk#define	VR_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->vr_mtx, MA_OWNED)
24641502Swpaul
247168946Sphk/*
248168946Sphk * register space access macros
249168946Sphk */
250168946Sphk#define CSR_WRITE_4(sc, reg, val)	bus_write_4(sc->vr_res, reg, val)
251168946Sphk#define CSR_WRITE_2(sc, reg, val)	bus_write_2(sc->vr_res, reg, val)
252168946Sphk#define CSR_WRITE_1(sc, reg, val)	bus_write_1(sc->vr_res, reg, val)
25341502Swpaul
254168946Sphk#define CSR_READ_2(sc, reg)		bus_read_2(sc->vr_res, reg)
255168946Sphk#define CSR_READ_1(sc, reg)		bus_read_1(sc->vr_res, reg)
25641502Swpaul
257168946Sphk#define VR_SETBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | (x))
258168946Sphk#define VR_CLRBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~(x))
25941502Swpaul
260168946Sphk#define VR_SETBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | (x))
261168946Sphk#define VR_CLRBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~(x))
26241502Swpaul
26341502Swpaul
26441502Swpaul/*
26541502Swpaul * Read an PHY register through the MII.
26641502Swpaul */
267102336Salfredstatic int
268168946Sphkvr_mii_readreg(const struct vr_softc *sc, struct vr_mii_frame *frame)
26941502Swpaul{
270131518Sbms	int	i;
27141502Swpaul
272131503Sbms	/* Set the PHY address. */
273110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
274110168Ssilby	    frame->mii_phyaddr);
275110168Ssilby
276131503Sbms	/* Set the register address. */
277110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
278110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
279131503Sbms
280110168Ssilby	for (i = 0; i < 10000; i++) {
281110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
282110168Ssilby			break;
283110168Ssilby		DELAY(1);
284110168Ssilby	}
285110168Ssilby	frame->mii_data = CSR_READ_2(sc, VR_MIIDATA);
286110168Ssilby
287131503Sbms	return (0);
288110168Ssilby}
289110168Ssilby
290110168Ssilby
29141502Swpaul/*
29241502Swpaul * Write to a PHY register through the MII.
29341502Swpaul */
294102336Salfredstatic int
295168946Sphkvr_mii_writereg(const struct vr_softc *sc, const struct vr_mii_frame *frame)
29641502Swpaul{
297131518Sbms	int	i;
29841502Swpaul
299131503Sbms	/* Set the PHY address. */
300110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
301131503Sbms	    frame->mii_phyaddr);
302110168Ssilby
303131503Sbms	/* Set the register address and data to write. */
304110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
305110168Ssilby	CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data);
306110168Ssilby
307110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
308110168Ssilby
309110168Ssilby	for (i = 0; i < 10000; i++) {
310110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
311110168Ssilby			break;
312110168Ssilby		DELAY(1);
313110168Ssilby	}
314110168Ssilby
315131503Sbms	return (0);
316110168Ssilby}
317110168Ssilby
318102336Salfredstatic int
319131517Sbmsvr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg)
32051432Swpaul{
32141502Swpaul	struct vr_mii_frame	frame;
322131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
32341502Swpaul
324168946Sphk	if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1)
325168946Sphk		return (0);
326110168Ssilby
32741502Swpaul	bzero((char *)&frame, sizeof(frame));
32851432Swpaul	frame.mii_phyaddr = phy;
32941502Swpaul	frame.mii_regaddr = reg;
33041502Swpaul	vr_mii_readreg(sc, &frame);
331131503Sbms	return (frame.mii_data);
33241502Swpaul}
33341502Swpaul
334102336Salfredstatic int
335131503Sbmsvr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data)
33651432Swpaul{
33741502Swpaul	struct vr_mii_frame	frame;
338131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
33941502Swpaul
340168946Sphk	if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1)
341168946Sphk		return (0);
342110168Ssilby
34341502Swpaul	bzero((char *)&frame, sizeof(frame));
34451432Swpaul	frame.mii_phyaddr = phy;
34541502Swpaul	frame.mii_regaddr = reg;
34641502Swpaul	frame.mii_data = data;
34741502Swpaul	vr_mii_writereg(sc, &frame);
34841502Swpaul
349131503Sbms	return (0);
35051432Swpaul}
35151432Swpaul
352102336Salfredstatic void
353131503Sbmsvr_miibus_statchg(device_t dev)
35451432Swpaul{
35551432Swpaul	struct mii_data		*mii;
356131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
35751432Swpaul
35851432Swpaul	mii = device_get_softc(sc->vr_miibus);
35951432Swpaul	vr_setcfg(sc, mii->mii_media_active);
36041502Swpaul}
36141502Swpaul
36241502Swpaul/*
36341502Swpaul * Program the 64-bit multicast hash filter.
36441502Swpaul */
365102336Salfredstatic void
366131503Sbmsvr_setmulti(struct vr_softc *sc)
36741502Swpaul{
368147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
36941502Swpaul	int			h = 0;
370131503Sbms	uint32_t		hashes[2] = { 0, 0 };
37141502Swpaul	struct ifmultiaddr	*ifma;
372131503Sbms	uint8_t			rxfilt;
37341502Swpaul	int			mcnt = 0;
37441502Swpaul
375131518Sbms	VR_LOCK_ASSERT(sc);
37641502Swpaul
37741502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
37841502Swpaul
37941502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
38041502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
38141502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
38241502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
38341502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
38441502Swpaul		return;
38541502Swpaul	}
38641502Swpaul
387131503Sbms	/* First, zero out all the existing hash bits. */
38841502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
38941502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
39041502Swpaul
391131503Sbms	/* Now program new ones. */
392148654Srwatson	IF_ADDR_LOCK(ifp);
39372084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
39441502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
39541502Swpaul			continue;
396130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
397130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
39841502Swpaul		if (h < 32)
39941502Swpaul			hashes[0] |= (1 << h);
40041502Swpaul		else
40141502Swpaul			hashes[1] |= (1 << (h - 32));
40241502Swpaul		mcnt++;
40341502Swpaul	}
404148654Srwatson	IF_ADDR_UNLOCK(ifp);
40541502Swpaul
40641502Swpaul	if (mcnt)
40741502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
40841502Swpaul	else
40941502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
41041502Swpaul
41141502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
41241502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
41341502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
41441502Swpaul}
41541502Swpaul
41641502Swpaul/*
41741502Swpaul * In order to fiddle with the
41841502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
41941502Swpaul * first have to put the transmit and/or receive logic in the idle state.
42041502Swpaul */
421102336Salfredstatic void
422131503Sbmsvr_setcfg(struct vr_softc *sc, int media)
42341502Swpaul{
424131517Sbms	int	restart = 0;
42541502Swpaul
426131518Sbms	VR_LOCK_ASSERT(sc);
427131518Sbms
42841502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
42941502Swpaul		restart = 1;
43041502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
43141502Swpaul	}
43241502Swpaul
43351432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
43441502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
43541502Swpaul	else
43641502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
43741502Swpaul
43841502Swpaul	if (restart)
43941502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
44041502Swpaul}
44141502Swpaul
442102336Salfredstatic void
443168946Sphkvr_reset(const struct vr_softc *sc)
44441502Swpaul{
445131517Sbms	register int	i;
44641502Swpaul
447151773Sjhb	/*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during attach w/o lock. */
448131518Sbms
44941502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
45041502Swpaul
45141502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
45241502Swpaul		DELAY(10);
45341502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
45441502Swpaul			break;
45541502Swpaul	}
456107220Ssilby	if (i == VR_TIMEOUT) {
457107220Ssilby		if (sc->vr_revid < REV_ID_VT3065_A)
458162315Sglebius			device_printf(sc->vr_dev, "reset never completed!\n");
459107220Ssilby		else {
460107220Ssilby			/* Use newer force reset command */
461162315Sglebius			device_printf(sc->vr_dev, "Using force reset command.\n");
462107220Ssilby			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
463107220Ssilby		}
464107220Ssilby	}
46541502Swpaul
46641502Swpaul	/* Wait a little while for the chip to get its brains in order. */
46741502Swpaul	DELAY(1000);
46841502Swpaul}
46941502Swpaul
47041502Swpaul/*
47141502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
472168813Sphk * IDs against our list and return a match or NULL
473168813Sphk */
474168813Sphkstatic struct vr_type *
475168813Sphkvr_match(device_t dev)
476168813Sphk{
477168813Sphk	struct vr_type	*t = vr_devs;
478168813Sphk
479168813Sphk	for (t = vr_devs; t->vr_name != NULL; t++)
480168813Sphk		if ((pci_get_vendor(dev) == t->vr_vid) &&
481168813Sphk		    (pci_get_device(dev) == t->vr_did))
482168813Sphk			return (t);
483168813Sphk	return (NULL);
484168813Sphk}
485168813Sphk
486168813Sphk/*
487168813Sphk * Probe for a VIA Rhine chip. Check the PCI vendor and device
48841502Swpaul * IDs against our list and return a device name if we find a match.
48941502Swpaul */
490102336Salfredstatic int
491131503Sbmsvr_probe(device_t dev)
49241502Swpaul{
493168813Sphk	struct vr_type	*t;
49441502Swpaul
495168813Sphk	t = vr_match(dev);
496168813Sphk	if (t != NULL) {
497168813Sphk		device_set_desc(dev, t->vr_name);
498168813Sphk		return (BUS_PROBE_DEFAULT);
49941502Swpaul	}
500131503Sbms	return (ENXIO);
50141502Swpaul}
50241502Swpaul
50341502Swpaul/*
50441502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
50541502Swpaul * setup and ethernet/BPF attach.
50641502Swpaul */
507102336Salfredstatic int
508168946Sphkvr_attach(device_t dev)
50941502Swpaul{
51067087Swpaul	int			i;
51141502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
51241502Swpaul	struct vr_softc		*sc;
51341502Swpaul	struct ifnet		*ifp;
514168946Sphk	int			error = 0, rid;
515168813Sphk	struct vr_type		*t;
51641502Swpaul
51749610Swpaul	sc = device_get_softc(dev);
518162315Sglebius	sc->vr_dev = dev;
519168813Sphk	t = vr_match(dev);
520168813Sphk	KASSERT(t != NULL, ("Lost if_vr device match"));
521168813Sphk	sc->vr_quirks = t->vr_quirks;
522168813Sphk	device_printf(dev, "Quirks: 0x%x\n", sc->vr_quirks);
52341502Swpaul
52493818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
525131518Sbms	    MTX_DEF);
526151911Sjhb	callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0);
527151911Sjhb
52841502Swpaul	/*
52941502Swpaul	 * Map control/status registers.
53041502Swpaul	 */
53172813Swpaul	pci_enable_busmaster(dev);
532107220Ssilby	sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF;
53341502Swpaul
53449610Swpaul	rid = VR_RID;
535127135Snjl	sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE);
53649610Swpaul
53749610Swpaul	if (sc->vr_res == NULL) {
538151773Sjhb		device_printf(dev, "couldn't map ports/memory\n");
53949610Swpaul		error = ENXIO;
54041502Swpaul		goto fail;
54141502Swpaul	}
54241502Swpaul
54341502Swpaul	/* Allocate interrupt */
54449610Swpaul	rid = 0;
545127135Snjl	sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
54649610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
54749610Swpaul
54849610Swpaul	if (sc->vr_irq == NULL) {
549151773Sjhb		device_printf(dev, "couldn't map interrupt\n");
55049610Swpaul		error = ENXIO;
55141502Swpaul		goto fail;
55241502Swpaul	}
55341502Swpaul
554151773Sjhb	/* Allocate ifnet structure. */
555151773Sjhb	ifp = sc->vr_ifp = if_alloc(IFT_ETHER);
556151773Sjhb	if (ifp == NULL) {
557151773Sjhb		device_printf(dev, "can not if_alloc()\n");
558151773Sjhb		error = ENOSPC;
559151773Sjhb		goto fail;
560151773Sjhb	}
561151773Sjhb	ifp->if_softc = sc;
562151773Sjhb	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
563151773Sjhb	ifp->if_mtu = ETHERMTU;
564151773Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
565151773Sjhb	ifp->if_ioctl = vr_ioctl;
566151773Sjhb	ifp->if_start = vr_start;
567151773Sjhb	ifp->if_watchdog = vr_watchdog;
568151773Sjhb	ifp->if_init = vr_init;
569151773Sjhb	IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1);
570151773Sjhb	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
571151773Sjhb	IFQ_SET_READY(&ifp->if_snd);
572168827Sphk
573168827Sphk	if (sc->vr_quirks & VR_Q_CSUM) {
574168827Sphk		ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
575168827Sphk		ifp->if_capabilities |= IFCAP_HWCSUM;
576168827Sphk	}
577168827Sphk
578151773Sjhb	ifp->if_capenable = ifp->if_capabilities;
579168827Sphk	if (ifp->if_capenable & IFCAP_TXCSUM)
580168827Sphk		ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
581168827Sphk	else
582168827Sphk		ifp->if_hwassist = 0;
583168827Sphk
584151773Sjhb#ifdef DEVICE_POLLING
585151773Sjhb	ifp->if_capabilities |= IFCAP_POLLING;
586151773Sjhb#endif
587151773Sjhb
58876586Swpaul	/*
58976586Swpaul	 * Windows may put the chip in suspend mode when it
59076586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
59176586Swpaul	 * up again.
59276586Swpaul	 */
59376586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
59476586Swpaul
59541502Swpaul	/* Reset the adapter. */
59641502Swpaul	vr_reset(sc);
59741502Swpaul
598131503Sbms	/*
599110168Ssilby	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
600110168Ssilby	 * initialization and disable AUTOPOLL.
601110168Ssilby	 */
602131503Sbms	pci_write_config(dev, VR_PCI_MODE,
603110168Ssilby	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
604110168Ssilby	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
605110168Ssilby
60641502Swpaul	/*
60741502Swpaul	 * Get station address. The way the Rhine chips work,
60841502Swpaul	 * you're not allowed to directly access the EEPROM once
60941502Swpaul	 * they've been programmed a special way. Consequently,
61041502Swpaul	 * we need to read the node address from the PAR0 and PAR1
61141502Swpaul	 * registers.
61241502Swpaul	 */
61341502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
61441502Swpaul	DELAY(200);
61541502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
61641502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
61741502Swpaul
61851432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
619151773Sjhb	    M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
62051432Swpaul
62151432Swpaul	if (sc->vr_ldata == NULL) {
622151773Sjhb		device_printf(dev, "no memory for list buffers!\n");
62349610Swpaul		error = ENXIO;
62449610Swpaul		goto fail;
62541502Swpaul	}
62641502Swpaul
627131503Sbms	/* Do MII setup. */
62851432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
62951432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
630151773Sjhb		device_printf(dev, "MII without any phy!\n");
63149610Swpaul		error = ENXIO;
63241502Swpaul		goto fail;
63341502Swpaul	}
63441502Swpaul
635131503Sbms	/* Call MI attach routine. */
636106936Ssam	ether_ifattach(ifp, eaddr);
63741502Swpaul
638168948Sphk	sc->vr_suspended = 0;
639131844Sbms
640113609Snjl	/* Hook interrupt last to avoid having to lock softc */
641131518Sbms	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE,
642166901Spiso	    NULL, vr_intr, sc, &sc->vr_intrhand);
643112872Snjl
644112872Snjl	if (error) {
645151773Sjhb		device_printf(dev, "couldn't set up irq\n");
646113609Snjl		ether_ifdetach(ifp);
647112872Snjl		goto fail;
648112872Snjl	}
649112872Snjl
65041502Swpaulfail:
651112872Snjl	if (error)
652112872Snjl		vr_detach(dev);
65367087Swpaul
654131503Sbms	return (error);
65541502Swpaul}
65641502Swpaul
657113609Snjl/*
658113609Snjl * Shutdown hardware and free up resources. This can be called any
659113609Snjl * time after the mutex has been initialized. It is called in both
660113609Snjl * the error case in attach and the normal detach case so it needs
661113609Snjl * to be careful about only freeing resources that have actually been
662113609Snjl * allocated.
663113609Snjl */
664102336Salfredstatic int
665131503Sbmsvr_detach(device_t dev)
66649610Swpaul{
667131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
668147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
66949610Swpaul
670112880Sjhb	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
671131518Sbms
672150789Sglebius#ifdef DEVICE_POLLING
673150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
674150789Sglebius		ether_poll_deregister(ifp);
675150789Sglebius#endif
676150789Sglebius
677113609Snjl	/* These should only be active if attach succeeded */
678113812Simp	if (device_is_attached(dev)) {
679151911Sjhb		VR_LOCK(sc);
680168948Sphk		sc->vr_suspended = 1;
681113609Snjl		vr_stop(sc);
682151911Sjhb		VR_UNLOCK(sc);
683151911Sjhb		callout_drain(&sc->vr_stat_callout);
684112872Snjl		ether_ifdetach(ifp);
685113609Snjl	}
686113609Snjl	if (sc->vr_miibus)
687112872Snjl		device_delete_child(dev, sc->vr_miibus);
688113609Snjl	bus_generic_detach(dev);
68949610Swpaul
690112872Snjl	if (sc->vr_intrhand)
691112872Snjl		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
692112872Snjl	if (sc->vr_irq)
693112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
694112872Snjl	if (sc->vr_res)
695112872Snjl		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
69651432Swpaul
697151297Sru	if (ifp)
698151297Sru		if_free(ifp);
699151297Sru
700112872Snjl	if (sc->vr_ldata)
701112872Snjl		contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
70249610Swpaul
70367087Swpaul	mtx_destroy(&sc->vr_mtx);
70449610Swpaul
705131503Sbms	return (0);
70649610Swpaul}
70749610Swpaul
70841502Swpaul/*
70941502Swpaul * Initialize the transmit descriptors.
71041502Swpaul */
711102336Salfredstatic int
712131503Sbmsvr_list_tx_init(struct vr_softc *sc)
71341502Swpaul{
71441502Swpaul	struct vr_list_data	*ld;
71541502Swpaul	int			i;
71641502Swpaul
71741502Swpaul	ld = sc->vr_ldata;
71841502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
719168950Sphk		if (i == (VR_TX_LIST_CNT - 1)) {
720168952Sphk			ld->vr_tx_list[i].vr_next =
721168952Sphk			    &ld->vr_tx_list[0];
722168950Sphk			ld->vr_tx_list[i].vr_nextphys =
723168950Sphk			    vtophys(&ld->vr_tx_list[0]);
724168950Sphk		} else {
725168952Sphk			ld->vr_tx_list[i].vr_next =
726168952Sphk				&ld->vr_tx_list[i + 1];
727168950Sphk			ld->vr_tx_list[i].vr_nextphys =
728168950Sphk			    vtophys(&ld->vr_tx_list[i + 1]);
729168950Sphk		}
73041502Swpaul	}
731168952Sphk	sc->vr_tx_cons = sc->vr_tx_prod = &ld->vr_tx_list[0];
73241502Swpaul
733131503Sbms	return (0);
73441502Swpaul}
73541502Swpaul
73641502Swpaul
73741502Swpaul/*
73841502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
73941502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
74041502Swpaul * points back to the first.
74141502Swpaul */
742102336Salfredstatic int
743131503Sbmsvr_list_rx_init(struct vr_softc *sc)
74441502Swpaul{
74541502Swpaul	struct vr_list_data	*ld;
74641502Swpaul	int			i;
74741502Swpaul
748131518Sbms	VR_LOCK_ASSERT(sc);
749131518Sbms
75041502Swpaul	ld = sc->vr_ldata;
75141502Swpaul
75241502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
753168952Sphk		if (vr_newbuf(&ld->vr_rx_list[i], NULL) == ENOBUFS)
754131503Sbms			return (ENOBUFS);
75541502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
756168952Sphk			ld->vr_rx_list[i].vr_next = &ld->vr_rx_list[0];
757168948Sphk			ld->vr_rx_list[i].vr_nextphys =
75841502Swpaul					vtophys(&ld->vr_rx_list[0]);
75941502Swpaul		} else {
760168952Sphk			ld->vr_rx_list[i].vr_next =
761168952Sphk					&ld->vr_rx_list[i + 1];
762168948Sphk			ld->vr_rx_list[i].vr_nextphys =
76341502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
76441502Swpaul		}
76541502Swpaul	}
76641502Swpaul
767168952Sphk	sc->vr_rx_head = &ld->vr_rx_list[0];
76841502Swpaul
769131503Sbms	return (0);
77041502Swpaul}
77141502Swpaul
77241502Swpaul/*
77341502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
77441502Swpaul * Note: the length fields are only 11 bits wide, which means the
77541502Swpaul * largest size we can specify is 2047. This is important because
77641502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
77741502Swpaul * overflow the field and make a mess.
77841502Swpaul */
779102336Salfredstatic int
780168952Sphkvr_newbuf(struct vr_desc *c, struct mbuf *m)
78141502Swpaul{
78241502Swpaul	struct mbuf		*m_new = NULL;
78341502Swpaul
78449610Swpaul	if (m == NULL) {
785168952Sphk		m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
78687846Sluigi		if (m_new == NULL)
787131503Sbms			return (ENOBUFS);
78849610Swpaul	} else {
78949610Swpaul		m_new = m;
79049610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
79149610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
79241502Swpaul	}
79341502Swpaul
794131503Sbms	m_adj(m_new, sizeof(uint64_t));
79549610Swpaul
79641502Swpaul	c->vr_mbuf = m_new;
797168952Sphk	c->vr_status = VR_RXSTAT;
798168952Sphk	c->vr_data = vtophys(mtod(m_new, caddr_t));
799168952Sphk	c->vr_ctl = VR_RXCTL | VR_RXLEN;
80041502Swpaul
801131503Sbms	return (0);
80241502Swpaul}
80341502Swpaul
80441502Swpaul/*
80541502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
80641502Swpaul * the higher level protocols.
80741502Swpaul */
808102336Salfredstatic void
809131503Sbmsvr_rxeof(struct vr_softc *sc)
81041502Swpaul{
811131503Sbms	struct mbuf		*m, *m0;
812131503Sbms	struct ifnet		*ifp;
813168952Sphk	struct vr_desc		*cur_rx;
81441502Swpaul	int			total_len = 0;
815168827Sphk	uint32_t		rxstat, rxctl;
81641502Swpaul
817122689Ssam	VR_LOCK_ASSERT(sc);
818147256Sbrooks	ifp = sc->vr_ifp;
81941502Swpaul
820168952Sphk	while (!((rxstat = sc->vr_rx_head->vr_status) &
821131503Sbms	    VR_RXSTAT_OWN)) {
822127901Sru#ifdef DEVICE_POLLING
823150789Sglebius		if (ifp->if_capenable & IFCAP_POLLING) {
824127901Sru			if (sc->rxcycles <= 0)
825127901Sru				break;
826127901Sru			sc->rxcycles--;
827127901Sru		}
828150789Sglebius#endif
829127901Sru		m0 = NULL;
830168952Sphk		cur_rx = sc->vr_rx_head;
831168952Sphk		sc->vr_rx_head = cur_rx->vr_next;
83249610Swpaul		m = cur_rx->vr_mbuf;
83341502Swpaul
83441502Swpaul		/*
83541502Swpaul		 * If an error occurs, update stats, clear the
83641502Swpaul		 * status word and leave the mbuf cluster in place:
83741502Swpaul		 * it should simply get re-used next time this descriptor
838131503Sbms		 * comes up in the ring.
83941502Swpaul		 */
84041502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
84141502Swpaul			ifp->if_ierrors++;
842162315Sglebius			device_printf(sc->vr_dev,
843162315Sglebius			    "rx error (%02x):", rxstat & 0x000000ff);
844110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
845110131Ssilby				printf(" crc error");
846110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
847110131Ssilby				printf(" frame alignment error\n");
848110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
849110131Ssilby				printf(" FIFO overflow");
850110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
851110131Ssilby				printf(" received giant packet");
852110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
853110131Ssilby				printf(" received runt packet");
854110131Ssilby			if (rxstat & VR_RXSTAT_BUSERR)
855110131Ssilby				printf(" system bus error");
856110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
857110131Ssilby				printf("rx buffer error");
858110131Ssilby			printf("\n");
859168946Sphk			vr_newbuf(cur_rx, m);
86041502Swpaul			continue;
86141502Swpaul		}
86241502Swpaul
863131503Sbms		/* No errors; receive the packet. */
864168952Sphk		total_len = VR_RXBYTES(cur_rx->vr_status);
865168827Sphk		if (ifp->if_capenable & IFCAP_RXCSUM) {
866168952Sphk			rxctl = cur_rx->vr_ctl;
867168827Sphk			if ((rxctl & VR_RXCTL_GOODIP) == VR_RXCTL_GOODIP)
868168827Sphk				m->m_pkthdr.csum_flags |=
869168827Sphk				    CSUM_IP_CHECKED | CSUM_IP_VALID;
870168827Sphk			if ((rxctl & VR_RXCTL_GOODTCPUDP)) {
871168827Sphk				m->m_pkthdr.csum_flags |=
872168827Sphk				    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
873168827Sphk				m->m_pkthdr.csum_data = 0xffff;
874168827Sphk			}
875168827Sphk		}
87641502Swpaul
87741502Swpaul		/*
87842048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
87942048Swpaul		 * received frame, and there's no way to turn this
88042048Swpaul		 * behavior off (at least, I can't find anything in
881131503Sbms		 * the manual that explains how to do it) so we have
88242048Swpaul		 * to trim off the CRC manually.
88342048Swpaul		 */
88442048Swpaul		total_len -= ETHER_CRC_LEN;
88542048Swpaul
88678508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
88778508Sbmilekic		    NULL);
888168946Sphk		vr_newbuf(cur_rx, m);
88949610Swpaul		if (m0 == NULL) {
89041502Swpaul			ifp->if_ierrors++;
89141502Swpaul			continue;
89241502Swpaul		}
89349610Swpaul		m = m0;
89441502Swpaul
89541502Swpaul		ifp->if_ipackets++;
896122689Ssam		VR_UNLOCK(sc);
897106936Ssam		(*ifp->if_input)(ifp, m);
898122689Ssam		VR_LOCK(sc);
89941502Swpaul	}
90041502Swpaul}
90141502Swpaul
902105221Sphkstatic void
903131503Sbmsvr_rxeoc(struct vr_softc *sc)
90441502Swpaul{
905147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
906110131Ssilby	int			i;
90741502Swpaul
908131518Sbms	VR_LOCK_ASSERT(sc);
909131518Sbms
910110131Ssilby	ifp->if_ierrors++;
911110131Ssilby
912131503Sbms	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
913131503Sbms	DELAY(10000);
914110131Ssilby
915131503Sbms	/* Wait for receiver to stop */
916110131Ssilby	for (i = 0x400;
917110131Ssilby	     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON);
918131503Sbms	     i--) {
919131503Sbms		;
920131503Sbms	}
921110131Ssilby
922110131Ssilby	if (!i) {
923162315Sglebius		device_printf(sc->vr_dev, "rx shutdown error!\n");
924110131Ssilby		sc->vr_flags |= VR_F_RESTART;
925110131Ssilby		return;
926131503Sbms	}
927110131Ssilby
92841502Swpaul	vr_rxeof(sc);
929110131Ssilby
930168952Sphk	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_rx_head));
93141502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
93241502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
93341502Swpaul}
93441502Swpaul
93541502Swpaul/*
93641502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
93741502Swpaul * the list buffers.
93841502Swpaul */
939102336Salfredstatic void
940131503Sbmsvr_txeof(struct vr_softc *sc)
94141502Swpaul{
942168952Sphk	struct vr_desc		*cur_tx;
943147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
94441502Swpaul
945131518Sbms	VR_LOCK_ASSERT(sc);
94641502Swpaul
94741502Swpaul	/*
94841502Swpaul	 * Go through our tx list and free mbufs for those
94941502Swpaul	 * frames that have been transmitted.
95041502Swpaul	 */
951168952Sphk	cur_tx = sc->vr_tx_cons;
952168952Sphk	while (cur_tx != sc->vr_tx_prod) {
953131503Sbms		uint32_t		txstat;
954110131Ssilby		int			i;
95541502Swpaul
956168952Sphk		txstat = cur_tx->vr_status;
95741502Swpaul
958101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
959101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
960110131Ssilby			for (i = 0x400;
961110131Ssilby			     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON);
962110131Ssilby			     i--)
963101896Ssilby				;	/* Wait for chip to shutdown */
964110131Ssilby			if (!i) {
965162315Sglebius				device_printf(sc->vr_dev, "tx shutdown timeout\n");
966110131Ssilby				sc->vr_flags |= VR_F_RESTART;
967110131Ssilby				break;
968110131Ssilby			}
969168952Sphk			atomic_set_acq_32(&cur_tx->vr_status, VR_TXSTAT_OWN);
970168952Sphk			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx));
971101896Ssilby			break;
972101896Ssilby		}
973101896Ssilby
97442491Swpaul		if (txstat & VR_TXSTAT_OWN)
97541502Swpaul			break;
97641502Swpaul
97741502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
97841502Swpaul			ifp->if_oerrors++;
97941502Swpaul			if (txstat & VR_TXSTAT_DEFER)
98041502Swpaul				ifp->if_collisions++;
98141502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
98241502Swpaul				ifp->if_collisions++;
98341502Swpaul		}
98441502Swpaul
98541502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
98641502Swpaul
98741502Swpaul		ifp->if_opackets++;
988168813Sphk		if (cur_tx->vr_mbuf != NULL)
989168813Sphk			m_freem(cur_tx->vr_mbuf);
990127901Sru		cur_tx->vr_mbuf = NULL;
991148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
99241502Swpaul
993168952Sphk		cur_tx = cur_tx->vr_next;
99441502Swpaul	}
995168952Sphk	sc->vr_tx_cons = cur_tx;
996127901Sru	if (cur_tx->vr_mbuf == NULL)
99796677Ssilby		ifp->if_timer = 0;
99841502Swpaul}
99941502Swpaul
1000102336Salfredstatic void
1001131503Sbmsvr_tick(void *xsc)
100251432Swpaul{
1003131503Sbms	struct vr_softc		*sc = xsc;
100451432Swpaul	struct mii_data		*mii;
100551432Swpaul
1006151911Sjhb	VR_LOCK_ASSERT(sc);
1007131517Sbms
1008110131Ssilby	if (sc->vr_flags & VR_F_RESTART) {
1009162315Sglebius		device_printf(sc->vr_dev, "restarting\n");
1010110131Ssilby		vr_stop(sc);
1011110131Ssilby		vr_reset(sc);
1012131844Sbms		vr_init_locked(sc);
1013110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1014110131Ssilby	}
1015110131Ssilby
101651432Swpaul	mii = device_get_softc(sc->vr_miibus);
101751432Swpaul	mii_tick(mii);
1018151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
101951432Swpaul}
102051432Swpaul
1021127901Sru#ifdef DEVICE_POLLING
1022127901Srustatic poll_handler_t vr_poll;
1023131844Sbmsstatic poll_handler_t vr_poll_locked;
1024127901Sru
1025102336Salfredstatic void
1026127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1027127901Sru{
1028127901Sru	struct vr_softc *sc = ifp->if_softc;
1029127901Sru
1030127901Sru	VR_LOCK(sc);
1031150789Sglebius	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1032150789Sglebius		vr_poll_locked(ifp, cmd, count);
1033131844Sbms	VR_UNLOCK(sc);
1034131844Sbms}
1035131517Sbms
1036131844Sbmsstatic void
1037131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
1038131844Sbms{
1039131844Sbms	struct vr_softc *sc = ifp->if_softc;
1040131844Sbms
1041131844Sbms	VR_LOCK_ASSERT(sc);
1042131844Sbms
1043127901Sru	sc->rxcycles = count;
1044127901Sru	vr_rxeof(sc);
1045127901Sru	vr_txeof(sc);
1046133006Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1047131844Sbms		vr_start_locked(ifp);
1048127901Sru
1049131503Sbms	if (cmd == POLL_AND_CHECK_STATUS) {
1050131503Sbms		uint16_t status;
1051127901Sru
1052131503Sbms		/* Also check status register. */
1053127901Sru		status = CSR_READ_2(sc, VR_ISR);
1054127901Sru		if (status)
1055127901Sru			CSR_WRITE_2(sc, VR_ISR, status);
1056127901Sru
1057127901Sru		if ((status & VR_INTRS) == 0)
1058131844Sbms			return;
1059127901Sru
1060127901Sru		if (status & VR_ISR_RX_DROPPED) {
1061151773Sjhb			if_printf(ifp, "rx packet lost\n");
1062127901Sru			ifp->if_ierrors++;
1063127901Sru		}
1064127901Sru
1065127901Sru		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1066127901Sru		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1067151773Sjhb			if_printf(ifp, "receive error (%04x)", status);
1068127901Sru			if (status & VR_ISR_RX_NOBUF)
1069127901Sru				printf(" no buffers");
1070127901Sru			if (status & VR_ISR_RX_OFLOW)
1071127901Sru				printf(" overflow");
1072127901Sru			if (status & VR_ISR_RX_DROPPED)
1073127901Sru				printf(" packet lost");
1074127901Sru			printf("\n");
1075127901Sru			vr_rxeoc(sc);
1076127901Sru		}
1077127901Sru
1078131503Sbms		if ((status & VR_ISR_BUSERR) ||
1079131503Sbms		    (status & VR_ISR_TX_UNDERRUN)) {
1080127901Sru			vr_reset(sc);
1081131844Sbms			vr_init_locked(sc);
1082131518Sbms			return;
1083127901Sru		}
1084127901Sru
1085127901Sru		if ((status & VR_ISR_UDFI) ||
1086127901Sru		    (status & VR_ISR_TX_ABRT2) ||
1087127901Sru		    (status & VR_ISR_TX_ABRT)) {
1088127901Sru			ifp->if_oerrors++;
1089168952Sphk			if (sc->vr_tx_cons->vr_mbuf != NULL) {
1090127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1091127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1092127901Sru			}
1093127901Sru		}
1094127901Sru	}
1095127901Sru}
1096127901Sru#endif /* DEVICE_POLLING */
1097127901Sru
1098127901Srustatic void
1099131503Sbmsvr_intr(void *arg)
110041502Swpaul{
1101131503Sbms	struct vr_softc		*sc = arg;
1102147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
1103131503Sbms	uint16_t		status;
110441502Swpaul
110567087Swpaul	VR_LOCK(sc);
1106131844Sbms
1107168948Sphk	if (sc->vr_suspended) {
1108136997Sbms		/*
1109136997Sbms		 * Forcibly disable interrupts.
1110136997Sbms		 * XXX: Mobile VIA based platforms may need
1111136997Sbms		 * interrupt re-enable on resume.
1112136997Sbms		 */
1113136997Sbms		CSR_WRITE_2(sc, VR_IMR, 0x0000);
1114131844Sbms		goto done_locked;
1115136997Sbms	}
1116131844Sbms
1117127901Sru#ifdef DEVICE_POLLING
1118150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1119131844Sbms		goto done_locked;
1120150789Sglebius#endif
1121131844Sbms
1122131844Sbms	/* Suppress unwanted interrupts. */
112341502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
112441502Swpaul		vr_stop(sc);
1125131844Sbms		goto done_locked;
112641502Swpaul	}
112741502Swpaul
112841502Swpaul	/* Disable interrupts. */
112941502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
113041502Swpaul
113141502Swpaul	for (;;) {
113241502Swpaul		status = CSR_READ_2(sc, VR_ISR);
1133168813Sphk
113441502Swpaul		if (status)
113541502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
113641502Swpaul
113741502Swpaul		if ((status & VR_INTRS) == 0)
113841502Swpaul			break;
113941502Swpaul
114041502Swpaul		if (status & VR_ISR_RX_OK)
114141502Swpaul			vr_rxeof(sc);
114241502Swpaul
1143110131Ssilby		if (status & VR_ISR_RX_DROPPED) {
1144162315Sglebius			device_printf(sc->vr_dev, "rx packet lost\n");
1145110131Ssilby			ifp->if_ierrors++;
1146131503Sbms		}
1147110131Ssilby
114841502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1149110131Ssilby		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1150162315Sglebius			device_printf(sc->vr_dev, "receive error (%04x)", status);
1151110131Ssilby			if (status & VR_ISR_RX_NOBUF)
1152110131Ssilby				printf(" no buffers");
1153110131Ssilby			if (status & VR_ISR_RX_OFLOW)
1154110131Ssilby				printf(" overflow");
1155110131Ssilby			if (status & VR_ISR_RX_DROPPED)
1156110131Ssilby				printf(" packet lost");
1157110131Ssilby			printf("\n");
115841502Swpaul			vr_rxeoc(sc);
115941502Swpaul		}
116041502Swpaul
1161101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1162101896Ssilby			vr_reset(sc);
1163131844Sbms			vr_init_locked(sc);
1164101896Ssilby			break;
116541502Swpaul		}
116641502Swpaul
1167101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1168101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
116941502Swpaul			vr_txeof(sc);
1170101896Ssilby			if ((status & VR_ISR_UDFI) ||
1171101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1172101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1173101896Ssilby				ifp->if_oerrors++;
1174168952Sphk				if (sc->vr_tx_cons->vr_mbuf != NULL) {
1175131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1176131503Sbms					    VR_CMD_TX_ON);
1177131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1178131503Sbms					    VR_CMD_TX_GO);
1179101896Ssilby				}
1180127901Sru			}
118141502Swpaul		}
118241502Swpaul	}
118341502Swpaul
118441502Swpaul	/* Re-enable interrupts. */
118541502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
118641502Swpaul
1187132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1188131844Sbms		vr_start_locked(ifp);
1189131844Sbms
1190131844Sbmsdone_locked:
1191131844Sbms	VR_UNLOCK(sc);
119241502Swpaul}
119341502Swpaul
119441502Swpaul/*
119541502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
119641502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
119741502Swpaul * copy of the pointers since the transmit list fragment pointers are
119841502Swpaul * physical addresses.
119941502Swpaul */
120041502Swpaul
1201102336Salfredstatic void
1202131503Sbmsvr_start(struct ifnet *ifp)
120341502Swpaul{
1204131518Sbms	struct vr_softc		*sc = ifp->if_softc;
1205131844Sbms
1206131844Sbms	VR_LOCK(sc);
1207131844Sbms	vr_start_locked(ifp);
1208131844Sbms	VR_UNLOCK(sc);
1209131844Sbms}
1210131844Sbms
1211131844Sbmsstatic void
1212131844Sbmsvr_start_locked(struct ifnet *ifp)
1213131844Sbms{
1214131844Sbms	struct vr_softc		*sc = ifp->if_softc;
1215168813Sphk	struct mbuf		*m, *m_head;
1216168952Sphk	struct vr_desc		*cur_tx, *n_tx;
1217168813Sphk	struct vr_desc		*f = NULL;
1218168813Sphk	uint32_t		cval;
121941502Swpaul
1220148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
1221127901Sru		return;
1222127901Sru
1223168952Sphk	for (cur_tx = sc->vr_tx_prod;
1224168952Sphk	    cur_tx->vr_next != sc->vr_tx_cons; ) {
1225132986Smlaier       	        IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
122641502Swpaul		if (m_head == NULL)
122741502Swpaul			break;
122841502Swpaul
1229168813Sphk		VR_LOCK_ASSERT(sc);
1230168813Sphk		/*
1231168813Sphk		 * Some VIA Rhine wants packet buffers to be longword
1232168813Sphk		 * aligned, but very often our mbufs aren't. Rather than
1233168813Sphk		 * waste time trying to decide when to copy and when not
1234168813Sphk		 * to copy, just do it all the time.
1235168813Sphk		 */
1236168827Sphk		if (sc->vr_quirks & VR_Q_NEEDALIGN) {
1237168813Sphk			m = m_defrag(m_head, M_DONTWAIT);
1238168813Sphk			if (m == NULL) {
1239168813Sphk				/* Rollback, send what we were able to encap. */
1240168813Sphk				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1241168813Sphk				break;
1242168813Sphk			}
1243168813Sphk			m_head = m;
1244168813Sphk		}
124541502Swpaul
124641502Swpaul		/*
1247168813Sphk		 * The Rhine chip doesn't auto-pad, so we have to make
1248168813Sphk		 * sure to pad short frames out to the minimum frame length
1249168813Sphk		 * ourselves.
125041502Swpaul		 */
1251168813Sphk		if (m_head->m_pkthdr.len < VR_MIN_FRAMELEN) {
1252168813Sphk			if (m_head->m_next != NULL)
1253168813Sphk				m_head = m_defrag(m_head, M_DONTWAIT);
1254168813Sphk			m_head->m_pkthdr.len += VR_MIN_FRAMELEN - m_head->m_len;
1255168813Sphk			m_head->m_len = m_head->m_pkthdr.len;
1256168813Sphk			/* XXX: bzero the padding bytes */
1257168813Sphk		}
125851583Swpaul
1259168813Sphk		n_tx = cur_tx;
1260168813Sphk		for (m = m_head; m != NULL; m = m->m_next) {
1261168813Sphk			if (m->m_len == 0)
1262168813Sphk				continue;
1263168952Sphk			if (n_tx->vr_next == sc->vr_tx_cons) {
1264168813Sphk				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1265168952Sphk				sc->vr_tx_prod = cur_tx;
1266168813Sphk				return;
1267168813Sphk			}
1268168813Sphk			KASSERT(n_tx->vr_mbuf == NULL, ("if_vr_tx overrun"));
1269168813Sphk
1270168952Sphk			f = n_tx;
1271168813Sphk			f->vr_data = vtophys(mtod(m, caddr_t));
1272168813Sphk			cval = m->m_len;
1273168813Sphk			cval |= VR_TXCTL_TLINK;
1274168827Sphk
1275168827Sphk			if ((ifp->if_capenable & IFCAP_TXCSUM) &&
1276168827Sphk			    m_head->m_pkthdr.csum_flags) {
1277168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_IP)
1278168827Sphk					cval |= VR_TXCTL_IPCSUM;
1279168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_TCP)
1280168827Sphk					cval |= VR_TXCTL_TCPCSUM;
1281168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_UDP)
1282168827Sphk					cval |= VR_TXCTL_UDPCSUM;
1283168827Sphk			}
1284168827Sphk
1285168813Sphk			if (m == m_head)
1286168813Sphk				cval |= VR_TXCTL_FIRSTFRAG;
1287168813Sphk			f->vr_ctl = cval;
1288168813Sphk			f->vr_status = 0;
1289168952Sphk			n_tx = n_tx->vr_next;
1290168813Sphk		}
129141502Swpaul
1292168946Sphk		KASSERT(f != NULL, ("if_vr: no packet processed"));
1293168813Sphk		f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
1294168813Sphk		cur_tx->vr_mbuf = m_head;
1295168952Sphk		atomic_set_acq_32(&cur_tx->vr_status, VR_TXSTAT_OWN);
1296168813Sphk
1297127901Sru		/* Tell the chip to start transmitting. */
1298131517Sbms		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO);
129941526Swpaul
1300168813Sphk		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1301127901Sru		ifp->if_timer = 5;
130241502Swpaul
1303168813Sphk		/*
1304168813Sphk		 * If there's a BPF listener, bounce a copy of this frame
1305168813Sphk		 * to him.
1306168813Sphk		 */
1307168813Sphk		BPF_MTAP(ifp, m_head);
1308168813Sphk		cur_tx = n_tx;
1309127901Sru	}
1310168952Sphk	sc->vr_tx_prod = cur_tx;
1311131844Sbms}
131241502Swpaul
1313131844Sbmsstatic void
1314131844Sbmsvr_init(void *xsc)
1315131844Sbms{
1316131844Sbms	struct vr_softc		*sc = xsc;
1317131844Sbms
1318131844Sbms	VR_LOCK(sc);
1319131844Sbms	vr_init_locked(sc);
132067087Swpaul	VR_UNLOCK(sc);
132141502Swpaul}
132241502Swpaul
1323102336Salfredstatic void
1324131844Sbmsvr_init_locked(struct vr_softc *sc)
132541502Swpaul{
1326147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
132751432Swpaul	struct mii_data		*mii;
132873963Swpaul	int			i;
132941502Swpaul
1330131844Sbms	VR_LOCK_ASSERT(sc);
133141502Swpaul
133251432Swpaul	mii = device_get_softc(sc->vr_miibus);
133341502Swpaul
1334131503Sbms	/* Cancel pending I/O and free all RX/TX buffers. */
133541502Swpaul	vr_stop(sc);
133641502Swpaul	vr_reset(sc);
133741502Swpaul
1338131503Sbms	/* Set our station address. */
133973963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
1340152315Sru		CSR_WRITE_1(sc, VR_PAR0 + i, IF_LLADDR(sc->vr_ifp)[i]);
1341131503Sbms
1342131503Sbms	/* Set DMA size. */
1343101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1344101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
134573963Swpaul
1346131503Sbms	/*
1347101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1348101108Ssilby	 * so we must set both.
1349101108Ssilby	 */
1350101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1351110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
1352101108Ssilby
1353101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1354101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1355101108Ssilby
135641502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
1357110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
135841502Swpaul
135941502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
136041502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
136141502Swpaul
136241502Swpaul	/* Init circular RX list. */
136341502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
1364162315Sglebius		device_printf(sc->vr_dev,
1365151773Sjhb		    "initialization failed: no memory for rx buffers\n");
136641502Swpaul		vr_stop(sc);
136741502Swpaul		return;
136841502Swpaul	}
136941502Swpaul
1370131503Sbms	/* Init tx descriptors. */
137141502Swpaul	vr_list_tx_init(sc);
137241502Swpaul
137341502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
137441502Swpaul	if (ifp->if_flags & IFF_PROMISC)
137541502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
137641502Swpaul	else
137741502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
137841502Swpaul
137941502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
138041502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
138141502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
138241502Swpaul	else
138341502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
138441502Swpaul
138541502Swpaul	/*
138641502Swpaul	 * Program the multicast filter, if necessary.
138741502Swpaul	 */
138841502Swpaul	vr_setmulti(sc);
138941502Swpaul
139041502Swpaul	/*
139141502Swpaul	 * Load the address of the RX list.
139241502Swpaul	 */
1393168952Sphk	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_rx_head));
139441502Swpaul
139541502Swpaul	/* Enable receiver and transmitter. */
139641502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
139741502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
139841502Swpaul				    VR_CMD_RX_GO);
139941502Swpaul
140041502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
140141502Swpaul
1402127901Sru	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
1403127901Sru#ifdef DEVICE_POLLING
140441502Swpaul	/*
1405127901Sru	 * Disable interrupts if we are polling.
1406127901Sru	 */
1407150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1408127901Sru		CSR_WRITE_2(sc, VR_IMR, 0);
1409131503Sbms	else
1410150789Sglebius#endif
1411127901Sru	/*
141241502Swpaul	 * Enable interrupts.
141341502Swpaul	 */
141441502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
141541502Swpaul
141651432Swpaul	mii_mediachg(mii);
141741502Swpaul
1418148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1419148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
142041502Swpaul
1421151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
142241502Swpaul}
142341502Swpaul
142441502Swpaul/*
142541502Swpaul * Set media options.
142641502Swpaul */
1427102336Salfredstatic int
1428131503Sbmsvr_ifmedia_upd(struct ifnet *ifp)
142941502Swpaul{
1430131503Sbms	struct vr_softc		*sc = ifp->if_softc;
143141502Swpaul
143251432Swpaul	if (ifp->if_flags & IFF_UP)
143351432Swpaul		vr_init(sc);
143441502Swpaul
1435131503Sbms	return (0);
143641502Swpaul}
143741502Swpaul
143841502Swpaul/*
143941502Swpaul * Report current media status.
144041502Swpaul */
1441102336Salfredstatic void
1442131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
144341502Swpaul{
1444131518Sbms	struct vr_softc		*sc = ifp->if_softc;
144551432Swpaul	struct mii_data		*mii;
144641502Swpaul
144751432Swpaul	mii = device_get_softc(sc->vr_miibus);
1448133468Sscottl	VR_LOCK(sc);
144951432Swpaul	mii_pollstat(mii);
1450133468Sscottl	VR_UNLOCK(sc);
145151432Swpaul	ifmr->ifm_active = mii->mii_media_active;
145251432Swpaul	ifmr->ifm_status = mii->mii_media_status;
145341502Swpaul}
145441502Swpaul
1455102336Salfredstatic int
1456131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
145741502Swpaul{
145841502Swpaul	struct vr_softc		*sc = ifp->if_softc;
145941502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
146051432Swpaul	struct mii_data		*mii;
146167087Swpaul	int			error = 0;
146241502Swpaul
1463131503Sbms	switch (command) {
146441502Swpaul	case SIOCSIFFLAGS:
1465131844Sbms		VR_LOCK(sc);
146641502Swpaul		if (ifp->if_flags & IFF_UP) {
1467131844Sbms			vr_init_locked(sc);
146841502Swpaul		} else {
1469148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
147041502Swpaul				vr_stop(sc);
147141502Swpaul		}
1472131844Sbms		VR_UNLOCK(sc);
147341502Swpaul		error = 0;
147441502Swpaul		break;
147541502Swpaul	case SIOCADDMULTI:
147641502Swpaul	case SIOCDELMULTI:
1477131518Sbms		VR_LOCK(sc);
147841502Swpaul		vr_setmulti(sc);
1479131518Sbms		VR_UNLOCK(sc);
148041502Swpaul		error = 0;
148141502Swpaul		break;
148241502Swpaul	case SIOCGIFMEDIA:
148341502Swpaul	case SIOCSIFMEDIA:
148451432Swpaul		mii = device_get_softc(sc->vr_miibus);
148551432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
148641502Swpaul		break;
1487128118Sru	case SIOCSIFCAP:
1488150789Sglebius#ifdef DEVICE_POLLING
1489150789Sglebius		if (ifr->ifr_reqcap & IFCAP_POLLING &&
1490150789Sglebius		    !(ifp->if_capenable & IFCAP_POLLING)) {
1491150789Sglebius			error = ether_poll_register(vr_poll, ifp);
1492150789Sglebius			if (error)
1493150789Sglebius				return(error);
1494150789Sglebius			VR_LOCK(sc);
1495150789Sglebius			/* Disable interrupts */
1496150789Sglebius			CSR_WRITE_2(sc, VR_IMR, 0x0000);
1497150789Sglebius			ifp->if_capenable |= IFCAP_POLLING;
1498150789Sglebius			VR_UNLOCK(sc);
1499150789Sglebius			return (error);
1500150789Sglebius
1501150789Sglebius		}
1502150789Sglebius		if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
1503150789Sglebius		    ifp->if_capenable & IFCAP_POLLING) {
1504150789Sglebius			error = ether_poll_deregister(ifp);
1505150789Sglebius			/* Enable interrupts. */
1506150789Sglebius			VR_LOCK(sc);
1507150789Sglebius			CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
1508150789Sglebius			ifp->if_capenable &= ~IFCAP_POLLING;
1509150789Sglebius			VR_UNLOCK(sc);
1510150789Sglebius			return (error);
1511150789Sglebius		}
1512150789Sglebius#endif /* DEVICE_POLLING */
1513168827Sphk		ifp->if_capenable = ifr->ifr_reqcap;
1514168827Sphk		if (ifp->if_capenable & IFCAP_TXCSUM)
1515168827Sphk			ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
1516168827Sphk		else
1517168827Sphk			ifp->if_hwassist = 0;
1518128118Sru		break;
151941502Swpaul	default:
1520106936Ssam		error = ether_ioctl(ifp, command, data);
152141502Swpaul		break;
152241502Swpaul	}
152341502Swpaul
1524131503Sbms	return (error);
152541502Swpaul}
152641502Swpaul
1527102336Salfredstatic void
1528131503Sbmsvr_watchdog(struct ifnet *ifp)
152941502Swpaul{
1530131518Sbms	struct vr_softc		*sc = ifp->if_softc;
153141502Swpaul
153267087Swpaul	VR_LOCK(sc);
1533131844Sbms
153441502Swpaul	ifp->if_oerrors++;
1535151773Sjhb	if_printf(ifp, "watchdog timeout\n");
153641502Swpaul
153741502Swpaul	vr_stop(sc);
153841502Swpaul	vr_reset(sc);
1539131844Sbms	vr_init_locked(sc);
1540131518Sbms
1541132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1542131844Sbms		vr_start_locked(ifp);
1543131844Sbms
1544131844Sbms	VR_UNLOCK(sc);
154541502Swpaul}
154641502Swpaul
154741502Swpaul/*
154841502Swpaul * Stop the adapter and free any mbufs allocated to the
154941502Swpaul * RX and TX lists.
155041502Swpaul */
1551102336Salfredstatic void
1552131503Sbmsvr_stop(struct vr_softc *sc)
155341502Swpaul{
1554131503Sbms	register int	i;
1555131503Sbms	struct ifnet	*ifp;
155641502Swpaul
1557131518Sbms	VR_LOCK_ASSERT(sc);
155867087Swpaul
1559147256Sbrooks	ifp = sc->vr_ifp;
156041502Swpaul	ifp->if_timer = 0;
156141502Swpaul
1562151911Sjhb	callout_stop(&sc->vr_stat_callout);
1563148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
156451432Swpaul
156541502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
156641502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
156741502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
156841502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
156941502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
157041502Swpaul
157141502Swpaul	/*
157241502Swpaul	 * Free data in the RX lists.
157341502Swpaul	 */
1574168952Sphk	for (i = 0; i < VR_RX_LIST_CNT; i++)
1575168952Sphk		if (sc->vr_ldata->vr_rx_list[i].vr_mbuf != NULL)
1576168952Sphk			m_freem(sc->vr_ldata->vr_rx_list[i].vr_mbuf);
157741502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
1578131517Sbms	    sizeof(sc->vr_ldata->vr_rx_list));
157941502Swpaul
158041502Swpaul	/*
158141502Swpaul	 * Free the TX list buffers.
158241502Swpaul	 */
1583168952Sphk	for (i = 0; i < VR_TX_LIST_CNT; i++)
1584168952Sphk		if (sc->vr_ldata->vr_tx_list[i].vr_mbuf != NULL)
1585168952Sphk			m_freem(sc->vr_ldata->vr_tx_list[i].vr_mbuf);
158641502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
1587131517Sbms	    sizeof(sc->vr_ldata->vr_tx_list));
158841502Swpaul}
158941502Swpaul
159041502Swpaul/*
159141502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
159241502Swpaul * get confused by errant DMAs when rebooting.
159341502Swpaul */
1594102336Salfredstatic void
1595131503Sbmsvr_shutdown(device_t dev)
159641502Swpaul{
159741502Swpaul
1598136696Sbms	vr_detach(dev);
159941502Swpaul}
1600