if_vr.c revision 168973
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 168973 2007-04-23 12:19:02Z 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
578168973Sphk	ifp->if_capabilities |= IFCAP_VLAN_MTU;
579151773Sjhb	ifp->if_capenable = ifp->if_capabilities;
580168827Sphk	if (ifp->if_capenable & IFCAP_TXCSUM)
581168827Sphk		ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
582168827Sphk	else
583168827Sphk		ifp->if_hwassist = 0;
584168827Sphk
585151773Sjhb#ifdef DEVICE_POLLING
586151773Sjhb	ifp->if_capabilities |= IFCAP_POLLING;
587151773Sjhb#endif
588151773Sjhb
58976586Swpaul	/*
59076586Swpaul	 * Windows may put the chip in suspend mode when it
59176586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
59276586Swpaul	 * up again.
59376586Swpaul	 */
59476586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
59576586Swpaul
59641502Swpaul	/* Reset the adapter. */
59741502Swpaul	vr_reset(sc);
59841502Swpaul
599131503Sbms	/*
600110168Ssilby	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
601110168Ssilby	 * initialization and disable AUTOPOLL.
602110168Ssilby	 */
603131503Sbms	pci_write_config(dev, VR_PCI_MODE,
604110168Ssilby	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
605110168Ssilby	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
606110168Ssilby
60741502Swpaul	/*
60841502Swpaul	 * Get station address. The way the Rhine chips work,
60941502Swpaul	 * you're not allowed to directly access the EEPROM once
61041502Swpaul	 * they've been programmed a special way. Consequently,
61141502Swpaul	 * we need to read the node address from the PAR0 and PAR1
61241502Swpaul	 * registers.
61341502Swpaul	 */
61441502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
61541502Swpaul	DELAY(200);
61641502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
61741502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
61841502Swpaul
61951432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
620151773Sjhb	    M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
62151432Swpaul
62251432Swpaul	if (sc->vr_ldata == NULL) {
623151773Sjhb		device_printf(dev, "no memory for list buffers!\n");
62449610Swpaul		error = ENXIO;
62549610Swpaul		goto fail;
62641502Swpaul	}
62741502Swpaul
628131503Sbms	/* Do MII setup. */
62951432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
63051432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
631151773Sjhb		device_printf(dev, "MII without any phy!\n");
63249610Swpaul		error = ENXIO;
63341502Swpaul		goto fail;
63441502Swpaul	}
63541502Swpaul
636131503Sbms	/* Call MI attach routine. */
637106936Ssam	ether_ifattach(ifp, eaddr);
63841502Swpaul
639168948Sphk	sc->vr_suspended = 0;
640131844Sbms
641113609Snjl	/* Hook interrupt last to avoid having to lock softc */
642131518Sbms	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE,
643166901Spiso	    NULL, vr_intr, sc, &sc->vr_intrhand);
644112872Snjl
645112872Snjl	if (error) {
646151773Sjhb		device_printf(dev, "couldn't set up irq\n");
647113609Snjl		ether_ifdetach(ifp);
648112872Snjl		goto fail;
649112872Snjl	}
650112872Snjl
65141502Swpaulfail:
652112872Snjl	if (error)
653112872Snjl		vr_detach(dev);
65467087Swpaul
655131503Sbms	return (error);
65641502Swpaul}
65741502Swpaul
658113609Snjl/*
659113609Snjl * Shutdown hardware and free up resources. This can be called any
660113609Snjl * time after the mutex has been initialized. It is called in both
661113609Snjl * the error case in attach and the normal detach case so it needs
662113609Snjl * to be careful about only freeing resources that have actually been
663113609Snjl * allocated.
664113609Snjl */
665102336Salfredstatic int
666131503Sbmsvr_detach(device_t dev)
66749610Swpaul{
668131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
669147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
67049610Swpaul
671112880Sjhb	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
672131518Sbms
673150789Sglebius#ifdef DEVICE_POLLING
674150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
675150789Sglebius		ether_poll_deregister(ifp);
676150789Sglebius#endif
677150789Sglebius
678113609Snjl	/* These should only be active if attach succeeded */
679113812Simp	if (device_is_attached(dev)) {
680151911Sjhb		VR_LOCK(sc);
681168948Sphk		sc->vr_suspended = 1;
682113609Snjl		vr_stop(sc);
683151911Sjhb		VR_UNLOCK(sc);
684151911Sjhb		callout_drain(&sc->vr_stat_callout);
685112872Snjl		ether_ifdetach(ifp);
686113609Snjl	}
687113609Snjl	if (sc->vr_miibus)
688112872Snjl		device_delete_child(dev, sc->vr_miibus);
689113609Snjl	bus_generic_detach(dev);
69049610Swpaul
691112872Snjl	if (sc->vr_intrhand)
692112872Snjl		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
693112872Snjl	if (sc->vr_irq)
694112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
695112872Snjl	if (sc->vr_res)
696112872Snjl		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
69751432Swpaul
698151297Sru	if (ifp)
699151297Sru		if_free(ifp);
700151297Sru
701112872Snjl	if (sc->vr_ldata)
702112872Snjl		contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
70349610Swpaul
70467087Swpaul	mtx_destroy(&sc->vr_mtx);
70549610Swpaul
706131503Sbms	return (0);
70749610Swpaul}
70849610Swpaul
70941502Swpaul/*
71041502Swpaul * Initialize the transmit descriptors.
71141502Swpaul */
712102336Salfredstatic int
713131503Sbmsvr_list_tx_init(struct vr_softc *sc)
71441502Swpaul{
71541502Swpaul	struct vr_list_data	*ld;
71641502Swpaul	int			i;
71741502Swpaul
71841502Swpaul	ld = sc->vr_ldata;
71941502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
720168950Sphk		if (i == (VR_TX_LIST_CNT - 1)) {
721168952Sphk			ld->vr_tx_list[i].vr_next =
722168952Sphk			    &ld->vr_tx_list[0];
723168950Sphk			ld->vr_tx_list[i].vr_nextphys =
724168950Sphk			    vtophys(&ld->vr_tx_list[0]);
725168950Sphk		} else {
726168952Sphk			ld->vr_tx_list[i].vr_next =
727168952Sphk				&ld->vr_tx_list[i + 1];
728168950Sphk			ld->vr_tx_list[i].vr_nextphys =
729168950Sphk			    vtophys(&ld->vr_tx_list[i + 1]);
730168950Sphk		}
73141502Swpaul	}
732168952Sphk	sc->vr_tx_cons = sc->vr_tx_prod = &ld->vr_tx_list[0];
73341502Swpaul
734131503Sbms	return (0);
73541502Swpaul}
73641502Swpaul
73741502Swpaul
73841502Swpaul/*
73941502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
74041502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
74141502Swpaul * points back to the first.
74241502Swpaul */
743102336Salfredstatic int
744131503Sbmsvr_list_rx_init(struct vr_softc *sc)
74541502Swpaul{
74641502Swpaul	struct vr_list_data	*ld;
74741502Swpaul	int			i;
74841502Swpaul
749131518Sbms	VR_LOCK_ASSERT(sc);
750131518Sbms
75141502Swpaul	ld = sc->vr_ldata;
75241502Swpaul
75341502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
754168952Sphk		if (vr_newbuf(&ld->vr_rx_list[i], NULL) == ENOBUFS)
755131503Sbms			return (ENOBUFS);
75641502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
757168952Sphk			ld->vr_rx_list[i].vr_next = &ld->vr_rx_list[0];
758168948Sphk			ld->vr_rx_list[i].vr_nextphys =
75941502Swpaul					vtophys(&ld->vr_rx_list[0]);
76041502Swpaul		} else {
761168952Sphk			ld->vr_rx_list[i].vr_next =
762168952Sphk					&ld->vr_rx_list[i + 1];
763168948Sphk			ld->vr_rx_list[i].vr_nextphys =
76441502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
76541502Swpaul		}
76641502Swpaul	}
76741502Swpaul
768168952Sphk	sc->vr_rx_head = &ld->vr_rx_list[0];
76941502Swpaul
770131503Sbms	return (0);
77141502Swpaul}
77241502Swpaul
77341502Swpaul/*
77441502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
77541502Swpaul * Note: the length fields are only 11 bits wide, which means the
77641502Swpaul * largest size we can specify is 2047. This is important because
77741502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
77841502Swpaul * overflow the field and make a mess.
77941502Swpaul */
780102336Salfredstatic int
781168952Sphkvr_newbuf(struct vr_desc *c, struct mbuf *m)
78241502Swpaul{
78341502Swpaul	struct mbuf		*m_new = NULL;
78441502Swpaul
78549610Swpaul	if (m == NULL) {
786168952Sphk		m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
78787846Sluigi		if (m_new == NULL)
788131503Sbms			return (ENOBUFS);
78949610Swpaul	} else {
79049610Swpaul		m_new = m;
79149610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
79249610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
79341502Swpaul	}
79441502Swpaul
795131503Sbms	m_adj(m_new, sizeof(uint64_t));
79649610Swpaul
79741502Swpaul	c->vr_mbuf = m_new;
798168952Sphk	c->vr_status = VR_RXSTAT;
799168952Sphk	c->vr_data = vtophys(mtod(m_new, caddr_t));
800168952Sphk	c->vr_ctl = VR_RXCTL | VR_RXLEN;
80141502Swpaul
802131503Sbms	return (0);
80341502Swpaul}
80441502Swpaul
80541502Swpaul/*
80641502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
80741502Swpaul * the higher level protocols.
80841502Swpaul */
809102336Salfredstatic void
810131503Sbmsvr_rxeof(struct vr_softc *sc)
81141502Swpaul{
812131503Sbms	struct mbuf		*m, *m0;
813131503Sbms	struct ifnet		*ifp;
814168952Sphk	struct vr_desc		*cur_rx;
81541502Swpaul	int			total_len = 0;
816168827Sphk	uint32_t		rxstat, rxctl;
81741502Swpaul
818122689Ssam	VR_LOCK_ASSERT(sc);
819147256Sbrooks	ifp = sc->vr_ifp;
82041502Swpaul
821168952Sphk	while (!((rxstat = sc->vr_rx_head->vr_status) &
822131503Sbms	    VR_RXSTAT_OWN)) {
823127901Sru#ifdef DEVICE_POLLING
824150789Sglebius		if (ifp->if_capenable & IFCAP_POLLING) {
825127901Sru			if (sc->rxcycles <= 0)
826127901Sru				break;
827127901Sru			sc->rxcycles--;
828127901Sru		}
829150789Sglebius#endif
830127901Sru		m0 = NULL;
831168952Sphk		cur_rx = sc->vr_rx_head;
832168952Sphk		sc->vr_rx_head = cur_rx->vr_next;
83349610Swpaul		m = cur_rx->vr_mbuf;
83441502Swpaul
83541502Swpaul		/*
83641502Swpaul		 * If an error occurs, update stats, clear the
83741502Swpaul		 * status word and leave the mbuf cluster in place:
83841502Swpaul		 * it should simply get re-used next time this descriptor
839131503Sbms		 * comes up in the ring.
84041502Swpaul		 */
84141502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
84241502Swpaul			ifp->if_ierrors++;
843162315Sglebius			device_printf(sc->vr_dev,
844162315Sglebius			    "rx error (%02x):", rxstat & 0x000000ff);
845110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
846110131Ssilby				printf(" crc error");
847110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
848110131Ssilby				printf(" frame alignment error\n");
849110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
850110131Ssilby				printf(" FIFO overflow");
851110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
852110131Ssilby				printf(" received giant packet");
853110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
854110131Ssilby				printf(" received runt packet");
855110131Ssilby			if (rxstat & VR_RXSTAT_BUSERR)
856110131Ssilby				printf(" system bus error");
857110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
858110131Ssilby				printf("rx buffer error");
859110131Ssilby			printf("\n");
860168946Sphk			vr_newbuf(cur_rx, m);
86141502Swpaul			continue;
86241502Swpaul		}
86341502Swpaul
864131503Sbms		/* No errors; receive the packet. */
865168952Sphk		total_len = VR_RXBYTES(cur_rx->vr_status);
866168827Sphk		if (ifp->if_capenable & IFCAP_RXCSUM) {
867168952Sphk			rxctl = cur_rx->vr_ctl;
868168827Sphk			if ((rxctl & VR_RXCTL_GOODIP) == VR_RXCTL_GOODIP)
869168827Sphk				m->m_pkthdr.csum_flags |=
870168827Sphk				    CSUM_IP_CHECKED | CSUM_IP_VALID;
871168827Sphk			if ((rxctl & VR_RXCTL_GOODTCPUDP)) {
872168827Sphk				m->m_pkthdr.csum_flags |=
873168827Sphk				    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
874168827Sphk				m->m_pkthdr.csum_data = 0xffff;
875168827Sphk			}
876168827Sphk		}
87741502Swpaul
87841502Swpaul		/*
87942048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
88042048Swpaul		 * received frame, and there's no way to turn this
88142048Swpaul		 * behavior off (at least, I can't find anything in
882131503Sbms		 * the manual that explains how to do it) so we have
88342048Swpaul		 * to trim off the CRC manually.
88442048Swpaul		 */
88542048Swpaul		total_len -= ETHER_CRC_LEN;
88642048Swpaul
88778508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
88878508Sbmilekic		    NULL);
889168946Sphk		vr_newbuf(cur_rx, m);
89049610Swpaul		if (m0 == NULL) {
89141502Swpaul			ifp->if_ierrors++;
89241502Swpaul			continue;
89341502Swpaul		}
89449610Swpaul		m = m0;
89541502Swpaul
89641502Swpaul		ifp->if_ipackets++;
897122689Ssam		VR_UNLOCK(sc);
898106936Ssam		(*ifp->if_input)(ifp, m);
899122689Ssam		VR_LOCK(sc);
90041502Swpaul	}
90141502Swpaul}
90241502Swpaul
903105221Sphkstatic void
904131503Sbmsvr_rxeoc(struct vr_softc *sc)
90541502Swpaul{
906147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
907110131Ssilby	int			i;
90841502Swpaul
909131518Sbms	VR_LOCK_ASSERT(sc);
910131518Sbms
911110131Ssilby	ifp->if_ierrors++;
912110131Ssilby
913131503Sbms	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
914131503Sbms	DELAY(10000);
915110131Ssilby
916131503Sbms	/* Wait for receiver to stop */
917110131Ssilby	for (i = 0x400;
918110131Ssilby	     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON);
919131503Sbms	     i--) {
920131503Sbms		;
921131503Sbms	}
922110131Ssilby
923110131Ssilby	if (!i) {
924162315Sglebius		device_printf(sc->vr_dev, "rx shutdown error!\n");
925110131Ssilby		sc->vr_flags |= VR_F_RESTART;
926110131Ssilby		return;
927131503Sbms	}
928110131Ssilby
92941502Swpaul	vr_rxeof(sc);
930110131Ssilby
931168952Sphk	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_rx_head));
93241502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
93341502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
93441502Swpaul}
93541502Swpaul
93641502Swpaul/*
93741502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
93841502Swpaul * the list buffers.
93941502Swpaul */
940102336Salfredstatic void
941131503Sbmsvr_txeof(struct vr_softc *sc)
94241502Swpaul{
943168952Sphk	struct vr_desc		*cur_tx;
944147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
94541502Swpaul
946131518Sbms	VR_LOCK_ASSERT(sc);
94741502Swpaul
94841502Swpaul	/*
94941502Swpaul	 * Go through our tx list and free mbufs for those
95041502Swpaul	 * frames that have been transmitted.
95141502Swpaul	 */
952168952Sphk	cur_tx = sc->vr_tx_cons;
953168952Sphk	while (cur_tx != sc->vr_tx_prod) {
954131503Sbms		uint32_t		txstat;
955110131Ssilby		int			i;
95641502Swpaul
957168952Sphk		txstat = cur_tx->vr_status;
95841502Swpaul
959101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
960101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
961110131Ssilby			for (i = 0x400;
962110131Ssilby			     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON);
963110131Ssilby			     i--)
964101896Ssilby				;	/* Wait for chip to shutdown */
965110131Ssilby			if (!i) {
966162315Sglebius				device_printf(sc->vr_dev, "tx shutdown timeout\n");
967110131Ssilby				sc->vr_flags |= VR_F_RESTART;
968110131Ssilby				break;
969110131Ssilby			}
970168952Sphk			atomic_set_acq_32(&cur_tx->vr_status, VR_TXSTAT_OWN);
971168952Sphk			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx));
972101896Ssilby			break;
973101896Ssilby		}
974101896Ssilby
97542491Swpaul		if (txstat & VR_TXSTAT_OWN)
97641502Swpaul			break;
97741502Swpaul
97841502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
97941502Swpaul			ifp->if_oerrors++;
98041502Swpaul			if (txstat & VR_TXSTAT_DEFER)
98141502Swpaul				ifp->if_collisions++;
98241502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
98341502Swpaul				ifp->if_collisions++;
98441502Swpaul		}
98541502Swpaul
98641502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
98741502Swpaul
98841502Swpaul		ifp->if_opackets++;
989168813Sphk		if (cur_tx->vr_mbuf != NULL)
990168813Sphk			m_freem(cur_tx->vr_mbuf);
991127901Sru		cur_tx->vr_mbuf = NULL;
992148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
99341502Swpaul
994168952Sphk		cur_tx = cur_tx->vr_next;
99541502Swpaul	}
996168952Sphk	sc->vr_tx_cons = cur_tx;
997127901Sru	if (cur_tx->vr_mbuf == NULL)
99896677Ssilby		ifp->if_timer = 0;
99941502Swpaul}
100041502Swpaul
1001102336Salfredstatic void
1002131503Sbmsvr_tick(void *xsc)
100351432Swpaul{
1004131503Sbms	struct vr_softc		*sc = xsc;
100551432Swpaul	struct mii_data		*mii;
100651432Swpaul
1007151911Sjhb	VR_LOCK_ASSERT(sc);
1008131517Sbms
1009110131Ssilby	if (sc->vr_flags & VR_F_RESTART) {
1010162315Sglebius		device_printf(sc->vr_dev, "restarting\n");
1011110131Ssilby		vr_stop(sc);
1012110131Ssilby		vr_reset(sc);
1013131844Sbms		vr_init_locked(sc);
1014110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1015110131Ssilby	}
1016110131Ssilby
101751432Swpaul	mii = device_get_softc(sc->vr_miibus);
101851432Swpaul	mii_tick(mii);
1019151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
102051432Swpaul}
102151432Swpaul
1022127901Sru#ifdef DEVICE_POLLING
1023127901Srustatic poll_handler_t vr_poll;
1024131844Sbmsstatic poll_handler_t vr_poll_locked;
1025127901Sru
1026102336Salfredstatic void
1027127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1028127901Sru{
1029127901Sru	struct vr_softc *sc = ifp->if_softc;
1030127901Sru
1031127901Sru	VR_LOCK(sc);
1032150789Sglebius	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1033150789Sglebius		vr_poll_locked(ifp, cmd, count);
1034131844Sbms	VR_UNLOCK(sc);
1035131844Sbms}
1036131517Sbms
1037131844Sbmsstatic void
1038131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
1039131844Sbms{
1040131844Sbms	struct vr_softc *sc = ifp->if_softc;
1041131844Sbms
1042131844Sbms	VR_LOCK_ASSERT(sc);
1043131844Sbms
1044127901Sru	sc->rxcycles = count;
1045127901Sru	vr_rxeof(sc);
1046127901Sru	vr_txeof(sc);
1047133006Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1048131844Sbms		vr_start_locked(ifp);
1049127901Sru
1050131503Sbms	if (cmd == POLL_AND_CHECK_STATUS) {
1051131503Sbms		uint16_t status;
1052127901Sru
1053131503Sbms		/* Also check status register. */
1054127901Sru		status = CSR_READ_2(sc, VR_ISR);
1055127901Sru		if (status)
1056127901Sru			CSR_WRITE_2(sc, VR_ISR, status);
1057127901Sru
1058127901Sru		if ((status & VR_INTRS) == 0)
1059131844Sbms			return;
1060127901Sru
1061127901Sru		if (status & VR_ISR_RX_DROPPED) {
1062151773Sjhb			if_printf(ifp, "rx packet lost\n");
1063127901Sru			ifp->if_ierrors++;
1064127901Sru		}
1065127901Sru
1066127901Sru		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1067127901Sru		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1068151773Sjhb			if_printf(ifp, "receive error (%04x)", status);
1069127901Sru			if (status & VR_ISR_RX_NOBUF)
1070127901Sru				printf(" no buffers");
1071127901Sru			if (status & VR_ISR_RX_OFLOW)
1072127901Sru				printf(" overflow");
1073127901Sru			if (status & VR_ISR_RX_DROPPED)
1074127901Sru				printf(" packet lost");
1075127901Sru			printf("\n");
1076127901Sru			vr_rxeoc(sc);
1077127901Sru		}
1078127901Sru
1079131503Sbms		if ((status & VR_ISR_BUSERR) ||
1080131503Sbms		    (status & VR_ISR_TX_UNDERRUN)) {
1081127901Sru			vr_reset(sc);
1082131844Sbms			vr_init_locked(sc);
1083131518Sbms			return;
1084127901Sru		}
1085127901Sru
1086127901Sru		if ((status & VR_ISR_UDFI) ||
1087127901Sru		    (status & VR_ISR_TX_ABRT2) ||
1088127901Sru		    (status & VR_ISR_TX_ABRT)) {
1089127901Sru			ifp->if_oerrors++;
1090168952Sphk			if (sc->vr_tx_cons->vr_mbuf != NULL) {
1091127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1092127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1093127901Sru			}
1094127901Sru		}
1095127901Sru	}
1096127901Sru}
1097127901Sru#endif /* DEVICE_POLLING */
1098127901Sru
1099127901Srustatic void
1100131503Sbmsvr_intr(void *arg)
110141502Swpaul{
1102131503Sbms	struct vr_softc		*sc = arg;
1103147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
1104131503Sbms	uint16_t		status;
110541502Swpaul
110667087Swpaul	VR_LOCK(sc);
1107131844Sbms
1108168948Sphk	if (sc->vr_suspended) {
1109136997Sbms		/*
1110136997Sbms		 * Forcibly disable interrupts.
1111136997Sbms		 * XXX: Mobile VIA based platforms may need
1112136997Sbms		 * interrupt re-enable on resume.
1113136997Sbms		 */
1114136997Sbms		CSR_WRITE_2(sc, VR_IMR, 0x0000);
1115131844Sbms		goto done_locked;
1116136997Sbms	}
1117131844Sbms
1118127901Sru#ifdef DEVICE_POLLING
1119150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1120131844Sbms		goto done_locked;
1121150789Sglebius#endif
1122131844Sbms
1123131844Sbms	/* Suppress unwanted interrupts. */
112441502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
112541502Swpaul		vr_stop(sc);
1126131844Sbms		goto done_locked;
112741502Swpaul	}
112841502Swpaul
112941502Swpaul	/* Disable interrupts. */
113041502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
113141502Swpaul
113241502Swpaul	for (;;) {
113341502Swpaul		status = CSR_READ_2(sc, VR_ISR);
1134168813Sphk
113541502Swpaul		if (status)
113641502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
113741502Swpaul
113841502Swpaul		if ((status & VR_INTRS) == 0)
113941502Swpaul			break;
114041502Swpaul
114141502Swpaul		if (status & VR_ISR_RX_OK)
114241502Swpaul			vr_rxeof(sc);
114341502Swpaul
1144110131Ssilby		if (status & VR_ISR_RX_DROPPED) {
1145162315Sglebius			device_printf(sc->vr_dev, "rx packet lost\n");
1146110131Ssilby			ifp->if_ierrors++;
1147131503Sbms		}
1148110131Ssilby
114941502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1150110131Ssilby		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1151162315Sglebius			device_printf(sc->vr_dev, "receive error (%04x)", status);
1152110131Ssilby			if (status & VR_ISR_RX_NOBUF)
1153110131Ssilby				printf(" no buffers");
1154110131Ssilby			if (status & VR_ISR_RX_OFLOW)
1155110131Ssilby				printf(" overflow");
1156110131Ssilby			if (status & VR_ISR_RX_DROPPED)
1157110131Ssilby				printf(" packet lost");
1158110131Ssilby			printf("\n");
115941502Swpaul			vr_rxeoc(sc);
116041502Swpaul		}
116141502Swpaul
1162101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1163101896Ssilby			vr_reset(sc);
1164131844Sbms			vr_init_locked(sc);
1165101896Ssilby			break;
116641502Swpaul		}
116741502Swpaul
1168101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1169101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
117041502Swpaul			vr_txeof(sc);
1171101896Ssilby			if ((status & VR_ISR_UDFI) ||
1172101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1173101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1174101896Ssilby				ifp->if_oerrors++;
1175168952Sphk				if (sc->vr_tx_cons->vr_mbuf != NULL) {
1176131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1177131503Sbms					    VR_CMD_TX_ON);
1178131503Sbms					VR_SETBIT16(sc, VR_COMMAND,
1179131503Sbms					    VR_CMD_TX_GO);
1180101896Ssilby				}
1181127901Sru			}
118241502Swpaul		}
118341502Swpaul	}
118441502Swpaul
118541502Swpaul	/* Re-enable interrupts. */
118641502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
118741502Swpaul
1188132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1189131844Sbms		vr_start_locked(ifp);
1190131844Sbms
1191131844Sbmsdone_locked:
1192131844Sbms	VR_UNLOCK(sc);
119341502Swpaul}
119441502Swpaul
119541502Swpaul/*
119641502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
119741502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
119841502Swpaul * copy of the pointers since the transmit list fragment pointers are
119941502Swpaul * physical addresses.
120041502Swpaul */
120141502Swpaul
1202102336Salfredstatic void
1203131503Sbmsvr_start(struct ifnet *ifp)
120441502Swpaul{
1205131518Sbms	struct vr_softc		*sc = ifp->if_softc;
1206131844Sbms
1207131844Sbms	VR_LOCK(sc);
1208131844Sbms	vr_start_locked(ifp);
1209131844Sbms	VR_UNLOCK(sc);
1210131844Sbms}
1211131844Sbms
1212131844Sbmsstatic void
1213131844Sbmsvr_start_locked(struct ifnet *ifp)
1214131844Sbms{
1215131844Sbms	struct vr_softc		*sc = ifp->if_softc;
1216168813Sphk	struct mbuf		*m, *m_head;
1217168952Sphk	struct vr_desc		*cur_tx, *n_tx;
1218168813Sphk	struct vr_desc		*f = NULL;
1219168813Sphk	uint32_t		cval;
122041502Swpaul
1221148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
1222127901Sru		return;
1223127901Sru
1224168952Sphk	for (cur_tx = sc->vr_tx_prod;
1225168952Sphk	    cur_tx->vr_next != sc->vr_tx_cons; ) {
1226132986Smlaier       	        IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
122741502Swpaul		if (m_head == NULL)
122841502Swpaul			break;
122941502Swpaul
1230168813Sphk		VR_LOCK_ASSERT(sc);
1231168813Sphk		/*
1232168813Sphk		 * Some VIA Rhine wants packet buffers to be longword
1233168813Sphk		 * aligned, but very often our mbufs aren't. Rather than
1234168813Sphk		 * waste time trying to decide when to copy and when not
1235168813Sphk		 * to copy, just do it all the time.
1236168813Sphk		 */
1237168827Sphk		if (sc->vr_quirks & VR_Q_NEEDALIGN) {
1238168813Sphk			m = m_defrag(m_head, M_DONTWAIT);
1239168813Sphk			if (m == NULL) {
1240168813Sphk				/* Rollback, send what we were able to encap. */
1241168813Sphk				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1242168813Sphk				break;
1243168813Sphk			}
1244168813Sphk			m_head = m;
1245168813Sphk		}
124641502Swpaul
124741502Swpaul		/*
1248168813Sphk		 * The Rhine chip doesn't auto-pad, so we have to make
1249168813Sphk		 * sure to pad short frames out to the minimum frame length
1250168813Sphk		 * ourselves.
125141502Swpaul		 */
1252168813Sphk		if (m_head->m_pkthdr.len < VR_MIN_FRAMELEN) {
1253168813Sphk			if (m_head->m_next != NULL)
1254168813Sphk				m_head = m_defrag(m_head, M_DONTWAIT);
1255168813Sphk			m_head->m_pkthdr.len += VR_MIN_FRAMELEN - m_head->m_len;
1256168813Sphk			m_head->m_len = m_head->m_pkthdr.len;
1257168813Sphk			/* XXX: bzero the padding bytes */
1258168813Sphk		}
125951583Swpaul
1260168813Sphk		n_tx = cur_tx;
1261168813Sphk		for (m = m_head; m != NULL; m = m->m_next) {
1262168813Sphk			if (m->m_len == 0)
1263168813Sphk				continue;
1264168952Sphk			if (n_tx->vr_next == sc->vr_tx_cons) {
1265168813Sphk				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1266168952Sphk				sc->vr_tx_prod = cur_tx;
1267168813Sphk				return;
1268168813Sphk			}
1269168813Sphk			KASSERT(n_tx->vr_mbuf == NULL, ("if_vr_tx overrun"));
1270168813Sphk
1271168952Sphk			f = n_tx;
1272168813Sphk			f->vr_data = vtophys(mtod(m, caddr_t));
1273168813Sphk			cval = m->m_len;
1274168813Sphk			cval |= VR_TXCTL_TLINK;
1275168827Sphk
1276168827Sphk			if ((ifp->if_capenable & IFCAP_TXCSUM) &&
1277168827Sphk			    m_head->m_pkthdr.csum_flags) {
1278168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_IP)
1279168827Sphk					cval |= VR_TXCTL_IPCSUM;
1280168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_TCP)
1281168827Sphk					cval |= VR_TXCTL_TCPCSUM;
1282168827Sphk				if (m_head->m_pkthdr.csum_flags & CSUM_UDP)
1283168827Sphk					cval |= VR_TXCTL_UDPCSUM;
1284168827Sphk			}
1285168827Sphk
1286168813Sphk			if (m == m_head)
1287168813Sphk				cval |= VR_TXCTL_FIRSTFRAG;
1288168813Sphk			f->vr_ctl = cval;
1289168813Sphk			f->vr_status = 0;
1290168952Sphk			n_tx = n_tx->vr_next;
1291168813Sphk		}
129241502Swpaul
1293168946Sphk		KASSERT(f != NULL, ("if_vr: no packet processed"));
1294168813Sphk		f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
1295168813Sphk		cur_tx->vr_mbuf = m_head;
1296168952Sphk		atomic_set_acq_32(&cur_tx->vr_status, VR_TXSTAT_OWN);
1297168813Sphk
1298127901Sru		/* Tell the chip to start transmitting. */
1299131517Sbms		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO);
130041526Swpaul
1301168813Sphk		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1302127901Sru		ifp->if_timer = 5;
130341502Swpaul
1304168813Sphk		/*
1305168813Sphk		 * If there's a BPF listener, bounce a copy of this frame
1306168813Sphk		 * to him.
1307168813Sphk		 */
1308168813Sphk		BPF_MTAP(ifp, m_head);
1309168813Sphk		cur_tx = n_tx;
1310127901Sru	}
1311168952Sphk	sc->vr_tx_prod = cur_tx;
1312131844Sbms}
131341502Swpaul
1314131844Sbmsstatic void
1315131844Sbmsvr_init(void *xsc)
1316131844Sbms{
1317131844Sbms	struct vr_softc		*sc = xsc;
1318131844Sbms
1319131844Sbms	VR_LOCK(sc);
1320131844Sbms	vr_init_locked(sc);
132167087Swpaul	VR_UNLOCK(sc);
132241502Swpaul}
132341502Swpaul
1324102336Salfredstatic void
1325131844Sbmsvr_init_locked(struct vr_softc *sc)
132641502Swpaul{
1327147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
132851432Swpaul	struct mii_data		*mii;
132973963Swpaul	int			i;
133041502Swpaul
1331131844Sbms	VR_LOCK_ASSERT(sc);
133241502Swpaul
133351432Swpaul	mii = device_get_softc(sc->vr_miibus);
133441502Swpaul
1335131503Sbms	/* Cancel pending I/O and free all RX/TX buffers. */
133641502Swpaul	vr_stop(sc);
133741502Swpaul	vr_reset(sc);
133841502Swpaul
1339131503Sbms	/* Set our station address. */
134073963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
1341152315Sru		CSR_WRITE_1(sc, VR_PAR0 + i, IF_LLADDR(sc->vr_ifp)[i]);
1342131503Sbms
1343131503Sbms	/* Set DMA size. */
1344101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1345101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
134673963Swpaul
1347131503Sbms	/*
1348101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1349101108Ssilby	 * so we must set both.
1350101108Ssilby	 */
1351101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1352110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
1353101108Ssilby
1354101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1355101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1356101108Ssilby
135741502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
1358110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
135941502Swpaul
136041502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
136141502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
136241502Swpaul
136341502Swpaul	/* Init circular RX list. */
136441502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
1365162315Sglebius		device_printf(sc->vr_dev,
1366151773Sjhb		    "initialization failed: no memory for rx buffers\n");
136741502Swpaul		vr_stop(sc);
136841502Swpaul		return;
136941502Swpaul	}
137041502Swpaul
1371131503Sbms	/* Init tx descriptors. */
137241502Swpaul	vr_list_tx_init(sc);
137341502Swpaul
137441502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
137541502Swpaul	if (ifp->if_flags & IFF_PROMISC)
137641502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
137741502Swpaul	else
137841502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
137941502Swpaul
138041502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
138141502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
138241502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
138341502Swpaul	else
138441502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
138541502Swpaul
138641502Swpaul	/*
138741502Swpaul	 * Program the multicast filter, if necessary.
138841502Swpaul	 */
138941502Swpaul	vr_setmulti(sc);
139041502Swpaul
139141502Swpaul	/*
139241502Swpaul	 * Load the address of the RX list.
139341502Swpaul	 */
1394168952Sphk	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_rx_head));
139541502Swpaul
139641502Swpaul	/* Enable receiver and transmitter. */
139741502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
139841502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
139941502Swpaul				    VR_CMD_RX_GO);
140041502Swpaul
140141502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
140241502Swpaul
1403127901Sru	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
1404127901Sru#ifdef DEVICE_POLLING
140541502Swpaul	/*
1406127901Sru	 * Disable interrupts if we are polling.
1407127901Sru	 */
1408150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1409127901Sru		CSR_WRITE_2(sc, VR_IMR, 0);
1410131503Sbms	else
1411150789Sglebius#endif
1412127901Sru	/*
141341502Swpaul	 * Enable interrupts.
141441502Swpaul	 */
141541502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
141641502Swpaul
141751432Swpaul	mii_mediachg(mii);
141841502Swpaul
1419148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1420148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
142141502Swpaul
1422151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
142341502Swpaul}
142441502Swpaul
142541502Swpaul/*
142641502Swpaul * Set media options.
142741502Swpaul */
1428102336Salfredstatic int
1429131503Sbmsvr_ifmedia_upd(struct ifnet *ifp)
143041502Swpaul{
1431131503Sbms	struct vr_softc		*sc = ifp->if_softc;
143241502Swpaul
143351432Swpaul	if (ifp->if_flags & IFF_UP)
143451432Swpaul		vr_init(sc);
143541502Swpaul
1436131503Sbms	return (0);
143741502Swpaul}
143841502Swpaul
143941502Swpaul/*
144041502Swpaul * Report current media status.
144141502Swpaul */
1442102336Salfredstatic void
1443131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
144441502Swpaul{
1445131518Sbms	struct vr_softc		*sc = ifp->if_softc;
144651432Swpaul	struct mii_data		*mii;
144741502Swpaul
144851432Swpaul	mii = device_get_softc(sc->vr_miibus);
1449133468Sscottl	VR_LOCK(sc);
145051432Swpaul	mii_pollstat(mii);
1451133468Sscottl	VR_UNLOCK(sc);
145251432Swpaul	ifmr->ifm_active = mii->mii_media_active;
145351432Swpaul	ifmr->ifm_status = mii->mii_media_status;
145441502Swpaul}
145541502Swpaul
1456102336Salfredstatic int
1457131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
145841502Swpaul{
145941502Swpaul	struct vr_softc		*sc = ifp->if_softc;
146041502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
146151432Swpaul	struct mii_data		*mii;
146267087Swpaul	int			error = 0;
146341502Swpaul
1464131503Sbms	switch (command) {
146541502Swpaul	case SIOCSIFFLAGS:
1466131844Sbms		VR_LOCK(sc);
146741502Swpaul		if (ifp->if_flags & IFF_UP) {
1468131844Sbms			vr_init_locked(sc);
146941502Swpaul		} else {
1470148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
147141502Swpaul				vr_stop(sc);
147241502Swpaul		}
1473131844Sbms		VR_UNLOCK(sc);
147441502Swpaul		error = 0;
147541502Swpaul		break;
147641502Swpaul	case SIOCADDMULTI:
147741502Swpaul	case SIOCDELMULTI:
1478131518Sbms		VR_LOCK(sc);
147941502Swpaul		vr_setmulti(sc);
1480131518Sbms		VR_UNLOCK(sc);
148141502Swpaul		error = 0;
148241502Swpaul		break;
148341502Swpaul	case SIOCGIFMEDIA:
148441502Swpaul	case SIOCSIFMEDIA:
148551432Swpaul		mii = device_get_softc(sc->vr_miibus);
148651432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
148741502Swpaul		break;
1488128118Sru	case SIOCSIFCAP:
1489150789Sglebius#ifdef DEVICE_POLLING
1490150789Sglebius		if (ifr->ifr_reqcap & IFCAP_POLLING &&
1491150789Sglebius		    !(ifp->if_capenable & IFCAP_POLLING)) {
1492150789Sglebius			error = ether_poll_register(vr_poll, ifp);
1493150789Sglebius			if (error)
1494150789Sglebius				return(error);
1495150789Sglebius			VR_LOCK(sc);
1496150789Sglebius			/* Disable interrupts */
1497150789Sglebius			CSR_WRITE_2(sc, VR_IMR, 0x0000);
1498150789Sglebius			ifp->if_capenable |= IFCAP_POLLING;
1499150789Sglebius			VR_UNLOCK(sc);
1500150789Sglebius			return (error);
1501150789Sglebius
1502150789Sglebius		}
1503150789Sglebius		if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
1504150789Sglebius		    ifp->if_capenable & IFCAP_POLLING) {
1505150789Sglebius			error = ether_poll_deregister(ifp);
1506150789Sglebius			/* Enable interrupts. */
1507150789Sglebius			VR_LOCK(sc);
1508150789Sglebius			CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
1509150789Sglebius			ifp->if_capenable &= ~IFCAP_POLLING;
1510150789Sglebius			VR_UNLOCK(sc);
1511150789Sglebius			return (error);
1512150789Sglebius		}
1513150789Sglebius#endif /* DEVICE_POLLING */
1514168827Sphk		ifp->if_capenable = ifr->ifr_reqcap;
1515168827Sphk		if (ifp->if_capenable & IFCAP_TXCSUM)
1516168827Sphk			ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
1517168827Sphk		else
1518168827Sphk			ifp->if_hwassist = 0;
1519128118Sru		break;
152041502Swpaul	default:
1521106936Ssam		error = ether_ioctl(ifp, command, data);
152241502Swpaul		break;
152341502Swpaul	}
152441502Swpaul
1525131503Sbms	return (error);
152641502Swpaul}
152741502Swpaul
1528102336Salfredstatic void
1529131503Sbmsvr_watchdog(struct ifnet *ifp)
153041502Swpaul{
1531131518Sbms	struct vr_softc		*sc = ifp->if_softc;
153241502Swpaul
153367087Swpaul	VR_LOCK(sc);
1534131844Sbms
153541502Swpaul	ifp->if_oerrors++;
1536151773Sjhb	if_printf(ifp, "watchdog timeout\n");
153741502Swpaul
153841502Swpaul	vr_stop(sc);
153941502Swpaul	vr_reset(sc);
1540131844Sbms	vr_init_locked(sc);
1541131518Sbms
1542132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1543131844Sbms		vr_start_locked(ifp);
1544131844Sbms
1545131844Sbms	VR_UNLOCK(sc);
154641502Swpaul}
154741502Swpaul
154841502Swpaul/*
154941502Swpaul * Stop the adapter and free any mbufs allocated to the
155041502Swpaul * RX and TX lists.
155141502Swpaul */
1552102336Salfredstatic void
1553131503Sbmsvr_stop(struct vr_softc *sc)
155441502Swpaul{
1555131503Sbms	register int	i;
1556131503Sbms	struct ifnet	*ifp;
155741502Swpaul
1558131518Sbms	VR_LOCK_ASSERT(sc);
155967087Swpaul
1560147256Sbrooks	ifp = sc->vr_ifp;
156141502Swpaul	ifp->if_timer = 0;
156241502Swpaul
1563151911Sjhb	callout_stop(&sc->vr_stat_callout);
1564148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
156551432Swpaul
156641502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
156741502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
156841502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
156941502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
157041502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
157141502Swpaul
157241502Swpaul	/*
157341502Swpaul	 * Free data in the RX lists.
157441502Swpaul	 */
1575168952Sphk	for (i = 0; i < VR_RX_LIST_CNT; i++)
1576168952Sphk		if (sc->vr_ldata->vr_rx_list[i].vr_mbuf != NULL)
1577168952Sphk			m_freem(sc->vr_ldata->vr_rx_list[i].vr_mbuf);
157841502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
1579131517Sbms	    sizeof(sc->vr_ldata->vr_rx_list));
158041502Swpaul
158141502Swpaul	/*
158241502Swpaul	 * Free the TX list buffers.
158341502Swpaul	 */
1584168952Sphk	for (i = 0; i < VR_TX_LIST_CNT; i++)
1585168952Sphk		if (sc->vr_ldata->vr_tx_list[i].vr_mbuf != NULL)
1586168952Sphk			m_freem(sc->vr_ldata->vr_tx_list[i].vr_mbuf);
158741502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
1588131517Sbms	    sizeof(sc->vr_ldata->vr_tx_list));
158941502Swpaul}
159041502Swpaul
159141502Swpaul/*
159241502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
159341502Swpaul * get confused by errant DMAs when rebooting.
159441502Swpaul */
1595102336Salfredstatic void
1596131503Sbmsvr_shutdown(device_t dev)
159741502Swpaul{
159841502Swpaul
1599136696Sbms	vr_detach(dev);
160041502Swpaul}
1601