if_vr.c revision 296272
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 296272 2016-03-01 17:47:32Z jhb $");
35122678Sobrien
3641502Swpaul/*
3741502Swpaul * VIA Rhine fast ethernet PCI NIC driver
3841502Swpaul *
3941502Swpaul * Supports various network adapters based on the VIA Rhine
4041502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX.
4141502Swpaul * Datasheets are available at http://www.via.com.tw.
4241502Swpaul *
4341502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4441502Swpaul * Electrical Engineering Department
4541502Swpaul * Columbia University, New York City
4641502Swpaul */
47131503Sbms
4841502Swpaul/*
4941502Swpaul * The VIA Rhine controllers are similar in some respects to the
5041502Swpaul * the DEC tulip chips, except less complicated. The controller
5141502Swpaul * uses an MII bus and an external physical layer interface. The
5241502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table
5341502Swpaul * multicast filter. Transmit and receive descriptors are similar
5441502Swpaul * to the tulip.
5541502Swpaul *
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>
69177050Syongari#include <sys/bus.h>
70177050Syongari#include <sys/endian.h>
71177050Syongari#include <sys/kernel.h>
72177050Syongari#include <sys/malloc.h>
7341502Swpaul#include <sys/mbuf.h>
74129878Sphk#include <sys/module.h>
75177050Syongari#include <sys/rman.h>
7641502Swpaul#include <sys/socket.h>
77177050Syongari#include <sys/sockio.h>
78177050Syongari#include <sys/sysctl.h>
79177050Syongari#include <sys/taskqueue.h>
8041502Swpaul
81177050Syongari#include <net/bpf.h>
8241502Swpaul#include <net/if.h>
83257176Sglebius#include <net/if_var.h>
8441502Swpaul#include <net/ethernet.h>
8541502Swpaul#include <net/if_dl.h>
8641502Swpaul#include <net/if_media.h>
87147256Sbrooks#include <net/if_types.h>
88177050Syongari#include <net/if_vlan_var.h>
8941502Swpaul
90177050Syongari#include <dev/mii/mii.h>
9151432Swpaul#include <dev/mii/miivar.h>
9251432Swpaul
93172555Syongari#include <dev/pci/pcireg.h>
94119288Simp#include <dev/pci/pcivar.h>
9541502Swpaul
96177050Syongari#include <machine/bus.h>
9741502Swpaul
98177047Syongari#include <dev/vr/if_vrreg.h>
9941502Swpaul
100177050Syongari/* "device miibus" required.  See GENERIC if you get errors here. */
101177050Syongari#include "miibus_if.h"
102177050Syongari
103113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1);
104113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1);
10559758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
10659758Speter
107177050Syongari/* Define to show Rx/Tx error status. */
108177050Syongari#undef	VR_SHOW_ERRORS
109177050Syongari#define	VR_CSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP)
11051432Swpaul
11141502Swpaul/*
112177050Syongari * Various supported device vendors/types, their names & quirks.
11341502Swpaul */
114168952Sphk#define VR_Q_NEEDALIGN		(1<<0)
115168952Sphk#define VR_Q_CSUM		(1<<1)
116177050Syongari#define VR_Q_CAM		(1<<2)
117168952Sphk
118226171Smariusstatic const struct vr_type {
119168952Sphk	u_int16_t		vr_vid;
120168952Sphk	u_int16_t		vr_did;
121168952Sphk	int			vr_quirks;
122226171Smarius	const char		*vr_name;
123242625Sdim} vr_devs[] = {
124168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
125168827Sphk	    VR_Q_NEEDALIGN,
126168827Sphk	    "VIA VT3043 Rhine I 10/100BaseTX" },
127168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
128168827Sphk	    VR_Q_NEEDALIGN,
129168827Sphk	    "VIA VT86C100A Rhine II 10/100BaseTX" },
130168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
131168827Sphk	    0,
132168827Sphk	    "VIA VT6102 Rhine II 10/100BaseTX" },
133168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III,
134168827Sphk	    0,
135168827Sphk	    "VIA VT6105 Rhine III 10/100BaseTX" },
136168827Sphk	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
137185962Syongari	    VR_Q_CSUM,
138168827Sphk	    "VIA VT6105M Rhine III 10/100BaseTX" },
139168827Sphk	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
140168827Sphk	    VR_Q_NEEDALIGN,
141168827Sphk	    "Delta Electronics Rhine II 10/100BaseTX" },
142168827Sphk	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
143168827Sphk	    VR_Q_NEEDALIGN,
144168827Sphk	    "Addtron Technology Rhine II 10/100BaseTX" },
145168813Sphk	{ 0, 0, 0, NULL }
14641502Swpaul};
14741502Swpaul
148142407Simpstatic int vr_probe(device_t);
149142407Simpstatic int vr_attach(device_t);
150142407Simpstatic int vr_detach(device_t);
151177050Syongaristatic int vr_shutdown(device_t);
152177050Syongaristatic int vr_suspend(device_t);
153177050Syongaristatic int vr_resume(device_t);
15441502Swpaul
155177050Syongaristatic void vr_dmamap_cb(void *, bus_dma_segment_t *, int, int);
156177050Syongaristatic int vr_dma_alloc(struct vr_softc *);
157177050Syongaristatic void vr_dma_free(struct vr_softc *);
158177050Syongaristatic __inline void vr_discard_rxbuf(struct vr_rxdesc *);
159177050Syongaristatic int vr_newbuf(struct vr_softc *, int);
16041502Swpaul
161177050Syongari#ifndef __NO_STRICT_ALIGNMENT
162177050Syongaristatic __inline void vr_fixup_rx(struct mbuf *);
163177050Syongari#endif
164193096Sattiliostatic int vr_rxeof(struct vr_softc *);
165142407Simpstatic void vr_txeof(struct vr_softc *);
166142407Simpstatic void vr_tick(void *);
167177050Syongaristatic int vr_error(struct vr_softc *, uint16_t);
168177050Syongaristatic void vr_tx_underrun(struct vr_softc *);
169235334Srpaulostatic int vr_intr(void *);
170235334Srpaulostatic void vr_int_task(void *, int);
171142407Simpstatic void vr_start(struct ifnet *);
172142407Simpstatic void vr_start_locked(struct ifnet *);
173177050Syongaristatic int vr_encap(struct vr_softc *, struct mbuf **);
174142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t);
175142407Simpstatic void vr_init(void *);
176142407Simpstatic void vr_init_locked(struct vr_softc *);
177177050Syongaristatic void vr_tx_start(struct vr_softc *);
178177050Syongaristatic void vr_rx_start(struct vr_softc *);
179177050Syongaristatic int vr_tx_stop(struct vr_softc *);
180177050Syongaristatic int vr_rx_stop(struct vr_softc *);
181142407Simpstatic void vr_stop(struct vr_softc *);
182177050Syongaristatic void vr_watchdog(struct vr_softc *);
183142407Simpstatic int vr_ifmedia_upd(struct ifnet *);
184142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
18541502Swpaul
186177050Syongaristatic int vr_miibus_readreg(device_t, int, int);
187177050Syongaristatic int vr_miibus_writereg(device_t, int, int, int);
188142407Simpstatic void vr_miibus_statchg(device_t);
18941502Swpaul
190180552Syongaristatic void vr_cam_mask(struct vr_softc *, uint32_t, int);
191180552Syongaristatic int vr_cam_data(struct vr_softc *, int, int, uint8_t *);
192177050Syongaristatic void vr_set_filter(struct vr_softc *);
193168946Sphkstatic void vr_reset(const struct vr_softc *);
194177050Syongaristatic int vr_tx_ring_init(struct vr_softc *);
195177050Syongaristatic int vr_rx_ring_init(struct vr_softc *);
196177050Syongaristatic void vr_setwol(struct vr_softc *);
197177050Syongaristatic void vr_clrwol(struct vr_softc *);
198177050Syongaristatic int vr_sysctl_stats(SYSCTL_HANDLER_ARGS);
19941502Swpaul
200226171Smariusstatic const struct vr_tx_threshold_table {
201177050Syongari	int tx_cfg;
202177050Syongari	int bcr_cfg;
203177050Syongari	int value;
204242625Sdim} vr_tx_threshold_tables[] = {
205177050Syongari	{ VR_TXTHRESH_64BYTES, VR_BCR1_TXTHRESH64BYTES,	64 },
206177050Syongari	{ VR_TXTHRESH_128BYTES, VR_BCR1_TXTHRESH128BYTES, 128 },
207177050Syongari	{ VR_TXTHRESH_256BYTES, VR_BCR1_TXTHRESH256BYTES, 256 },
208177050Syongari	{ VR_TXTHRESH_512BYTES, VR_BCR1_TXTHRESH512BYTES, 512 },
209177050Syongari	{ VR_TXTHRESH_1024BYTES, VR_BCR1_TXTHRESH1024BYTES, 1024 },
210177050Syongari	{ VR_TXTHRESH_STORENFWD, VR_BCR1_TXTHRESHSTORENFWD, 2048 }
211177050Syongari};
21249610Swpaul
21349610Swpaulstatic device_method_t vr_methods[] = {
21449610Swpaul	/* Device interface */
21549610Swpaul	DEVMETHOD(device_probe,		vr_probe),
21649610Swpaul	DEVMETHOD(device_attach,	vr_attach),
21749610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
21849610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
219177050Syongari	DEVMETHOD(device_suspend,	vr_suspend),
220177050Syongari	DEVMETHOD(device_resume,	vr_resume),
22151432Swpaul
22251432Swpaul	/* MII interface */
22351432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
22451432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
22551432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
22651432Swpaul
227227843Smarius	DEVMETHOD_END
22849610Swpaul};
22949610Swpaul
23049610Swpaulstatic driver_t vr_driver = {
23151455Swpaul	"vr",
23249610Swpaul	vr_methods,
23349610Swpaul	sizeof(struct vr_softc)
23449610Swpaul};
23549610Swpaul
23649610Swpaulstatic devclass_t vr_devclass;
23749610Swpaul
238113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0);
23951473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
24049610Swpaul
241102336Salfredstatic int
242177050Syongarivr_miibus_readreg(device_t dev, int phy, int reg)
24341502Swpaul{
244177050Syongari	struct vr_softc		*sc;
245177050Syongari	int			i;
24641502Swpaul
247177050Syongari	sc = device_get_softc(dev);
248110168Ssilby
249131503Sbms	/* Set the register address. */
250177050Syongari	CSR_WRITE_1(sc, VR_MIIADDR, reg);
251110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
252131503Sbms
253177050Syongari	for (i = 0; i < VR_MII_TIMEOUT; i++) {
254177050Syongari		DELAY(1);
255110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
256110168Ssilby			break;
257110168Ssilby	}
258177050Syongari	if (i == VR_MII_TIMEOUT)
259177050Syongari		device_printf(sc->vr_dev, "phy read timeout %d:%d\n", phy, reg);
260110168Ssilby
261177050Syongari	return (CSR_READ_2(sc, VR_MIIDATA));
262110168Ssilby}
263110168Ssilby
264102336Salfredstatic int
265177050Syongarivr_miibus_writereg(device_t dev, int phy, int reg, int data)
26641502Swpaul{
267177050Syongari	struct vr_softc		*sc;
268177050Syongari	int			i;
26941502Swpaul
270177050Syongari	sc = device_get_softc(dev);
271110168Ssilby
272131503Sbms	/* Set the register address and data to write. */
273177050Syongari	CSR_WRITE_1(sc, VR_MIIADDR, reg);
274177050Syongari	CSR_WRITE_2(sc, VR_MIIDATA, data);
275110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
276110168Ssilby
277177050Syongari	for (i = 0; i < VR_MII_TIMEOUT; i++) {
278177050Syongari		DELAY(1);
279110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
280110168Ssilby			break;
281110168Ssilby	}
282177050Syongari	if (i == VR_MII_TIMEOUT)
283177050Syongari		device_printf(sc->vr_dev, "phy write timeout %d:%d\n", phy,
284177050Syongari		    reg);
285110168Ssilby
286131503Sbms	return (0);
287110168Ssilby}
288110168Ssilby
289177050Syongari/*
290177050Syongari * In order to fiddle with the
291177050Syongari * 'full-duplex' and '100Mbps' bits in the netconfig register, we
292177050Syongari * first have to put the transmit and/or receive logic in the idle state.
293177050Syongari */
294177050Syongaristatic void
295223405Syongarivr_miibus_statchg(device_t dev)
29651432Swpaul{
297177050Syongari	struct vr_softc		*sc;
298177050Syongari	struct mii_data		*mii;
299177050Syongari	struct ifnet		*ifp;
300177050Syongari	int			lfdx, mfdx;
301177050Syongari	uint8_t			cr0, cr1, fc;
30241502Swpaul
303223405Syongari	sc = device_get_softc(dev);
304177050Syongari	mii = device_get_softc(sc->vr_miibus);
305177050Syongari	ifp = sc->vr_ifp;
306177050Syongari	if (mii == NULL || ifp == NULL ||
307223405Syongari	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
308177050Syongari		return;
30941502Swpaul
310228086Syongari	sc->vr_flags &= ~(VR_F_LINK | VR_F_TXPAUSE);
311223405Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
312223405Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
313223405Syongari		switch (IFM_SUBTYPE(mii->mii_media_active)) {
314223405Syongari		case IFM_10_T:
315223405Syongari		case IFM_100_TX:
316228084Syongari			sc->vr_flags |= VR_F_LINK;
317223405Syongari			break;
318223405Syongari		default:
319223405Syongari			break;
320223405Syongari		}
321223405Syongari	}
322177050Syongari
323228084Syongari	if ((sc->vr_flags & VR_F_LINK) != 0) {
324177050Syongari		cr0 = CSR_READ_1(sc, VR_CR0);
325177050Syongari		cr1 = CSR_READ_1(sc, VR_CR1);
326177050Syongari		mfdx = (cr1 & VR_CR1_FULLDUPLEX) != 0;
327177050Syongari		lfdx = (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0;
328177050Syongari		if (mfdx != lfdx) {
329177050Syongari			if ((cr0 & (VR_CR0_TX_ON | VR_CR0_RX_ON)) != 0) {
330177050Syongari				if (vr_tx_stop(sc) != 0 ||
331177050Syongari				    vr_rx_stop(sc) != 0) {
332177050Syongari					device_printf(sc->vr_dev,
333177050Syongari					    "%s: Tx/Rx shutdown error -- "
334177050Syongari					    "resetting\n", __func__);
335177050Syongari					sc->vr_flags |= VR_F_RESTART;
336177050Syongari					VR_UNLOCK(sc);
337177050Syongari					return;
338177050Syongari				}
339177050Syongari			}
340177050Syongari			if (lfdx)
341177050Syongari				cr1 |= VR_CR1_FULLDUPLEX;
342177050Syongari			else
343177050Syongari				cr1 &= ~VR_CR1_FULLDUPLEX;
344177050Syongari			CSR_WRITE_1(sc, VR_CR1, cr1);
345177050Syongari		}
346177050Syongari		fc = 0;
347177050Syongari		/* Configure flow-control. */
348177050Syongari		if (sc->vr_revid >= REV_ID_VT6105_A0) {
349177050Syongari			fc = CSR_READ_1(sc, VR_FLOWCR1);
350177050Syongari			fc &= ~(VR_FLOWCR1_TXPAUSE | VR_FLOWCR1_RXPAUSE);
351177050Syongari			if ((IFM_OPTIONS(mii->mii_media_active) &
352177050Syongari			    IFM_ETH_RXPAUSE) != 0)
353177050Syongari				fc |= VR_FLOWCR1_RXPAUSE;
354177050Syongari			if ((IFM_OPTIONS(mii->mii_media_active) &
355228086Syongari			    IFM_ETH_TXPAUSE) != 0) {
356177050Syongari				fc |= VR_FLOWCR1_TXPAUSE;
357228086Syongari				sc->vr_flags |= VR_F_TXPAUSE;
358228086Syongari			}
359177050Syongari			CSR_WRITE_1(sc, VR_FLOWCR1, fc);
360177050Syongari		} else if (sc->vr_revid >= REV_ID_VT6102_A) {
361177050Syongari			/* No Tx puase capability available for Rhine II. */
362177050Syongari			fc = CSR_READ_1(sc, VR_MISC_CR0);
363177050Syongari			fc &= ~VR_MISCCR0_RXPAUSE;
364177050Syongari			if ((IFM_OPTIONS(mii->mii_media_active) &
365177050Syongari			    IFM_ETH_RXPAUSE) != 0)
366177050Syongari				fc |= VR_MISCCR0_RXPAUSE;
367177050Syongari			CSR_WRITE_1(sc, VR_MISC_CR0, fc);
368177050Syongari		}
369177050Syongari		vr_rx_start(sc);
370177050Syongari		vr_tx_start(sc);
371177050Syongari	} else {
372177050Syongari		if (vr_tx_stop(sc) != 0 || vr_rx_stop(sc) != 0) {
373177050Syongari			device_printf(sc->vr_dev,
374177050Syongari			    "%s: Tx/Rx shutdown error -- resetting\n",
375177050Syongari			    __func__);
376177050Syongari			sc->vr_flags |= VR_F_RESTART;
377177050Syongari		}
378177050Syongari	}
37951432Swpaul}
38051432Swpaul
381180552Syongari
382180552Syongaristatic void
383180552Syongarivr_cam_mask(struct vr_softc *sc, uint32_t mask, int type)
384180552Syongari{
385180552Syongari
386180552Syongari	if (type == VR_MCAST_CAM)
387180552Syongari		CSR_WRITE_1(sc, VR_CAMCTL, VR_CAMCTL_ENA | VR_CAMCTL_MCAST);
388180552Syongari	else
389180552Syongari		CSR_WRITE_1(sc, VR_CAMCTL, VR_CAMCTL_ENA | VR_CAMCTL_VLAN);
390180552Syongari	CSR_WRITE_4(sc, VR_CAMMASK, mask);
391180552Syongari	CSR_WRITE_1(sc, VR_CAMCTL, 0);
392180552Syongari}
393180552Syongari
394177050Syongaristatic int
395180552Syongarivr_cam_data(struct vr_softc *sc, int type, int idx, uint8_t *mac)
39651432Swpaul{
397177050Syongari	int	i;
39851432Swpaul
399180552Syongari	if (type == VR_MCAST_CAM) {
400180552Syongari		if (idx < 0 || idx >= VR_CAM_MCAST_CNT || mac == NULL)
401180552Syongari			return (EINVAL);
402180552Syongari		CSR_WRITE_1(sc, VR_CAMCTL, VR_CAMCTL_ENA | VR_CAMCTL_MCAST);
403180552Syongari	} else
404180552Syongari		CSR_WRITE_1(sc, VR_CAMCTL, VR_CAMCTL_ENA | VR_CAMCTL_VLAN);
405177050Syongari
406177050Syongari	/* Set CAM entry address. */
407177050Syongari	CSR_WRITE_1(sc, VR_CAMADDR, idx);
408177050Syongari	/* Set CAM entry data. */
409180552Syongari	if (type == VR_MCAST_CAM) {
410180552Syongari		for (i = 0; i < ETHER_ADDR_LEN; i++)
411180552Syongari			CSR_WRITE_1(sc, VR_MCAM0 + i, mac[i]);
412180552Syongari	} else {
413180552Syongari		CSR_WRITE_1(sc, VR_VCAM0, mac[0]);
414180552Syongari		CSR_WRITE_1(sc, VR_VCAM1, mac[1]);
415180552Syongari	}
416180552Syongari	DELAY(10);
417177050Syongari	/* Write CAM and wait for self-clear of VR_CAMCTL_WRITE bit. */
418180552Syongari	CSR_WRITE_1(sc, VR_CAMCTL, VR_CAMCTL_ENA | VR_CAMCTL_WRITE);
419177050Syongari	for (i = 0; i < VR_TIMEOUT; i++) {
420177050Syongari		DELAY(1);
421177050Syongari		if ((CSR_READ_1(sc, VR_CAMCTL) & VR_CAMCTL_WRITE) == 0)
422177050Syongari			break;
423177050Syongari	}
424177050Syongari
425177050Syongari	if (i == VR_TIMEOUT)
426177050Syongari		device_printf(sc->vr_dev, "%s: setting CAM filter timeout!\n",
427177050Syongari		    __func__);
428180552Syongari	CSR_WRITE_1(sc, VR_CAMCTL, 0);
429177050Syongari
430177050Syongari	return (i == VR_TIMEOUT ? ETIMEDOUT : 0);
43141502Swpaul}
43241502Swpaul
43341502Swpaul/*
43441502Swpaul * Program the 64-bit multicast hash filter.
43541502Swpaul */
436102336Salfredstatic void
437177050Syongarivr_set_filter(struct vr_softc *sc)
43841502Swpaul{
439177050Syongari	struct ifnet		*ifp;
440177050Syongari	int			h;
441131503Sbms	uint32_t		hashes[2] = { 0, 0 };
44241502Swpaul	struct ifmultiaddr	*ifma;
443131503Sbms	uint8_t			rxfilt;
444177050Syongari	int			error, mcnt;
445177050Syongari	uint32_t		cam_mask;
44641502Swpaul
447131518Sbms	VR_LOCK_ASSERT(sc);
44841502Swpaul
449177050Syongari	ifp = sc->vr_ifp;
45041502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
451185014Syongari	rxfilt &= ~(VR_RXCFG_RX_PROMISC | VR_RXCFG_RX_BROAD |
452185014Syongari	    VR_RXCFG_RX_MULTI);
453177050Syongari	if (ifp->if_flags & IFF_BROADCAST)
454177050Syongari		rxfilt |= VR_RXCFG_RX_BROAD;
45541502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
45641502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
457177050Syongari		if (ifp->if_flags & IFF_PROMISC)
458177050Syongari			rxfilt |= VR_RXCFG_RX_PROMISC;
45941502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
46041502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
46141502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
46241502Swpaul		return;
46341502Swpaul	}
46441502Swpaul
465131503Sbms	/* Now program new ones. */
466177050Syongari	error = 0;
467180552Syongari	mcnt = 0;
468195049Srwatson	if_maddr_rlock(ifp);
469177050Syongari	if ((sc->vr_quirks & VR_Q_CAM) != 0) {
470177050Syongari		/*
471177050Syongari		 * For hardwares that have CAM capability, use
472177050Syongari		 * 32 entries multicast perfect filter.
473177050Syongari		 */
474177050Syongari		cam_mask = 0;
475177050Syongari		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
476177050Syongari			if (ifma->ifma_addr->sa_family != AF_LINK)
477177050Syongari				continue;
478180552Syongari			error = vr_cam_data(sc, VR_MCAST_CAM, mcnt,
479177050Syongari			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
480177050Syongari			if (error != 0) {
481177050Syongari				cam_mask = 0;
482177050Syongari				break;
483177050Syongari			}
484177050Syongari			cam_mask |= 1 << mcnt;
485177050Syongari			mcnt++;
486177050Syongari		}
487180552Syongari		vr_cam_mask(sc, VR_MCAST_CAM, cam_mask);
48841502Swpaul	}
489177050Syongari
490177050Syongari	if ((sc->vr_quirks & VR_Q_CAM) == 0 || error != 0) {
491177050Syongari		/*
492177050Syongari		 * If there are too many multicast addresses or
493177050Syongari		 * setting multicast CAM filter failed, use hash
494177050Syongari		 * table based filtering.
495177050Syongari		 */
496180552Syongari		mcnt = 0;
497177050Syongari		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
498177050Syongari			if (ifma->ifma_addr->sa_family != AF_LINK)
499177050Syongari				continue;
500177050Syongari			h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
501177050Syongari			    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
502177050Syongari			if (h < 32)
503177050Syongari				hashes[0] |= (1 << h);
504177050Syongari			else
505177050Syongari				hashes[1] |= (1 << (h - 32));
506177050Syongari			mcnt++;
507177050Syongari		}
508177050Syongari	}
509195049Srwatson	if_maddr_runlock(ifp);
51041502Swpaul
511177050Syongari	if (mcnt > 0)
51241502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
51341502Swpaul
51441502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
51541502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
51641502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
51741502Swpaul}
51841502Swpaul
519102336Salfredstatic void
520168946Sphkvr_reset(const struct vr_softc *sc)
52141502Swpaul{
522177050Syongari	int		i;
52341502Swpaul
524151773Sjhb	/*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during attach w/o lock. */
525131518Sbms
526177050Syongari	CSR_WRITE_1(sc, VR_CR1, VR_CR1_RESET);
527177050Syongari	if (sc->vr_revid < REV_ID_VT6102_A) {
528177050Syongari		/* VT86C100A needs more delay after reset. */
529177050Syongari		DELAY(100);
530177050Syongari	}
53141502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
53241502Swpaul		DELAY(10);
533177050Syongari		if (!(CSR_READ_1(sc, VR_CR1) & VR_CR1_RESET))
53441502Swpaul			break;
53541502Swpaul	}
536107220Ssilby	if (i == VR_TIMEOUT) {
537177050Syongari		if (sc->vr_revid < REV_ID_VT6102_A)
538162315Sglebius			device_printf(sc->vr_dev, "reset never completed!\n");
539107220Ssilby		else {
540177050Syongari			/* Use newer force reset command. */
541177050Syongari			device_printf(sc->vr_dev,
542177050Syongari			    "Using force reset command.\n");
543107220Ssilby			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
544177050Syongari			/*
545177050Syongari			 * Wait a little while for the chip to get its brains
546177050Syongari			 * in order.
547177050Syongari			 */
548177050Syongari			DELAY(2000);
549107220Ssilby		}
550107220Ssilby	}
55141502Swpaul
55241502Swpaul}
55341502Swpaul
55441502Swpaul/*
55541502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
556168813Sphk * IDs against our list and return a match or NULL
557168813Sphk */
558226171Smariusstatic const struct vr_type *
559168813Sphkvr_match(device_t dev)
560168813Sphk{
561226171Smarius	const struct vr_type	*t = vr_devs;
562168813Sphk
563168813Sphk	for (t = vr_devs; t->vr_name != NULL; t++)
564168813Sphk		if ((pci_get_vendor(dev) == t->vr_vid) &&
565168813Sphk		    (pci_get_device(dev) == t->vr_did))
566168813Sphk			return (t);
567168813Sphk	return (NULL);
568168813Sphk}
569168813Sphk
570168813Sphk/*
571168813Sphk * Probe for a VIA Rhine chip. Check the PCI vendor and device
57241502Swpaul * IDs against our list and return a device name if we find a match.
57341502Swpaul */
574102336Salfredstatic int
575131503Sbmsvr_probe(device_t dev)
57641502Swpaul{
577226171Smarius	const struct vr_type	*t;
57841502Swpaul
579168813Sphk	t = vr_match(dev);
580168813Sphk	if (t != NULL) {
581168813Sphk		device_set_desc(dev, t->vr_name);
582168813Sphk		return (BUS_PROBE_DEFAULT);
58341502Swpaul	}
584131503Sbms	return (ENXIO);
58541502Swpaul}
58641502Swpaul
58741502Swpaul/*
58841502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
58941502Swpaul * setup and ethernet/BPF attach.
59041502Swpaul */
591102336Salfredstatic int
592168946Sphkvr_attach(device_t dev)
59341502Swpaul{
59441502Swpaul	struct vr_softc		*sc;
59541502Swpaul	struct ifnet		*ifp;
596226171Smarius	const struct vr_type	*t;
597177050Syongari	uint8_t			eaddr[ETHER_ADDR_LEN];
598177050Syongari	int			error, rid;
599213893Smarius	int			i, phy, pmc;
60041502Swpaul
60149610Swpaul	sc = device_get_softc(dev);
602162315Sglebius	sc->vr_dev = dev;
603168813Sphk	t = vr_match(dev);
604168813Sphk	KASSERT(t != NULL, ("Lost if_vr device match"));
605168813Sphk	sc->vr_quirks = t->vr_quirks;
606168813Sphk	device_printf(dev, "Quirks: 0x%x\n", sc->vr_quirks);
60741502Swpaul
60893818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
609131518Sbms	    MTX_DEF);
610151911Sjhb	callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0);
611177050Syongari	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
612177050Syongari	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
613177050Syongari	    OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
614177050Syongari	    vr_sysctl_stats, "I", "Statistics");
615151911Sjhb
616177050Syongari	error = 0;
617177050Syongari
61841502Swpaul	/*
61941502Swpaul	 * Map control/status registers.
62041502Swpaul	 */
62172813Swpaul	pci_enable_busmaster(dev);
622177050Syongari	sc->vr_revid = pci_get_revid(dev);
623177050Syongari	device_printf(dev, "Revision: 0x%x\n", sc->vr_revid);
62441502Swpaul
625177050Syongari	sc->vr_res_id = PCIR_BAR(0);
626177050Syongari	sc->vr_res_type = SYS_RES_IOPORT;
627177050Syongari	sc->vr_res = bus_alloc_resource_any(dev, sc->vr_res_type,
628177050Syongari	    &sc->vr_res_id, RF_ACTIVE);
62949610Swpaul	if (sc->vr_res == NULL) {
630177050Syongari		device_printf(dev, "couldn't map ports\n");
63149610Swpaul		error = ENXIO;
63241502Swpaul		goto fail;
63341502Swpaul	}
63441502Swpaul
635177050Syongari	/* Allocate interrupt. */
63649610Swpaul	rid = 0;
637127135Snjl	sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
63849610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
63949610Swpaul
64049610Swpaul	if (sc->vr_irq == NULL) {
641151773Sjhb		device_printf(dev, "couldn't map interrupt\n");
64249610Swpaul		error = ENXIO;
64341502Swpaul		goto fail;
64441502Swpaul	}
64541502Swpaul
646151773Sjhb	/* Allocate ifnet structure. */
647151773Sjhb	ifp = sc->vr_ifp = if_alloc(IFT_ETHER);
648151773Sjhb	if (ifp == NULL) {
649177050Syongari		device_printf(dev, "couldn't allocate ifnet structure\n");
650151773Sjhb		error = ENOSPC;
651151773Sjhb		goto fail;
652151773Sjhb	}
653151773Sjhb	ifp->if_softc = sc;
654151773Sjhb	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
655151773Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
656151773Sjhb	ifp->if_ioctl = vr_ioctl;
657151773Sjhb	ifp->if_start = vr_start;
658151773Sjhb	ifp->if_init = vr_init;
659177050Syongari	IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_RING_CNT - 1);
660177050Syongari	ifp->if_snd.ifq_maxlen = VR_TX_RING_CNT - 1;
661151773Sjhb	IFQ_SET_READY(&ifp->if_snd);
662168827Sphk
663235334Srpaulo	TASK_INIT(&sc->vr_inttask, 0, vr_int_task, sc);
664235334Srpaulo
665177050Syongari	/* Configure Tx FIFO threshold. */
666177050Syongari	sc->vr_txthresh = VR_TXTHRESH_MIN;
667177050Syongari	if (sc->vr_revid < REV_ID_VT6105_A0) {
668177050Syongari		/*
669177050Syongari		 * Use store and forward mode for Rhine I/II.
670177050Syongari		 * Otherwise they produce a lot of Tx underruns and
671177050Syongari		 * it would take a while to get working FIFO threshold
672177050Syongari		 * value.
673177050Syongari		 */
674177050Syongari		sc->vr_txthresh = VR_TXTHRESH_MAX;
675177050Syongari	}
676177050Syongari	if ((sc->vr_quirks & VR_Q_CSUM) != 0) {
677177050Syongari		ifp->if_hwassist = VR_CSUM_FEATURES;
678168827Sphk		ifp->if_capabilities |= IFCAP_HWCSUM;
679177050Syongari		/*
680177050Syongari		 * To update checksum field the hardware may need to
681177050Syongari		 * store entire frames into FIFO before transmitting.
682177050Syongari		 */
683177050Syongari		sc->vr_txthresh = VR_TXTHRESH_MAX;
684168827Sphk	}
685168827Sphk
686177050Syongari	if (sc->vr_revid >= REV_ID_VT6102_A &&
687219902Sjhb	    pci_find_cap(dev, PCIY_PMG, &pmc) == 0)
688177050Syongari		ifp->if_capabilities |= IFCAP_WOL_UCAST | IFCAP_WOL_MAGIC;
689177050Syongari
690177050Syongari	/* Rhine supports oversized VLAN frame. */
691168973Sphk	ifp->if_capabilities |= IFCAP_VLAN_MTU;
692151773Sjhb	ifp->if_capenable = ifp->if_capabilities;
693151773Sjhb#ifdef DEVICE_POLLING
694151773Sjhb	ifp->if_capabilities |= IFCAP_POLLING;
695151773Sjhb#endif
696151773Sjhb
69776586Swpaul	/*
69876586Swpaul	 * Windows may put the chip in suspend mode when it
69976586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
70076586Swpaul	 * up again.
70176586Swpaul	 */
702219902Sjhb	if (pci_find_cap(dev, PCIY_PMG, &pmc) == 0)
703172555Syongari		VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
70476586Swpaul
705131503Sbms	/*
70641502Swpaul	 * Get station address. The way the Rhine chips work,
70741502Swpaul	 * you're not allowed to directly access the EEPROM once
70841502Swpaul	 * they've been programmed a special way. Consequently,
70941502Swpaul	 * we need to read the node address from the PAR0 and PAR1
71041502Swpaul	 * registers.
711177050Syongari	 * Reloading EEPROM also overwrites VR_CFGA, VR_CFGB,
712177050Syongari	 * VR_CFGC and VR_CFGD such that memory mapped IO configured
713177050Syongari	 * by driver is reset to default state.
71441502Swpaul	 */
71541502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
716177050Syongari	for (i = VR_TIMEOUT; i > 0; i--) {
717177050Syongari		DELAY(1);
718177050Syongari		if ((CSR_READ_1(sc, VR_EECSR) & VR_EECSR_LOAD) == 0)
719177050Syongari			break;
720177050Syongari	}
721177050Syongari	if (i == 0)
722177050Syongari		device_printf(dev, "Reloading EEPROM timeout!\n");
72341502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
72441502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
72541502Swpaul
726177050Syongari	/* Reset the adapter. */
727177050Syongari	vr_reset(sc);
728177050Syongari	/* Ack intr & disable further interrupts. */
729177050Syongari	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
730177050Syongari	CSR_WRITE_2(sc, VR_IMR, 0);
731177050Syongari	if (sc->vr_revid >= REV_ID_VT6102_A)
732177050Syongari		CSR_WRITE_2(sc, VR_MII_IMR, 0);
73351432Swpaul
734177050Syongari	if (sc->vr_revid < REV_ID_VT6102_A) {
735177050Syongari		pci_write_config(dev, VR_PCI_MODE2,
736177050Syongari		    pci_read_config(dev, VR_PCI_MODE2, 1) |
737177050Syongari		    VR_MODE2_MODE10T, 1);
738177050Syongari	} else {
739177050Syongari		/* Report error instead of retrying forever. */
740177050Syongari		pci_write_config(dev, VR_PCI_MODE2,
741177050Syongari		    pci_read_config(dev, VR_PCI_MODE2, 1) |
742177050Syongari		    VR_MODE2_PCEROPT, 1);
743177050Syongari        	/* Detect MII coding error. */
744177050Syongari		pci_write_config(dev, VR_PCI_MODE3,
745177050Syongari		    pci_read_config(dev, VR_PCI_MODE3, 1) |
746177050Syongari		    VR_MODE3_MIION, 1);
747177050Syongari		if (sc->vr_revid >= REV_ID_VT6105_LOM &&
748177050Syongari		    sc->vr_revid < REV_ID_VT6105M_A0)
749177050Syongari			pci_write_config(dev, VR_PCI_MODE2,
750177050Syongari			    pci_read_config(dev, VR_PCI_MODE2, 1) |
751177050Syongari			    VR_MODE2_MODE10T, 1);
752177050Syongari		/* Enable Memory-Read-Multiple. */
753177050Syongari		if (sc->vr_revid >= REV_ID_VT6107_A1 &&
754177050Syongari		    sc->vr_revid < REV_ID_VT6105M_A0)
755177050Syongari			pci_write_config(dev, VR_PCI_MODE2,
756177050Syongari			    pci_read_config(dev, VR_PCI_MODE2, 1) |
757177050Syongari			    VR_MODE2_MRDPL, 1);
758177050Syongari	}
759177050Syongari	/* Disable MII AUTOPOLL. */
760177050Syongari	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
761177050Syongari
762177050Syongari	if (vr_dma_alloc(sc) != 0) {
76349610Swpaul		error = ENXIO;
76449610Swpaul		goto fail;
76541502Swpaul	}
76641502Swpaul
767213893Smarius	/* Do MII setup. */
768177050Syongari	if (sc->vr_revid >= REV_ID_VT6105_A0)
769213893Smarius		phy = 1;
770177050Syongari	else
771213893Smarius		phy = CSR_READ_1(sc, VR_PHYADDR) & VR_PHYADDR_MASK;
772213893Smarius	error = mii_attach(dev, &sc->vr_miibus, ifp, vr_ifmedia_upd,
773228086Syongari	    vr_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY,
774228086Syongari	    sc->vr_revid >= REV_ID_VT6102_A ? MIIF_DOPAUSE : 0);
775213893Smarius	if (error != 0) {
776213893Smarius		device_printf(dev, "attaching PHYs failed\n");
77741502Swpaul		goto fail;
77841502Swpaul	}
77941502Swpaul
780131503Sbms	/* Call MI attach routine. */
781106936Ssam	ether_ifattach(ifp, eaddr);
782177050Syongari	/*
783177050Syongari	 * Tell the upper layer(s) we support long frames.
784177050Syongari	 * Must appear after the call to ether_ifattach() because
785177050Syongari	 * ether_ifattach() sets ifi_hdrlen to the default value.
786177050Syongari	 */
787270856Sglebius	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
78841502Swpaul
789177050Syongari	/* Hook interrupt last to avoid having to lock softc. */
790131518Sbms	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE,
791235334Srpaulo	    vr_intr, NULL, sc, &sc->vr_intrhand);
792112872Snjl
793112872Snjl	if (error) {
794151773Sjhb		device_printf(dev, "couldn't set up irq\n");
795113609Snjl		ether_ifdetach(ifp);
796112872Snjl		goto fail;
797112872Snjl	}
798112872Snjl
79941502Swpaulfail:
800112872Snjl	if (error)
801112872Snjl		vr_detach(dev);
80267087Swpaul
803131503Sbms	return (error);
80441502Swpaul}
80541502Swpaul
806113609Snjl/*
807113609Snjl * Shutdown hardware and free up resources. This can be called any
808113609Snjl * time after the mutex has been initialized. It is called in both
809113609Snjl * the error case in attach and the normal detach case so it needs
810113609Snjl * to be careful about only freeing resources that have actually been
811113609Snjl * allocated.
812113609Snjl */
813102336Salfredstatic int
814131503Sbmsvr_detach(device_t dev)
81549610Swpaul{
816131503Sbms	struct vr_softc		*sc = device_get_softc(dev);
817147256Sbrooks	struct ifnet		*ifp = sc->vr_ifp;
81849610Swpaul
819112880Sjhb	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
820131518Sbms
821150789Sglebius#ifdef DEVICE_POLLING
822177050Syongari	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
823150789Sglebius		ether_poll_deregister(ifp);
824150789Sglebius#endif
825150789Sglebius
826177050Syongari	/* These should only be active if attach succeeded. */
827113812Simp	if (device_is_attached(dev)) {
828151911Sjhb		VR_LOCK(sc);
829228084Syongari		sc->vr_flags |= VR_F_DETACHED;
830113609Snjl		vr_stop(sc);
831151911Sjhb		VR_UNLOCK(sc);
832151911Sjhb		callout_drain(&sc->vr_stat_callout);
833235334Srpaulo		taskqueue_drain(taskqueue_fast, &sc->vr_inttask);
834112872Snjl		ether_ifdetach(ifp);
835113609Snjl	}
836113609Snjl	if (sc->vr_miibus)
837112872Snjl		device_delete_child(dev, sc->vr_miibus);
838113609Snjl	bus_generic_detach(dev);
83949610Swpaul
840112872Snjl	if (sc->vr_intrhand)
841112872Snjl		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
842112872Snjl	if (sc->vr_irq)
843112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
844112872Snjl	if (sc->vr_res)
845177050Syongari		bus_release_resource(dev, sc->vr_res_type, sc->vr_res_id,
846177050Syongari		    sc->vr_res);
84751432Swpaul
848151297Sru	if (ifp)
849151297Sru		if_free(ifp);
850151297Sru
851177050Syongari	vr_dma_free(sc);
85249610Swpaul
85367087Swpaul	mtx_destroy(&sc->vr_mtx);
85449610Swpaul
855131503Sbms	return (0);
85649610Swpaul}
85749610Swpaul
858177050Syongaristruct vr_dmamap_arg {
859177050Syongari	bus_addr_t	vr_busaddr;
860177050Syongari};
861177050Syongari
862177050Syongaristatic void
863177050Syongarivr_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
864177050Syongari{
865177050Syongari	struct vr_dmamap_arg	*ctx;
866177050Syongari
867177050Syongari	if (error != 0)
868177050Syongari		return;
869177050Syongari	ctx = arg;
870177050Syongari	ctx->vr_busaddr = segs[0].ds_addr;
871177050Syongari}
872177050Syongari
873177050Syongaristatic int
874177050Syongarivr_dma_alloc(struct vr_softc *sc)
875177050Syongari{
876177050Syongari	struct vr_dmamap_arg	ctx;
877177050Syongari	struct vr_txdesc	*txd;
878177050Syongari	struct vr_rxdesc	*rxd;
879177050Syongari	bus_size_t		tx_alignment;
880177050Syongari	int			error, i;
881177050Syongari
882177050Syongari	/* Create parent DMA tag. */
883177050Syongari	error = bus_dma_tag_create(
884177050Syongari	    bus_get_dma_tag(sc->vr_dev),	/* parent */
885177050Syongari	    1, 0,			/* alignment, boundary */
886177050Syongari	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
887177050Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
888177050Syongari	    NULL, NULL,			/* filter, filterarg */
889177050Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
890177050Syongari	    0,				/* nsegments */
891177050Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
892177050Syongari	    0,				/* flags */
893177050Syongari	    NULL, NULL,			/* lockfunc, lockarg */
894177050Syongari	    &sc->vr_cdata.vr_parent_tag);
895177050Syongari	if (error != 0) {
896177050Syongari		device_printf(sc->vr_dev, "failed to create parent DMA tag\n");
897177050Syongari		goto fail;
898177050Syongari	}
899177050Syongari	/* Create tag for Tx ring. */
900177050Syongari	error = bus_dma_tag_create(
901177050Syongari	    sc->vr_cdata.vr_parent_tag,	/* parent */
902177050Syongari	    VR_RING_ALIGN, 0,		/* alignment, boundary */
903177050Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
904177050Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
905177050Syongari	    NULL, NULL,			/* filter, filterarg */
906177050Syongari	    VR_TX_RING_SIZE,		/* maxsize */
907177050Syongari	    1,				/* nsegments */
908177050Syongari	    VR_TX_RING_SIZE,		/* maxsegsize */
909177050Syongari	    0,				/* flags */
910177050Syongari	    NULL, NULL,			/* lockfunc, lockarg */
911177050Syongari	    &sc->vr_cdata.vr_tx_ring_tag);
912177050Syongari	if (error != 0) {
913177050Syongari		device_printf(sc->vr_dev, "failed to create Tx ring DMA tag\n");
914177050Syongari		goto fail;
915177050Syongari	}
916177050Syongari
917177050Syongari	/* Create tag for Rx ring. */
918177050Syongari	error = bus_dma_tag_create(
919177050Syongari	    sc->vr_cdata.vr_parent_tag,	/* parent */
920177050Syongari	    VR_RING_ALIGN, 0,		/* alignment, boundary */
921177050Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
922177050Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
923177050Syongari	    NULL, NULL,			/* filter, filterarg */
924177050Syongari	    VR_RX_RING_SIZE,		/* maxsize */
925177050Syongari	    1,				/* nsegments */
926177050Syongari	    VR_RX_RING_SIZE,		/* maxsegsize */
927177050Syongari	    0,				/* flags */
928177050Syongari	    NULL, NULL,			/* lockfunc, lockarg */
929177050Syongari	    &sc->vr_cdata.vr_rx_ring_tag);
930177050Syongari	if (error != 0) {
931177050Syongari		device_printf(sc->vr_dev, "failed to create Rx ring DMA tag\n");
932177050Syongari		goto fail;
933177050Syongari	}
934177050Syongari
935177050Syongari	if ((sc->vr_quirks & VR_Q_NEEDALIGN) != 0)
936177050Syongari		tx_alignment = sizeof(uint32_t);
937177050Syongari	else
938177050Syongari		tx_alignment = 1;
939177050Syongari	/* Create tag for Tx buffers. */
940177050Syongari	error = bus_dma_tag_create(
941177050Syongari	    sc->vr_cdata.vr_parent_tag,	/* parent */
942177050Syongari	    tx_alignment, 0,		/* alignment, boundary */
943177050Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
944177050Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
945177050Syongari	    NULL, NULL,			/* filter, filterarg */
946177050Syongari	    MCLBYTES * VR_MAXFRAGS,	/* maxsize */
947177050Syongari	    VR_MAXFRAGS,		/* nsegments */
948177050Syongari	    MCLBYTES,			/* maxsegsize */
949177050Syongari	    0,				/* flags */
950177050Syongari	    NULL, NULL,			/* lockfunc, lockarg */
951177050Syongari	    &sc->vr_cdata.vr_tx_tag);
952177050Syongari	if (error != 0) {
953177050Syongari		device_printf(sc->vr_dev, "failed to create Tx DMA tag\n");
954177050Syongari		goto fail;
955177050Syongari	}
956177050Syongari
957177050Syongari	/* Create tag for Rx buffers. */
958177050Syongari	error = bus_dma_tag_create(
959177050Syongari	    sc->vr_cdata.vr_parent_tag,	/* parent */
960177050Syongari	    VR_RX_ALIGN, 0,		/* alignment, boundary */
961177050Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
962177050Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
963177050Syongari	    NULL, NULL,			/* filter, filterarg */
964177050Syongari	    MCLBYTES,			/* maxsize */
965177050Syongari	    1,				/* nsegments */
966177050Syongari	    MCLBYTES,			/* maxsegsize */
967177050Syongari	    0,				/* flags */
968177050Syongari	    NULL, NULL,			/* lockfunc, lockarg */
969177050Syongari	    &sc->vr_cdata.vr_rx_tag);
970177050Syongari	if (error != 0) {
971177050Syongari		device_printf(sc->vr_dev, "failed to create Rx DMA tag\n");
972177050Syongari		goto fail;
973177050Syongari	}
974177050Syongari
975177050Syongari	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
976177050Syongari	error = bus_dmamem_alloc(sc->vr_cdata.vr_tx_ring_tag,
977177050Syongari	    (void **)&sc->vr_rdata.vr_tx_ring, BUS_DMA_WAITOK |
978177050Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->vr_cdata.vr_tx_ring_map);
979177050Syongari	if (error != 0) {
980177050Syongari		device_printf(sc->vr_dev,
981177050Syongari		    "failed to allocate DMA'able memory for Tx ring\n");
982177050Syongari		goto fail;
983177050Syongari	}
984177050Syongari
985177050Syongari	ctx.vr_busaddr = 0;
986177050Syongari	error = bus_dmamap_load(sc->vr_cdata.vr_tx_ring_tag,
987177050Syongari	    sc->vr_cdata.vr_tx_ring_map, sc->vr_rdata.vr_tx_ring,
988177050Syongari	    VR_TX_RING_SIZE, vr_dmamap_cb, &ctx, 0);
989177050Syongari	if (error != 0 || ctx.vr_busaddr == 0) {
990177050Syongari		device_printf(sc->vr_dev,
991177050Syongari		    "failed to load DMA'able memory for Tx ring\n");
992177050Syongari		goto fail;
993177050Syongari	}
994177050Syongari	sc->vr_rdata.vr_tx_ring_paddr = ctx.vr_busaddr;
995177050Syongari
996177050Syongari	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
997177050Syongari	error = bus_dmamem_alloc(sc->vr_cdata.vr_rx_ring_tag,
998177050Syongari	    (void **)&sc->vr_rdata.vr_rx_ring, BUS_DMA_WAITOK |
999177050Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->vr_cdata.vr_rx_ring_map);
1000177050Syongari	if (error != 0) {
1001177050Syongari		device_printf(sc->vr_dev,
1002177050Syongari		    "failed to allocate DMA'able memory for Rx ring\n");
1003177050Syongari		goto fail;
1004177050Syongari	}
1005177050Syongari
1006177050Syongari	ctx.vr_busaddr = 0;
1007177050Syongari	error = bus_dmamap_load(sc->vr_cdata.vr_rx_ring_tag,
1008177050Syongari	    sc->vr_cdata.vr_rx_ring_map, sc->vr_rdata.vr_rx_ring,
1009177050Syongari	    VR_RX_RING_SIZE, vr_dmamap_cb, &ctx, 0);
1010177050Syongari	if (error != 0 || ctx.vr_busaddr == 0) {
1011177050Syongari		device_printf(sc->vr_dev,
1012177050Syongari		    "failed to load DMA'able memory for Rx ring\n");
1013177050Syongari		goto fail;
1014177050Syongari	}
1015177050Syongari	sc->vr_rdata.vr_rx_ring_paddr = ctx.vr_busaddr;
1016177050Syongari
1017177050Syongari	/* Create DMA maps for Tx buffers. */
1018177050Syongari	for (i = 0; i < VR_TX_RING_CNT; i++) {
1019177050Syongari		txd = &sc->vr_cdata.vr_txdesc[i];
1020177050Syongari		txd->tx_m = NULL;
1021177050Syongari		txd->tx_dmamap = NULL;
1022177050Syongari		error = bus_dmamap_create(sc->vr_cdata.vr_tx_tag, 0,
1023177050Syongari		    &txd->tx_dmamap);
1024177050Syongari		if (error != 0) {
1025177050Syongari			device_printf(sc->vr_dev,
1026177050Syongari			    "failed to create Tx dmamap\n");
1027177050Syongari			goto fail;
1028177050Syongari		}
1029177050Syongari	}
1030177050Syongari	/* Create DMA maps for Rx buffers. */
1031177050Syongari	if ((error = bus_dmamap_create(sc->vr_cdata.vr_rx_tag, 0,
1032177050Syongari	    &sc->vr_cdata.vr_rx_sparemap)) != 0) {
1033177050Syongari		device_printf(sc->vr_dev,
1034177050Syongari		    "failed to create spare Rx dmamap\n");
1035177050Syongari		goto fail;
1036177050Syongari	}
1037177050Syongari	for (i = 0; i < VR_RX_RING_CNT; i++) {
1038177050Syongari		rxd = &sc->vr_cdata.vr_rxdesc[i];
1039177050Syongari		rxd->rx_m = NULL;
1040177050Syongari		rxd->rx_dmamap = NULL;
1041177050Syongari		error = bus_dmamap_create(sc->vr_cdata.vr_rx_tag, 0,
1042177050Syongari		    &rxd->rx_dmamap);
1043177050Syongari		if (error != 0) {
1044177050Syongari			device_printf(sc->vr_dev,
1045177050Syongari			    "failed to create Rx dmamap\n");
1046177050Syongari			goto fail;
1047177050Syongari		}
1048177050Syongari	}
1049177050Syongari
1050177050Syongarifail:
1051177050Syongari	return (error);
1052177050Syongari}
1053177050Syongari
1054177050Syongaristatic void
1055177050Syongarivr_dma_free(struct vr_softc *sc)
1056177050Syongari{
1057177050Syongari	struct vr_txdesc	*txd;
1058177050Syongari	struct vr_rxdesc	*rxd;
1059177050Syongari	int			i;
1060177050Syongari
1061177050Syongari	/* Tx ring. */
1062177050Syongari	if (sc->vr_cdata.vr_tx_ring_tag) {
1063267363Sjhb		if (sc->vr_rdata.vr_tx_ring_paddr)
1064177050Syongari			bus_dmamap_unload(sc->vr_cdata.vr_tx_ring_tag,
1065177050Syongari			    sc->vr_cdata.vr_tx_ring_map);
1066267363Sjhb		if (sc->vr_rdata.vr_tx_ring)
1067177050Syongari			bus_dmamem_free(sc->vr_cdata.vr_tx_ring_tag,
1068177050Syongari			    sc->vr_rdata.vr_tx_ring,
1069177050Syongari			    sc->vr_cdata.vr_tx_ring_map);
1070177050Syongari		sc->vr_rdata.vr_tx_ring = NULL;
1071267363Sjhb		sc->vr_rdata.vr_tx_ring_paddr = 0;
1072177050Syongari		bus_dma_tag_destroy(sc->vr_cdata.vr_tx_ring_tag);
1073177050Syongari		sc->vr_cdata.vr_tx_ring_tag = NULL;
1074177050Syongari	}
1075177050Syongari	/* Rx ring. */
1076177050Syongari	if (sc->vr_cdata.vr_rx_ring_tag) {
1077267363Sjhb		if (sc->vr_rdata.vr_rx_ring_paddr)
1078177050Syongari			bus_dmamap_unload(sc->vr_cdata.vr_rx_ring_tag,
1079177050Syongari			    sc->vr_cdata.vr_rx_ring_map);
1080267363Sjhb		if (sc->vr_rdata.vr_rx_ring)
1081177050Syongari			bus_dmamem_free(sc->vr_cdata.vr_rx_ring_tag,
1082177050Syongari			    sc->vr_rdata.vr_rx_ring,
1083177050Syongari			    sc->vr_cdata.vr_rx_ring_map);
1084177050Syongari		sc->vr_rdata.vr_rx_ring = NULL;
1085267363Sjhb		sc->vr_rdata.vr_rx_ring_paddr = 0;
1086177050Syongari		bus_dma_tag_destroy(sc->vr_cdata.vr_rx_ring_tag);
1087177050Syongari		sc->vr_cdata.vr_rx_ring_tag = NULL;
1088177050Syongari	}
1089177050Syongari	/* Tx buffers. */
1090177050Syongari	if (sc->vr_cdata.vr_tx_tag) {
1091177050Syongari		for (i = 0; i < VR_TX_RING_CNT; i++) {
1092177050Syongari			txd = &sc->vr_cdata.vr_txdesc[i];
1093177050Syongari			if (txd->tx_dmamap) {
1094177050Syongari				bus_dmamap_destroy(sc->vr_cdata.vr_tx_tag,
1095177050Syongari				    txd->tx_dmamap);
1096177050Syongari				txd->tx_dmamap = NULL;
1097177050Syongari			}
1098177050Syongari		}
1099177050Syongari		bus_dma_tag_destroy(sc->vr_cdata.vr_tx_tag);
1100177050Syongari		sc->vr_cdata.vr_tx_tag = NULL;
1101177050Syongari	}
1102177050Syongari	/* Rx buffers. */
1103177050Syongari	if (sc->vr_cdata.vr_rx_tag) {
1104177050Syongari		for (i = 0; i < VR_RX_RING_CNT; i++) {
1105177050Syongari			rxd = &sc->vr_cdata.vr_rxdesc[i];
1106177050Syongari			if (rxd->rx_dmamap) {
1107177050Syongari				bus_dmamap_destroy(sc->vr_cdata.vr_rx_tag,
1108177050Syongari				    rxd->rx_dmamap);
1109177050Syongari				rxd->rx_dmamap = NULL;
1110177050Syongari			}
1111177050Syongari		}
1112177050Syongari		if (sc->vr_cdata.vr_rx_sparemap) {
1113177050Syongari			bus_dmamap_destroy(sc->vr_cdata.vr_rx_tag,
1114177050Syongari			    sc->vr_cdata.vr_rx_sparemap);
1115177050Syongari			sc->vr_cdata.vr_rx_sparemap = 0;
1116177050Syongari		}
1117177050Syongari		bus_dma_tag_destroy(sc->vr_cdata.vr_rx_tag);
1118177050Syongari		sc->vr_cdata.vr_rx_tag = NULL;
1119177050Syongari	}
1120177050Syongari
1121177050Syongari	if (sc->vr_cdata.vr_parent_tag) {
1122177050Syongari		bus_dma_tag_destroy(sc->vr_cdata.vr_parent_tag);
1123177050Syongari		sc->vr_cdata.vr_parent_tag = NULL;
1124177050Syongari	}
1125177050Syongari}
1126177050Syongari
112741502Swpaul/*
112841502Swpaul * Initialize the transmit descriptors.
112941502Swpaul */
1130102336Salfredstatic int
1131177050Syongarivr_tx_ring_init(struct vr_softc *sc)
113241502Swpaul{
1133177050Syongari	struct vr_ring_data	*rd;
1134177050Syongari	struct vr_txdesc	*txd;
1135177050Syongari	bus_addr_t		addr;
113641502Swpaul	int			i;
113741502Swpaul
1138177050Syongari	sc->vr_cdata.vr_tx_prod = 0;
1139177050Syongari	sc->vr_cdata.vr_tx_cons = 0;
1140177050Syongari	sc->vr_cdata.vr_tx_cnt = 0;
1141177050Syongari	sc->vr_cdata.vr_tx_pkts = 0;
1142177050Syongari
1143177050Syongari	rd = &sc->vr_rdata;
1144177050Syongari	bzero(rd->vr_tx_ring, VR_TX_RING_SIZE);
1145177050Syongari	for (i = 0; i < VR_TX_RING_CNT; i++) {
1146177050Syongari		if (i == VR_TX_RING_CNT - 1)
1147177050Syongari			addr = VR_TX_RING_ADDR(sc, 0);
1148177050Syongari		else
1149177050Syongari			addr = VR_TX_RING_ADDR(sc, i + 1);
1150177050Syongari		rd->vr_tx_ring[i].vr_nextphys = htole32(VR_ADDR_LO(addr));
1151177050Syongari		txd = &sc->vr_cdata.vr_txdesc[i];
1152177050Syongari		txd->tx_m = NULL;
115341502Swpaul	}
115441502Swpaul
1155177050Syongari	bus_dmamap_sync(sc->vr_cdata.vr_tx_ring_tag,
1156177050Syongari	    sc->vr_cdata.vr_tx_ring_map,
1157177050Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1158177050Syongari
1159131503Sbms	return (0);
116041502Swpaul}
116141502Swpaul
116241502Swpaul/*
116341502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
116441502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
116541502Swpaul * points back to the first.
116641502Swpaul */
1167102336Salfredstatic int
1168177050Syongarivr_rx_ring_init(struct vr_softc *sc)
116941502Swpaul{
1170177050Syongari	struct vr_ring_data	*rd;
1171177050Syongari	struct vr_rxdesc	*rxd;
1172177050Syongari	bus_addr_t		addr;
117341502Swpaul	int			i;
117441502Swpaul
1175177050Syongari	sc->vr_cdata.vr_rx_cons = 0;
1176131518Sbms
1177177050Syongari	rd = &sc->vr_rdata;
1178177050Syongari	bzero(rd->vr_rx_ring, VR_RX_RING_SIZE);
1179177050Syongari	for (i = 0; i < VR_RX_RING_CNT; i++) {
1180177050Syongari		rxd = &sc->vr_cdata.vr_rxdesc[i];
1181177050Syongari		rxd->rx_m = NULL;
1182177050Syongari		rxd->desc = &rd->vr_rx_ring[i];
1183177050Syongari		if (i == VR_RX_RING_CNT - 1)
1184177050Syongari			addr = VR_RX_RING_ADDR(sc, 0);
1185177050Syongari		else
1186177050Syongari			addr = VR_RX_RING_ADDR(sc, i + 1);
1187177050Syongari		rd->vr_rx_ring[i].vr_nextphys = htole32(VR_ADDR_LO(addr));
1188177050Syongari		if (vr_newbuf(sc, i) != 0)
1189131503Sbms			return (ENOBUFS);
119041502Swpaul	}
119141502Swpaul
1192177050Syongari	bus_dmamap_sync(sc->vr_cdata.vr_rx_ring_tag,
1193177050Syongari	    sc->vr_cdata.vr_rx_ring_map,
1194177050Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
119541502Swpaul
1196131503Sbms	return (0);
119741502Swpaul}
119841502Swpaul
1199177050Syongaristatic __inline void
1200177050Syongarivr_discard_rxbuf(struct vr_rxdesc *rxd)
1201177050Syongari{
1202177050Syongari	struct vr_desc	*desc;
1203177050Syongari
1204177050Syongari	desc = rxd->desc;
1205177050Syongari	desc->vr_ctl = htole32(VR_RXCTL | (MCLBYTES - sizeof(uint64_t)));
1206177050Syongari	desc->vr_status = htole32(VR_RXSTAT_OWN);
1207177050Syongari}
1208177050Syongari
120941502Swpaul/*
121041502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
121141502Swpaul * Note: the length fields are only 11 bits wide, which means the
121241502Swpaul * largest size we can specify is 2047. This is important because
121341502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
121441502Swpaul * overflow the field and make a mess.
121541502Swpaul */
1216102336Salfredstatic int
1217177050Syongarivr_newbuf(struct vr_softc *sc, int idx)
121841502Swpaul{
1219177050Syongari	struct vr_desc		*desc;
1220177050Syongari	struct vr_rxdesc	*rxd;
1221177050Syongari	struct mbuf		*m;
1222177050Syongari	bus_dma_segment_t	segs[1];
1223177050Syongari	bus_dmamap_t		map;
1224177050Syongari	int			nsegs;
122541502Swpaul
1226243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1227177050Syongari	if (m == NULL)
1228177050Syongari		return (ENOBUFS);
1229177050Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
1230177050Syongari	m_adj(m, sizeof(uint64_t));
1231177050Syongari
1232177050Syongari	if (bus_dmamap_load_mbuf_sg(sc->vr_cdata.vr_rx_tag,
1233177050Syongari	    sc->vr_cdata.vr_rx_sparemap, m, segs, &nsegs, 0) != 0) {
1234177050Syongari		m_freem(m);
1235177050Syongari		return (ENOBUFS);
123641502Swpaul	}
1237177050Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
123841502Swpaul
1239177050Syongari	rxd = &sc->vr_cdata.vr_rxdesc[idx];
1240177050Syongari	if (rxd->rx_m != NULL) {
1241177050Syongari		bus_dmamap_sync(sc->vr_cdata.vr_rx_tag, rxd->rx_dmamap,
1242177050Syongari		    BUS_DMASYNC_POSTREAD);
1243177050Syongari		bus_dmamap_unload(sc->vr_cdata.vr_rx_tag, rxd->rx_dmamap);
1244177050Syongari	}
1245177050Syongari	map = rxd->rx_dmamap;
1246177050Syongari	rxd->rx_dmamap = sc->vr_cdata.vr_rx_sparemap;
1247177050Syongari	sc->vr_cdata.vr_rx_sparemap = map;
1248177050Syongari	bus_dmamap_sync(sc->vr_cdata.vr_rx_tag, rxd->rx_dmamap,
1249177050Syongari	    BUS_DMASYNC_PREREAD);
1250177050Syongari	rxd->rx_m = m;
1251177050Syongari	desc = rxd->desc;
1252177050Syongari	desc->vr_data = htole32(VR_ADDR_LO(segs[0].ds_addr));
1253177050Syongari	desc->vr_ctl = htole32(VR_RXCTL | segs[0].ds_len);
1254177050Syongari	desc->vr_status = htole32(VR_RXSTAT_OWN);
125549610Swpaul
1256131503Sbms	return (0);
125741502Swpaul}
125841502Swpaul
1259177050Syongari#ifndef __NO_STRICT_ALIGNMENT
1260177050Syongaristatic __inline void
1261177050Syongarivr_fixup_rx(struct mbuf *m)
1262177050Syongari{
1263177050Syongari        uint16_t		*src, *dst;
1264177050Syongari        int			i;
1265177050Syongari
1266177050Syongari	src = mtod(m, uint16_t *);
1267177050Syongari	dst = src - 1;
1268177050Syongari
1269177050Syongari	for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
1270177050Syongari		*dst++ = *src++;
1271177050Syongari
1272177050Syongari	m->m_data -= ETHER_ALIGN;
1273177050Syongari}
1274177050Syongari#endif
1275177050Syongari
127641502Swpaul/*
127741502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
127841502Swpaul * the higher level protocols.
127941502Swpaul */
1280193096Sattiliostatic int
1281131503Sbmsvr_rxeof(struct vr_softc *sc)
128241502Swpaul{
1283177050Syongari	struct vr_rxdesc	*rxd;
1284177050Syongari	struct mbuf		*m;
1285131503Sbms	struct ifnet		*ifp;
1286168952Sphk	struct vr_desc		*cur_rx;
1287193096Sattilio	int			cons, prog, total_len, rx_npkts;
1288168827Sphk	uint32_t		rxstat, rxctl;
128941502Swpaul
1290122689Ssam	VR_LOCK_ASSERT(sc);
1291147256Sbrooks	ifp = sc->vr_ifp;
1292177050Syongari	cons = sc->vr_cdata.vr_rx_cons;
1293193096Sattilio	rx_npkts = 0;
129441502Swpaul
1295177050Syongari	bus_dmamap_sync(sc->vr_cdata.vr_rx_ring_tag,
1296177050Syongari	    sc->vr_cdata.vr_rx_ring_map,
1297177050Syongari	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1298177050Syongari
1299177050Syongari	for (prog = 0; prog < VR_RX_RING_CNT; VR_INC(cons, VR_RX_RING_CNT)) {
1300127901Sru#ifdef DEVICE_POLLING
1301150789Sglebius		if (ifp->if_capenable & IFCAP_POLLING) {
1302127901Sru			if (sc->rxcycles <= 0)
1303127901Sru				break;
1304127901Sru			sc->rxcycles--;
1305127901Sru		}
1306150789Sglebius#endif
1307177050Syongari		cur_rx = &sc->vr_rdata.vr_rx_ring[cons];
1308177050Syongari		rxstat = le32toh(cur_rx->vr_status);
1309177050Syongari		rxctl = le32toh(cur_rx->vr_ctl);
1310177050Syongari		if ((rxstat & VR_RXSTAT_OWN) == VR_RXSTAT_OWN)
1311177050Syongari			break;
131241502Swpaul
1313177050Syongari		prog++;
1314177050Syongari		rxd = &sc->vr_cdata.vr_rxdesc[cons];
1315177050Syongari		m = rxd->rx_m;
1316177050Syongari
131741502Swpaul		/*
131841502Swpaul		 * If an error occurs, update stats, clear the
131941502Swpaul		 * status word and leave the mbuf cluster in place:
132041502Swpaul		 * it should simply get re-used next time this descriptor
1321131503Sbms		 * comes up in the ring.
1322177050Syongari		 * We don't support SG in Rx path yet, so discard
1323177050Syongari		 * partial frame.
132441502Swpaul		 */
1325180551Syongari		if ((rxstat & VR_RXSTAT_RX_OK) == 0 ||
1326180551Syongari		    (rxstat & (VR_RXSTAT_FIRSTFRAG | VR_RXSTAT_LASTFRAG)) !=
1327177050Syongari		    (VR_RXSTAT_FIRSTFRAG | VR_RXSTAT_LASTFRAG)) {
1328271808Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1329177050Syongari			sc->vr_stat.rx_errors++;
1330110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
1331177050Syongari				sc->vr_stat.rx_crc_errors++;
1332110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
1333177050Syongari				sc->vr_stat.rx_alignment++;
1334110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
1335177050Syongari				sc->vr_stat.rx_fifo_overflows++;
1336110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
1337177050Syongari				sc->vr_stat.rx_giants++;
1338110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
1339177050Syongari				sc->vr_stat.rx_runts++;
1340110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
1341177050Syongari				sc->vr_stat.rx_no_buffers++;
1342177050Syongari#ifdef	VR_SHOW_ERRORS
1343177050Syongari			device_printf(sc->vr_dev, "%s: receive error = 0x%b\n",
1344177050Syongari			    __func__, rxstat & 0xff, VR_RXSTAT_ERR_BITS);
1345177050Syongari#endif
1346177050Syongari			vr_discard_rxbuf(rxd);
134741502Swpaul			continue;
134841502Swpaul		}
134941502Swpaul
1350177050Syongari		if (vr_newbuf(sc, cons) != 0) {
1351271808Sglebius			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
1352177050Syongari			sc->vr_stat.rx_errors++;
1353177050Syongari			sc->vr_stat.rx_no_mbufs++;
1354177050Syongari			vr_discard_rxbuf(rxd);
1355177050Syongari			continue;
1356168827Sphk		}
135741502Swpaul
135841502Swpaul		/*
135942048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
136042048Swpaul		 * received frame, and there's no way to turn this
136142048Swpaul		 * behavior off (at least, I can't find anything in
1362131503Sbms		 * the manual that explains how to do it) so we have
136342048Swpaul		 * to trim off the CRC manually.
136442048Swpaul		 */
1365177050Syongari		total_len = VR_RXBYTES(rxstat);
136642048Swpaul		total_len -= ETHER_CRC_LEN;
1367177050Syongari		m->m_pkthdr.len = m->m_len = total_len;
1368177050Syongari#ifndef	__NO_STRICT_ALIGNMENT
1369177050Syongari		/*
1370177050Syongari		 * RX buffers must be 32-bit aligned.
1371177050Syongari		 * Ignore the alignment problems on the non-strict alignment
1372177050Syongari		 * platform. The performance hit incurred due to unaligned
1373177050Syongari		 * accesses is much smaller than the hit produced by forcing
1374177050Syongari		 * buffer copies all the time.
1375177050Syongari		 */
1376177050Syongari		vr_fixup_rx(m);
1377177050Syongari#endif
1378177050Syongari		m->m_pkthdr.rcvif = ifp;
1379271808Sglebius		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
1380177050Syongari		sc->vr_stat.rx_ok++;
1381177050Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0 &&
1382177050Syongari		    (rxstat & VR_RXSTAT_FRAG) == 0 &&
1383177050Syongari		    (rxctl & VR_RXCTL_IP) != 0) {
1384177050Syongari			/* Checksum is valid for non-fragmented IP packets. */
1385177050Syongari			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
1386177050Syongari			if ((rxctl & VR_RXCTL_IPOK) == VR_RXCTL_IPOK) {
1387177050Syongari				m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
1388177050Syongari				if (rxctl & (VR_RXCTL_TCP | VR_RXCTL_UDP)) {
1389177050Syongari					m->m_pkthdr.csum_flags |=
1390177050Syongari					    CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
1391177050Syongari					if ((rxctl & VR_RXCTL_TCPUDPOK) != 0)
1392177050Syongari						m->m_pkthdr.csum_data = 0xffff;
1393177050Syongari				}
1394177050Syongari			}
139541502Swpaul		}
1396122689Ssam		VR_UNLOCK(sc);
1397106936Ssam		(*ifp->if_input)(ifp, m);
1398122689Ssam		VR_LOCK(sc);
1399193096Sattilio		rx_npkts++;
140041502Swpaul	}
140141502Swpaul
1402177050Syongari	if (prog > 0) {
1403228086Syongari		/*
1404228086Syongari		 * Let controller know how many number of RX buffers
1405228086Syongari		 * are posted but avoid expensive register access if
1406228086Syongari		 * TX pause capability was not negotiated with link
1407228086Syongari		 * partner.
1408228086Syongari		 */
1409228086Syongari		if ((sc->vr_flags & VR_F_TXPAUSE) != 0) {
1410228086Syongari			if (prog >= VR_RX_RING_CNT)
1411228086Syongari				prog = VR_RX_RING_CNT - 1;
1412228086Syongari			CSR_WRITE_1(sc, VR_FLOWCR0, prog);
1413228086Syongari		}
1414177050Syongari		sc->vr_cdata.vr_rx_cons = cons;
1415177050Syongari		bus_dmamap_sync(sc->vr_cdata.vr_rx_ring_tag,
1416177050Syongari		    sc->vr_cdata.vr_rx_ring_map,
1417177050Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1418131503Sbms	}
1419193096Sattilio	return (rx_npkts);
142041502Swpaul}
142141502Swpaul
142241502Swpaul/*
142341502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
142441502Swpaul * the list buffers.
142541502Swpaul */
1426102336Salfredstatic void
1427131503Sbmsvr_txeof(struct vr_softc *sc)
142841502Swpaul{
1429177050Syongari	struct vr_txdesc	*txd;
1430168952Sphk	struct vr_desc		*cur_tx;
1431177050Syongari	struct ifnet		*ifp;
1432177050Syongari	uint32_t		txctl, txstat;
1433177050Syongari	int			cons, prod;
143441502Swpaul
1435131518Sbms	VR_LOCK_ASSERT(sc);
143641502Swpaul
1437177050Syongari	cons = sc->vr_cdata.vr_tx_cons;
1438177050Syongari	prod = sc->vr_cdata.vr_tx_prod;
1439177050Syongari	if (cons == prod)
1440177050Syongari		return;
1441177050Syongari
1442177050Syongari	bus_dmamap_sync(sc->vr_cdata.vr_tx_ring_tag,
1443177050Syongari	    sc->vr_cdata.vr_tx_ring_map,
1444177050Syongari	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1445177050Syongari
1446177050Syongari	ifp = sc->vr_ifp;
144741502Swpaul	/*
144841502Swpaul	 * Go through our tx list and free mbufs for those
144941502Swpaul	 * frames that have been transmitted.
145041502Swpaul	 */
1451177050Syongari	for (; cons != prod; VR_INC(cons, VR_TX_RING_CNT)) {
1452177050Syongari		cur_tx = &sc->vr_rdata.vr_tx_ring[cons];
1453177050Syongari		txctl = le32toh(cur_tx->vr_ctl);
1454177050Syongari		txstat = le32toh(cur_tx->vr_status);
1455177050Syongari		if ((txstat & VR_TXSTAT_OWN) == VR_TXSTAT_OWN)
1456177050Syongari			break;
145741502Swpaul
1458177050Syongari		sc->vr_cdata.vr_tx_cnt--;
1459177050Syongari		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1460177050Syongari		/* Only the first descriptor in the chain is valid. */
1461177050Syongari		if ((txctl & VR_TXCTL_FIRSTFRAG) == 0)
1462177050Syongari			continue;
146341502Swpaul
1464177050Syongari		txd = &sc->vr_cdata.vr_txdesc[cons];
1465177050Syongari		KASSERT(txd->tx_m != NULL, ("%s: accessing NULL mbuf!\n",
1466177050Syongari		    __func__));
1467177050Syongari
1468177050Syongari		if ((txstat & VR_TXSTAT_ERRSUM) != 0) {
1469271808Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1470177050Syongari			sc->vr_stat.tx_errors++;
1471177050Syongari			if ((txstat & VR_TXSTAT_ABRT) != 0) {
1472177050Syongari				/* Give up and restart Tx. */
1473177050Syongari				sc->vr_stat.tx_abort++;
1474177050Syongari				bus_dmamap_sync(sc->vr_cdata.vr_tx_tag,
1475177050Syongari				    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
1476177050Syongari				bus_dmamap_unload(sc->vr_cdata.vr_tx_tag,
1477177050Syongari				    txd->tx_dmamap);
1478177050Syongari				m_freem(txd->tx_m);
1479177050Syongari				txd->tx_m = NULL;
1480177050Syongari				VR_INC(cons, VR_TX_RING_CNT);
1481177050Syongari				sc->vr_cdata.vr_tx_cons = cons;
1482177050Syongari				if (vr_tx_stop(sc) != 0) {
1483177050Syongari					device_printf(sc->vr_dev,
1484177050Syongari					    "%s: Tx shutdown error -- "
1485177050Syongari					    "resetting\n", __func__);
1486177050Syongari					sc->vr_flags |= VR_F_RESTART;
1487177050Syongari					return;
1488177050Syongari				}
1489177050Syongari				vr_tx_start(sc);
1490110131Ssilby				break;
1491110131Ssilby			}
1492177050Syongari			if ((sc->vr_revid < REV_ID_VT3071_A &&
1493177050Syongari			    (txstat & VR_TXSTAT_UNDERRUN)) ||
1494177050Syongari			    (txstat & (VR_TXSTAT_UDF | VR_TXSTAT_TBUFF))) {
1495177050Syongari				sc->vr_stat.tx_underrun++;
1496177050Syongari				/* Retry and restart Tx. */
1497177050Syongari				sc->vr_cdata.vr_tx_cnt++;
1498177050Syongari				sc->vr_cdata.vr_tx_cons = cons;
1499177050Syongari				cur_tx->vr_status = htole32(VR_TXSTAT_OWN);
1500177050Syongari				bus_dmamap_sync(sc->vr_cdata.vr_tx_ring_tag,
1501177050Syongari				    sc->vr_cdata.vr_tx_ring_map,
1502177050Syongari				    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1503177050Syongari				vr_tx_underrun(sc);
1504177050Syongari				return;
1505177050Syongari			}
1506177050Syongari			if ((txstat & VR_TXSTAT_DEFER) != 0) {
1507271808Sglebius				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1);
1508177050Syongari				sc->vr_stat.tx_collisions++;
1509177050Syongari			}
1510177050Syongari			if ((txstat & VR_TXSTAT_LATECOLL) != 0) {
1511271808Sglebius				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1);
1512177050Syongari				sc->vr_stat.tx_late_collisions++;
1513177050Syongari			}
1514177050Syongari		} else {
1515177050Syongari			sc->vr_stat.tx_ok++;
1516271808Sglebius			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
151741502Swpaul		}
151841502Swpaul
1519177050Syongari		bus_dmamap_sync(sc->vr_cdata.vr_tx_tag, txd->tx_dmamap,
1520177050Syongari		    BUS_DMASYNC_POSTWRITE);
1521177050Syongari		bus_dmamap_unload(sc->vr_cdata.vr_tx_tag, txd->tx_dmamap);
1522177050Syongari		if (sc->vr_revid < REV_ID_VT3071_A) {
1523271808Sglebius			if_inc_counter(ifp, IFCOUNTER_COLLISIONS,
1524271808Sglebius			    (txstat & VR_TXSTAT_COLLCNT) >> 3);
1525177050Syongari			sc->vr_stat.tx_collisions +=
1526177050Syongari			    (txstat & VR_TXSTAT_COLLCNT) >> 3;
1527177050Syongari		} else {
1528271808Sglebius			if_inc_counter(ifp, IFCOUNTER_COLLISIONS, (txstat & 0x0f));
1529177050Syongari			sc->vr_stat.tx_collisions += (txstat & 0x0f);
1530177050Syongari		}
1531177050Syongari		m_freem(txd->tx_m);
1532177050Syongari		txd->tx_m = NULL;
1533177050Syongari	}
153441502Swpaul
1535177050Syongari	sc->vr_cdata.vr_tx_cons = cons;
1536177050Syongari	if (sc->vr_cdata.vr_tx_cnt == 0)
1537177050Syongari		sc->vr_watchdog_timer = 0;
153841502Swpaul}
153941502Swpaul
1540102336Salfredstatic void
1541131503Sbmsvr_tick(void *xsc)
154251432Swpaul{
1543177050Syongari	struct vr_softc		*sc;
154451432Swpaul	struct mii_data		*mii;
154551432Swpaul
1546177050Syongari	sc = (struct vr_softc *)xsc;
1547177050Syongari
1548151911Sjhb	VR_LOCK_ASSERT(sc);
1549131517Sbms
1550177050Syongari	if ((sc->vr_flags & VR_F_RESTART) != 0) {
1551162315Sglebius		device_printf(sc->vr_dev, "restarting\n");
1552177050Syongari		sc->vr_stat.num_restart++;
1553211765Syongari		sc->vr_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1554131844Sbms		vr_init_locked(sc);
1555110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1556110131Ssilby	}
1557110131Ssilby
155851432Swpaul	mii = device_get_softc(sc->vr_miibus);
155951432Swpaul	mii_tick(mii);
1560228084Syongari	if ((sc->vr_flags & VR_F_LINK) == 0)
1561223405Syongari		vr_miibus_statchg(sc->vr_dev);
1562177050Syongari	vr_watchdog(sc);
1563151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
156451432Swpaul}
156551432Swpaul
1566127901Sru#ifdef DEVICE_POLLING
1567127901Srustatic poll_handler_t vr_poll;
1568131844Sbmsstatic poll_handler_t vr_poll_locked;
1569127901Sru
1570193096Sattiliostatic int
1571127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1572127901Sru{
1573177050Syongari	struct vr_softc *sc;
1574193096Sattilio	int rx_npkts;
1575127901Sru
1576177050Syongari	sc = ifp->if_softc;
1577193096Sattilio	rx_npkts = 0;
1578177050Syongari
1579127901Sru	VR_LOCK(sc);
1580177050Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1581193096Sattilio		rx_npkts = vr_poll_locked(ifp, cmd, count);
1582131844Sbms	VR_UNLOCK(sc);
1583193096Sattilio	return (rx_npkts);
1584131844Sbms}
1585131517Sbms
1586193096Sattiliostatic int
1587131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
1588131844Sbms{
1589177050Syongari	struct vr_softc *sc;
1590193096Sattilio	int rx_npkts;
1591131844Sbms
1592177050Syongari	sc = ifp->if_softc;
1593177050Syongari
1594131844Sbms	VR_LOCK_ASSERT(sc);
1595131844Sbms
1596127901Sru	sc->rxcycles = count;
1597193096Sattilio	rx_npkts = vr_rxeof(sc);
1598127901Sru	vr_txeof(sc);
1599133006Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1600131844Sbms		vr_start_locked(ifp);
1601127901Sru
1602131503Sbms	if (cmd == POLL_AND_CHECK_STATUS) {
1603131503Sbms		uint16_t status;
1604127901Sru
1605131503Sbms		/* Also check status register. */
1606127901Sru		status = CSR_READ_2(sc, VR_ISR);
1607127901Sru		if (status)
1608127901Sru			CSR_WRITE_2(sc, VR_ISR, status);
1609127901Sru
1610127901Sru		if ((status & VR_INTRS) == 0)
1611193096Sattilio			return (rx_npkts);
1612127901Sru
1613177050Syongari		if ((status & (VR_ISR_BUSERR | VR_ISR_LINKSTAT2 |
1614177050Syongari		    VR_ISR_STATSOFLOW)) != 0) {
1615177050Syongari			if (vr_error(sc, status) != 0)
1616193096Sattilio				return (rx_npkts);
1617127901Sru		}
1618177050Syongari		if ((status & (VR_ISR_RX_NOBUF | VR_ISR_RX_OFLOW)) != 0) {
1619177050Syongari#ifdef	VR_SHOW_ERRORS
1620177050Syongari			device_printf(sc->vr_dev, "%s: receive error : 0x%b\n",
1621177050Syongari			    __func__, status, VR_ISR_ERR_BITS);
1622177050Syongari#endif
1623177050Syongari			vr_rx_start(sc);
1624127901Sru		}
1625177050Syongari	}
1626193096Sattilio	return (rx_npkts);
1627177050Syongari}
1628177050Syongari#endif /* DEVICE_POLLING */
1629127901Sru
1630177050Syongari/* Back off the transmit threshold. */
1631177050Syongaristatic void
1632177050Syongarivr_tx_underrun(struct vr_softc *sc)
1633177050Syongari{
1634177050Syongari	int	thresh;
1635127901Sru
1636177050Syongari	device_printf(sc->vr_dev, "Tx underrun -- ");
1637177050Syongari	if (sc->vr_txthresh < VR_TXTHRESH_MAX) {
1638177050Syongari		thresh = sc->vr_txthresh;
1639177050Syongari		sc->vr_txthresh++;
1640177050Syongari		if (sc->vr_txthresh >= VR_TXTHRESH_MAX) {
1641177050Syongari			sc->vr_txthresh = VR_TXTHRESH_MAX;
1642177050Syongari			printf("using store and forward mode\n");
1643177050Syongari		} else
1644177050Syongari			printf("increasing Tx threshold(%d -> %d)\n",
1645177050Syongari			    vr_tx_threshold_tables[thresh].value,
1646177050Syongari			    vr_tx_threshold_tables[thresh + 1].value);
1647177050Syongari	} else
1648177050Syongari		printf("\n");
1649177050Syongari	sc->vr_stat.tx_underrun++;
1650177050Syongari	if (vr_tx_stop(sc) != 0) {
1651177050Syongari		device_printf(sc->vr_dev, "%s: Tx shutdown error -- "
1652177050Syongari		    "resetting\n", __func__);
1653177050Syongari		sc->vr_flags |= VR_F_RESTART;
1654177050Syongari		return;
1655127901Sru	}
1656177050Syongari	vr_tx_start(sc);
1657127901Sru}
1658127901Sru
1659235334Srpaulostatic int
1660131503Sbmsvr_intr(void *arg)
166141502Swpaul{
1662177050Syongari	struct vr_softc		*sc;
1663235334Srpaulo	uint16_t		status;
1664235334Srpaulo
1665235334Srpaulo	sc = (struct vr_softc *)arg;
1666235334Srpaulo
1667235334Srpaulo	status = CSR_READ_2(sc, VR_ISR);
1668235334Srpaulo	if (status == 0 || status == 0xffff || (status & VR_INTRS) == 0)
1669235334Srpaulo		return (FILTER_STRAY);
1670235334Srpaulo
1671235334Srpaulo	/* Disable interrupts. */
1672235334Srpaulo	CSR_WRITE_2(sc, VR_IMR, 0x0000);
1673235334Srpaulo
1674296272Sjhb	taskqueue_enqueue(taskqueue_fast, &sc->vr_inttask);
1675235334Srpaulo
1676235334Srpaulo	return (FILTER_HANDLED);
1677235334Srpaulo}
1678235334Srpaulo
1679235334Srpaulostatic void
1680235334Srpaulovr_int_task(void *arg, int npending)
1681235334Srpaulo{
1682235334Srpaulo	struct vr_softc		*sc;
1683177050Syongari	struct ifnet		*ifp;
1684131503Sbms	uint16_t		status;
168541502Swpaul
1686177050Syongari	sc = (struct vr_softc *)arg;
1687177050Syongari
168867087Swpaul	VR_LOCK(sc);
1689131844Sbms
1690228084Syongari	if ((sc->vr_flags & VR_F_SUSPENDED) != 0)
1691131844Sbms		goto done_locked;
1692131844Sbms
1693177050Syongari	status = CSR_READ_2(sc, VR_ISR);
1694177050Syongari	ifp = sc->vr_ifp;
1695127901Sru#ifdef DEVICE_POLLING
1696177050Syongari	if ((ifp->if_capenable & IFCAP_POLLING) != 0)
1697131844Sbms		goto done_locked;
1698150789Sglebius#endif
1699131844Sbms
1700131844Sbms	/* Suppress unwanted interrupts. */
1701177050Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
1702177050Syongari	    (sc->vr_flags & VR_F_RESTART) != 0) {
1703177050Syongari		CSR_WRITE_2(sc, VR_IMR, 0);
1704177050Syongari		CSR_WRITE_2(sc, VR_ISR, status);
1705131844Sbms		goto done_locked;
170641502Swpaul	}
170741502Swpaul
1708177050Syongari	for (; (status & VR_INTRS) != 0;) {
1709177050Syongari		CSR_WRITE_2(sc, VR_ISR, status);
1710177050Syongari		if ((status & (VR_ISR_BUSERR | VR_ISR_LINKSTAT2 |
1711177050Syongari		    VR_ISR_STATSOFLOW)) != 0) {
1712177050Syongari			if (vr_error(sc, status) != 0) {
1713177050Syongari				VR_UNLOCK(sc);
1714177050Syongari				return;
1715177050Syongari			}
1716177050Syongari		}
1717177050Syongari		vr_rxeof(sc);
1718177050Syongari		if ((status & (VR_ISR_RX_NOBUF | VR_ISR_RX_OFLOW)) != 0) {
1719177050Syongari#ifdef	VR_SHOW_ERRORS
1720177050Syongari			device_printf(sc->vr_dev, "%s: receive error = 0x%b\n",
1721177050Syongari			    __func__, status, VR_ISR_ERR_BITS);
1722177050Syongari#endif
1723177050Syongari			/* Restart Rx if RxDMA SM was stopped. */
1724177050Syongari			vr_rx_start(sc);
1725177050Syongari		}
1726177050Syongari		vr_txeof(sc);
1727235334Srpaulo
1728235334Srpaulo		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1729235334Srpaulo			vr_start_locked(ifp);
1730235334Srpaulo
173141502Swpaul		status = CSR_READ_2(sc, VR_ISR);
1732177050Syongari	}
1733168813Sphk
1734177050Syongari	/* Re-enable interrupts. */
1735177050Syongari	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
173641502Swpaul
1737177050Syongaridone_locked:
1738177050Syongari	VR_UNLOCK(sc);
1739177050Syongari}
174041502Swpaul
1741177050Syongaristatic int
1742177050Syongarivr_error(struct vr_softc *sc, uint16_t status)
1743177050Syongari{
1744177050Syongari	uint16_t pcis;
1745110131Ssilby
1746177050Syongari	status &= VR_ISR_BUSERR | VR_ISR_LINKSTAT2 | VR_ISR_STATSOFLOW;
1747177050Syongari	if ((status & VR_ISR_BUSERR) != 0) {
1748177050Syongari		status &= ~VR_ISR_BUSERR;
1749177050Syongari		sc->vr_stat.bus_errors++;
1750177050Syongari		/* Disable further interrupts. */
1751177050Syongari		CSR_WRITE_2(sc, VR_IMR, 0);
1752177050Syongari		pcis = pci_read_config(sc->vr_dev, PCIR_STATUS, 2);
1753177050Syongari		device_printf(sc->vr_dev, "PCI bus error(0x%04x) -- "
1754177050Syongari		    "resetting\n", pcis);
1755177050Syongari		pci_write_config(sc->vr_dev, PCIR_STATUS, pcis, 2);
1756177050Syongari		sc->vr_flags |= VR_F_RESTART;
1757177050Syongari		return (EAGAIN);
1758177050Syongari	}
1759177050Syongari	if ((status & VR_ISR_LINKSTAT2) != 0) {
1760177050Syongari		/* Link state change, duplex changes etc. */
1761177050Syongari		status &= ~VR_ISR_LINKSTAT2;
1762177050Syongari	}
1763177050Syongari	if ((status & VR_ISR_STATSOFLOW) != 0) {
1764177050Syongari		status &= ~VR_ISR_STATSOFLOW;
1765177050Syongari		if (sc->vr_revid >= REV_ID_VT6105M_A0) {
1766177050Syongari			/* Update MIB counters. */
176741502Swpaul		}
1768177050Syongari	}
176941502Swpaul
1770177050Syongari	if (status != 0)
1771177050Syongari		device_printf(sc->vr_dev,
1772177050Syongari		    "unhandled interrupt, status = 0x%04x\n", status);
1773177050Syongari	return (0);
1774177050Syongari}
1775177050Syongari
1776177050Syongari/*
1777177050Syongari * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
1778177050Syongari * pointers to the fragment pointers.
1779177050Syongari */
1780177050Syongaristatic int
1781177050Syongarivr_encap(struct vr_softc *sc, struct mbuf **m_head)
1782177050Syongari{
1783177050Syongari	struct vr_txdesc	*txd;
1784177050Syongari	struct vr_desc		*desc;
1785177050Syongari	struct mbuf		*m;
1786177050Syongari	bus_dma_segment_t	txsegs[VR_MAXFRAGS];
1787177050Syongari	uint32_t		csum_flags, txctl;
1788177050Syongari	int			error, i, nsegs, prod, si;
1789177050Syongari	int			padlen;
1790177050Syongari
1791177050Syongari	VR_LOCK_ASSERT(sc);
1792177050Syongari
1793177050Syongari	M_ASSERTPKTHDR((*m_head));
1794177050Syongari
1795177050Syongari	/*
1796177050Syongari	 * Some VIA Rhine wants packet buffers to be longword
1797177050Syongari	 * aligned, but very often our mbufs aren't. Rather than
1798177050Syongari	 * waste time trying to decide when to copy and when not
1799177050Syongari	 * to copy, just do it all the time.
1800177050Syongari	 */
1801177050Syongari	if ((sc->vr_quirks & VR_Q_NEEDALIGN) != 0) {
1802243857Sglebius		m = m_defrag(*m_head, M_NOWAIT);
1803177050Syongari		if (m == NULL) {
1804177050Syongari			m_freem(*m_head);
1805177050Syongari			*m_head = NULL;
1806177050Syongari			return (ENOBUFS);
180741502Swpaul		}
1808177050Syongari		*m_head = m;
1809177050Syongari	}
181041502Swpaul
1811177050Syongari	/*
1812177050Syongari	 * The Rhine chip doesn't auto-pad, so we have to make
1813177050Syongari	 * sure to pad short frames out to the minimum frame length
1814177050Syongari	 * ourselves.
1815177050Syongari	 */
1816177050Syongari	if ((*m_head)->m_pkthdr.len < VR_MIN_FRAMELEN) {
1817177050Syongari		m = *m_head;
1818177050Syongari		padlen = VR_MIN_FRAMELEN - m->m_pkthdr.len;
1819177050Syongari		if (M_WRITABLE(m) == 0) {
1820177050Syongari			/* Get a writable copy. */
1821243857Sglebius			m = m_dup(*m_head, M_NOWAIT);
1822177050Syongari			m_freem(*m_head);
1823177050Syongari			if (m == NULL) {
1824177050Syongari				*m_head = NULL;
1825177050Syongari				return (ENOBUFS);
1826127901Sru			}
1827177050Syongari			*m_head = m;
182841502Swpaul		}
1829177050Syongari		if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) {
1830243857Sglebius			m = m_defrag(m, M_NOWAIT);
1831177050Syongari			if (m == NULL) {
1832177050Syongari				m_freem(*m_head);
1833177050Syongari				*m_head = NULL;
1834177050Syongari				return (ENOBUFS);
1835177050Syongari			}
1836177050Syongari		}
1837177050Syongari		/*
1838177050Syongari		 * Manually pad short frames, and zero the pad space
1839177050Syongari		 * to avoid leaking data.
1840177050Syongari		 */
1841177050Syongari		bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
1842177050Syongari		m->m_pkthdr.len += padlen;
1843177050Syongari		m->m_len = m->m_pkthdr.len;
1844177050Syongari		*m_head = m;
184541502Swpaul	}
184641502Swpaul
1847177050Syongari	prod = sc->vr_cdata.vr_tx_prod;
1848177050Syongari	txd = &sc->vr_cdata.vr_txdesc[prod];
1849177050Syongari	error = bus_dmamap_load_mbuf_sg(sc->vr_cdata.vr_tx_tag, txd->tx_dmamap,
1850177050Syongari	    *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
1851177050Syongari	if (error == EFBIG) {
1852243857Sglebius		m = m_collapse(*m_head, M_NOWAIT, VR_MAXFRAGS);
1853177050Syongari		if (m == NULL) {
1854177050Syongari			m_freem(*m_head);
1855177050Syongari			*m_head = NULL;
1856177050Syongari			return (ENOBUFS);
1857177050Syongari		}
1858177050Syongari		*m_head = m;
1859177050Syongari		error = bus_dmamap_load_mbuf_sg(sc->vr_cdata.vr_tx_tag,
1860177050Syongari		    txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
1861177050Syongari		if (error != 0) {
1862177050Syongari			m_freem(*m_head);
1863177050Syongari			*m_head = NULL;
1864177050Syongari			return (error);
1865177050Syongari		}
1866177050Syongari	} else if (error != 0)
1867177050Syongari		return (error);
1868177050Syongari	if (nsegs == 0) {
1869177050Syongari		m_freem(*m_head);
1870177050Syongari		*m_head = NULL;
1871177050Syongari		return (EIO);
1872177050Syongari	}
187341502Swpaul
1874177050Syongari	/* Check number of available descriptors. */
1875177050Syongari	if (sc->vr_cdata.vr_tx_cnt + nsegs >= (VR_TX_RING_CNT - 1)) {
1876177050Syongari		bus_dmamap_unload(sc->vr_cdata.vr_tx_tag, txd->tx_dmamap);
1877177050Syongari		return (ENOBUFS);
1878177050Syongari	}
1879131844Sbms
1880177050Syongari	txd->tx_m = *m_head;
1881177050Syongari	bus_dmamap_sync(sc->vr_cdata.vr_tx_tag, txd->tx_dmamap,
1882177050Syongari	    BUS_DMASYNC_PREWRITE);
1883177050Syongari
1884177050Syongari	/* Set checksum offload. */
1885177050Syongari	csum_flags = 0;
1886177050Syongari	if (((*m_head)->m_pkthdr.csum_flags & VR_CSUM_FEATURES) != 0) {
1887177050Syongari		if ((*m_head)->m_pkthdr.csum_flags & CSUM_IP)
1888177050Syongari			csum_flags |= VR_TXCTL_IPCSUM;
1889177050Syongari		if ((*m_head)->m_pkthdr.csum_flags & CSUM_TCP)
1890177050Syongari			csum_flags |= VR_TXCTL_TCPCSUM;
1891177050Syongari		if ((*m_head)->m_pkthdr.csum_flags & CSUM_UDP)
1892177050Syongari			csum_flags |= VR_TXCTL_UDPCSUM;
1893177050Syongari	}
1894177050Syongari
1895177050Syongari	/*
1896177050Syongari	 * Quite contrary to datasheet for VIA Rhine, VR_TXCTL_TLINK bit
1897177050Syongari	 * is required for all descriptors regardless of single or
1898177050Syongari	 * multiple buffers. Also VR_TXSTAT_OWN bit is valid only for
1899177050Syongari	 * the first descriptor for a multi-fragmented frames. Without
1900177050Syongari	 * that VIA Rhine chip generates Tx underrun interrupts and can't
1901177050Syongari	 * send any frames.
1902177050Syongari	 */
1903177050Syongari	si = prod;
1904177050Syongari	for (i = 0; i < nsegs; i++) {
1905177050Syongari		desc = &sc->vr_rdata.vr_tx_ring[prod];
1906177050Syongari		desc->vr_status = 0;
1907177050Syongari		txctl = txsegs[i].ds_len | VR_TXCTL_TLINK | csum_flags;
1908177050Syongari		if (i == 0)
1909177050Syongari			txctl |= VR_TXCTL_FIRSTFRAG;
1910177050Syongari		desc->vr_ctl = htole32(txctl);
1911177050Syongari		desc->vr_data = htole32(VR_ADDR_LO(txsegs[i].ds_addr));
1912177050Syongari		sc->vr_cdata.vr_tx_cnt++;
1913177050Syongari		VR_INC(prod, VR_TX_RING_CNT);
1914177050Syongari	}
1915177050Syongari	/* Update producer index. */
1916177050Syongari	sc->vr_cdata.vr_tx_prod = prod;
1917177050Syongari
1918177050Syongari	prod = (prod + VR_TX_RING_CNT - 1) % VR_TX_RING_CNT;
1919177050Syongari	desc = &sc->vr_rdata.vr_tx_ring[prod];
1920177050Syongari
1921177050Syongari	/*
1922177050Syongari	 * Set EOP on the last desciptor and reuqest Tx completion
1923177050Syongari	 * interrupt for every VR_TX_INTR_THRESH-th frames.
1924177050Syongari	 */
1925177050Syongari	VR_INC(sc->vr_cdata.vr_tx_pkts, VR_TX_INTR_THRESH);
1926177050Syongari	if (sc->vr_cdata.vr_tx_pkts == 0)
1927177050Syongari		desc->vr_ctl |= htole32(VR_TXCTL_LASTFRAG | VR_TXCTL_FINT);
1928177050Syongari	else
1929177050Syongari		desc->vr_ctl |= htole32(VR_TXCTL_LASTFRAG);
1930177050Syongari
1931177050Syongari	/* Lastly turn the first descriptor ownership to hardware. */
1932177050Syongari	desc = &sc->vr_rdata.vr_tx_ring[si];
1933177050Syongari	desc->vr_status |= htole32(VR_TXSTAT_OWN);
1934177050Syongari
1935177050Syongari	/* Sync descriptors. */
1936177050Syongari	bus_dmamap_sync(sc->vr_cdata.vr_tx_ring_tag,
1937177050Syongari	    sc->vr_cdata.vr_tx_ring_map,
1938177050Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1939177050Syongari
1940177050Syongari	return (0);
194141502Swpaul}
194241502Swpaul
1943102336Salfredstatic void
1944131503Sbmsvr_start(struct ifnet *ifp)
194541502Swpaul{
1946177050Syongari	struct vr_softc		*sc;
1947131844Sbms
1948177050Syongari	sc = ifp->if_softc;
1949131844Sbms	VR_LOCK(sc);
1950131844Sbms	vr_start_locked(ifp);
1951131844Sbms	VR_UNLOCK(sc);
1952131844Sbms}
1953131844Sbms
1954131844Sbmsstatic void
1955131844Sbmsvr_start_locked(struct ifnet *ifp)
1956131844Sbms{
1957177050Syongari	struct vr_softc		*sc;
1958177050Syongari	struct mbuf		*m_head;
1959177050Syongari	int			enq;
196041502Swpaul
1961177050Syongari	sc = ifp->if_softc;
1962177050Syongari
1963177050Syongari	VR_LOCK_ASSERT(sc);
1964177050Syongari
1965177050Syongari	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1966228084Syongari	    IFF_DRV_RUNNING || (sc->vr_flags & VR_F_LINK) == 0)
1967127901Sru		return;
1968127901Sru
1969177050Syongari	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
1970177050Syongari	    sc->vr_cdata.vr_tx_cnt < VR_TX_RING_CNT - 2; ) {
1971177050Syongari		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
197241502Swpaul		if (m_head == NULL)
197341502Swpaul			break;
1974168813Sphk		/*
1975177050Syongari		 * Pack the data into the transmit ring. If we
1976177050Syongari		 * don't have room, set the OACTIVE flag and wait
1977177050Syongari		 * for the NIC to drain the ring.
1978168813Sphk		 */
1979177050Syongari		if (vr_encap(sc, &m_head)) {
1980177050Syongari			if (m_head == NULL)
1981168813Sphk				break;
1982177050Syongari			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1983177050Syongari			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1984177050Syongari			break;
1985168813Sphk		}
198651583Swpaul
1987177050Syongari		enq++;
1988168813Sphk		/*
1989168813Sphk		 * If there's a BPF listener, bounce a copy of this frame
1990168813Sphk		 * to him.
1991168813Sphk		 */
1992177050Syongari		ETHER_BPF_MTAP(ifp, m_head);
1993127901Sru	}
1994177050Syongari
1995177050Syongari	if (enq > 0) {
1996177050Syongari		/* Tell the chip to start transmitting. */
1997177050Syongari		VR_SETBIT(sc, VR_CR0, VR_CR0_TX_GO);
1998177050Syongari		/* Set a timeout in case the chip goes out to lunch. */
1999177050Syongari		sc->vr_watchdog_timer = 5;
2000177050Syongari	}
2001131844Sbms}
200241502Swpaul
2003131844Sbmsstatic void
2004131844Sbmsvr_init(void *xsc)
2005131844Sbms{
2006177050Syongari	struct vr_softc		*sc;
2007131844Sbms
2008177050Syongari	sc = (struct vr_softc *)xsc;
2009131844Sbms	VR_LOCK(sc);
2010131844Sbms	vr_init_locked(sc);
201167087Swpaul	VR_UNLOCK(sc);
201241502Swpaul}
201341502Swpaul
2014102336Salfredstatic void
2015131844Sbmsvr_init_locked(struct vr_softc *sc)
201641502Swpaul{
2017177050Syongari	struct ifnet		*ifp;
201851432Swpaul	struct mii_data		*mii;
2019177050Syongari	bus_addr_t		addr;
202073963Swpaul	int			i;
202141502Swpaul
2022131844Sbms	VR_LOCK_ASSERT(sc);
202341502Swpaul
2024177050Syongari	ifp = sc->vr_ifp;
202551432Swpaul	mii = device_get_softc(sc->vr_miibus);
202641502Swpaul
2027211765Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
2028211765Syongari		return;
2029211765Syongari
2030131503Sbms	/* Cancel pending I/O and free all RX/TX buffers. */
203141502Swpaul	vr_stop(sc);
203241502Swpaul	vr_reset(sc);
203341502Swpaul
2034131503Sbms	/* Set our station address. */
203573963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
2036152315Sru		CSR_WRITE_1(sc, VR_PAR0 + i, IF_LLADDR(sc->vr_ifp)[i]);
2037131503Sbms
2038131503Sbms	/* Set DMA size. */
2039101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
2040101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
204173963Swpaul
2042131503Sbms	/*
2043101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
2044101108Ssilby	 * so we must set both.
2045101108Ssilby	 */
2046101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
2047110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
2048101108Ssilby
2049101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
2050177050Syongari	VR_SETBIT(sc, VR_BCR1, vr_tx_threshold_tables[sc->vr_txthresh].bcr_cfg);
2051101108Ssilby
205241502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
2053110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
205441502Swpaul
205541502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
2056177050Syongari	VR_SETBIT(sc, VR_TXCFG, vr_tx_threshold_tables[sc->vr_txthresh].tx_cfg);
205741502Swpaul
205841502Swpaul	/* Init circular RX list. */
2059177050Syongari	if (vr_rx_ring_init(sc) != 0) {
2060162315Sglebius		device_printf(sc->vr_dev,
2061151773Sjhb		    "initialization failed: no memory for rx buffers\n");
206241502Swpaul		vr_stop(sc);
206341502Swpaul		return;
206441502Swpaul	}
206541502Swpaul
2066131503Sbms	/* Init tx descriptors. */
2067177050Syongari	vr_tx_ring_init(sc);
206841502Swpaul
2069177050Syongari	if ((sc->vr_quirks & VR_Q_CAM) != 0) {
2070180552Syongari		uint8_t vcam[2] = { 0, 0 };
2071180552Syongari
2072180552Syongari		/* Disable VLAN hardware tag insertion/stripping. */
2073180552Syongari		VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TXTAGEN | VR_TXCFG_RXTAGCTL);
2074180552Syongari		/* Disable VLAN hardware filtering. */
2075180552Syongari		VR_CLRBIT(sc, VR_BCR1, VR_BCR1_VLANFILT_ENB);
2076180552Syongari		/* Disable all CAM entries. */
2077180552Syongari		vr_cam_mask(sc, VR_MCAST_CAM, 0);
2078180552Syongari		vr_cam_mask(sc, VR_VLAN_CAM, 0);
2079180552Syongari		/* Enable the first VLAN CAM. */
2080180552Syongari		vr_cam_data(sc, VR_VLAN_CAM, 0, vcam);
2081180552Syongari		vr_cam_mask(sc, VR_VLAN_CAM, 1);
2082177050Syongari	}
208341502Swpaul
208441502Swpaul	/*
2085177050Syongari	 * Set up receive filter.
208641502Swpaul	 */
2087177050Syongari	vr_set_filter(sc);
208841502Swpaul
208941502Swpaul	/*
2090177050Syongari	 * Load the address of the RX ring.
209141502Swpaul	 */
2092177050Syongari	addr = VR_RX_RING_ADDR(sc, 0);
2093177050Syongari	CSR_WRITE_4(sc, VR_RXADDR, VR_ADDR_LO(addr));
2094177050Syongari	/*
2095177050Syongari	 * Load the address of the TX ring.
2096177050Syongari	 */
2097177050Syongari	addr = VR_TX_RING_ADDR(sc, 0);
2098177050Syongari	CSR_WRITE_4(sc, VR_TXADDR, VR_ADDR_LO(addr));
2099177050Syongari	/* Default : full-duplex, no Tx poll. */
2100177050Syongari	CSR_WRITE_1(sc, VR_CR1, VR_CR1_FULLDUPLEX | VR_CR1_TX_NOPOLL);
210141502Swpaul
2102177050Syongari	/* Set flow-control parameters for Rhine III. */
2103177050Syongari	if (sc->vr_revid >= REV_ID_VT6105_A0) {
2104177050Syongari		/*
2105228086Syongari		 * Configure Rx buffer count available for incoming
2106228086Syongari		 * packet.
2107228086Syongari		 * Even though data sheet says almost nothing about
2108228086Syongari		 * this register, this register should be updated
2109228086Syongari		 * whenever driver adds new RX buffers to controller.
2110228086Syongari		 * Otherwise, XON frame is not sent to link partner
2111228086Syongari		 * even if controller has enough RX buffers and you
2112228086Syongari		 * would be isolated from network.
2113228086Syongari		 * The controller is not smart enough to know number
2114228086Syongari		 * of available RX buffers so driver have to let
2115228086Syongari		 * controller know how many RX buffers are posted.
2116228086Syongari		 * In other words, this register works like a residue
2117228086Syongari		 * counter for RX buffers and should be initialized
2118228086Syongari		 * to the number of total RX buffers  - 1 before
2119228086Syongari		 * enabling RX MAC.  Note, this register is 8bits so
2120228086Syongari		 * it effectively limits the maximum number of RX
2121228086Syongari		 * buffer to be configured by controller is 255.
2122177050Syongari		 */
2123228086Syongari		CSR_WRITE_1(sc, VR_FLOWCR0, VR_RX_RING_CNT - 1);
2124228086Syongari		/*
2125228086Syongari		 * Tx pause low threshold : 8 free receive buffers
2126228086Syongari		 * Tx pause XON high threshold : 24 free receive buffers
2127228086Syongari		 */
2128177050Syongari		CSR_WRITE_1(sc, VR_FLOWCR1,
2129228086Syongari		    VR_FLOWCR1_TXLO8 | VR_FLOWCR1_TXHI24 | VR_FLOWCR1_XONXOFF);
2130177050Syongari		/* Set Tx pause timer. */
2131177050Syongari		CSR_WRITE_2(sc, VR_PAUSETIMER, 0xffff);
2132177050Syongari	}
2133177050Syongari
213441502Swpaul	/* Enable receiver and transmitter. */
2135177050Syongari	CSR_WRITE_1(sc, VR_CR0,
2136177050Syongari	    VR_CR0_START | VR_CR0_TX_ON | VR_CR0_RX_ON | VR_CR0_RX_GO);
213741502Swpaul
2138127901Sru	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
2139127901Sru#ifdef DEVICE_POLLING
214041502Swpaul	/*
2141127901Sru	 * Disable interrupts if we are polling.
2142127901Sru	 */
2143150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
2144127901Sru		CSR_WRITE_2(sc, VR_IMR, 0);
2145131503Sbms	else
2146150789Sglebius#endif
2147127901Sru	/*
2148177050Syongari	 * Enable interrupts and disable MII intrs.
214941502Swpaul	 */
215041502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
2151177050Syongari	if (sc->vr_revid > REV_ID_VT6102_A)
2152177050Syongari		CSR_WRITE_2(sc, VR_MII_IMR, 0);
215341502Swpaul
2154148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2155148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
215641502Swpaul
2157228086Syongari	sc->vr_flags &= ~(VR_F_LINK | VR_F_TXPAUSE);
2158228084Syongari	mii_mediachg(mii);
2159228084Syongari
2160151911Sjhb	callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc);
216141502Swpaul}
216241502Swpaul
216341502Swpaul/*
216441502Swpaul * Set media options.
216541502Swpaul */
2166102336Salfredstatic int
2167131503Sbmsvr_ifmedia_upd(struct ifnet *ifp)
216841502Swpaul{
2169177050Syongari	struct vr_softc		*sc;
2170177050Syongari	struct mii_data		*mii;
2171177050Syongari	struct mii_softc	*miisc;
2172177050Syongari	int			error;
217341502Swpaul
2174177050Syongari	sc = ifp->if_softc;
2175177050Syongari	VR_LOCK(sc);
2176177050Syongari	mii = device_get_softc(sc->vr_miibus);
2177221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
2178221407Smarius		PHY_RESET(miisc);
2179228086Syongari	sc->vr_flags &= ~(VR_F_LINK | VR_F_TXPAUSE);
2180177050Syongari	error = mii_mediachg(mii);
2181177050Syongari	VR_UNLOCK(sc);
218241502Swpaul
2183177050Syongari	return (error);
218441502Swpaul}
218541502Swpaul
218641502Swpaul/*
218741502Swpaul * Report current media status.
218841502Swpaul */
2189102336Salfredstatic void
2190131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
219141502Swpaul{
2192177050Syongari	struct vr_softc		*sc;
219351432Swpaul	struct mii_data		*mii;
219441502Swpaul
2195177050Syongari	sc = ifp->if_softc;
219651432Swpaul	mii = device_get_softc(sc->vr_miibus);
2197133468Sscottl	VR_LOCK(sc);
2198223405Syongari	if ((ifp->if_flags & IFF_UP) == 0) {
2199223405Syongari		VR_UNLOCK(sc);
2200223405Syongari		return;
2201223405Syongari	}
220251432Swpaul	mii_pollstat(mii);
220351432Swpaul	ifmr->ifm_active = mii->mii_media_active;
220451432Swpaul	ifmr->ifm_status = mii->mii_media_status;
2205226478Syongari	VR_UNLOCK(sc);
220641502Swpaul}
220741502Swpaul
2208102336Salfredstatic int
2209131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
221041502Swpaul{
2211177050Syongari	struct vr_softc		*sc;
2212177050Syongari	struct ifreq		*ifr;
221351432Swpaul	struct mii_data		*mii;
2214177050Syongari	int			error, mask;
221541502Swpaul
2216177050Syongari	sc = ifp->if_softc;
2217177050Syongari	ifr = (struct ifreq *)data;
2218177050Syongari	error = 0;
2219177050Syongari
2220131503Sbms	switch (command) {
222141502Swpaul	case SIOCSIFFLAGS:
2222131844Sbms		VR_LOCK(sc);
222341502Swpaul		if (ifp->if_flags & IFF_UP) {
2224177050Syongari			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2225177050Syongari				if ((ifp->if_flags ^ sc->vr_if_flags) &
2226177050Syongari				    (IFF_PROMISC | IFF_ALLMULTI))
2227177050Syongari					vr_set_filter(sc);
2228177050Syongari			} else {
2229228084Syongari				if ((sc->vr_flags & VR_F_DETACHED) == 0)
2230177050Syongari					vr_init_locked(sc);
2231177050Syongari			}
223241502Swpaul		} else {
2233148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
223441502Swpaul				vr_stop(sc);
223541502Swpaul		}
2236177050Syongari		sc->vr_if_flags = ifp->if_flags;
2237131844Sbms		VR_UNLOCK(sc);
223841502Swpaul		break;
223941502Swpaul	case SIOCADDMULTI:
224041502Swpaul	case SIOCDELMULTI:
2241131518Sbms		VR_LOCK(sc);
2242177050Syongari		vr_set_filter(sc);
2243131518Sbms		VR_UNLOCK(sc);
224441502Swpaul		break;
224541502Swpaul	case SIOCGIFMEDIA:
224641502Swpaul	case SIOCSIFMEDIA:
224751432Swpaul		mii = device_get_softc(sc->vr_miibus);
224851432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
224941502Swpaul		break;
2250128118Sru	case SIOCSIFCAP:
2251177050Syongari		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
2252150789Sglebius#ifdef DEVICE_POLLING
2253177050Syongari		if (mask & IFCAP_POLLING) {
2254177050Syongari			if (ifr->ifr_reqcap & IFCAP_POLLING) {
2255177050Syongari				error = ether_poll_register(vr_poll, ifp);
2256177050Syongari				if (error != 0)
2257177050Syongari					break;
2258177050Syongari				VR_LOCK(sc);
2259177050Syongari				/* Disable interrupts. */
2260177050Syongari				CSR_WRITE_2(sc, VR_IMR, 0x0000);
2261177050Syongari				ifp->if_capenable |= IFCAP_POLLING;
2262177050Syongari				VR_UNLOCK(sc);
2263177050Syongari			} else {
2264177050Syongari				error = ether_poll_deregister(ifp);
2265177050Syongari				/* Enable interrupts. */
2266177050Syongari				VR_LOCK(sc);
2267177050Syongari				CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
2268177050Syongari				ifp->if_capenable &= ~IFCAP_POLLING;
2269177050Syongari				VR_UNLOCK(sc);
2270177050Syongari			}
2271150789Sglebius		}
2272177050Syongari#endif /* DEVICE_POLLING */
2273177050Syongari		if ((mask & IFCAP_TXCSUM) != 0 &&
2274177050Syongari		    (IFCAP_TXCSUM & ifp->if_capabilities) != 0) {
2275177050Syongari			ifp->if_capenable ^= IFCAP_TXCSUM;
2276177050Syongari			if ((IFCAP_TXCSUM & ifp->if_capenable) != 0)
2277177050Syongari				ifp->if_hwassist |= VR_CSUM_FEATURES;
2278177050Syongari			else
2279177050Syongari				ifp->if_hwassist &= ~VR_CSUM_FEATURES;
2280150789Sglebius		}
2281177050Syongari		if ((mask & IFCAP_RXCSUM) != 0 &&
2282177050Syongari		    (IFCAP_RXCSUM & ifp->if_capabilities) != 0)
2283177050Syongari			ifp->if_capenable ^= IFCAP_RXCSUM;
2284177050Syongari		if ((mask & IFCAP_WOL_UCAST) != 0 &&
2285177050Syongari		    (ifp->if_capabilities & IFCAP_WOL_UCAST) != 0)
2286177050Syongari			ifp->if_capenable ^= IFCAP_WOL_UCAST;
2287177050Syongari		if ((mask & IFCAP_WOL_MAGIC) != 0 &&
2288177050Syongari		    (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
2289177050Syongari			ifp->if_capenable ^= IFCAP_WOL_MAGIC;
2290128118Sru		break;
229141502Swpaul	default:
2292106936Ssam		error = ether_ioctl(ifp, command, data);
229341502Swpaul		break;
229441502Swpaul	}
229541502Swpaul
2296131503Sbms	return (error);
229741502Swpaul}
229841502Swpaul
2299102336Salfredstatic void
2300177050Syongarivr_watchdog(struct vr_softc *sc)
230141502Swpaul{
2302177050Syongari	struct ifnet		*ifp;
230341502Swpaul
2304177050Syongari	VR_LOCK_ASSERT(sc);
2305131844Sbms
2306177050Syongari	if (sc->vr_watchdog_timer == 0 || --sc->vr_watchdog_timer)
2307177050Syongari		return;
2308177050Syongari
2309177050Syongari	ifp = sc->vr_ifp;
2310177050Syongari	/*
2311177050Syongari	 * Reclaim first as we don't request interrupt for every packets.
2312177050Syongari	 */
2313177050Syongari	vr_txeof(sc);
2314177050Syongari	if (sc->vr_cdata.vr_tx_cnt == 0)
2315177050Syongari		return;
2316177050Syongari
2317228084Syongari	if ((sc->vr_flags & VR_F_LINK) == 0) {
2318177050Syongari		if (bootverbose)
2319177050Syongari			if_printf(sc->vr_ifp, "watchdog timeout "
2320177050Syongari			   "(missed link)\n");
2321271808Sglebius		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2322211765Syongari		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2323177050Syongari		vr_init_locked(sc);
2324177050Syongari		return;
2325177050Syongari	}
2326177050Syongari
2327271808Sglebius	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
2328151773Sjhb	if_printf(ifp, "watchdog timeout\n");
232941502Swpaul
2330211765Syongari	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2331131844Sbms	vr_init_locked(sc);
2332131518Sbms
2333132986Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2334131844Sbms		vr_start_locked(ifp);
2335177050Syongari}
2336131844Sbms
2337177050Syongaristatic void
2338177050Syongarivr_tx_start(struct vr_softc *sc)
2339177050Syongari{
2340177050Syongari	bus_addr_t	addr;
2341177050Syongari	uint8_t		cmd;
2342177050Syongari
2343177050Syongari	cmd = CSR_READ_1(sc, VR_CR0);
2344177050Syongari	if ((cmd & VR_CR0_TX_ON) == 0) {
2345177050Syongari		addr = VR_TX_RING_ADDR(sc, sc->vr_cdata.vr_tx_cons);
2346177050Syongari		CSR_WRITE_4(sc, VR_TXADDR, VR_ADDR_LO(addr));
2347177050Syongari		cmd |= VR_CR0_TX_ON;
2348177050Syongari		CSR_WRITE_1(sc, VR_CR0, cmd);
2349177050Syongari	}
2350177050Syongari	if (sc->vr_cdata.vr_tx_cnt != 0) {
2351177050Syongari		sc->vr_watchdog_timer = 5;
2352177050Syongari		VR_SETBIT(sc, VR_CR0, VR_CR0_TX_GO);
2353177050Syongari	}
235441502Swpaul}
235541502Swpaul
2356177050Syongaristatic void
2357177050Syongarivr_rx_start(struct vr_softc *sc)
2358177050Syongari{
2359177050Syongari	bus_addr_t	addr;
2360177050Syongari	uint8_t		cmd;
2361177050Syongari
2362177050Syongari	cmd = CSR_READ_1(sc, VR_CR0);
2363177050Syongari	if ((cmd & VR_CR0_RX_ON) == 0) {
2364177050Syongari		addr = VR_RX_RING_ADDR(sc, sc->vr_cdata.vr_rx_cons);
2365177050Syongari		CSR_WRITE_4(sc, VR_RXADDR, VR_ADDR_LO(addr));
2366177050Syongari		cmd |= VR_CR0_RX_ON;
2367177050Syongari		CSR_WRITE_1(sc, VR_CR0, cmd);
2368177050Syongari	}
2369177050Syongari	CSR_WRITE_1(sc, VR_CR0, cmd | VR_CR0_RX_GO);
2370177050Syongari}
2371177050Syongari
2372177050Syongaristatic int
2373177050Syongarivr_tx_stop(struct vr_softc *sc)
2374177050Syongari{
2375177050Syongari	int		i;
2376177050Syongari	uint8_t		cmd;
2377177050Syongari
2378177050Syongari	cmd = CSR_READ_1(sc, VR_CR0);
2379177050Syongari	if ((cmd & VR_CR0_TX_ON) != 0) {
2380177050Syongari		cmd &= ~VR_CR0_TX_ON;
2381177050Syongari		CSR_WRITE_1(sc, VR_CR0, cmd);
2382177050Syongari		for (i = VR_TIMEOUT; i > 0; i--) {
2383177050Syongari			DELAY(5);
2384177050Syongari			cmd = CSR_READ_1(sc, VR_CR0);
2385177050Syongari			if ((cmd & VR_CR0_TX_ON) == 0)
2386177050Syongari				break;
2387177050Syongari		}
2388177050Syongari		if (i == 0)
2389177050Syongari			return (ETIMEDOUT);
2390177050Syongari	}
2391177050Syongari	return (0);
2392177050Syongari}
2393177050Syongari
2394177050Syongaristatic int
2395177050Syongarivr_rx_stop(struct vr_softc *sc)
2396177050Syongari{
2397177050Syongari	int		i;
2398177050Syongari	uint8_t		cmd;
2399177050Syongari
2400177050Syongari	cmd = CSR_READ_1(sc, VR_CR0);
2401177050Syongari	if ((cmd & VR_CR0_RX_ON) != 0) {
2402177050Syongari		cmd &= ~VR_CR0_RX_ON;
2403177050Syongari		CSR_WRITE_1(sc, VR_CR0, cmd);
2404177050Syongari		for (i = VR_TIMEOUT; i > 0; i--) {
2405177050Syongari			DELAY(5);
2406177050Syongari			cmd = CSR_READ_1(sc, VR_CR0);
2407177050Syongari			if ((cmd & VR_CR0_RX_ON) == 0)
2408177050Syongari				break;
2409177050Syongari		}
2410177050Syongari		if (i == 0)
2411177050Syongari			return (ETIMEDOUT);
2412177050Syongari	}
2413177050Syongari	return (0);
2414177050Syongari}
2415177050Syongari
241641502Swpaul/*
241741502Swpaul * Stop the adapter and free any mbufs allocated to the
241841502Swpaul * RX and TX lists.
241941502Swpaul */
2420102336Salfredstatic void
2421131503Sbmsvr_stop(struct vr_softc *sc)
242241502Swpaul{
2423177050Syongari	struct vr_txdesc	*txd;
2424177050Syongari	struct vr_rxdesc	*rxd;
2425177050Syongari	struct ifnet		*ifp;
2426177050Syongari	int			i;
242741502Swpaul
2428131518Sbms	VR_LOCK_ASSERT(sc);
242967087Swpaul
2430147256Sbrooks	ifp = sc->vr_ifp;
2431177050Syongari	sc->vr_watchdog_timer = 0;
243241502Swpaul
2433151911Sjhb	callout_stop(&sc->vr_stat_callout);
2434148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
243551432Swpaul
2436177050Syongari	CSR_WRITE_1(sc, VR_CR0, VR_CR0_STOP);
2437177050Syongari	if (vr_rx_stop(sc) != 0)
2438177050Syongari		device_printf(sc->vr_dev, "%s: Rx shutdown error\n", __func__);
2439177050Syongari	if (vr_tx_stop(sc) != 0)
2440177050Syongari		device_printf(sc->vr_dev, "%s: Tx shutdown error\n", __func__);
2441177050Syongari	/* Clear pending interrupts. */
2442177050Syongari	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
244341502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
244441502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
244541502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
244641502Swpaul
244741502Swpaul	/*
2448177050Syongari	 * Free RX and TX mbufs still in the queues.
244941502Swpaul	 */
2450177050Syongari	for (i = 0; i < VR_RX_RING_CNT; i++) {
2451177050Syongari		rxd = &sc->vr_cdata.vr_rxdesc[i];
2452177050Syongari		if (rxd->rx_m != NULL) {
2453177050Syongari			bus_dmamap_sync(sc->vr_cdata.vr_rx_tag,
2454177050Syongari			    rxd->rx_dmamap, BUS_DMASYNC_POSTREAD);
2455177050Syongari			bus_dmamap_unload(sc->vr_cdata.vr_rx_tag,
2456177050Syongari			    rxd->rx_dmamap);
2457177050Syongari			m_freem(rxd->rx_m);
2458177050Syongari			rxd->rx_m = NULL;
2459177050Syongari		}
2460177050Syongari        }
2461177050Syongari	for (i = 0; i < VR_TX_RING_CNT; i++) {
2462177050Syongari		txd = &sc->vr_cdata.vr_txdesc[i];
2463177050Syongari		if (txd->tx_m != NULL) {
2464177050Syongari			bus_dmamap_sync(sc->vr_cdata.vr_tx_tag,
2465177050Syongari			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
2466177050Syongari			bus_dmamap_unload(sc->vr_cdata.vr_tx_tag,
2467177050Syongari			    txd->tx_dmamap);
2468177050Syongari			m_freem(txd->tx_m);
2469177050Syongari			txd->tx_m = NULL;
2470177050Syongari		}
2471177050Syongari        }
247241502Swpaul}
247341502Swpaul
247441502Swpaul/*
247541502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
247641502Swpaul * get confused by errant DMAs when rebooting.
247741502Swpaul */
2478173839Syongaristatic int
2479131503Sbmsvr_shutdown(device_t dev)
248041502Swpaul{
248141502Swpaul
2482177050Syongari	return (vr_suspend(dev));
2483177050Syongari}
2484173839Syongari
2485177050Syongaristatic int
2486177050Syongarivr_suspend(device_t dev)
2487177050Syongari{
2488177050Syongari	struct vr_softc		*sc;
2489177050Syongari
2490177050Syongari	sc = device_get_softc(dev);
2491177050Syongari
2492177050Syongari	VR_LOCK(sc);
2493177050Syongari	vr_stop(sc);
2494177050Syongari	vr_setwol(sc);
2495228084Syongari	sc->vr_flags |= VR_F_SUSPENDED;
2496177050Syongari	VR_UNLOCK(sc);
2497177050Syongari
2498173839Syongari	return (0);
249941502Swpaul}
2500177050Syongari
2501177050Syongaristatic int
2502177050Syongarivr_resume(device_t dev)
2503177050Syongari{
2504177050Syongari	struct vr_softc		*sc;
2505177050Syongari	struct ifnet		*ifp;
2506177050Syongari
2507177050Syongari	sc = device_get_softc(dev);
2508177050Syongari
2509177050Syongari	VR_LOCK(sc);
2510177050Syongari	ifp = sc->vr_ifp;
2511177050Syongari	vr_clrwol(sc);
2512177050Syongari	vr_reset(sc);
2513177050Syongari	if (ifp->if_flags & IFF_UP)
2514177050Syongari		vr_init_locked(sc);
2515177050Syongari
2516228084Syongari	sc->vr_flags &= ~VR_F_SUSPENDED;
2517177050Syongari	VR_UNLOCK(sc);
2518177050Syongari
2519177050Syongari	return (0);
2520177050Syongari}
2521177050Syongari
2522177050Syongaristatic void
2523177050Syongarivr_setwol(struct vr_softc *sc)
2524177050Syongari{
2525177050Syongari	struct ifnet		*ifp;
2526177050Syongari	int			pmc;
2527177050Syongari	uint16_t		pmstat;
2528177050Syongari	uint8_t			v;
2529177050Syongari
2530177050Syongari	VR_LOCK_ASSERT(sc);
2531177050Syongari
2532177050Syongari	if (sc->vr_revid < REV_ID_VT6102_A ||
2533219902Sjhb	    pci_find_cap(sc->vr_dev, PCIY_PMG, &pmc) != 0)
2534177050Syongari		return;
2535177050Syongari
2536177050Syongari	ifp = sc->vr_ifp;
2537177050Syongari
2538177050Syongari	/* Clear WOL configuration. */
2539177050Syongari	CSR_WRITE_1(sc, VR_WOLCR_CLR, 0xFF);
2540177050Syongari	CSR_WRITE_1(sc, VR_WOLCFG_CLR, VR_WOLCFG_SAB | VR_WOLCFG_SAM);
2541177050Syongari	CSR_WRITE_1(sc, VR_PWRCSR_CLR, 0xFF);
2542177050Syongari	CSR_WRITE_1(sc, VR_PWRCFG_CLR, VR_PWRCFG_WOLEN);
2543177050Syongari	if (sc->vr_revid > REV_ID_VT6105_B0) {
2544177050Syongari		/* Newer Rhine III supports two additional patterns. */
2545177050Syongari		CSR_WRITE_1(sc, VR_WOLCFG_CLR, VR_WOLCFG_PATTERN_PAGE);
2546177050Syongari		CSR_WRITE_1(sc, VR_TESTREG_CLR, 3);
2547177050Syongari		CSR_WRITE_1(sc, VR_PWRCSR1_CLR, 3);
2548177050Syongari	}
2549177050Syongari	if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0)
2550177050Syongari		CSR_WRITE_1(sc, VR_WOLCR_SET, VR_WOLCR_UCAST);
2551177050Syongari	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
2552177050Syongari		CSR_WRITE_1(sc, VR_WOLCR_SET, VR_WOLCR_MAGIC);
2553177050Syongari	/*
2554177050Syongari	 * It seems that multicast wakeup frames require programming pattern
2555177050Syongari	 * registers and valid CRC as well as pattern mask for each pattern.
2556177050Syongari	 * While it's possible to setup such a pattern it would complicate
2557177050Syongari	 * WOL configuration so ignore multicast wakeup frames.
2558177050Syongari	 */
2559177050Syongari	if ((ifp->if_capenable & IFCAP_WOL) != 0) {
2560177050Syongari		CSR_WRITE_1(sc, VR_WOLCFG_SET, VR_WOLCFG_SAB | VR_WOLCFG_SAM);
2561177050Syongari		v = CSR_READ_1(sc, VR_STICKHW);
2562177050Syongari		CSR_WRITE_1(sc, VR_STICKHW, v | VR_STICKHW_WOL_ENB);
2563177050Syongari		CSR_WRITE_1(sc, VR_PWRCFG_SET, VR_PWRCFG_WOLEN);
2564177050Syongari	}
2565177050Syongari
2566177050Syongari	/* Put hardware into sleep. */
2567177050Syongari	v = CSR_READ_1(sc, VR_STICKHW);
2568177050Syongari	v |= VR_STICKHW_DS0 | VR_STICKHW_DS1;
2569177050Syongari	CSR_WRITE_1(sc, VR_STICKHW, v);
2570177050Syongari
2571177050Syongari	/* Request PME if WOL is requested. */
2572177050Syongari	pmstat = pci_read_config(sc->vr_dev, pmc + PCIR_POWER_STATUS, 2);
2573177050Syongari	pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
2574177050Syongari	if ((ifp->if_capenable & IFCAP_WOL) != 0)
2575177050Syongari		pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
2576177050Syongari	pci_write_config(sc->vr_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
2577177050Syongari}
2578177050Syongari
2579177050Syongaristatic void
2580177050Syongarivr_clrwol(struct vr_softc *sc)
2581177050Syongari{
2582177050Syongari	uint8_t			v;
2583177050Syongari
2584177050Syongari	VR_LOCK_ASSERT(sc);
2585177050Syongari
2586177050Syongari	if (sc->vr_revid < REV_ID_VT6102_A)
2587177050Syongari		return;
2588177050Syongari
2589177050Syongari	/* Take hardware out of sleep. */
2590177050Syongari	v = CSR_READ_1(sc, VR_STICKHW);
2591177050Syongari	v &= ~(VR_STICKHW_DS0 | VR_STICKHW_DS1 | VR_STICKHW_WOL_ENB);
2592177050Syongari	CSR_WRITE_1(sc, VR_STICKHW, v);
2593177050Syongari
2594177050Syongari	/* Clear WOL configuration as WOL may interfere normal operation. */
2595177050Syongari	CSR_WRITE_1(sc, VR_WOLCR_CLR, 0xFF);
2596177050Syongari	CSR_WRITE_1(sc, VR_WOLCFG_CLR,
2597177050Syongari	    VR_WOLCFG_SAB | VR_WOLCFG_SAM | VR_WOLCFG_PMEOVR);
2598177050Syongari	CSR_WRITE_1(sc, VR_PWRCSR_CLR, 0xFF);
2599177050Syongari	CSR_WRITE_1(sc, VR_PWRCFG_CLR, VR_PWRCFG_WOLEN);
2600177050Syongari	if (sc->vr_revid > REV_ID_VT6105_B0) {
2601177050Syongari		/* Newer Rhine III supports two additional patterns. */
2602177050Syongari		CSR_WRITE_1(sc, VR_WOLCFG_CLR, VR_WOLCFG_PATTERN_PAGE);
2603177050Syongari		CSR_WRITE_1(sc, VR_TESTREG_CLR, 3);
2604177050Syongari		CSR_WRITE_1(sc, VR_PWRCSR1_CLR, 3);
2605177050Syongari	}
2606177050Syongari}
2607177050Syongari
2608177050Syongaristatic int
2609177050Syongarivr_sysctl_stats(SYSCTL_HANDLER_ARGS)
2610177050Syongari{
2611177050Syongari	struct vr_softc		*sc;
2612177050Syongari	struct vr_statistics	*stat;
2613177050Syongari	int			error;
2614177050Syongari	int			result;
2615177050Syongari
2616177050Syongari	result = -1;
2617177050Syongari	error = sysctl_handle_int(oidp, &result, 0, req);
2618177050Syongari
2619177050Syongari	if (error != 0 || req->newptr == NULL)
2620177050Syongari		return (error);
2621177050Syongari
2622177050Syongari	if (result == 1) {
2623177050Syongari		sc = (struct vr_softc *)arg1;
2624177050Syongari		stat = &sc->vr_stat;
2625177050Syongari
2626177050Syongari		printf("%s statistics:\n", device_get_nameunit(sc->vr_dev));
2627177050Syongari		printf("Outbound good frames : %ju\n",
2628177050Syongari		    (uintmax_t)stat->tx_ok);
2629177050Syongari		printf("Inbound good frames : %ju\n",
2630177050Syongari		    (uintmax_t)stat->rx_ok);
2631177050Syongari		printf("Outbound errors : %u\n", stat->tx_errors);
2632177050Syongari		printf("Inbound errors : %u\n", stat->rx_errors);
2633177050Syongari		printf("Inbound no buffers : %u\n", stat->rx_no_buffers);
2634177050Syongari		printf("Inbound no mbuf clusters: %d\n", stat->rx_no_mbufs);
2635177050Syongari		printf("Inbound FIFO overflows : %d\n",
2636177050Syongari		    stat->rx_fifo_overflows);
2637177050Syongari		printf("Inbound CRC errors : %u\n", stat->rx_crc_errors);
2638177050Syongari		printf("Inbound frame alignment errors : %u\n",
2639177050Syongari		    stat->rx_alignment);
2640177050Syongari		printf("Inbound giant frames : %u\n", stat->rx_giants);
2641177050Syongari		printf("Inbound runt frames : %u\n", stat->rx_runts);
2642177050Syongari		printf("Outbound aborted with excessive collisions : %u\n",
2643177050Syongari		    stat->tx_abort);
2644177050Syongari		printf("Outbound collisions : %u\n", stat->tx_collisions);
2645177050Syongari		printf("Outbound late collisions : %u\n",
2646177050Syongari		    stat->tx_late_collisions);
2647177050Syongari		printf("Outbound underrun : %u\n", stat->tx_underrun);
2648177050Syongari		printf("PCI bus errors : %u\n", stat->bus_errors);
2649177050Syongari		printf("driver restarted due to Rx/Tx shutdown failure : %u\n",
2650177050Syongari		    stat->num_restart);
2651177050Syongari	}
2652177050Syongari
2653177050Syongari	return (error);
2654177050Syongari}
2655