if_vr.c revision 130270
141502Swpaul/*
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 130270 2004-06-09 14:34:04Z naddy $");
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 */
4741502Swpaul/*
4841502Swpaul * The VIA Rhine controllers are similar in some respects to the
4941502Swpaul * the DEC tulip chips, except less complicated. The controller
5041502Swpaul * uses an MII bus and an external physical layer interface. The
5141502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table
5241502Swpaul * multicast filter. Transmit and receive descriptors are similar
5341502Swpaul * to the tulip.
5441502Swpaul *
5541502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism:
5641502Swpaul * transmit buffers must be longword aligned. Unfortunately,
5741502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting
5841502Swpaul * at longword boundaries, so we have to do a buffer copy before
5941502Swpaul * transmission.
6041502Swpaul */
6141502Swpaul
6241502Swpaul#include <sys/param.h>
6341502Swpaul#include <sys/systm.h>
6441502Swpaul#include <sys/sockio.h>
6541502Swpaul#include <sys/mbuf.h>
6641502Swpaul#include <sys/malloc.h>
6741502Swpaul#include <sys/kernel.h>
68129878Sphk#include <sys/module.h>
6941502Swpaul#include <sys/socket.h>
7041502Swpaul
7141502Swpaul#include <net/if.h>
7241502Swpaul#include <net/if_arp.h>
7341502Swpaul#include <net/ethernet.h>
7441502Swpaul#include <net/if_dl.h>
7541502Swpaul#include <net/if_media.h>
7641502Swpaul
7741502Swpaul#include <net/bpf.h>
7841502Swpaul
7941502Swpaul#include <vm/vm.h>              /* for vtophys */
8041502Swpaul#include <vm/pmap.h>            /* for vtophys */
8141502Swpaul#include <machine/bus_pio.h>
8241502Swpaul#include <machine/bus_memio.h>
8341502Swpaul#include <machine/bus.h>
8449610Swpaul#include <machine/resource.h>
8549610Swpaul#include <sys/bus.h>
8649610Swpaul#include <sys/rman.h>
8741502Swpaul
8851432Swpaul#include <dev/mii/mii.h>
8951432Swpaul#include <dev/mii/miivar.h>
9051432Swpaul
91119288Simp#include <dev/pci/pcireg.h>
92119288Simp#include <dev/pci/pcivar.h>
9341502Swpaul
9441502Swpaul#define VR_USEIOSPACE
9541502Swpaul
9641502Swpaul#include <pci/if_vrreg.h>
9741502Swpaul
98113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1);
99113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1);
10059758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
10159758Speter
10251432Swpaul/* "controller miibus0" required.  See GENERIC if you get errors here. */
10351432Swpaul#include "miibus_if.h"
10451432Swpaul
105110168Ssilby#undef VR_USESWSHIFT
106110168Ssilby
10741502Swpaul/*
10841502Swpaul * Various supported device vendors/types and their names.
10941502Swpaul */
11041502Swpaulstatic struct vr_type vr_devs[] = {
11141502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
11241502Swpaul		"VIA VT3043 Rhine I 10/100BaseTX" },
11341502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
11441502Swpaul		"VIA VT86C100A Rhine II 10/100BaseTX" },
11562653Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
11662653Swpaul		"VIA VT6102 Rhine II 10/100BaseTX" },
117110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III,
118110170Ssilby		"VIA VT6105 Rhine III 10/100BaseTX" },
119110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
120110170Ssilby		"VIA VT6105M Rhine III 10/100BaseTX" },
12144238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
12244238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
12344238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
12444238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
12541502Swpaul	{ 0, 0, NULL }
12641502Swpaul};
12741502Swpaul
12892739Salfredstatic int vr_probe		(device_t);
12992739Salfredstatic int vr_attach		(device_t);
13092739Salfredstatic int vr_detach		(device_t);
13141502Swpaul
13292739Salfredstatic int vr_newbuf		(struct vr_softc *,
13349610Swpaul					struct vr_chain_onefrag *,
13492739Salfred					struct mbuf *);
13592739Salfredstatic int vr_encap		(struct vr_softc *, struct vr_chain *,
13692739Salfred						struct mbuf * );
13741502Swpaul
13892739Salfredstatic void vr_rxeof		(struct vr_softc *);
13992739Salfredstatic void vr_rxeoc		(struct vr_softc *);
14092739Salfredstatic void vr_txeof		(struct vr_softc *);
14192739Salfredstatic void vr_tick		(void *);
14292739Salfredstatic void vr_intr		(void *);
14392739Salfredstatic void vr_start		(struct ifnet *);
14492739Salfredstatic int vr_ioctl		(struct ifnet *, u_long, caddr_t);
14592739Salfredstatic void vr_init		(void *);
14692739Salfredstatic void vr_stop		(struct vr_softc *);
14792739Salfredstatic void vr_watchdog		(struct ifnet *);
14892739Salfredstatic void vr_shutdown		(device_t);
14992739Salfredstatic int vr_ifmedia_upd	(struct ifnet *);
15092739Salfredstatic void vr_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
15141502Swpaul
152110168Ssilby#ifdef VR_USESWSHIFT
15392739Salfredstatic void vr_mii_sync		(struct vr_softc *);
15492739Salfredstatic void vr_mii_send		(struct vr_softc *, u_int32_t, int);
155110168Ssilby#endif
15692739Salfredstatic int vr_mii_readreg	(struct vr_softc *, struct vr_mii_frame *);
15792739Salfredstatic int vr_mii_writereg	(struct vr_softc *, struct vr_mii_frame *);
15892739Salfredstatic int vr_miibus_readreg	(device_t, int, int);
15992739Salfredstatic int vr_miibus_writereg	(device_t, int, int, int);
16092739Salfredstatic void vr_miibus_statchg	(device_t);
16141502Swpaul
16292739Salfredstatic void vr_setcfg		(struct vr_softc *, int);
16392739Salfredstatic void vr_setmulti		(struct vr_softc *);
16492739Salfredstatic void vr_reset		(struct vr_softc *);
16592739Salfredstatic int vr_list_rx_init	(struct vr_softc *);
16692739Salfredstatic int vr_list_tx_init	(struct vr_softc *);
16741502Swpaul
16849610Swpaul#ifdef VR_USEIOSPACE
16949610Swpaul#define VR_RES			SYS_RES_IOPORT
17049610Swpaul#define VR_RID			VR_PCI_LOIO
17149610Swpaul#else
17249610Swpaul#define VR_RES			SYS_RES_MEMORY
17349610Swpaul#define VR_RID			VR_PCI_LOMEM
17449610Swpaul#endif
17549610Swpaul
17649610Swpaulstatic device_method_t vr_methods[] = {
17749610Swpaul	/* Device interface */
17849610Swpaul	DEVMETHOD(device_probe,		vr_probe),
17949610Swpaul	DEVMETHOD(device_attach,	vr_attach),
18049610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
18149610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
18251432Swpaul
18351432Swpaul	/* bus interface */
18451432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18551432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
18651432Swpaul
18751432Swpaul	/* MII interface */
18851432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
18951432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
19051432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
19151432Swpaul
19249610Swpaul	{ 0, 0 }
19349610Swpaul};
19449610Swpaul
19549610Swpaulstatic driver_t vr_driver = {
19651455Swpaul	"vr",
19749610Swpaul	vr_methods,
19849610Swpaul	sizeof(struct vr_softc)
19949610Swpaul};
20049610Swpaul
20149610Swpaulstatic devclass_t vr_devclass;
20249610Swpaul
203113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0);
20451473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
20549610Swpaul
20641502Swpaul#define VR_SETBIT(sc, reg, x)				\
20741502Swpaul	CSR_WRITE_1(sc, reg,				\
208105221Sphk		CSR_READ_1(sc, reg) | (x))
20941502Swpaul
21041502Swpaul#define VR_CLRBIT(sc, reg, x)				\
21141502Swpaul	CSR_WRITE_1(sc, reg,				\
212105221Sphk		CSR_READ_1(sc, reg) & ~(x))
21341502Swpaul
21441502Swpaul#define VR_SETBIT16(sc, reg, x)				\
21541502Swpaul	CSR_WRITE_2(sc, reg,				\
216105221Sphk		CSR_READ_2(sc, reg) | (x))
21741502Swpaul
21841502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
21941502Swpaul	CSR_WRITE_2(sc, reg,				\
220105221Sphk		CSR_READ_2(sc, reg) & ~(x))
22141502Swpaul
22241502Swpaul#define VR_SETBIT32(sc, reg, x)				\
22341502Swpaul	CSR_WRITE_4(sc, reg,				\
224105221Sphk		CSR_READ_4(sc, reg) | (x))
22541502Swpaul
22641502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
22741502Swpaul	CSR_WRITE_4(sc, reg,				\
228105221Sphk		CSR_READ_4(sc, reg) & ~(x))
22941502Swpaul
23041502Swpaul#define SIO_SET(x)					\
23141502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
232105221Sphk		CSR_READ_1(sc, VR_MIICMD) | (x))
23341502Swpaul
23441502Swpaul#define SIO_CLR(x)					\
23541502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
236105221Sphk		CSR_READ_1(sc, VR_MIICMD) & ~(x))
23741502Swpaul
238110168Ssilby#ifdef VR_USESWSHIFT
23941502Swpaul/*
24041502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
24141502Swpaul */
242102336Salfredstatic void
243102336Salfredvr_mii_sync(sc)
24441502Swpaul	struct vr_softc		*sc;
24541502Swpaul{
24641502Swpaul	register int		i;
24741502Swpaul
24841502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
24941502Swpaul
25041502Swpaul	for (i = 0; i < 32; i++) {
25141502Swpaul		SIO_SET(VR_MIICMD_CLK);
25241502Swpaul		DELAY(1);
25341502Swpaul		SIO_CLR(VR_MIICMD_CLK);
25441502Swpaul		DELAY(1);
25541502Swpaul	}
25641502Swpaul
25741502Swpaul	return;
25841502Swpaul}
25941502Swpaul
26041502Swpaul/*
26141502Swpaul * Clock a series of bits through the MII.
26241502Swpaul */
263102336Salfredstatic void
264102336Salfredvr_mii_send(sc, bits, cnt)
26541502Swpaul	struct vr_softc		*sc;
26641502Swpaul	u_int32_t		bits;
26741502Swpaul	int			cnt;
26841502Swpaul{
26941502Swpaul	int			i;
27041502Swpaul
27141502Swpaul	SIO_CLR(VR_MIICMD_CLK);
27241502Swpaul
27341502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
27441502Swpaul                if (bits & i) {
27541502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
27641502Swpaul                } else {
27741502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
27841502Swpaul                }
27941502Swpaul		DELAY(1);
28041502Swpaul		SIO_CLR(VR_MIICMD_CLK);
28141502Swpaul		DELAY(1);
28241502Swpaul		SIO_SET(VR_MIICMD_CLK);
28341502Swpaul	}
28441502Swpaul}
285110168Ssilby#endif
28641502Swpaul
28741502Swpaul/*
28841502Swpaul * Read an PHY register through the MII.
28941502Swpaul */
290102336Salfredstatic int
291102336Salfredvr_mii_readreg(sc, frame)
29241502Swpaul	struct vr_softc		*sc;
29341502Swpaul	struct vr_mii_frame	*frame;
29441502Swpaul
295110168Ssilby#ifdef VR_USESWSHIFT
29641502Swpaul{
29767087Swpaul	int			i, ack;
29841502Swpaul
29967087Swpaul	VR_LOCK(sc);
30041502Swpaul
30141502Swpaul	/*
30241502Swpaul	 * Set up frame for RX.
30341502Swpaul	 */
30441502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
30541502Swpaul	frame->mii_opcode = VR_MII_READOP;
30641502Swpaul	frame->mii_turnaround = 0;
30741502Swpaul	frame->mii_data = 0;
30841502Swpaul
30941502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
31041502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
31141502Swpaul
31241502Swpaul	/*
31341502Swpaul 	 * Turn on data xmit.
31441502Swpaul	 */
31541502Swpaul	SIO_SET(VR_MIICMD_DIR);
31641502Swpaul
31741502Swpaul	vr_mii_sync(sc);
31841502Swpaul
31941502Swpaul	/*
32041502Swpaul	 * Send command/address info.
32141502Swpaul	 */
32241502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
32341502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
32441502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
32541502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
32641502Swpaul
32741502Swpaul	/* Idle bit */
32841502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
32941502Swpaul	DELAY(1);
33041502Swpaul	SIO_SET(VR_MIICMD_CLK);
33141502Swpaul	DELAY(1);
33241502Swpaul
33341502Swpaul	/* Turn off xmit. */
33441502Swpaul	SIO_CLR(VR_MIICMD_DIR);
33541502Swpaul
33641502Swpaul	/* Check for ack */
33741502Swpaul	SIO_CLR(VR_MIICMD_CLK);
33841502Swpaul	DELAY(1);
339109058Smbr	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
34041502Swpaul	SIO_SET(VR_MIICMD_CLK);
34141502Swpaul	DELAY(1);
34241502Swpaul
34341502Swpaul	/*
34441502Swpaul	 * Now try reading data bits. If the ack failed, we still
34541502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
34641502Swpaul	 */
34741502Swpaul	if (ack) {
34841502Swpaul		for(i = 0; i < 16; i++) {
34941502Swpaul			SIO_CLR(VR_MIICMD_CLK);
35041502Swpaul			DELAY(1);
35141502Swpaul			SIO_SET(VR_MIICMD_CLK);
35241502Swpaul			DELAY(1);
35341502Swpaul		}
35441502Swpaul		goto fail;
35541502Swpaul	}
35641502Swpaul
35741502Swpaul	for (i = 0x8000; i; i >>= 1) {
35841502Swpaul		SIO_CLR(VR_MIICMD_CLK);
35941502Swpaul		DELAY(1);
36041502Swpaul		if (!ack) {
36141502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
36241502Swpaul				frame->mii_data |= i;
36341502Swpaul			DELAY(1);
36441502Swpaul		}
36541502Swpaul		SIO_SET(VR_MIICMD_CLK);
36641502Swpaul		DELAY(1);
36741502Swpaul	}
36841502Swpaul
36941502Swpaulfail:
37041502Swpaul
37141502Swpaul	SIO_CLR(VR_MIICMD_CLK);
37241502Swpaul	DELAY(1);
37341502Swpaul	SIO_SET(VR_MIICMD_CLK);
37441502Swpaul	DELAY(1);
37541502Swpaul
37667087Swpaul	VR_UNLOCK(sc);
37741502Swpaul
37841502Swpaul	if (ack)
37941502Swpaul		return(1);
38041502Swpaul	return(0);
38141502Swpaul}
382110168Ssilby#else
383110168Ssilby{
384110168Ssilby	int			s, i;
38541502Swpaul
386110168Ssilby	s = splimp();
387110168Ssilby
388110168Ssilby  	/* Set the PHY-adress */
389110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
390110168Ssilby	    frame->mii_phyaddr);
391110168Ssilby
392110168Ssilby  	/* Set the register-adress */
393110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
394110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
395110168Ssilby
396110168Ssilby	for (i = 0; i < 10000; i++) {
397110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
398110168Ssilby			break;
399110168Ssilby		DELAY(1);
400110168Ssilby	}
401110168Ssilby
402110168Ssilby	frame->mii_data = CSR_READ_2(sc, VR_MIIDATA);
403110168Ssilby
404110168Ssilby	(void)splx(s);
405110168Ssilby
406110168Ssilby	return(0);
407110168Ssilby}
408110168Ssilby#endif
409110168Ssilby
410110168Ssilby
41141502Swpaul/*
41241502Swpaul * Write to a PHY register through the MII.
41341502Swpaul */
414102336Salfredstatic int
415102336Salfredvr_mii_writereg(sc, frame)
41641502Swpaul	struct vr_softc		*sc;
41741502Swpaul	struct vr_mii_frame	*frame;
41841502Swpaul
419110168Ssilby#ifdef VR_USESWSHIFT
42041502Swpaul{
42167087Swpaul	VR_LOCK(sc);
42241502Swpaul
42341502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
42441502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
42541502Swpaul
42641502Swpaul	/*
42741502Swpaul	 * Set up frame for TX.
42841502Swpaul	 */
42941502Swpaul
43041502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
43141502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
43241502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
43341502Swpaul
43441502Swpaul	/*
43541502Swpaul 	 * Turn on data output.
43641502Swpaul	 */
43741502Swpaul	SIO_SET(VR_MIICMD_DIR);
43841502Swpaul
43941502Swpaul	vr_mii_sync(sc);
44041502Swpaul
44141502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
44241502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
44341502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
44441502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
44541502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
44641502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
44741502Swpaul
44841502Swpaul	/* Idle bit. */
44941502Swpaul	SIO_SET(VR_MIICMD_CLK);
45041502Swpaul	DELAY(1);
45141502Swpaul	SIO_CLR(VR_MIICMD_CLK);
45241502Swpaul	DELAY(1);
45341502Swpaul
45441502Swpaul	/*
45541502Swpaul	 * Turn off xmit.
45641502Swpaul	 */
45741502Swpaul	SIO_CLR(VR_MIICMD_DIR);
45841502Swpaul
45967087Swpaul	VR_UNLOCK(sc);
46041502Swpaul
46141502Swpaul	return(0);
46241502Swpaul}
463110168Ssilby#else
464110168Ssilby{
465110168Ssilby	int			s, i;
46641502Swpaul
467110168Ssilby	s = splimp();
468110168Ssilby
469110168Ssilby  	/* Set the PHY-adress */
470110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
471110168Ssilby		    frame->mii_phyaddr);
472110168Ssilby
473110168Ssilby  	/* Set the register-adress and data to write */
474110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
475110168Ssilby	CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data);
476110168Ssilby
477110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
478110168Ssilby
479110168Ssilby	for (i = 0; i < 10000; i++) {
480110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
481110168Ssilby			break;
482110168Ssilby		DELAY(1);
483110168Ssilby	}
484110168Ssilby
485110168Ssilby	(void)splx(s);
486110168Ssilby
487110168Ssilby	return(0);
488110168Ssilby}
489110168Ssilby#endif
490110168Ssilby
491102336Salfredstatic int
492102336Salfredvr_miibus_readreg(dev, phy, reg)
49351432Swpaul	device_t		dev;
49451432Swpaul	int			phy, reg;
49551432Swpaul{
49641502Swpaul	struct vr_softc		*sc;
49741502Swpaul	struct vr_mii_frame	frame;
49841502Swpaul
49951432Swpaul	sc = device_get_softc(dev);
500110168Ssilby
501110168Ssilby	switch (sc->vr_revid) {
502110168Ssilby		case REV_ID_VT6102_APOLLO:
503110168Ssilby			if (phy != 1)
504110168Ssilby				return 0;
505110168Ssilby		default:
506110168Ssilby			break;
507110168Ssilby		}
508110168Ssilby
50941502Swpaul	bzero((char *)&frame, sizeof(frame));
51041502Swpaul
51151432Swpaul	frame.mii_phyaddr = phy;
51241502Swpaul	frame.mii_regaddr = reg;
51341502Swpaul	vr_mii_readreg(sc, &frame);
51441502Swpaul
51541502Swpaul	return(frame.mii_data);
51641502Swpaul}
51741502Swpaul
518102336Salfredstatic int
519102336Salfredvr_miibus_writereg(dev, phy, reg, data)
52051432Swpaul	device_t		dev;
52151432Swpaul	u_int16_t		phy, reg, data;
52251432Swpaul{
52341502Swpaul	struct vr_softc		*sc;
52441502Swpaul	struct vr_mii_frame	frame;
52541502Swpaul
52651432Swpaul	sc = device_get_softc(dev);
527110168Ssilby
528110168Ssilby	switch (sc->vr_revid) {
529110168Ssilby		case REV_ID_VT6102_APOLLO:
530110168Ssilby			if (phy != 1)
531110168Ssilby				return 0;
532110168Ssilby		default:
533110168Ssilby			break;
534110168Ssilby		}
535110168Ssilby
53641502Swpaul	bzero((char *)&frame, sizeof(frame));
53741502Swpaul
53851432Swpaul	frame.mii_phyaddr = phy;
53941502Swpaul	frame.mii_regaddr = reg;
54041502Swpaul	frame.mii_data = data;
54141502Swpaul
54241502Swpaul	vr_mii_writereg(sc, &frame);
54341502Swpaul
54451432Swpaul	return(0);
54551432Swpaul}
54651432Swpaul
547102336Salfredstatic void
548102336Salfredvr_miibus_statchg(dev)
54951432Swpaul	device_t		dev;
55051432Swpaul{
55151432Swpaul	struct vr_softc		*sc;
55251432Swpaul	struct mii_data		*mii;
55351432Swpaul
55451432Swpaul	sc = device_get_softc(dev);
55567087Swpaul	VR_LOCK(sc);
55651432Swpaul	mii = device_get_softc(sc->vr_miibus);
55751432Swpaul	vr_setcfg(sc, mii->mii_media_active);
55867087Swpaul	VR_UNLOCK(sc);
55951432Swpaul
56041502Swpaul	return;
56141502Swpaul}
56241502Swpaul
56341502Swpaul/*
56441502Swpaul * Program the 64-bit multicast hash filter.
56541502Swpaul */
566102336Salfredstatic void
567102336Salfredvr_setmulti(sc)
56841502Swpaul	struct vr_softc		*sc;
56941502Swpaul{
57041502Swpaul	struct ifnet		*ifp;
57141502Swpaul	int			h = 0;
57241502Swpaul	u_int32_t		hashes[2] = { 0, 0 };
57341502Swpaul	struct ifmultiaddr	*ifma;
57441502Swpaul	u_int8_t		rxfilt;
57541502Swpaul	int			mcnt = 0;
57641502Swpaul
57741502Swpaul	ifp = &sc->arpcom.ac_if;
57841502Swpaul
57941502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
58041502Swpaul
58141502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
58241502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
58341502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
58441502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
58541502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
58641502Swpaul		return;
58741502Swpaul	}
58841502Swpaul
58941502Swpaul	/* first, zot all the existing hash bits */
59041502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
59141502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
59241502Swpaul
59341502Swpaul	/* now program new ones */
59472084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
59541502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
59641502Swpaul			continue;
597130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
598130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
59941502Swpaul		if (h < 32)
60041502Swpaul			hashes[0] |= (1 << h);
60141502Swpaul		else
60241502Swpaul			hashes[1] |= (1 << (h - 32));
60341502Swpaul		mcnt++;
60441502Swpaul	}
60541502Swpaul
60641502Swpaul	if (mcnt)
60741502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
60841502Swpaul	else
60941502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
61041502Swpaul
61141502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
61241502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
61341502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
61441502Swpaul
61541502Swpaul	return;
61641502Swpaul}
61741502Swpaul
61841502Swpaul/*
61941502Swpaul * In order to fiddle with the
62041502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
62141502Swpaul * first have to put the transmit and/or receive logic in the idle state.
62241502Swpaul */
623102336Salfredstatic void
624102336Salfredvr_setcfg(sc, media)
62541502Swpaul	struct vr_softc		*sc;
62651432Swpaul	int			media;
62741502Swpaul{
62841502Swpaul	int			restart = 0;
62941502Swpaul
63041502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
63141502Swpaul		restart = 1;
63241502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
63341502Swpaul	}
63441502Swpaul
63551432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
63641502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
63741502Swpaul	else
63841502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
63941502Swpaul
64041502Swpaul	if (restart)
64141502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
64241502Swpaul
64341502Swpaul	return;
64441502Swpaul}
64541502Swpaul
646102336Salfredstatic void
647102336Salfredvr_reset(sc)
64841502Swpaul	struct vr_softc		*sc;
64941502Swpaul{
65041502Swpaul	register int		i;
65141502Swpaul
65241502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
65341502Swpaul
65441502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
65541502Swpaul		DELAY(10);
65641502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
65741502Swpaul			break;
65841502Swpaul	}
659107220Ssilby	if (i == VR_TIMEOUT) {
660107220Ssilby		if (sc->vr_revid < REV_ID_VT3065_A)
661107220Ssilby			printf("vr%d: reset never completed!\n", sc->vr_unit);
662107220Ssilby		else {
663107220Ssilby			/* Use newer force reset command */
664107220Ssilby			printf("vr%d: Using force reset command.\n", sc->vr_unit);
665107220Ssilby			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
666107220Ssilby		}
667107220Ssilby	}
66841502Swpaul
66941502Swpaul	/* Wait a little while for the chip to get its brains in order. */
67041502Swpaul	DELAY(1000);
67141502Swpaul
67241502Swpaul        return;
67341502Swpaul}
67441502Swpaul
67541502Swpaul/*
67641502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
67741502Swpaul * IDs against our list and return a device name if we find a match.
67841502Swpaul */
679102336Salfredstatic int
680102336Salfredvr_probe(dev)
68149610Swpaul	device_t		dev;
68241502Swpaul{
68341502Swpaul	struct vr_type		*t;
68441502Swpaul
68541502Swpaul	t = vr_devs;
68641502Swpaul
68741502Swpaul	while(t->vr_name != NULL) {
68849610Swpaul		if ((pci_get_vendor(dev) == t->vr_vid) &&
68949610Swpaul		    (pci_get_device(dev) == t->vr_did)) {
69049610Swpaul			device_set_desc(dev, t->vr_name);
69149610Swpaul			return(0);
69241502Swpaul		}
69341502Swpaul		t++;
69441502Swpaul	}
69541502Swpaul
69649610Swpaul	return(ENXIO);
69741502Swpaul}
69841502Swpaul
69941502Swpaul/*
70041502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
70141502Swpaul * setup and ethernet/BPF attach.
70241502Swpaul */
703102336Salfredstatic int
704102336Salfredvr_attach(dev)
70549610Swpaul	device_t		dev;
70641502Swpaul{
70767087Swpaul	int			i;
70841502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
70941502Swpaul	struct vr_softc		*sc;
71041502Swpaul	struct ifnet		*ifp;
71149610Swpaul	int			unit, error = 0, rid;
71241502Swpaul
71349610Swpaul	sc = device_get_softc(dev);
71449610Swpaul	unit = device_get_unit(dev);
71541502Swpaul
71693818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
71793818Sjhb	    MTX_DEF | MTX_RECURSE);
718117208Simp#ifndef BURN_BRIDGES
71941502Swpaul	/*
72041502Swpaul	 * Handle power management nonsense.
72141502Swpaul	 */
72272813Swpaul	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
72372813Swpaul		u_int32_t		iobase, membase, irq;
72441502Swpaul
72572813Swpaul		/* Save important PCI config data. */
72672813Swpaul		iobase = pci_read_config(dev, VR_PCI_LOIO, 4);
72772813Swpaul		membase = pci_read_config(dev, VR_PCI_LOMEM, 4);
72872813Swpaul		irq = pci_read_config(dev, VR_PCI_INTLINE, 4);
72941502Swpaul
73072813Swpaul		/* Reset the power state. */
73172813Swpaul		printf("vr%d: chip is in D%d power mode "
73272813Swpaul		    "-- setting to D0\n", unit,
73372813Swpaul		    pci_get_powerstate(dev));
73472813Swpaul		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
73541502Swpaul
73641502Swpaul			/* Restore PCI config data. */
73772813Swpaul		pci_write_config(dev, VR_PCI_LOIO, iobase, 4);
73872813Swpaul		pci_write_config(dev, VR_PCI_LOMEM, membase, 4);
73972813Swpaul		pci_write_config(dev, VR_PCI_INTLINE, irq, 4);
74041502Swpaul	}
741117208Simp#endif
74241502Swpaul	/*
74341502Swpaul	 * Map control/status registers.
74441502Swpaul	 */
74572813Swpaul	pci_enable_busmaster(dev);
746107220Ssilby	sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF;
74741502Swpaul
74849610Swpaul	rid = VR_RID;
749127135Snjl	sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE);
75049610Swpaul
75149610Swpaul	if (sc->vr_res == NULL) {
75249610Swpaul		printf("vr%d: couldn't map ports/memory\n", unit);
75349610Swpaul		error = ENXIO;
75441502Swpaul		goto fail;
75541502Swpaul	}
75641502Swpaul
75749610Swpaul	sc->vr_btag = rman_get_bustag(sc->vr_res);
75849610Swpaul	sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
75941502Swpaul
76041502Swpaul	/* Allocate interrupt */
76149610Swpaul	rid = 0;
762127135Snjl	sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
76349610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
76449610Swpaul
76549610Swpaul	if (sc->vr_irq == NULL) {
76641502Swpaul		printf("vr%d: couldn't map interrupt\n", unit);
76749610Swpaul		error = ENXIO;
76841502Swpaul		goto fail;
76941502Swpaul	}
77041502Swpaul
77176586Swpaul	/*
77276586Swpaul	 * Windows may put the chip in suspend mode when it
77376586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
77476586Swpaul	 * up again.
77576586Swpaul	 */
77676586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
77776586Swpaul
77841502Swpaul	/* Reset the adapter. */
77941502Swpaul	vr_reset(sc);
78041502Swpaul
781110168Ssilby        /*
782110168Ssilby	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
783110168Ssilby	 * initialization and disable AUTOPOLL.
784110168Ssilby	 */
785110168Ssilby        pci_write_config(dev, VR_PCI_MODE,
786110168Ssilby	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
787110168Ssilby	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
788110168Ssilby
78941502Swpaul	/*
79041502Swpaul	 * Get station address. The way the Rhine chips work,
79141502Swpaul	 * you're not allowed to directly access the EEPROM once
79241502Swpaul	 * they've been programmed a special way. Consequently,
79341502Swpaul	 * we need to read the node address from the PAR0 and PAR1
79441502Swpaul	 * registers.
79541502Swpaul	 */
79641502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
79741502Swpaul	DELAY(200);
79841502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
79941502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
80041502Swpaul
80141502Swpaul	sc->vr_unit = unit;
80241502Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
80341502Swpaul
80451432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
80551657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
80651432Swpaul
80751432Swpaul	if (sc->vr_ldata == NULL) {
80841502Swpaul		printf("vr%d: no memory for list buffers!\n", unit);
80949610Swpaul		error = ENXIO;
81049610Swpaul		goto fail;
81141502Swpaul	}
81241502Swpaul
81341502Swpaul	bzero(sc->vr_ldata, sizeof(struct vr_list_data));
81441502Swpaul
81541502Swpaul	ifp = &sc->arpcom.ac_if;
81641502Swpaul	ifp->if_softc = sc;
817121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
81841502Swpaul	ifp->if_mtu = ETHERMTU;
81941502Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
82041502Swpaul	ifp->if_ioctl = vr_ioctl;
82141502Swpaul	ifp->if_start = vr_start;
82241502Swpaul	ifp->if_watchdog = vr_watchdog;
82341502Swpaul	ifp->if_init = vr_init;
82441502Swpaul	ifp->if_baudrate = 10000000;
82543515Swpaul	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
826128118Sru#ifdef DEVICE_POLLING
827128118Sru	ifp->if_capabilities |= IFCAP_POLLING;
828128118Sru#endif
829128118Sru	ifp->if_capenable = ifp->if_capabilities;
83041502Swpaul
83151432Swpaul	/*
83251432Swpaul	 * Do MII setup.
83351432Swpaul	 */
83451432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
83551432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
83641502Swpaul		printf("vr%d: MII without any phy!\n", sc->vr_unit);
83749610Swpaul		error = ENXIO;
83841502Swpaul		goto fail;
83941502Swpaul	}
84041502Swpaul
84151432Swpaul	callout_handle_init(&sc->vr_stat_ch);
84241502Swpaul
84341502Swpaul	/*
84463090Sarchie	 * Call MI attach routine.
84541502Swpaul	 */
846106936Ssam	ether_ifattach(ifp, eaddr);
84741502Swpaul
848113609Snjl	/* Hook interrupt last to avoid having to lock softc */
849112872Snjl	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET,
850112872Snjl	    vr_intr, sc, &sc->vr_intrhand);
851112872Snjl
852112872Snjl	if (error) {
853112872Snjl		printf("vr%d: couldn't set up irq\n", unit);
854113609Snjl		ether_ifdetach(ifp);
855112872Snjl		goto fail;
856112872Snjl	}
857112872Snjl
85841502Swpaulfail:
859112872Snjl	if (error)
860112872Snjl		vr_detach(dev);
86167087Swpaul
86249610Swpaul	return(error);
86341502Swpaul}
86441502Swpaul
865113609Snjl/*
866113609Snjl * Shutdown hardware and free up resources. This can be called any
867113609Snjl * time after the mutex has been initialized. It is called in both
868113609Snjl * the error case in attach and the normal detach case so it needs
869113609Snjl * to be careful about only freeing resources that have actually been
870113609Snjl * allocated.
871113609Snjl */
872102336Salfredstatic int
873102336Salfredvr_detach(dev)
87449610Swpaul	device_t		dev;
87549610Swpaul{
87649610Swpaul	struct vr_softc		*sc;
87749610Swpaul	struct ifnet		*ifp;
87849610Swpaul
87949610Swpaul	sc = device_get_softc(dev);
880112880Sjhb	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
88167087Swpaul	VR_LOCK(sc);
88249610Swpaul	ifp = &sc->arpcom.ac_if;
88349610Swpaul
884113609Snjl	/* These should only be active if attach succeeded */
885113812Simp	if (device_is_attached(dev)) {
886113609Snjl		vr_stop(sc);
887112872Snjl		ether_ifdetach(ifp);
888113609Snjl	}
889113609Snjl	if (sc->vr_miibus)
890112872Snjl		device_delete_child(dev, sc->vr_miibus);
891113609Snjl	bus_generic_detach(dev);
89249610Swpaul
893112872Snjl	if (sc->vr_intrhand)
894112872Snjl		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
895112872Snjl	if (sc->vr_irq)
896112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
897112872Snjl	if (sc->vr_res)
898112872Snjl		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
89951432Swpaul
900112872Snjl	if (sc->vr_ldata)
901112872Snjl		contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
90249610Swpaul
90367087Swpaul	VR_UNLOCK(sc);
90467087Swpaul	mtx_destroy(&sc->vr_mtx);
90549610Swpaul
90649610Swpaul	return(0);
90749610Swpaul}
90849610Swpaul
90941502Swpaul/*
91041502Swpaul * Initialize the transmit descriptors.
91141502Swpaul */
912102336Salfredstatic int
913102336Salfredvr_list_tx_init(sc)
91441502Swpaul	struct vr_softc		*sc;
91541502Swpaul{
91641502Swpaul	struct vr_chain_data	*cd;
91741502Swpaul	struct vr_list_data	*ld;
91841502Swpaul	int			i;
91941502Swpaul
92041502Swpaul	cd = &sc->vr_cdata;
92141502Swpaul	ld = sc->vr_ldata;
92241502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
92341502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
92441502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
92541502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
92641502Swpaul				&cd->vr_tx_chain[0];
92741502Swpaul		else
92841502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
92941502Swpaul				&cd->vr_tx_chain[i + 1];
93041502Swpaul	}
93141502Swpaul
932127901Sru	cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0];
93341502Swpaul
93441502Swpaul	return(0);
93541502Swpaul}
93641502Swpaul
93741502Swpaul
93841502Swpaul/*
93941502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
94041502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
94141502Swpaul * points back to the first.
94241502Swpaul */
943102336Salfredstatic int
944102336Salfredvr_list_rx_init(sc)
94541502Swpaul	struct vr_softc		*sc;
94641502Swpaul{
94741502Swpaul	struct vr_chain_data	*cd;
94841502Swpaul	struct vr_list_data	*ld;
94941502Swpaul	int			i;
95041502Swpaul
95141502Swpaul	cd = &sc->vr_cdata;
95241502Swpaul	ld = sc->vr_ldata;
95341502Swpaul
95441502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
95541502Swpaul		cd->vr_rx_chain[i].vr_ptr =
95641502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
95749610Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
95841502Swpaul			return(ENOBUFS);
95941502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
96041502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
96141502Swpaul					&cd->vr_rx_chain[0];
96241502Swpaul			ld->vr_rx_list[i].vr_next =
96341502Swpaul					vtophys(&ld->vr_rx_list[0]);
96441502Swpaul		} else {
96541502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
96641502Swpaul					&cd->vr_rx_chain[i + 1];
96741502Swpaul			ld->vr_rx_list[i].vr_next =
96841502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
96941502Swpaul		}
97041502Swpaul	}
97141502Swpaul
97241502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
97341502Swpaul
97441502Swpaul	return(0);
97541502Swpaul}
97641502Swpaul
97741502Swpaul/*
97841502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
97941502Swpaul * Note: the length fields are only 11 bits wide, which means the
98041502Swpaul * largest size we can specify is 2047. This is important because
98141502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
98241502Swpaul * overflow the field and make a mess.
98341502Swpaul */
984102336Salfredstatic int
985102336Salfredvr_newbuf(sc, c, m)
98641502Swpaul	struct vr_softc		*sc;
98741502Swpaul	struct vr_chain_onefrag	*c;
98849610Swpaul	struct mbuf		*m;
98941502Swpaul{
99041502Swpaul	struct mbuf		*m_new = NULL;
99141502Swpaul
99249610Swpaul	if (m == NULL) {
993111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
99487846Sluigi		if (m_new == NULL)
99549610Swpaul			return(ENOBUFS);
99641502Swpaul
997111119Simp		MCLGET(m_new, M_DONTWAIT);
99849610Swpaul		if (!(m_new->m_flags & M_EXT)) {
99949610Swpaul			m_freem(m_new);
100049610Swpaul			return(ENOBUFS);
100149610Swpaul		}
100249610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
100349610Swpaul	} else {
100449610Swpaul		m_new = m;
100549610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
100649610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
100741502Swpaul	}
100841502Swpaul
100949610Swpaul	m_adj(m_new, sizeof(u_int64_t));
101049610Swpaul
101141502Swpaul	c->vr_mbuf = m_new;
101241502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
101341502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
101442491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
101541502Swpaul
101641502Swpaul	return(0);
101741502Swpaul}
101841502Swpaul
101941502Swpaul/*
102041502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
102141502Swpaul * the higher level protocols.
102241502Swpaul */
1023102336Salfredstatic void
1024102336Salfredvr_rxeof(sc)
102541502Swpaul	struct vr_softc		*sc;
102641502Swpaul{
1027127901Sru        struct mbuf		*m, *m0;
102841502Swpaul        struct ifnet		*ifp;
102941502Swpaul	struct vr_chain_onefrag	*cur_rx;
103041502Swpaul	int			total_len = 0;
103141502Swpaul	u_int32_t		rxstat;
103241502Swpaul
1033122689Ssam	VR_LOCK_ASSERT(sc);
1034122689Ssam
103541502Swpaul	ifp = &sc->arpcom.ac_if;
103641502Swpaul
103741502Swpaul	while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
103841502Swpaul							VR_RXSTAT_OWN)) {
1039127901Sru#ifdef DEVICE_POLLING
1040127901Sru		if (ifp->if_flags & IFF_POLLING) {
1041127901Sru			if (sc->rxcycles <= 0)
1042127901Sru				break;
1043127901Sru			sc->rxcycles--;
1044127901Sru		}
1045127901Sru#endif /* DEVICE_POLLING */
1046127901Sru		m0 = NULL;
104741502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
104841502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
104949610Swpaul		m = cur_rx->vr_mbuf;
105041502Swpaul
105141502Swpaul		/*
105241502Swpaul		 * If an error occurs, update stats, clear the
105341502Swpaul		 * status word and leave the mbuf cluster in place:
105441502Swpaul		 * it should simply get re-used next time this descriptor
105541502Swpaul	 	 * comes up in the ring.
105641502Swpaul		 */
105741502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
105841502Swpaul			ifp->if_ierrors++;
1059110131Ssilby			printf("vr%d: rx error (%02x):",
1060110131Ssilby			       sc->vr_unit, rxstat & 0x000000ff);
1061110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
1062110131Ssilby				printf(" crc error");
1063110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
1064110131Ssilby				printf(" frame alignment error\n");
1065110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
1066110131Ssilby				printf(" FIFO overflow");
1067110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
1068110131Ssilby				printf(" received giant packet");
1069110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
1070110131Ssilby				printf(" received runt packet");
1071110131Ssilby			if (rxstat & VR_RXSTAT_BUSERR)
1072110131Ssilby				printf(" system bus error");
1073110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
1074110131Ssilby				printf("rx buffer error");
1075110131Ssilby			printf("\n");
107649610Swpaul			vr_newbuf(sc, cur_rx, m);
107741502Swpaul			continue;
107841502Swpaul		}
107941502Swpaul
108041502Swpaul		/* No errors; receive the packet. */
108141502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
108241502Swpaul
108341502Swpaul		/*
108442048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
108542048Swpaul		 * received frame, and there's no way to turn this
108642048Swpaul		 * behavior off (at least, I can't find anything in
108742048Swpaul	 	 * the manual that explains how to do it) so we have
108842048Swpaul		 * to trim off the CRC manually.
108942048Swpaul		 */
109042048Swpaul		total_len -= ETHER_CRC_LEN;
109142048Swpaul
109278508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
109378508Sbmilekic		    NULL);
109449610Swpaul		vr_newbuf(sc, cur_rx, m);
109549610Swpaul		if (m0 == NULL) {
109641502Swpaul			ifp->if_ierrors++;
109741502Swpaul			continue;
109841502Swpaul		}
109949610Swpaul		m = m0;
110041502Swpaul
110141502Swpaul		ifp->if_ipackets++;
1102122689Ssam		VR_UNLOCK(sc);
1103106936Ssam		(*ifp->if_input)(ifp, m);
1104122689Ssam		VR_LOCK(sc);
110541502Swpaul	}
110641502Swpaul
110741502Swpaul	return;
110841502Swpaul}
110941502Swpaul
1110105221Sphkstatic void
1111102336Salfredvr_rxeoc(sc)
111241502Swpaul	struct vr_softc		*sc;
111341502Swpaul{
1114110131Ssilby	struct ifnet		*ifp;
1115110131Ssilby	int			i;
111641502Swpaul
1117110131Ssilby	ifp = &sc->arpcom.ac_if;
1118110131Ssilby
1119110131Ssilby	ifp->if_ierrors++;
1120110131Ssilby
1121110131Ssilby	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
1122110131Ssilby        DELAY(10000);
1123110131Ssilby
1124110131Ssilby	for (i = 0x400;
1125110131Ssilby	     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON);
1126110131Ssilby	     i--)
1127110131Ssilby		;	/* Wait for receiver to stop */
1128110131Ssilby
1129110131Ssilby	if (!i) {
1130110131Ssilby		printf("vr%d: rx shutdown error!\n", sc->vr_unit);
1131110131Ssilby		sc->vr_flags |= VR_F_RESTART;
1132110131Ssilby		return;
1133110131Ssilby		}
1134110131Ssilby
113541502Swpaul	vr_rxeof(sc);
1136110131Ssilby
113741502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
113841502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
113941502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
114041502Swpaul
114141502Swpaul	return;
114241502Swpaul}
114341502Swpaul
114441502Swpaul/*
114541502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
114641502Swpaul * the list buffers.
114741502Swpaul */
114841502Swpaul
1149102336Salfredstatic void
1150102336Salfredvr_txeof(sc)
115141502Swpaul	struct vr_softc		*sc;
115241502Swpaul{
115341502Swpaul	struct vr_chain		*cur_tx;
115441502Swpaul	struct ifnet		*ifp;
115541502Swpaul
115641502Swpaul	ifp = &sc->arpcom.ac_if;
115741502Swpaul
115841502Swpaul	/*
115941502Swpaul	 * Go through our tx list and free mbufs for those
116041502Swpaul	 * frames that have been transmitted.
116141502Swpaul	 */
1162127901Sru	cur_tx = sc->vr_cdata.vr_tx_cons;
1163127901Sru	while (cur_tx->vr_mbuf != NULL) {
116441502Swpaul		u_int32_t		txstat;
1165110131Ssilby		int			i;
116641502Swpaul
116741502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
116841502Swpaul
1169101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
1170101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
1171110131Ssilby			for (i = 0x400;
1172110131Ssilby			     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON);
1173110131Ssilby			     i--)
1174101896Ssilby				;	/* Wait for chip to shutdown */
1175110131Ssilby			if (!i) {
1176110131Ssilby				printf("vr%d: tx shutdown timeout\n", sc->vr_unit);
1177110131Ssilby				sc->vr_flags |= VR_F_RESTART;
1178110131Ssilby				break;
1179110131Ssilby			}
1180101896Ssilby			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
1181101896Ssilby			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr));
1182101896Ssilby			break;
1183101896Ssilby		}
1184101896Ssilby
118542491Swpaul		if (txstat & VR_TXSTAT_OWN)
118641502Swpaul			break;
118741502Swpaul
118841502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
118941502Swpaul			ifp->if_oerrors++;
119041502Swpaul			if (txstat & VR_TXSTAT_DEFER)
119141502Swpaul				ifp->if_collisions++;
119241502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
119341502Swpaul				ifp->if_collisions++;
119441502Swpaul		}
119541502Swpaul
119641502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
119741502Swpaul
119841502Swpaul		ifp->if_opackets++;
1199127901Sru		m_freem(cur_tx->vr_mbuf);
1200127901Sru		cur_tx->vr_mbuf = NULL;
1201127901Sru		ifp->if_flags &= ~IFF_OACTIVE;
120241502Swpaul
1203127901Sru		cur_tx = cur_tx->vr_nextdesc;
120441502Swpaul	}
1205127901Sru	sc->vr_cdata.vr_tx_cons = cur_tx;
1206127901Sru	if (cur_tx->vr_mbuf == NULL)
120796677Ssilby		ifp->if_timer = 0;
120841502Swpaul}
120941502Swpaul
1210102336Salfredstatic void
1211102336Salfredvr_tick(xsc)
121251432Swpaul	void			*xsc;
121351432Swpaul{
121451432Swpaul	struct vr_softc		*sc;
121551432Swpaul	struct mii_data		*mii;
121651432Swpaul
121751432Swpaul	sc = xsc;
121867087Swpaul	VR_LOCK(sc);
1219110131Ssilby	if (sc->vr_flags & VR_F_RESTART) {
1220110131Ssilby		printf("vr%d: restarting\n", sc->vr_unit);
1221110131Ssilby		vr_stop(sc);
1222110131Ssilby		vr_reset(sc);
1223110131Ssilby		vr_init(sc);
1224110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1225110131Ssilby	}
1226110131Ssilby
122751432Swpaul	mii = device_get_softc(sc->vr_miibus);
122851432Swpaul	mii_tick(mii);
122951432Swpaul
123051432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
123151432Swpaul
123267087Swpaul	VR_UNLOCK(sc);
123351432Swpaul
123451432Swpaul	return;
123551432Swpaul}
123651432Swpaul
1237127901Sru#ifdef DEVICE_POLLING
1238127901Srustatic poll_handler_t vr_poll;
1239127901Sru
1240102336Salfredstatic void
1241127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1242127901Sru{
1243127901Sru	struct vr_softc *sc = ifp->if_softc;
1244127901Sru
1245127901Sru	VR_LOCK(sc);
1246128118Sru	if (!(ifp->if_capenable & IFCAP_POLLING)) {
1247128118Sru		ether_poll_deregister(ifp);
1248128118Sru		cmd = POLL_DEREGISTER;
1249128118Sru	}
1250127901Sru	if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
1251127901Sru		CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
1252127901Sru		goto done;
1253127901Sru	}
1254127901Sru
1255127901Sru	sc->rxcycles = count;
1256127901Sru	vr_rxeof(sc);
1257127901Sru	vr_txeof(sc);
1258127901Sru	if (ifp->if_snd.ifq_head != NULL)
1259127901Sru		vr_start(ifp);
1260127901Sru
1261127901Sru	if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */
1262127901Sru		u_int16_t status;
1263127901Sru
1264127901Sru		status = CSR_READ_2(sc, VR_ISR);
1265127901Sru		if (status)
1266127901Sru			CSR_WRITE_2(sc, VR_ISR, status);
1267127901Sru
1268127901Sru		if ((status & VR_INTRS) == 0)
1269127901Sru			goto done;
1270127901Sru
1271127901Sru		if (status & VR_ISR_RX_DROPPED) {
1272127901Sru			printf("vr%d: rx packet lost\n", sc->vr_unit);
1273127901Sru			ifp->if_ierrors++;
1274127901Sru		}
1275127901Sru
1276127901Sru		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1277127901Sru		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1278127901Sru			printf("vr%d: receive error (%04x)",
1279127901Sru			       sc->vr_unit, status);
1280127901Sru			if (status & VR_ISR_RX_NOBUF)
1281127901Sru				printf(" no buffers");
1282127901Sru			if (status & VR_ISR_RX_OFLOW)
1283127901Sru				printf(" overflow");
1284127901Sru			if (status & VR_ISR_RX_DROPPED)
1285127901Sru				printf(" packet lost");
1286127901Sru			printf("\n");
1287127901Sru			vr_rxeoc(sc);
1288127901Sru		}
1289127901Sru
1290127901Sru		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1291127901Sru			vr_reset(sc);
1292127901Sru			vr_init(sc);
1293127901Sru			goto done;
1294127901Sru		}
1295127901Sru
1296127901Sru		if ((status & VR_ISR_UDFI) ||
1297127901Sru		    (status & VR_ISR_TX_ABRT2) ||
1298127901Sru		    (status & VR_ISR_TX_ABRT)) {
1299127901Sru			ifp->if_oerrors++;
1300127901Sru			if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) {
1301127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1302127901Sru				VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1303127901Sru			}
1304127901Sru		}
1305127901Sru	}
1306127901Sru
1307127901Srudone:
1308127901Sru	VR_UNLOCK(sc);
1309127901Sru
1310127901Sru}
1311127901Sru#endif /* DEVICE_POLLING */
1312127901Sru
1313127901Srustatic void
1314102336Salfredvr_intr(arg)
131541502Swpaul	void			*arg;
131641502Swpaul{
131741502Swpaul	struct vr_softc		*sc;
131841502Swpaul	struct ifnet		*ifp;
131941502Swpaul	u_int16_t		status;
132041502Swpaul
132141502Swpaul	sc = arg;
132267087Swpaul	VR_LOCK(sc);
132341502Swpaul	ifp = &sc->arpcom.ac_if;
132441502Swpaul
1325127901Sru#ifdef DEVICE_POLLING
1326127901Sru	if (ifp->if_flags & IFF_POLLING)
1327127901Sru		goto done;
1328128118Sru	if ((ifp->if_capenable & IFCAP_POLLING) &&
1329128118Sru	    ether_poll_register(vr_poll, ifp)) { /* ok, disable interrupts */
1330127901Sru		CSR_WRITE_2(sc, VR_IMR, 0x0000);
1331127901Sru		vr_poll(ifp, 0, 1);
1332127901Sru		goto done;
1333127901Sru	}
1334127901Sru#endif /* DEVICE_POLLING */
1335127901Sru
133641502Swpaul	/* Supress unwanted interrupts. */
133741502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
133841502Swpaul		vr_stop(sc);
133967087Swpaul		VR_UNLOCK(sc);
134041502Swpaul		return;
134141502Swpaul	}
134241502Swpaul
134341502Swpaul	/* Disable interrupts. */
134441502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
134541502Swpaul
134641502Swpaul	for (;;) {
134741502Swpaul
134841502Swpaul		status = CSR_READ_2(sc, VR_ISR);
134941502Swpaul		if (status)
135041502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
135141502Swpaul
135241502Swpaul		if ((status & VR_INTRS) == 0)
135341502Swpaul			break;
135441502Swpaul
135541502Swpaul		if (status & VR_ISR_RX_OK)
135641502Swpaul			vr_rxeof(sc);
135741502Swpaul
1358110131Ssilby		if (status & VR_ISR_RX_DROPPED) {
1359110131Ssilby			printf("vr%d: rx packet lost\n", sc->vr_unit);
1360110131Ssilby			ifp->if_ierrors++;
1361110131Ssilby			}
1362110131Ssilby
136341502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1364110131Ssilby		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1365110131Ssilby			printf("vr%d: receive error (%04x)",
1366110131Ssilby			       sc->vr_unit, status);
1367110131Ssilby			if (status & VR_ISR_RX_NOBUF)
1368110131Ssilby				printf(" no buffers");
1369110131Ssilby			if (status & VR_ISR_RX_OFLOW)
1370110131Ssilby				printf(" overflow");
1371110131Ssilby			if (status & VR_ISR_RX_DROPPED)
1372110131Ssilby				printf(" packet lost");
1373110131Ssilby			printf("\n");
137441502Swpaul			vr_rxeoc(sc);
137541502Swpaul		}
137641502Swpaul
1377101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1378101896Ssilby			vr_reset(sc);
1379101896Ssilby			vr_init(sc);
1380101896Ssilby			break;
138141502Swpaul		}
138241502Swpaul
1383101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1384101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
138541502Swpaul			vr_txeof(sc);
1386101896Ssilby			if ((status & VR_ISR_UDFI) ||
1387101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1388101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1389101896Ssilby				ifp->if_oerrors++;
1390127901Sru				if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) {
1391101896Ssilby					VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1392101896Ssilby					VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1393101896Ssilby				}
1394127901Sru			}
139541502Swpaul		}
139641502Swpaul
139741502Swpaul	}
139841502Swpaul
139941502Swpaul	/* Re-enable interrupts. */
140041502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
140141502Swpaul
140241502Swpaul	if (ifp->if_snd.ifq_head != NULL) {
140341502Swpaul		vr_start(ifp);
140441502Swpaul	}
140541502Swpaul
1406127901Sru#ifdef DEVICE_POLLING
1407127901Srudone:
1408127901Sru#endif /* DEVICE_POLLING */
140967087Swpaul	VR_UNLOCK(sc);
141067087Swpaul
141141502Swpaul	return;
141241502Swpaul}
141341502Swpaul
141441502Swpaul/*
141541502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
141641502Swpaul * pointers to the fragment pointers.
141741502Swpaul */
1418102336Salfredstatic int
1419102336Salfredvr_encap(sc, c, m_head)
142041502Swpaul	struct vr_softc		*sc;
142141502Swpaul	struct vr_chain		*c;
142241502Swpaul	struct mbuf		*m_head;
142341502Swpaul{
142441502Swpaul	struct vr_desc		*f = NULL;
142541502Swpaul	struct mbuf		*m;
142641502Swpaul
142741502Swpaul	/*
142841502Swpaul	 * The VIA Rhine wants packet buffers to be longword
142941502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
143041502Swpaul	 * waste time trying to decide when to copy and when not
143141502Swpaul	 * to copy, just do it all the time.
143241502Swpaul	 */
1433127901Sru	m = m_defrag(m_head, M_DONTWAIT);
1434127901Sru	if (m == NULL) {
1435127901Sru		return(1);
1436127901Sru	}
143741502Swpaul
1438127901Sru	/*
1439127901Sru	 * The Rhine chip doesn't auto-pad, so we have to make
1440127901Sru	 * sure to pad short frames out to the minimum frame length
1441127901Sru	 * ourselves.
1442127901Sru	 */
1443127901Sru	if (m->m_len < VR_MIN_FRAMELEN) {
1444127901Sru		m->m_pkthdr.len += VR_MIN_FRAMELEN - m->m_len;
1445127901Sru		m->m_len = m->m_pkthdr.len;
144641502Swpaul	}
144741502Swpaul
1448127901Sru	c->vr_mbuf = m;
1449127901Sru	f = c->vr_ptr;
1450127901Sru	f->vr_data = vtophys(mtod(m, caddr_t));
1451127901Sru	f->vr_ctl = m->m_len;
1452127901Sru	f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
1453127901Sru	f->vr_status = 0;
1454127901Sru	f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
1455127901Sru	f->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
145641502Swpaul
145741502Swpaul	return(0);
145841502Swpaul}
145941502Swpaul
146041502Swpaul/*
146141502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
146241502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
146341502Swpaul * copy of the pointers since the transmit list fragment pointers are
146441502Swpaul * physical addresses.
146541502Swpaul */
146641502Swpaul
1467102336Salfredstatic void
1468102336Salfredvr_start(ifp)
146941502Swpaul	struct ifnet		*ifp;
147041502Swpaul{
147141502Swpaul	struct vr_softc		*sc;
1472127901Sru	struct mbuf		*m_head;
1473127901Sru	struct vr_chain		*cur_tx;
147441502Swpaul
1475127901Sru	if (ifp->if_flags & IFF_OACTIVE)
1476127901Sru		return;
1477127901Sru
147841502Swpaul	sc = ifp->if_softc;
147941502Swpaul
148067087Swpaul	VR_LOCK(sc);
148141502Swpaul
1482127901Sru	cur_tx = sc->vr_cdata.vr_tx_prod;
1483127901Sru	while (cur_tx->vr_mbuf == NULL) {
148441502Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
148541502Swpaul		if (m_head == NULL)
148641502Swpaul			break;
148741502Swpaul
148841502Swpaul		/* Pack the data into the descriptor. */
148971271Swpaul		if (vr_encap(sc, cur_tx, m_head)) {
1490113274Ssilby			/* Rollback, send what we were able to encap. */
149171271Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
149271271Swpaul			break;
149371271Swpaul		}
149441502Swpaul
1495127901Sru		VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
149641502Swpaul
149741502Swpaul		/*
149841502Swpaul		 * If there's a BPF listener, bounce a copy of this frame
149941502Swpaul		 * to him.
150041502Swpaul		 */
1501106936Ssam		BPF_MTAP(ifp, cur_tx->vr_mbuf);
150251583Swpaul
1503127901Sru		cur_tx = cur_tx->vr_nextdesc;
150441502Swpaul	}
1505127901Sru	if (cur_tx != sc->vr_cdata.vr_tx_prod || cur_tx->vr_mbuf != NULL) {
1506127901Sru		sc->vr_cdata.vr_tx_prod = cur_tx;
150741502Swpaul
1508127901Sru		/* Tell the chip to start transmitting. */
1509127901Sru		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO);
151041526Swpaul
1511127901Sru		/* Set a timeout in case the chip goes out to lunch. */
1512127901Sru		ifp->if_timer = 5;
151341502Swpaul
1514127901Sru		if (cur_tx->vr_mbuf != NULL)
1515127901Sru			ifp->if_flags |= IFF_OACTIVE;
1516127901Sru	}
151741502Swpaul
151867087Swpaul	VR_UNLOCK(sc);
151941502Swpaul
152041502Swpaul	return;
152141502Swpaul}
152241502Swpaul
1523102336Salfredstatic void
1524102336Salfredvr_init(xsc)
152541502Swpaul	void			*xsc;
152641502Swpaul{
152741502Swpaul	struct vr_softc		*sc = xsc;
152841502Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
152951432Swpaul	struct mii_data		*mii;
153073963Swpaul	int			i;
153141502Swpaul
153267087Swpaul	VR_LOCK(sc);
153341502Swpaul
153451432Swpaul	mii = device_get_softc(sc->vr_miibus);
153541502Swpaul
153641502Swpaul	/*
153741502Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
153841502Swpaul	 */
153941502Swpaul	vr_stop(sc);
154041502Swpaul	vr_reset(sc);
154141502Swpaul
154273963Swpaul	/*
154373963Swpaul	 * Set our station address.
154473963Swpaul	 */
154573963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
154673963Swpaul		CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]);
1547101375Ssilby
1548101375Ssilby	/* Set DMA size */
1549101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1550101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
155173963Swpaul
1552101375Ssilby	/*
1553101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1554101108Ssilby	 * so we must set both.
1555101108Ssilby	 */
1556101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1557110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
1558101108Ssilby
1559101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1560101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1561101108Ssilby
156241502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
1563110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
156441502Swpaul
156541502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
156641502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
156741502Swpaul
156841502Swpaul	/* Init circular RX list. */
156941502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
157041502Swpaul		printf("vr%d: initialization failed: no "
157141502Swpaul			"memory for rx buffers\n", sc->vr_unit);
157241502Swpaul		vr_stop(sc);
157367087Swpaul		VR_UNLOCK(sc);
157441502Swpaul		return;
157541502Swpaul	}
157641502Swpaul
157741502Swpaul	/*
157841502Swpaul	 * Init tx descriptors.
157941502Swpaul	 */
158041502Swpaul	vr_list_tx_init(sc);
158141502Swpaul
158241502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
158341502Swpaul	if (ifp->if_flags & IFF_PROMISC)
158441502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
158541502Swpaul	else
158641502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
158741502Swpaul
158841502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
158941502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
159041502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
159141502Swpaul	else
159241502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
159341502Swpaul
159441502Swpaul	/*
159541502Swpaul	 * Program the multicast filter, if necessary.
159641502Swpaul	 */
159741502Swpaul	vr_setmulti(sc);
159841502Swpaul
159941502Swpaul	/*
160041502Swpaul	 * Load the address of the RX list.
160141502Swpaul	 */
160241502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
160341502Swpaul
160441502Swpaul	/* Enable receiver and transmitter. */
160541502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
160641502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
160741502Swpaul				    VR_CMD_RX_GO);
160841502Swpaul
160941502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
161041502Swpaul
1611127901Sru	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
1612127901Sru#ifdef DEVICE_POLLING
161341502Swpaul	/*
1614127901Sru	 * Disable interrupts if we are polling.
1615127901Sru	 */
1616127901Sru	if (ifp->if_flags & IFF_POLLING)
1617127901Sru		CSR_WRITE_2(sc, VR_IMR, 0);
1618127901Sru	else
1619127901Sru#endif /* DEVICE_POLLING */
1620127901Sru	/*
162141502Swpaul	 * Enable interrupts.
162241502Swpaul	 */
162341502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
162441502Swpaul
162551432Swpaul	mii_mediachg(mii);
162641502Swpaul
162741502Swpaul	ifp->if_flags |= IFF_RUNNING;
162841502Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
162941502Swpaul
163051432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
163151432Swpaul
163267087Swpaul	VR_UNLOCK(sc);
163367087Swpaul
163441502Swpaul	return;
163541502Swpaul}
163641502Swpaul
163741502Swpaul/*
163841502Swpaul * Set media options.
163941502Swpaul */
1640102336Salfredstatic int
1641102336Salfredvr_ifmedia_upd(ifp)
164241502Swpaul	struct ifnet		*ifp;
164341502Swpaul{
164441502Swpaul	struct vr_softc		*sc;
164541502Swpaul
164641502Swpaul	sc = ifp->if_softc;
164741502Swpaul
164851432Swpaul	if (ifp->if_flags & IFF_UP)
164951432Swpaul		vr_init(sc);
165041502Swpaul
165141502Swpaul	return(0);
165241502Swpaul}
165341502Swpaul
165441502Swpaul/*
165541502Swpaul * Report current media status.
165641502Swpaul */
1657102336Salfredstatic void
1658102336Salfredvr_ifmedia_sts(ifp, ifmr)
165941502Swpaul	struct ifnet		*ifp;
166041502Swpaul	struct ifmediareq	*ifmr;
166141502Swpaul{
166241502Swpaul	struct vr_softc		*sc;
166351432Swpaul	struct mii_data		*mii;
166441502Swpaul
166541502Swpaul	sc = ifp->if_softc;
166651432Swpaul	mii = device_get_softc(sc->vr_miibus);
166751432Swpaul	mii_pollstat(mii);
166851432Swpaul	ifmr->ifm_active = mii->mii_media_active;
166951432Swpaul	ifmr->ifm_status = mii->mii_media_status;
167041502Swpaul
167141502Swpaul	return;
167241502Swpaul}
167341502Swpaul
1674102336Salfredstatic int
1675102336Salfredvr_ioctl(ifp, command, data)
167641502Swpaul	struct ifnet		*ifp;
167741502Swpaul	u_long			command;
167841502Swpaul	caddr_t			data;
167941502Swpaul{
168041502Swpaul	struct vr_softc		*sc = ifp->if_softc;
168141502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
168251432Swpaul	struct mii_data		*mii;
168367087Swpaul	int			error = 0;
168441502Swpaul
168567087Swpaul	VR_LOCK(sc);
168641502Swpaul
168741502Swpaul	switch(command) {
168841502Swpaul	case SIOCSIFFLAGS:
168941502Swpaul		if (ifp->if_flags & IFF_UP) {
169041502Swpaul			vr_init(sc);
169141502Swpaul		} else {
169241502Swpaul			if (ifp->if_flags & IFF_RUNNING)
169341502Swpaul				vr_stop(sc);
169441502Swpaul		}
169541502Swpaul		error = 0;
169641502Swpaul		break;
169741502Swpaul	case SIOCADDMULTI:
169841502Swpaul	case SIOCDELMULTI:
169941502Swpaul		vr_setmulti(sc);
170041502Swpaul		error = 0;
170141502Swpaul		break;
170241502Swpaul	case SIOCGIFMEDIA:
170341502Swpaul	case SIOCSIFMEDIA:
170451432Swpaul		mii = device_get_softc(sc->vr_miibus);
170551432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
170641502Swpaul		break;
1707128118Sru	case SIOCSIFCAP:
1708128118Sru		ifp->if_capenable = ifr->ifr_reqcap;
1709128118Sru		break;
171041502Swpaul	default:
1711106936Ssam		error = ether_ioctl(ifp, command, data);
171241502Swpaul		break;
171341502Swpaul	}
171441502Swpaul
171567087Swpaul	VR_UNLOCK(sc);
171641502Swpaul
171741502Swpaul	return(error);
171841502Swpaul}
171941502Swpaul
1720102336Salfredstatic void
1721102336Salfredvr_watchdog(ifp)
172241502Swpaul	struct ifnet		*ifp;
172341502Swpaul{
172441502Swpaul	struct vr_softc		*sc;
172541502Swpaul
172641502Swpaul	sc = ifp->if_softc;
172741502Swpaul
172867087Swpaul	VR_LOCK(sc);
172941502Swpaul	ifp->if_oerrors++;
173041502Swpaul	printf("vr%d: watchdog timeout\n", sc->vr_unit);
173141502Swpaul
173241502Swpaul	vr_stop(sc);
173341502Swpaul	vr_reset(sc);
173441502Swpaul	vr_init(sc);
173541502Swpaul
173641502Swpaul	if (ifp->if_snd.ifq_head != NULL)
173741502Swpaul		vr_start(ifp);
173841502Swpaul
173967087Swpaul	VR_UNLOCK(sc);
174067087Swpaul
174141502Swpaul	return;
174241502Swpaul}
174341502Swpaul
174441502Swpaul/*
174541502Swpaul * Stop the adapter and free any mbufs allocated to the
174641502Swpaul * RX and TX lists.
174741502Swpaul */
1748102336Salfredstatic void
1749102336Salfredvr_stop(sc)
175041502Swpaul	struct vr_softc		*sc;
175141502Swpaul{
175241502Swpaul	register int		i;
175341502Swpaul	struct ifnet		*ifp;
175441502Swpaul
175567087Swpaul	VR_LOCK(sc);
175667087Swpaul
175741502Swpaul	ifp = &sc->arpcom.ac_if;
175841502Swpaul	ifp->if_timer = 0;
175941502Swpaul
176051432Swpaul	untimeout(vr_tick, sc, sc->vr_stat_ch);
1761127901Sru	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1762127901Sru#ifdef DEVICE_POLLING
1763127901Sru	ether_poll_deregister(ifp);
1764127901Sru#endif /* DEVICE_POLLING */
176551432Swpaul
176641502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
176741502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
176841502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
176941502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
177041502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
177141502Swpaul
177241502Swpaul	/*
177341502Swpaul	 * Free data in the RX lists.
177441502Swpaul	 */
177541502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
177641502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
177741502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
177841502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
177941502Swpaul		}
178041502Swpaul	}
178141502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
178241502Swpaul		sizeof(sc->vr_ldata->vr_rx_list));
178341502Swpaul
178441502Swpaul	/*
178541502Swpaul	 * Free the TX list buffers.
178641502Swpaul	 */
178741502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
178841502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
178941502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
179041502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
179141502Swpaul		}
179241502Swpaul	}
179341502Swpaul
179441502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
179541502Swpaul		sizeof(sc->vr_ldata->vr_tx_list));
179641502Swpaul
179767087Swpaul	VR_UNLOCK(sc);
179841502Swpaul
179941502Swpaul	return;
180041502Swpaul}
180141502Swpaul
180241502Swpaul/*
180341502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
180441502Swpaul * get confused by errant DMAs when rebooting.
180541502Swpaul */
1806102336Salfredstatic void
1807102336Salfredvr_shutdown(dev)
180849610Swpaul	device_t		dev;
180941502Swpaul{
181049610Swpaul	struct vr_softc		*sc;
181141502Swpaul
181249610Swpaul	sc = device_get_softc(dev);
181349610Swpaul
181441502Swpaul	vr_stop(sc);
181541502Swpaul
181641502Swpaul	return;
181741502Swpaul}
1818