if_vr.c revision 110170
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 *
3250477Speter * $FreeBSD: head/sys/dev/vr/if_vr.c 110170 2003-02-01 01:27:05Z silby $
3341502Swpaul */
3441502Swpaul
3541502Swpaul/*
3641502Swpaul * VIA Rhine fast ethernet PCI NIC driver
3741502Swpaul *
3841502Swpaul * Supports various network adapters based on the VIA Rhine
3941502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX.
4041502Swpaul * Datasheets are available at http://www.via.com.tw.
4141502Swpaul *
4241502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4341502Swpaul * Electrical Engineering Department
4441502Swpaul * Columbia University, New York City
4541502Swpaul */
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>
6841502Swpaul#include <sys/socket.h>
6941502Swpaul
7041502Swpaul#include <net/if.h>
7141502Swpaul#include <net/if_arp.h>
7241502Swpaul#include <net/ethernet.h>
7341502Swpaul#include <net/if_dl.h>
7441502Swpaul#include <net/if_media.h>
7541502Swpaul
7641502Swpaul#include <net/bpf.h>
7741502Swpaul
7841502Swpaul#include <vm/vm.h>              /* for vtophys */
7941502Swpaul#include <vm/pmap.h>            /* for vtophys */
8041502Swpaul#include <machine/bus_pio.h>
8141502Swpaul#include <machine/bus_memio.h>
8241502Swpaul#include <machine/bus.h>
8349610Swpaul#include <machine/resource.h>
8449610Swpaul#include <sys/bus.h>
8549610Swpaul#include <sys/rman.h>
8641502Swpaul
8751432Swpaul#include <dev/mii/mii.h>
8851432Swpaul#include <dev/mii/miivar.h>
8951432Swpaul
9041502Swpaul#include <pci/pcireg.h>
9141502Swpaul#include <pci/pcivar.h>
9241502Swpaul
9341502Swpaul#define VR_USEIOSPACE
9441502Swpaul
9541502Swpaul#include <pci/if_vrreg.h>
9641502Swpaul
9759758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1);
9859758Speter
9951432Swpaul/* "controller miibus0" required.  See GENERIC if you get errors here. */
10051432Swpaul#include "miibus_if.h"
10151432Swpaul
10241502Swpaul#ifndef lint
10341591Sarchiestatic const char rcsid[] =
10450477Speter  "$FreeBSD: head/sys/dev/vr/if_vr.c 110170 2003-02-01 01:27:05Z silby $";
10541502Swpaul#endif
10641502Swpaul
107110168Ssilby#undef VR_USESWSHIFT
108110168Ssilby
10941502Swpaul/*
11041502Swpaul * Various supported device vendors/types and their names.
11141502Swpaul */
11241502Swpaulstatic struct vr_type vr_devs[] = {
11341502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE,
11441502Swpaul		"VIA VT3043 Rhine I 10/100BaseTX" },
11541502Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II,
11641502Swpaul		"VIA VT86C100A Rhine II 10/100BaseTX" },
11762653Swpaul	{ VIA_VENDORID, VIA_DEVICEID_RHINE_II_2,
11862653Swpaul		"VIA VT6102 Rhine II 10/100BaseTX" },
119110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III,
120110170Ssilby		"VIA VT6105 Rhine III 10/100BaseTX" },
121110170Ssilby	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
122110170Ssilby		"VIA VT6105M Rhine III 10/100BaseTX" },
12344238Swpaul	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
12444238Swpaul		"Delta Electronics Rhine II 10/100BaseTX" },
12544238Swpaul	{ ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II,
12644238Swpaul		"Addtron Technology Rhine II 10/100BaseTX" },
12741502Swpaul	{ 0, 0, NULL }
12841502Swpaul};
12941502Swpaul
13092739Salfredstatic int vr_probe		(device_t);
13192739Salfredstatic int vr_attach		(device_t);
13292739Salfredstatic int vr_detach		(device_t);
13341502Swpaul
13492739Salfredstatic int vr_newbuf		(struct vr_softc *,
13549610Swpaul					struct vr_chain_onefrag *,
13692739Salfred					struct mbuf *);
13792739Salfredstatic int vr_encap		(struct vr_softc *, struct vr_chain *,
13892739Salfred						struct mbuf * );
13941502Swpaul
14092739Salfredstatic void vr_rxeof		(struct vr_softc *);
14192739Salfredstatic void vr_rxeoc		(struct vr_softc *);
14292739Salfredstatic void vr_txeof		(struct vr_softc *);
14392739Salfredstatic void vr_txeoc		(struct vr_softc *);
14492739Salfredstatic void vr_tick		(void *);
14592739Salfredstatic void vr_intr		(void *);
14692739Salfredstatic void vr_start		(struct ifnet *);
14792739Salfredstatic int vr_ioctl		(struct ifnet *, u_long, caddr_t);
14892739Salfredstatic void vr_init		(void *);
14992739Salfredstatic void vr_stop		(struct vr_softc *);
15092739Salfredstatic void vr_watchdog		(struct ifnet *);
15192739Salfredstatic void vr_shutdown		(device_t);
15292739Salfredstatic int vr_ifmedia_upd	(struct ifnet *);
15392739Salfredstatic void vr_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
15441502Swpaul
155110168Ssilby#ifdef VR_USESWSHIFT
15692739Salfredstatic void vr_mii_sync		(struct vr_softc *);
15792739Salfredstatic void vr_mii_send		(struct vr_softc *, u_int32_t, int);
158110168Ssilby#endif
15992739Salfredstatic int vr_mii_readreg	(struct vr_softc *, struct vr_mii_frame *);
16092739Salfredstatic int vr_mii_writereg	(struct vr_softc *, struct vr_mii_frame *);
16192739Salfredstatic int vr_miibus_readreg	(device_t, int, int);
16292739Salfredstatic int vr_miibus_writereg	(device_t, int, int, int);
16392739Salfredstatic void vr_miibus_statchg	(device_t);
16441502Swpaul
16592739Salfredstatic void vr_setcfg		(struct vr_softc *, int);
16692739Salfredstatic u_int8_t vr_calchash	(u_int8_t *);
16792739Salfredstatic void vr_setmulti		(struct vr_softc *);
16892739Salfredstatic void vr_reset		(struct vr_softc *);
16992739Salfredstatic int vr_list_rx_init	(struct vr_softc *);
17092739Salfredstatic int vr_list_tx_init	(struct vr_softc *);
17141502Swpaul
17249610Swpaul#ifdef VR_USEIOSPACE
17349610Swpaul#define VR_RES			SYS_RES_IOPORT
17449610Swpaul#define VR_RID			VR_PCI_LOIO
17549610Swpaul#else
17649610Swpaul#define VR_RES			SYS_RES_MEMORY
17749610Swpaul#define VR_RID			VR_PCI_LOMEM
17849610Swpaul#endif
17949610Swpaul
18049610Swpaulstatic device_method_t vr_methods[] = {
18149610Swpaul	/* Device interface */
18249610Swpaul	DEVMETHOD(device_probe,		vr_probe),
18349610Swpaul	DEVMETHOD(device_attach,	vr_attach),
18449610Swpaul	DEVMETHOD(device_detach, 	vr_detach),
18549610Swpaul	DEVMETHOD(device_shutdown,	vr_shutdown),
18651432Swpaul
18751432Swpaul	/* bus interface */
18851432Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18951432Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
19051432Swpaul
19151432Swpaul	/* MII interface */
19251432Swpaul	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
19351432Swpaul	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
19451432Swpaul	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
19551432Swpaul
19649610Swpaul	{ 0, 0 }
19749610Swpaul};
19849610Swpaul
19949610Swpaulstatic driver_t vr_driver = {
20051455Swpaul	"vr",
20149610Swpaul	vr_methods,
20249610Swpaul	sizeof(struct vr_softc)
20349610Swpaul};
20449610Swpaul
20549610Swpaulstatic devclass_t vr_devclass;
20649610Swpaul
20751533SwpaulDRIVER_MODULE(if_vr, pci, vr_driver, vr_devclass, 0, 0);
20851473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
20949610Swpaul
21041502Swpaul#define VR_SETBIT(sc, reg, x)				\
21141502Swpaul	CSR_WRITE_1(sc, reg,				\
212105221Sphk		CSR_READ_1(sc, reg) | (x))
21341502Swpaul
21441502Swpaul#define VR_CLRBIT(sc, reg, x)				\
21541502Swpaul	CSR_WRITE_1(sc, reg,				\
216105221Sphk		CSR_READ_1(sc, reg) & ~(x))
21741502Swpaul
21841502Swpaul#define VR_SETBIT16(sc, reg, x)				\
21941502Swpaul	CSR_WRITE_2(sc, reg,				\
220105221Sphk		CSR_READ_2(sc, reg) | (x))
22141502Swpaul
22241502Swpaul#define VR_CLRBIT16(sc, reg, x)				\
22341502Swpaul	CSR_WRITE_2(sc, reg,				\
224105221Sphk		CSR_READ_2(sc, reg) & ~(x))
22541502Swpaul
22641502Swpaul#define VR_SETBIT32(sc, reg, x)				\
22741502Swpaul	CSR_WRITE_4(sc, reg,				\
228105221Sphk		CSR_READ_4(sc, reg) | (x))
22941502Swpaul
23041502Swpaul#define VR_CLRBIT32(sc, reg, x)				\
23141502Swpaul	CSR_WRITE_4(sc, reg,				\
232105221Sphk		CSR_READ_4(sc, reg) & ~(x))
23341502Swpaul
23441502Swpaul#define SIO_SET(x)					\
23541502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
236105221Sphk		CSR_READ_1(sc, VR_MIICMD) | (x))
23741502Swpaul
23841502Swpaul#define SIO_CLR(x)					\
23941502Swpaul	CSR_WRITE_1(sc, VR_MIICMD,			\
240105221Sphk		CSR_READ_1(sc, VR_MIICMD) & ~(x))
24141502Swpaul
242110168Ssilby#ifdef VR_USESWSHIFT
24341502Swpaul/*
24441502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
24541502Swpaul */
246102336Salfredstatic void
247102336Salfredvr_mii_sync(sc)
24841502Swpaul	struct vr_softc		*sc;
24941502Swpaul{
25041502Swpaul	register int		i;
25141502Swpaul
25241502Swpaul	SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN);
25341502Swpaul
25441502Swpaul	for (i = 0; i < 32; i++) {
25541502Swpaul		SIO_SET(VR_MIICMD_CLK);
25641502Swpaul		DELAY(1);
25741502Swpaul		SIO_CLR(VR_MIICMD_CLK);
25841502Swpaul		DELAY(1);
25941502Swpaul	}
26041502Swpaul
26141502Swpaul	return;
26241502Swpaul}
26341502Swpaul
26441502Swpaul/*
26541502Swpaul * Clock a series of bits through the MII.
26641502Swpaul */
267102336Salfredstatic void
268102336Salfredvr_mii_send(sc, bits, cnt)
26941502Swpaul	struct vr_softc		*sc;
27041502Swpaul	u_int32_t		bits;
27141502Swpaul	int			cnt;
27241502Swpaul{
27341502Swpaul	int			i;
27441502Swpaul
27541502Swpaul	SIO_CLR(VR_MIICMD_CLK);
27641502Swpaul
27741502Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
27841502Swpaul                if (bits & i) {
27941502Swpaul			SIO_SET(VR_MIICMD_DATAIN);
28041502Swpaul                } else {
28141502Swpaul			SIO_CLR(VR_MIICMD_DATAIN);
28241502Swpaul                }
28341502Swpaul		DELAY(1);
28441502Swpaul		SIO_CLR(VR_MIICMD_CLK);
28541502Swpaul		DELAY(1);
28641502Swpaul		SIO_SET(VR_MIICMD_CLK);
28741502Swpaul	}
28841502Swpaul}
289110168Ssilby#endif
29041502Swpaul
29141502Swpaul/*
29241502Swpaul * Read an PHY register through the MII.
29341502Swpaul */
294102336Salfredstatic int
295102336Salfredvr_mii_readreg(sc, frame)
29641502Swpaul	struct vr_softc		*sc;
29741502Swpaul	struct vr_mii_frame	*frame;
29841502Swpaul
299110168Ssilby#ifdef VR_USESWSHIFT
30041502Swpaul{
30167087Swpaul	int			i, ack;
30241502Swpaul
30367087Swpaul	VR_LOCK(sc);
30441502Swpaul
30541502Swpaul	/*
30641502Swpaul	 * Set up frame for RX.
30741502Swpaul	 */
30841502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
30941502Swpaul	frame->mii_opcode = VR_MII_READOP;
31041502Swpaul	frame->mii_turnaround = 0;
31141502Swpaul	frame->mii_data = 0;
31241502Swpaul
31341502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
31441502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
31541502Swpaul
31641502Swpaul	/*
31741502Swpaul 	 * Turn on data xmit.
31841502Swpaul	 */
31941502Swpaul	SIO_SET(VR_MIICMD_DIR);
32041502Swpaul
32141502Swpaul	vr_mii_sync(sc);
32241502Swpaul
32341502Swpaul	/*
32441502Swpaul	 * Send command/address info.
32541502Swpaul	 */
32641502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
32741502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
32841502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
32941502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
33041502Swpaul
33141502Swpaul	/* Idle bit */
33241502Swpaul	SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN));
33341502Swpaul	DELAY(1);
33441502Swpaul	SIO_SET(VR_MIICMD_CLK);
33541502Swpaul	DELAY(1);
33641502Swpaul
33741502Swpaul	/* Turn off xmit. */
33841502Swpaul	SIO_CLR(VR_MIICMD_DIR);
33941502Swpaul
34041502Swpaul	/* Check for ack */
34141502Swpaul	SIO_CLR(VR_MIICMD_CLK);
34241502Swpaul	DELAY(1);
343109058Smbr	ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT;
34441502Swpaul	SIO_SET(VR_MIICMD_CLK);
34541502Swpaul	DELAY(1);
34641502Swpaul
34741502Swpaul	/*
34841502Swpaul	 * Now try reading data bits. If the ack failed, we still
34941502Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
35041502Swpaul	 */
35141502Swpaul	if (ack) {
35241502Swpaul		for(i = 0; i < 16; i++) {
35341502Swpaul			SIO_CLR(VR_MIICMD_CLK);
35441502Swpaul			DELAY(1);
35541502Swpaul			SIO_SET(VR_MIICMD_CLK);
35641502Swpaul			DELAY(1);
35741502Swpaul		}
35841502Swpaul		goto fail;
35941502Swpaul	}
36041502Swpaul
36141502Swpaul	for (i = 0x8000; i; i >>= 1) {
36241502Swpaul		SIO_CLR(VR_MIICMD_CLK);
36341502Swpaul		DELAY(1);
36441502Swpaul		if (!ack) {
36541502Swpaul			if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT)
36641502Swpaul				frame->mii_data |= i;
36741502Swpaul			DELAY(1);
36841502Swpaul		}
36941502Swpaul		SIO_SET(VR_MIICMD_CLK);
37041502Swpaul		DELAY(1);
37141502Swpaul	}
37241502Swpaul
37341502Swpaulfail:
37441502Swpaul
37541502Swpaul	SIO_CLR(VR_MIICMD_CLK);
37641502Swpaul	DELAY(1);
37741502Swpaul	SIO_SET(VR_MIICMD_CLK);
37841502Swpaul	DELAY(1);
37941502Swpaul
38067087Swpaul	VR_UNLOCK(sc);
38141502Swpaul
38241502Swpaul	if (ack)
38341502Swpaul		return(1);
38441502Swpaul	return(0);
38541502Swpaul}
386110168Ssilby#else
387110168Ssilby{
388110168Ssilby	int			s, i;
38941502Swpaul
390110168Ssilby	s = splimp();
391110168Ssilby
392110168Ssilby  	/* Set the PHY-adress */
393110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
394110168Ssilby	    frame->mii_phyaddr);
395110168Ssilby
396110168Ssilby  	/* Set the register-adress */
397110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
398110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
399110168Ssilby
400110168Ssilby	for (i = 0; i < 10000; i++) {
401110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
402110168Ssilby			break;
403110168Ssilby		DELAY(1);
404110168Ssilby	}
405110168Ssilby
406110168Ssilby	frame->mii_data = CSR_READ_2(sc, VR_MIIDATA);
407110168Ssilby
408110168Ssilby	(void)splx(s);
409110168Ssilby
410110168Ssilby	return(0);
411110168Ssilby}
412110168Ssilby#endif
413110168Ssilby
414110168Ssilby
41541502Swpaul/*
41641502Swpaul * Write to a PHY register through the MII.
41741502Swpaul */
418102336Salfredstatic int
419102336Salfredvr_mii_writereg(sc, frame)
42041502Swpaul	struct vr_softc		*sc;
42141502Swpaul	struct vr_mii_frame	*frame;
42241502Swpaul
423110168Ssilby#ifdef VR_USESWSHIFT
42441502Swpaul{
42567087Swpaul	VR_LOCK(sc);
42641502Swpaul
42741502Swpaul	CSR_WRITE_1(sc, VR_MIICMD, 0);
42841502Swpaul	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM);
42941502Swpaul
43041502Swpaul	/*
43141502Swpaul	 * Set up frame for TX.
43241502Swpaul	 */
43341502Swpaul
43441502Swpaul	frame->mii_stdelim = VR_MII_STARTDELIM;
43541502Swpaul	frame->mii_opcode = VR_MII_WRITEOP;
43641502Swpaul	frame->mii_turnaround = VR_MII_TURNAROUND;
43741502Swpaul
43841502Swpaul	/*
43941502Swpaul 	 * Turn on data output.
44041502Swpaul	 */
44141502Swpaul	SIO_SET(VR_MIICMD_DIR);
44241502Swpaul
44341502Swpaul	vr_mii_sync(sc);
44441502Swpaul
44541502Swpaul	vr_mii_send(sc, frame->mii_stdelim, 2);
44641502Swpaul	vr_mii_send(sc, frame->mii_opcode, 2);
44741502Swpaul	vr_mii_send(sc, frame->mii_phyaddr, 5);
44841502Swpaul	vr_mii_send(sc, frame->mii_regaddr, 5);
44941502Swpaul	vr_mii_send(sc, frame->mii_turnaround, 2);
45041502Swpaul	vr_mii_send(sc, frame->mii_data, 16);
45141502Swpaul
45241502Swpaul	/* Idle bit. */
45341502Swpaul	SIO_SET(VR_MIICMD_CLK);
45441502Swpaul	DELAY(1);
45541502Swpaul	SIO_CLR(VR_MIICMD_CLK);
45641502Swpaul	DELAY(1);
45741502Swpaul
45841502Swpaul	/*
45941502Swpaul	 * Turn off xmit.
46041502Swpaul	 */
46141502Swpaul	SIO_CLR(VR_MIICMD_DIR);
46241502Swpaul
46367087Swpaul	VR_UNLOCK(sc);
46441502Swpaul
46541502Swpaul	return(0);
46641502Swpaul}
467110168Ssilby#else
468110168Ssilby{
469110168Ssilby	int			s, i;
47041502Swpaul
471110168Ssilby	s = splimp();
472110168Ssilby
473110168Ssilby  	/* Set the PHY-adress */
474110168Ssilby	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
475110168Ssilby		    frame->mii_phyaddr);
476110168Ssilby
477110168Ssilby  	/* Set the register-adress and data to write */
478110168Ssilby	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
479110168Ssilby	CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data);
480110168Ssilby
481110168Ssilby	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
482110168Ssilby
483110168Ssilby	for (i = 0; i < 10000; i++) {
484110168Ssilby		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
485110168Ssilby			break;
486110168Ssilby		DELAY(1);
487110168Ssilby	}
488110168Ssilby
489110168Ssilby	(void)splx(s);
490110168Ssilby
491110168Ssilby	return(0);
492110168Ssilby}
493110168Ssilby#endif
494110168Ssilby
495102336Salfredstatic int
496102336Salfredvr_miibus_readreg(dev, phy, reg)
49751432Swpaul	device_t		dev;
49851432Swpaul	int			phy, reg;
49951432Swpaul{
50041502Swpaul	struct vr_softc		*sc;
50141502Swpaul	struct vr_mii_frame	frame;
50241502Swpaul
50351432Swpaul	sc = device_get_softc(dev);
504110168Ssilby
505110168Ssilby	switch (sc->vr_revid) {
506110168Ssilby		case REV_ID_VT6102_APOLLO:
507110168Ssilby			if (phy != 1)
508110168Ssilby				return 0;
509110168Ssilby		default:
510110168Ssilby			break;
511110168Ssilby		}
512110168Ssilby
51341502Swpaul	bzero((char *)&frame, sizeof(frame));
51441502Swpaul
51551432Swpaul	frame.mii_phyaddr = phy;
51641502Swpaul	frame.mii_regaddr = reg;
51741502Swpaul	vr_mii_readreg(sc, &frame);
51841502Swpaul
51941502Swpaul	return(frame.mii_data);
52041502Swpaul}
52141502Swpaul
522102336Salfredstatic int
523102336Salfredvr_miibus_writereg(dev, phy, reg, data)
52451432Swpaul	device_t		dev;
52551432Swpaul	u_int16_t		phy, reg, data;
52651432Swpaul{
52741502Swpaul	struct vr_softc		*sc;
52841502Swpaul	struct vr_mii_frame	frame;
52941502Swpaul
53051432Swpaul	sc = device_get_softc(dev);
531110168Ssilby
532110168Ssilby	switch (sc->vr_revid) {
533110168Ssilby		case REV_ID_VT6102_APOLLO:
534110168Ssilby			if (phy != 1)
535110168Ssilby				return 0;
536110168Ssilby		default:
537110168Ssilby			break;
538110168Ssilby		}
539110168Ssilby
54041502Swpaul	bzero((char *)&frame, sizeof(frame));
54141502Swpaul
54251432Swpaul	frame.mii_phyaddr = phy;
54341502Swpaul	frame.mii_regaddr = reg;
54441502Swpaul	frame.mii_data = data;
54541502Swpaul
54641502Swpaul	vr_mii_writereg(sc, &frame);
54741502Swpaul
54851432Swpaul	return(0);
54951432Swpaul}
55051432Swpaul
551102336Salfredstatic void
552102336Salfredvr_miibus_statchg(dev)
55351432Swpaul	device_t		dev;
55451432Swpaul{
55551432Swpaul	struct vr_softc		*sc;
55651432Swpaul	struct mii_data		*mii;
55751432Swpaul
55851432Swpaul	sc = device_get_softc(dev);
55967087Swpaul	VR_LOCK(sc);
56051432Swpaul	mii = device_get_softc(sc->vr_miibus);
56151432Swpaul	vr_setcfg(sc, mii->mii_media_active);
56267087Swpaul	VR_UNLOCK(sc);
56351432Swpaul
56441502Swpaul	return;
56541502Swpaul}
56641502Swpaul
56741502Swpaul/*
56841502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits.
56941502Swpaul */
57041502Swpaulstatic u_int8_t vr_calchash(addr)
57141502Swpaul	u_int8_t		*addr;
57241502Swpaul{
57341502Swpaul	u_int32_t		crc, carry;
57441502Swpaul	int			i, j;
57541502Swpaul	u_int8_t		c;
57641502Swpaul
57741502Swpaul	/* Compute CRC for the address value. */
57841502Swpaul	crc = 0xFFFFFFFF; /* initial value */
57941502Swpaul
58041502Swpaul	for (i = 0; i < 6; i++) {
58141502Swpaul		c = *(addr + i);
58241502Swpaul		for (j = 0; j < 8; j++) {
58341502Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
58441502Swpaul			crc <<= 1;
58541502Swpaul			c >>= 1;
58641502Swpaul			if (carry)
58741502Swpaul				crc = (crc ^ 0x04c11db6) | carry;
58841502Swpaul		}
58941502Swpaul	}
59041502Swpaul
59141502Swpaul	/* return the filter bit position */
59241502Swpaul	return((crc >> 26) & 0x0000003F);
59341502Swpaul}
59441502Swpaul
59541502Swpaul/*
59641502Swpaul * Program the 64-bit multicast hash filter.
59741502Swpaul */
598102336Salfredstatic void
599102336Salfredvr_setmulti(sc)
60041502Swpaul	struct vr_softc		*sc;
60141502Swpaul{
60241502Swpaul	struct ifnet		*ifp;
60341502Swpaul	int			h = 0;
60441502Swpaul	u_int32_t		hashes[2] = { 0, 0 };
60541502Swpaul	struct ifmultiaddr	*ifma;
60641502Swpaul	u_int8_t		rxfilt;
60741502Swpaul	int			mcnt = 0;
60841502Swpaul
60941502Swpaul	ifp = &sc->arpcom.ac_if;
61041502Swpaul
61141502Swpaul	rxfilt = CSR_READ_1(sc, VR_RXCFG);
61241502Swpaul
61341502Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
61441502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
61541502Swpaul		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
61641502Swpaul		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
61741502Swpaul		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
61841502Swpaul		return;
61941502Swpaul	}
62041502Swpaul
62141502Swpaul	/* first, zot all the existing hash bits */
62241502Swpaul	CSR_WRITE_4(sc, VR_MAR0, 0);
62341502Swpaul	CSR_WRITE_4(sc, VR_MAR1, 0);
62441502Swpaul
62541502Swpaul	/* now program new ones */
62672084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
62741502Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
62841502Swpaul			continue;
62941502Swpaul		h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
63041502Swpaul		if (h < 32)
63141502Swpaul			hashes[0] |= (1 << h);
63241502Swpaul		else
63341502Swpaul			hashes[1] |= (1 << (h - 32));
63441502Swpaul		mcnt++;
63541502Swpaul	}
63641502Swpaul
63741502Swpaul	if (mcnt)
63841502Swpaul		rxfilt |= VR_RXCFG_RX_MULTI;
63941502Swpaul	else
64041502Swpaul		rxfilt &= ~VR_RXCFG_RX_MULTI;
64141502Swpaul
64241502Swpaul	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
64341502Swpaul	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
64441502Swpaul	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
64541502Swpaul
64641502Swpaul	return;
64741502Swpaul}
64841502Swpaul
64941502Swpaul/*
65041502Swpaul * In order to fiddle with the
65141502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we
65241502Swpaul * first have to put the transmit and/or receive logic in the idle state.
65341502Swpaul */
654102336Salfredstatic void
655102336Salfredvr_setcfg(sc, media)
65641502Swpaul	struct vr_softc		*sc;
65751432Swpaul	int			media;
65841502Swpaul{
65941502Swpaul	int			restart = 0;
66041502Swpaul
66141502Swpaul	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
66241502Swpaul		restart = 1;
66341502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
66441502Swpaul	}
66541502Swpaul
66651432Swpaul	if ((media & IFM_GMASK) == IFM_FDX)
66741502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
66841502Swpaul	else
66941502Swpaul		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
67041502Swpaul
67141502Swpaul	if (restart)
67241502Swpaul		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
67341502Swpaul
67441502Swpaul	return;
67541502Swpaul}
67641502Swpaul
677102336Salfredstatic void
678102336Salfredvr_reset(sc)
67941502Swpaul	struct vr_softc		*sc;
68041502Swpaul{
68141502Swpaul	register int		i;
68241502Swpaul
68341502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
68441502Swpaul
68541502Swpaul	for (i = 0; i < VR_TIMEOUT; i++) {
68641502Swpaul		DELAY(10);
68741502Swpaul		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
68841502Swpaul			break;
68941502Swpaul	}
690107220Ssilby	if (i == VR_TIMEOUT) {
691107220Ssilby		if (sc->vr_revid < REV_ID_VT3065_A)
692107220Ssilby			printf("vr%d: reset never completed!\n", sc->vr_unit);
693107220Ssilby		else {
694107220Ssilby			/* Use newer force reset command */
695107220Ssilby			printf("vr%d: Using force reset command.\n", sc->vr_unit);
696107220Ssilby			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
697107220Ssilby		}
698107220Ssilby	}
69941502Swpaul
70041502Swpaul	/* Wait a little while for the chip to get its brains in order. */
70141502Swpaul	DELAY(1000);
70241502Swpaul
70341502Swpaul        return;
70441502Swpaul}
70541502Swpaul
70641502Swpaul/*
70741502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device
70841502Swpaul * IDs against our list and return a device name if we find a match.
70941502Swpaul */
710102336Salfredstatic int
711102336Salfredvr_probe(dev)
71249610Swpaul	device_t		dev;
71341502Swpaul{
71441502Swpaul	struct vr_type		*t;
71541502Swpaul
71641502Swpaul	t = vr_devs;
71741502Swpaul
71841502Swpaul	while(t->vr_name != NULL) {
71949610Swpaul		if ((pci_get_vendor(dev) == t->vr_vid) &&
72049610Swpaul		    (pci_get_device(dev) == t->vr_did)) {
72149610Swpaul			device_set_desc(dev, t->vr_name);
72249610Swpaul			return(0);
72341502Swpaul		}
72441502Swpaul		t++;
72541502Swpaul	}
72641502Swpaul
72749610Swpaul	return(ENXIO);
72841502Swpaul}
72941502Swpaul
73041502Swpaul/*
73141502Swpaul * Attach the interface. Allocate softc structures, do ifmedia
73241502Swpaul * setup and ethernet/BPF attach.
73341502Swpaul */
734102336Salfredstatic int
735102336Salfredvr_attach(dev)
73649610Swpaul	device_t		dev;
73741502Swpaul{
73867087Swpaul	int			i;
73941502Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
74041502Swpaul	u_int32_t		command;
74141502Swpaul	struct vr_softc		*sc;
74241502Swpaul	struct ifnet		*ifp;
74349610Swpaul	int			unit, error = 0, rid;
74441502Swpaul
74549610Swpaul	sc = device_get_softc(dev);
74649610Swpaul	unit = device_get_unit(dev);
74749610Swpaul	bzero(sc, sizeof(struct vr_softc *));
74841502Swpaul
74993818Sjhb	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
75093818Sjhb	    MTX_DEF | MTX_RECURSE);
75169583Swpaul	VR_LOCK(sc);
75269583Swpaul
75341502Swpaul	/*
75441502Swpaul	 * Handle power management nonsense.
75541502Swpaul	 */
75672813Swpaul	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
75772813Swpaul		u_int32_t		iobase, membase, irq;
75841502Swpaul
75972813Swpaul		/* Save important PCI config data. */
76072813Swpaul		iobase = pci_read_config(dev, VR_PCI_LOIO, 4);
76172813Swpaul		membase = pci_read_config(dev, VR_PCI_LOMEM, 4);
76272813Swpaul		irq = pci_read_config(dev, VR_PCI_INTLINE, 4);
76341502Swpaul
76472813Swpaul		/* Reset the power state. */
76572813Swpaul		printf("vr%d: chip is in D%d power mode "
76672813Swpaul		    "-- setting to D0\n", unit,
76772813Swpaul		    pci_get_powerstate(dev));
76872813Swpaul		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
76941502Swpaul
77041502Swpaul			/* Restore PCI config data. */
77172813Swpaul		pci_write_config(dev, VR_PCI_LOIO, iobase, 4);
77272813Swpaul		pci_write_config(dev, VR_PCI_LOMEM, membase, 4);
77372813Swpaul		pci_write_config(dev, VR_PCI_INTLINE, irq, 4);
77441502Swpaul	}
77541502Swpaul
77641502Swpaul	/*
77741502Swpaul	 * Map control/status registers.
77841502Swpaul	 */
77972813Swpaul	pci_enable_busmaster(dev);
78079472Swpaul	pci_enable_io(dev, SYS_RES_IOPORT);
78179472Swpaul	pci_enable_io(dev, SYS_RES_MEMORY);
78261041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
783107220Ssilby	sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF;
78441502Swpaul
78541502Swpaul#ifdef VR_USEIOSPACE
78641502Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
78741502Swpaul		printf("vr%d: failed to enable I/O ports!\n", unit);
78841502Swpaul		free(sc, M_DEVBUF);
78941502Swpaul		goto fail;
79041502Swpaul	}
79141502Swpaul#else
79241502Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
79341502Swpaul		printf("vr%d: failed to enable memory mapping!\n", unit);
79441502Swpaul		goto fail;
79541502Swpaul	}
79649610Swpaul#endif
79741502Swpaul
79849610Swpaul	rid = VR_RID;
79949610Swpaul	sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid,
80049610Swpaul	    0, ~0, 1, RF_ACTIVE);
80149610Swpaul
80249610Swpaul	if (sc->vr_res == NULL) {
80349610Swpaul		printf("vr%d: couldn't map ports/memory\n", unit);
80449610Swpaul		error = ENXIO;
80541502Swpaul		goto fail;
80641502Swpaul	}
80741502Swpaul
80849610Swpaul	sc->vr_btag = rman_get_bustag(sc->vr_res);
80949610Swpaul	sc->vr_bhandle = rman_get_bushandle(sc->vr_res);
81041502Swpaul
81141502Swpaul	/* Allocate interrupt */
81249610Swpaul	rid = 0;
81349610Swpaul	sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
81449610Swpaul	    RF_SHAREABLE | RF_ACTIVE);
81549610Swpaul
81649610Swpaul	if (sc->vr_irq == NULL) {
81741502Swpaul		printf("vr%d: couldn't map interrupt\n", unit);
81849610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
81949610Swpaul		error = ENXIO;
82041502Swpaul		goto fail;
82141502Swpaul	}
82241502Swpaul
82349610Swpaul	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET,
82449610Swpaul	    vr_intr, sc, &sc->vr_intrhand);
82549610Swpaul
82649610Swpaul	if (error) {
82749610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
82849610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
82949610Swpaul		printf("vr%d: couldn't set up irq\n", unit);
83049610Swpaul		goto fail;
83149610Swpaul	}
83249610Swpaul
83376586Swpaul	/*
83476586Swpaul	 * Windows may put the chip in suspend mode when it
83576586Swpaul	 * shuts down. Be sure to kick it in the head to wake it
83676586Swpaul	 * up again.
83776586Swpaul	 */
83876586Swpaul	VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1));
83976586Swpaul
84041502Swpaul	/* Reset the adapter. */
84141502Swpaul	vr_reset(sc);
84241502Swpaul
843110168Ssilby        /*
844110168Ssilby	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
845110168Ssilby	 * initialization and disable AUTOPOLL.
846110168Ssilby	 */
847110168Ssilby        pci_write_config(dev, VR_PCI_MODE,
848110168Ssilby	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
849110168Ssilby	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
850110168Ssilby
85141502Swpaul	/*
85241502Swpaul	 * Get station address. The way the Rhine chips work,
85341502Swpaul	 * you're not allowed to directly access the EEPROM once
85441502Swpaul	 * they've been programmed a special way. Consequently,
85541502Swpaul	 * we need to read the node address from the PAR0 and PAR1
85641502Swpaul	 * registers.
85741502Swpaul	 */
85841502Swpaul	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
85941502Swpaul	DELAY(200);
86041502Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
86141502Swpaul		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
86241502Swpaul
86341502Swpaul	/*
86441502Swpaul	 * A Rhine chip was detected. Inform the world.
86541502Swpaul	 */
86641502Swpaul	printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":");
86741502Swpaul
86841502Swpaul	sc->vr_unit = unit;
86941502Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
87041502Swpaul
87151432Swpaul	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
87251657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
87351432Swpaul
87451432Swpaul	if (sc->vr_ldata == NULL) {
87541502Swpaul		printf("vr%d: no memory for list buffers!\n", unit);
87649610Swpaul		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
87749610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
87849610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
87949610Swpaul		error = ENXIO;
88049610Swpaul		goto fail;
88141502Swpaul	}
88241502Swpaul
88341502Swpaul	bzero(sc->vr_ldata, sizeof(struct vr_list_data));
88441502Swpaul
88541502Swpaul	ifp = &sc->arpcom.ac_if;
88641502Swpaul	ifp->if_softc = sc;
88741502Swpaul	ifp->if_unit = unit;
88841502Swpaul	ifp->if_name = "vr";
88941502Swpaul	ifp->if_mtu = ETHERMTU;
89041502Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
89141502Swpaul	ifp->if_ioctl = vr_ioctl;
89241502Swpaul	ifp->if_output = ether_output;
89341502Swpaul	ifp->if_start = vr_start;
89441502Swpaul	ifp->if_watchdog = vr_watchdog;
89541502Swpaul	ifp->if_init = vr_init;
89641502Swpaul	ifp->if_baudrate = 10000000;
89743515Swpaul	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
89841502Swpaul
89951432Swpaul	/*
90051432Swpaul	 * Do MII setup.
90151432Swpaul	 */
90251432Swpaul	if (mii_phy_probe(dev, &sc->vr_miibus,
90351432Swpaul	    vr_ifmedia_upd, vr_ifmedia_sts)) {
90441502Swpaul		printf("vr%d: MII without any phy!\n", sc->vr_unit);
90549610Swpaul		bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
90649610Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
90749610Swpaul		bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
90851432Swpaul		contigfree(sc->vr_ldata,
90951432Swpaul		    sizeof(struct vr_list_data), M_DEVBUF);
91049610Swpaul		error = ENXIO;
91141502Swpaul		goto fail;
91241502Swpaul	}
91341502Swpaul
91451432Swpaul	callout_handle_init(&sc->vr_stat_ch);
91541502Swpaul
91641502Swpaul	/*
91763090Sarchie	 * Call MI attach routine.
91841502Swpaul	 */
919106936Ssam	ether_ifattach(ifp, eaddr);
92067087Swpaul	VR_UNLOCK(sc);
92167087Swpaul	return(0);
92241502Swpaul
92341502Swpaulfail:
92467087Swpaul	VR_UNLOCK(sc);
92567087Swpaul	mtx_destroy(&sc->vr_mtx);
92667087Swpaul
92749610Swpaul	return(error);
92841502Swpaul}
92941502Swpaul
930102336Salfredstatic int
931102336Salfredvr_detach(dev)
93249610Swpaul	device_t		dev;
93349610Swpaul{
93449610Swpaul	struct vr_softc		*sc;
93549610Swpaul	struct ifnet		*ifp;
93649610Swpaul
93749610Swpaul	sc = device_get_softc(dev);
93867087Swpaul	VR_LOCK(sc);
93949610Swpaul	ifp = &sc->arpcom.ac_if;
94049610Swpaul
94149610Swpaul	vr_stop(sc);
942106936Ssam	ether_ifdetach(ifp);
94349610Swpaul
94451432Swpaul	bus_generic_detach(dev);
94551432Swpaul	device_delete_child(dev, sc->vr_miibus);
94651432Swpaul
94749610Swpaul	bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand);
94849610Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq);
94949610Swpaul	bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res);
95049610Swpaul
95151432Swpaul	contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
95249610Swpaul
95367087Swpaul	VR_UNLOCK(sc);
95467087Swpaul	mtx_destroy(&sc->vr_mtx);
95549610Swpaul
95649610Swpaul	return(0);
95749610Swpaul}
95849610Swpaul
95941502Swpaul/*
96041502Swpaul * Initialize the transmit descriptors.
96141502Swpaul */
962102336Salfredstatic int
963102336Salfredvr_list_tx_init(sc)
96441502Swpaul	struct vr_softc		*sc;
96541502Swpaul{
96641502Swpaul	struct vr_chain_data	*cd;
96741502Swpaul	struct vr_list_data	*ld;
96841502Swpaul	int			i;
96941502Swpaul
97041502Swpaul	cd = &sc->vr_cdata;
97141502Swpaul	ld = sc->vr_ldata;
97241502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
97341502Swpaul		cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i];
97441502Swpaul		if (i == (VR_TX_LIST_CNT - 1))
97541502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
97641502Swpaul				&cd->vr_tx_chain[0];
97741502Swpaul		else
97841502Swpaul			cd->vr_tx_chain[i].vr_nextdesc =
97941502Swpaul				&cd->vr_tx_chain[i + 1];
98041502Swpaul	}
98141502Swpaul
98241502Swpaul	cd->vr_tx_free = &cd->vr_tx_chain[0];
98341502Swpaul	cd->vr_tx_tail = cd->vr_tx_head = NULL;
98441502Swpaul
98541502Swpaul	return(0);
98641502Swpaul}
98741502Swpaul
98841502Swpaul
98941502Swpaul/*
99041502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
99141502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
99241502Swpaul * points back to the first.
99341502Swpaul */
994102336Salfredstatic int
995102336Salfredvr_list_rx_init(sc)
99641502Swpaul	struct vr_softc		*sc;
99741502Swpaul{
99841502Swpaul	struct vr_chain_data	*cd;
99941502Swpaul	struct vr_list_data	*ld;
100041502Swpaul	int			i;
100141502Swpaul
100241502Swpaul	cd = &sc->vr_cdata;
100341502Swpaul	ld = sc->vr_ldata;
100441502Swpaul
100541502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
100641502Swpaul		cd->vr_rx_chain[i].vr_ptr =
100741502Swpaul			(struct vr_desc *)&ld->vr_rx_list[i];
100849610Swpaul		if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS)
100941502Swpaul			return(ENOBUFS);
101041502Swpaul		if (i == (VR_RX_LIST_CNT - 1)) {
101141502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
101241502Swpaul					&cd->vr_rx_chain[0];
101341502Swpaul			ld->vr_rx_list[i].vr_next =
101441502Swpaul					vtophys(&ld->vr_rx_list[0]);
101541502Swpaul		} else {
101641502Swpaul			cd->vr_rx_chain[i].vr_nextdesc =
101741502Swpaul					&cd->vr_rx_chain[i + 1];
101841502Swpaul			ld->vr_rx_list[i].vr_next =
101941502Swpaul					vtophys(&ld->vr_rx_list[i + 1]);
102041502Swpaul		}
102141502Swpaul	}
102241502Swpaul
102341502Swpaul	cd->vr_rx_head = &cd->vr_rx_chain[0];
102441502Swpaul
102541502Swpaul	return(0);
102641502Swpaul}
102741502Swpaul
102841502Swpaul/*
102941502Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
103041502Swpaul * Note: the length fields are only 11 bits wide, which means the
103141502Swpaul * largest size we can specify is 2047. This is important because
103241502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll
103341502Swpaul * overflow the field and make a mess.
103441502Swpaul */
1035102336Salfredstatic int
1036102336Salfredvr_newbuf(sc, c, m)
103741502Swpaul	struct vr_softc		*sc;
103841502Swpaul	struct vr_chain_onefrag	*c;
103949610Swpaul	struct mbuf		*m;
104041502Swpaul{
104141502Swpaul	struct mbuf		*m_new = NULL;
104241502Swpaul
104349610Swpaul	if (m == NULL) {
1044109623Salfred		MGETHDR(m_new, M_NOWAIT, MT_DATA);
104587846Sluigi		if (m_new == NULL)
104649610Swpaul			return(ENOBUFS);
104741502Swpaul
1048109623Salfred		MCLGET(m_new, M_NOWAIT);
104949610Swpaul		if (!(m_new->m_flags & M_EXT)) {
105049610Swpaul			m_freem(m_new);
105149610Swpaul			return(ENOBUFS);
105249610Swpaul		}
105349610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
105449610Swpaul	} else {
105549610Swpaul		m_new = m;
105649610Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
105749610Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
105841502Swpaul	}
105941502Swpaul
106049610Swpaul	m_adj(m_new, sizeof(u_int64_t));
106149610Swpaul
106241502Swpaul	c->vr_mbuf = m_new;
106341502Swpaul	c->vr_ptr->vr_status = VR_RXSTAT;
106441502Swpaul	c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t));
106542491Swpaul	c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN;
106641502Swpaul
106741502Swpaul	return(0);
106841502Swpaul}
106941502Swpaul
107041502Swpaul/*
107141502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
107241502Swpaul * the higher level protocols.
107341502Swpaul */
1074102336Salfredstatic void
1075102336Salfredvr_rxeof(sc)
107641502Swpaul	struct vr_softc		*sc;
107741502Swpaul{
107841502Swpaul        struct mbuf		*m;
107941502Swpaul        struct ifnet		*ifp;
108041502Swpaul	struct vr_chain_onefrag	*cur_rx;
108141502Swpaul	int			total_len = 0;
108241502Swpaul	u_int32_t		rxstat;
108341502Swpaul
108441502Swpaul	ifp = &sc->arpcom.ac_if;
108541502Swpaul
108641502Swpaul	while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) &
108741502Swpaul							VR_RXSTAT_OWN)) {
108849610Swpaul		struct mbuf		*m0 = NULL;
108949610Swpaul
109041502Swpaul		cur_rx = sc->vr_cdata.vr_rx_head;
109141502Swpaul		sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc;
109249610Swpaul		m = cur_rx->vr_mbuf;
109341502Swpaul
109441502Swpaul		/*
109541502Swpaul		 * If an error occurs, update stats, clear the
109641502Swpaul		 * status word and leave the mbuf cluster in place:
109741502Swpaul		 * it should simply get re-used next time this descriptor
109841502Swpaul	 	 * comes up in the ring.
109941502Swpaul		 */
110041502Swpaul		if (rxstat & VR_RXSTAT_RXERR) {
110141502Swpaul			ifp->if_ierrors++;
1102110131Ssilby			printf("vr%d: rx error (%02x):",
1103110131Ssilby			       sc->vr_unit, rxstat & 0x000000ff);
1104110131Ssilby			if (rxstat & VR_RXSTAT_CRCERR)
1105110131Ssilby				printf(" crc error");
1106110131Ssilby			if (rxstat & VR_RXSTAT_FRAMEALIGNERR)
1107110131Ssilby				printf(" frame alignment error\n");
1108110131Ssilby			if (rxstat & VR_RXSTAT_FIFOOFLOW)
1109110131Ssilby				printf(" FIFO overflow");
1110110131Ssilby			if (rxstat & VR_RXSTAT_GIANT)
1111110131Ssilby				printf(" received giant packet");
1112110131Ssilby			if (rxstat & VR_RXSTAT_RUNT)
1113110131Ssilby				printf(" received runt packet");
1114110131Ssilby			if (rxstat & VR_RXSTAT_BUSERR)
1115110131Ssilby				printf(" system bus error");
1116110131Ssilby			if (rxstat & VR_RXSTAT_BUFFERR)
1117110131Ssilby				printf("rx buffer error");
1118110131Ssilby			printf("\n");
111949610Swpaul			vr_newbuf(sc, cur_rx, m);
112041502Swpaul			continue;
112141502Swpaul		}
112241502Swpaul
112341502Swpaul		/* No errors; receive the packet. */
112441502Swpaul		total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status);
112541502Swpaul
112641502Swpaul		/*
112742048Swpaul		 * XXX The VIA Rhine chip includes the CRC with every
112842048Swpaul		 * received frame, and there's no way to turn this
112942048Swpaul		 * behavior off (at least, I can't find anything in
113042048Swpaul	 	 * the manual that explains how to do it) so we have
113142048Swpaul		 * to trim off the CRC manually.
113242048Swpaul		 */
113342048Swpaul		total_len -= ETHER_CRC_LEN;
113442048Swpaul
113578508Sbmilekic		m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp,
113678508Sbmilekic		    NULL);
113749610Swpaul		vr_newbuf(sc, cur_rx, m);
113849610Swpaul		if (m0 == NULL) {
113941502Swpaul			ifp->if_ierrors++;
114041502Swpaul			continue;
114141502Swpaul		}
114249610Swpaul		m = m0;
114341502Swpaul
114441502Swpaul		ifp->if_ipackets++;
1145106936Ssam		(*ifp->if_input)(ifp, m);
114641502Swpaul	}
114741502Swpaul
114841502Swpaul	return;
114941502Swpaul}
115041502Swpaul
1151105221Sphkstatic void
1152102336Salfredvr_rxeoc(sc)
115341502Swpaul	struct vr_softc		*sc;
115441502Swpaul{
1155110131Ssilby	struct ifnet		*ifp;
1156110131Ssilby	int			i;
115741502Swpaul
1158110131Ssilby	ifp = &sc->arpcom.ac_if;
1159110131Ssilby
1160110131Ssilby	ifp->if_ierrors++;
1161110131Ssilby
1162110131Ssilby	VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
1163110131Ssilby        DELAY(10000);
1164110131Ssilby
1165110131Ssilby	for (i = 0x400;
1166110131Ssilby	     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON);
1167110131Ssilby	     i--)
1168110131Ssilby		;	/* Wait for receiver to stop */
1169110131Ssilby
1170110131Ssilby	if (!i) {
1171110131Ssilby		printf("vr%d: rx shutdown error!\n", sc->vr_unit);
1172110131Ssilby		sc->vr_flags |= VR_F_RESTART;
1173110131Ssilby		return;
1174110131Ssilby		}
1175110131Ssilby
117641502Swpaul	vr_rxeof(sc);
1177110131Ssilby
117841502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
117941502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON);
118041502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO);
118141502Swpaul
118241502Swpaul	return;
118341502Swpaul}
118441502Swpaul
118541502Swpaul/*
118641502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
118741502Swpaul * the list buffers.
118841502Swpaul */
118941502Swpaul
1190102336Salfredstatic void
1191102336Salfredvr_txeof(sc)
119241502Swpaul	struct vr_softc		*sc;
119341502Swpaul{
119441502Swpaul	struct vr_chain		*cur_tx;
119541502Swpaul	struct ifnet		*ifp;
119641502Swpaul
119741502Swpaul	ifp = &sc->arpcom.ac_if;
119841502Swpaul
119996677Ssilby	/* Reset the timeout timer; if_txeoc will clear it. */
120096677Ssilby	ifp->if_timer = 5;
120141502Swpaul
120241502Swpaul	/* Sanity check. */
120341502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
120441502Swpaul		return;
120541502Swpaul
120641502Swpaul	/*
120741502Swpaul	 * Go through our tx list and free mbufs for those
120841502Swpaul	 * frames that have been transmitted.
120941502Swpaul	 */
121041502Swpaul	while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) {
121141502Swpaul		u_int32_t		txstat;
1212110131Ssilby		int			i;
121341502Swpaul
121441502Swpaul		cur_tx = sc->vr_cdata.vr_tx_head;
121541502Swpaul		txstat = cur_tx->vr_ptr->vr_status;
121641502Swpaul
1217101896Ssilby		if ((txstat & VR_TXSTAT_ABRT) ||
1218101896Ssilby		    (txstat & VR_TXSTAT_UDF)) {
1219110131Ssilby			for (i = 0x400;
1220110131Ssilby			     i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON);
1221110131Ssilby			     i--)
1222101896Ssilby				;	/* Wait for chip to shutdown */
1223110131Ssilby			if (!i) {
1224110131Ssilby				printf("vr%d: tx shutdown timeout\n", sc->vr_unit);
1225110131Ssilby				sc->vr_flags |= VR_F_RESTART;
1226110131Ssilby				break;
1227110131Ssilby			}
1228101896Ssilby			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
1229101896Ssilby			CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr));
1230101896Ssilby			break;
1231101896Ssilby		}
1232101896Ssilby
123342491Swpaul		if (txstat & VR_TXSTAT_OWN)
123441502Swpaul			break;
123541502Swpaul
123641502Swpaul		if (txstat & VR_TXSTAT_ERRSUM) {
123741502Swpaul			ifp->if_oerrors++;
123841502Swpaul			if (txstat & VR_TXSTAT_DEFER)
123941502Swpaul				ifp->if_collisions++;
124041502Swpaul			if (txstat & VR_TXSTAT_LATECOLL)
124141502Swpaul				ifp->if_collisions++;
124241502Swpaul		}
124341502Swpaul
124441502Swpaul		ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3;
124541502Swpaul
124641502Swpaul		ifp->if_opackets++;
124751432Swpaul		if (cur_tx->vr_mbuf != NULL) {
124851432Swpaul			m_freem(cur_tx->vr_mbuf);
124951432Swpaul			cur_tx->vr_mbuf = NULL;
125051432Swpaul		}
125141502Swpaul
125241502Swpaul		if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) {
125341502Swpaul			sc->vr_cdata.vr_tx_head = NULL;
125441502Swpaul			sc->vr_cdata.vr_tx_tail = NULL;
125541502Swpaul			break;
125641502Swpaul		}
125741502Swpaul
125841502Swpaul		sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc;
125941502Swpaul	}
126041502Swpaul
126141502Swpaul	return;
126241502Swpaul}
126341502Swpaul
126441502Swpaul/*
126541502Swpaul * TX 'end of channel' interrupt handler.
126641502Swpaul */
1267102336Salfredstatic void
1268102336Salfredvr_txeoc(sc)
126941502Swpaul	struct vr_softc		*sc;
127041502Swpaul{
127141502Swpaul	struct ifnet		*ifp;
127241502Swpaul
127341502Swpaul	ifp = &sc->arpcom.ac_if;
127441502Swpaul
127541502Swpaul	if (sc->vr_cdata.vr_tx_head == NULL) {
127641502Swpaul		ifp->if_flags &= ~IFF_OACTIVE;
127741502Swpaul		sc->vr_cdata.vr_tx_tail = NULL;
127896677Ssilby		ifp->if_timer = 0;
127941502Swpaul	}
128041502Swpaul
128141502Swpaul	return;
128241502Swpaul}
128341502Swpaul
1284102336Salfredstatic void
1285102336Salfredvr_tick(xsc)
128651432Swpaul	void			*xsc;
128751432Swpaul{
128851432Swpaul	struct vr_softc		*sc;
128951432Swpaul	struct mii_data		*mii;
129051432Swpaul
129151432Swpaul	sc = xsc;
129267087Swpaul	VR_LOCK(sc);
1293110131Ssilby	if (sc->vr_flags & VR_F_RESTART) {
1294110131Ssilby		printf("vr%d: restarting\n", sc->vr_unit);
1295110131Ssilby		vr_stop(sc);
1296110131Ssilby		vr_reset(sc);
1297110131Ssilby		vr_init(sc);
1298110131Ssilby		sc->vr_flags &= ~VR_F_RESTART;
1299110131Ssilby	}
1300110131Ssilby
130151432Swpaul	mii = device_get_softc(sc->vr_miibus);
130251432Swpaul	mii_tick(mii);
130351432Swpaul
130451432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
130551432Swpaul
130667087Swpaul	VR_UNLOCK(sc);
130751432Swpaul
130851432Swpaul	return;
130951432Swpaul}
131051432Swpaul
1311102336Salfredstatic void
1312102336Salfredvr_intr(arg)
131341502Swpaul	void			*arg;
131441502Swpaul{
131541502Swpaul	struct vr_softc		*sc;
131641502Swpaul	struct ifnet		*ifp;
131741502Swpaul	u_int16_t		status;
131841502Swpaul
131941502Swpaul	sc = arg;
132067087Swpaul	VR_LOCK(sc);
132141502Swpaul	ifp = &sc->arpcom.ac_if;
132241502Swpaul
132341502Swpaul	/* Supress unwanted interrupts. */
132441502Swpaul	if (!(ifp->if_flags & IFF_UP)) {
132541502Swpaul		vr_stop(sc);
132667087Swpaul		VR_UNLOCK(sc);
132741502Swpaul		return;
132841502Swpaul	}
132941502Swpaul
133041502Swpaul	/* Disable interrupts. */
133141502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
133241502Swpaul
133341502Swpaul	for (;;) {
133441502Swpaul
133541502Swpaul		status = CSR_READ_2(sc, VR_ISR);
133641502Swpaul		if (status)
133741502Swpaul			CSR_WRITE_2(sc, VR_ISR, status);
133841502Swpaul
133941502Swpaul		if ((status & VR_INTRS) == 0)
134041502Swpaul			break;
134141502Swpaul
134241502Swpaul		if (status & VR_ISR_RX_OK)
134341502Swpaul			vr_rxeof(sc);
134441502Swpaul
1345110131Ssilby		if (status & VR_ISR_RX_DROPPED) {
1346110131Ssilby			printf("vr%d: rx packet lost\n", sc->vr_unit);
1347110131Ssilby			ifp->if_ierrors++;
1348110131Ssilby			}
1349110131Ssilby
135041502Swpaul		if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) ||
1351110131Ssilby		    (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) {
1352110131Ssilby			printf("vr%d: receive error (%04x)",
1353110131Ssilby			       sc->vr_unit, status);
1354110131Ssilby			if (status & VR_ISR_RX_NOBUF)
1355110131Ssilby				printf(" no buffers");
1356110131Ssilby			if (status & VR_ISR_RX_OFLOW)
1357110131Ssilby				printf(" overflow");
1358110131Ssilby			if (status & VR_ISR_RX_DROPPED)
1359110131Ssilby				printf(" packet lost");
1360110131Ssilby			printf("\n");
136141502Swpaul			vr_rxeoc(sc);
136241502Swpaul		}
136341502Swpaul
1364101896Ssilby		if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) {
1365101896Ssilby			vr_reset(sc);
1366101896Ssilby			vr_init(sc);
1367101896Ssilby			break;
136841502Swpaul		}
136941502Swpaul
1370101896Ssilby		if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) ||
1371101896Ssilby		    (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) {
137241502Swpaul			vr_txeof(sc);
1373101896Ssilby			if ((status & VR_ISR_UDFI) ||
1374101896Ssilby			    (status & VR_ISR_TX_ABRT2) ||
1375101896Ssilby			    (status & VR_ISR_TX_ABRT)) {
1376101896Ssilby				ifp->if_oerrors++;
1377101896Ssilby				if (sc->vr_cdata.vr_tx_head != NULL) {
1378101896Ssilby					VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON);
1379101896Ssilby					VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO);
1380101896Ssilby				}
1381101896Ssilby			} else
1382101896Ssilby				vr_txeoc(sc);
138341502Swpaul		}
138441502Swpaul
138541502Swpaul	}
138641502Swpaul
138741502Swpaul	/* Re-enable interrupts. */
138841502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
138941502Swpaul
139041502Swpaul	if (ifp->if_snd.ifq_head != NULL) {
139141502Swpaul		vr_start(ifp);
139241502Swpaul	}
139341502Swpaul
139467087Swpaul	VR_UNLOCK(sc);
139567087Swpaul
139641502Swpaul	return;
139741502Swpaul}
139841502Swpaul
139941502Swpaul/*
140041502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
140141502Swpaul * pointers to the fragment pointers.
140241502Swpaul */
1403102336Salfredstatic int
1404102336Salfredvr_encap(sc, c, m_head)
140541502Swpaul	struct vr_softc		*sc;
140641502Swpaul	struct vr_chain		*c;
140741502Swpaul	struct mbuf		*m_head;
140841502Swpaul{
140941502Swpaul	int			frag = 0;
141041502Swpaul	struct vr_desc		*f = NULL;
141141502Swpaul	int			total_len;
141241502Swpaul	struct mbuf		*m;
141341502Swpaul
141441502Swpaul	m = m_head;
141541502Swpaul	total_len = 0;
141641502Swpaul
141741502Swpaul	/*
141841502Swpaul	 * The VIA Rhine wants packet buffers to be longword
141941502Swpaul	 * aligned, but very often our mbufs aren't. Rather than
142041502Swpaul	 * waste time trying to decide when to copy and when not
142141502Swpaul	 * to copy, just do it all the time.
142241502Swpaul	 */
142341502Swpaul	if (m != NULL) {
142441502Swpaul		struct mbuf		*m_new = NULL;
142541502Swpaul
1426109623Salfred		MGETHDR(m_new, M_NOWAIT, MT_DATA);
142741502Swpaul		if (m_new == NULL) {
142871271Swpaul			printf("vr%d: no memory for tx list\n", sc->vr_unit);
142941502Swpaul			return(1);
143041502Swpaul		}
143141502Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
1432109623Salfred			MCLGET(m_new, M_NOWAIT);
143341502Swpaul			if (!(m_new->m_flags & M_EXT)) {
143441502Swpaul				m_freem(m_new);
143571271Swpaul				printf("vr%d: no memory for tx list\n",
143641502Swpaul						sc->vr_unit);
143741502Swpaul				return(1);
143841502Swpaul			}
143941502Swpaul		}
144041502Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
144141502Swpaul					mtod(m_new, caddr_t));
144241502Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
144341502Swpaul		m_freem(m_head);
144441502Swpaul		m_head = m_new;
144541502Swpaul		/*
144641502Swpaul		 * The Rhine chip doesn't auto-pad, so we have to make
144741502Swpaul		 * sure to pad short frames out to the minimum frame length
144841502Swpaul		 * ourselves.
144941502Swpaul		 */
145041502Swpaul		if (m_head->m_len < VR_MIN_FRAMELEN) {
145141502Swpaul			m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len;
145241502Swpaul			m_new->m_len = m_new->m_pkthdr.len;
145341502Swpaul		}
145441502Swpaul		f = c->vr_ptr;
145541502Swpaul		f->vr_data = vtophys(mtod(m_new, caddr_t));
145641502Swpaul		f->vr_ctl = total_len = m_new->m_len;
145741502Swpaul		f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG;
145841502Swpaul		f->vr_status = 0;
145941502Swpaul		frag = 1;
146041502Swpaul	}
146141502Swpaul
146241502Swpaul	c->vr_mbuf = m_head;
146342491Swpaul	c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT;
146441502Swpaul	c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr);
146541502Swpaul
146641502Swpaul	return(0);
146741502Swpaul}
146841502Swpaul
146941502Swpaul/*
147041502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
147141502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
147241502Swpaul * copy of the pointers since the transmit list fragment pointers are
147341502Swpaul * physical addresses.
147441502Swpaul */
147541502Swpaul
1476102336Salfredstatic void
1477102336Salfredvr_start(ifp)
147841502Swpaul	struct ifnet		*ifp;
147941502Swpaul{
148041502Swpaul	struct vr_softc		*sc;
148141502Swpaul	struct mbuf		*m_head = NULL;
148241502Swpaul	struct vr_chain		*cur_tx = NULL, *start_tx;
148341502Swpaul
148441502Swpaul	sc = ifp->if_softc;
148541502Swpaul
148667087Swpaul	VR_LOCK(sc);
148767087Swpaul	if (ifp->if_flags & IFF_OACTIVE) {
148867087Swpaul		VR_UNLOCK(sc);
148941502Swpaul		return;
149067087Swpaul	}
149141502Swpaul
149241502Swpaul	/*
149341502Swpaul	 * Check for an available queue slot. If there are none,
149441502Swpaul	 * punt.
149541502Swpaul	 */
149641502Swpaul	if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) {
149741502Swpaul		ifp->if_flags |= IFF_OACTIVE;
149841502Swpaul		return;
149941502Swpaul	}
150041502Swpaul
150141502Swpaul	start_tx = sc->vr_cdata.vr_tx_free;
150241502Swpaul
150341502Swpaul	while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) {
150441502Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
150541502Swpaul		if (m_head == NULL)
150641502Swpaul			break;
150741502Swpaul
150841502Swpaul		/* Pick a descriptor off the free list. */
150941502Swpaul		cur_tx = sc->vr_cdata.vr_tx_free;
151041502Swpaul		sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc;
151141502Swpaul
151241502Swpaul		/* Pack the data into the descriptor. */
151371271Swpaul		if (vr_encap(sc, cur_tx, m_head)) {
151471271Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
151571275Swpaul			ifp->if_flags |= IFF_OACTIVE;
151671271Swpaul			cur_tx = NULL;
151771271Swpaul			break;
151871271Swpaul		}
151941502Swpaul
152041502Swpaul		if (cur_tx != start_tx)
152141502Swpaul			VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
152241502Swpaul
152341502Swpaul		/*
152441502Swpaul		 * If there's a BPF listener, bounce a copy of this frame
152541502Swpaul		 * to him.
152641502Swpaul		 */
1527106936Ssam		BPF_MTAP(ifp, cur_tx->vr_mbuf);
152851583Swpaul
152942491Swpaul		VR_TXOWN(cur_tx) = VR_TXSTAT_OWN;
153051432Swpaul		VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO);
153141502Swpaul	}
153241502Swpaul
153341502Swpaul	/*
153441526Swpaul	 * If there are no frames queued, bail.
153541526Swpaul	 */
153667087Swpaul	if (cur_tx == NULL) {
153767087Swpaul		VR_UNLOCK(sc);
153841526Swpaul		return;
153967087Swpaul	}
154041526Swpaul
154141502Swpaul	sc->vr_cdata.vr_tx_tail = cur_tx;
154241502Swpaul
154342491Swpaul	if (sc->vr_cdata.vr_tx_head == NULL)
154441502Swpaul		sc->vr_cdata.vr_tx_head = start_tx;
154541502Swpaul
154641502Swpaul	/*
154741502Swpaul	 * Set a timeout in case the chip goes out to lunch.
154841502Swpaul	 */
154941502Swpaul	ifp->if_timer = 5;
155067087Swpaul	VR_UNLOCK(sc);
155141502Swpaul
155241502Swpaul	return;
155341502Swpaul}
155441502Swpaul
1555102336Salfredstatic void
1556102336Salfredvr_init(xsc)
155741502Swpaul	void			*xsc;
155841502Swpaul{
155941502Swpaul	struct vr_softc		*sc = xsc;
156041502Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
156151432Swpaul	struct mii_data		*mii;
156273963Swpaul	int			i;
156341502Swpaul
156467087Swpaul	VR_LOCK(sc);
156541502Swpaul
156651432Swpaul	mii = device_get_softc(sc->vr_miibus);
156741502Swpaul
156841502Swpaul	/*
156941502Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
157041502Swpaul	 */
157141502Swpaul	vr_stop(sc);
157241502Swpaul	vr_reset(sc);
157341502Swpaul
157473963Swpaul	/*
157573963Swpaul	 * Set our station address.
157673963Swpaul	 */
157773963Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
157873963Swpaul		CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]);
1579101375Ssilby
1580101375Ssilby	/* Set DMA size */
1581101375Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH);
1582101375Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD);
158373963Swpaul
1584101375Ssilby	/*
1585101375Ssilby	 * BCR0 and BCR1 can override the RXCFG and TXCFG registers,
1586101108Ssilby	 * so we must set both.
1587101108Ssilby	 */
1588101108Ssilby	VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH);
1589110131Ssilby	VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES);
1590101108Ssilby
1591101108Ssilby	VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH);
1592101108Ssilby	VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD);
1593101108Ssilby
159441502Swpaul	VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH);
1595110131Ssilby	VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES);
159641502Swpaul
159741502Swpaul	VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH);
159841502Swpaul	VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD);
159941502Swpaul
160041502Swpaul	/* Init circular RX list. */
160141502Swpaul	if (vr_list_rx_init(sc) == ENOBUFS) {
160241502Swpaul		printf("vr%d: initialization failed: no "
160341502Swpaul			"memory for rx buffers\n", sc->vr_unit);
160441502Swpaul		vr_stop(sc);
160567087Swpaul		VR_UNLOCK(sc);
160641502Swpaul		return;
160741502Swpaul	}
160841502Swpaul
160941502Swpaul	/*
161041502Swpaul	 * Init tx descriptors.
161141502Swpaul	 */
161241502Swpaul	vr_list_tx_init(sc);
161341502Swpaul
161441502Swpaul	/* If we want promiscuous mode, set the allframes bit. */
161541502Swpaul	if (ifp->if_flags & IFF_PROMISC)
161641502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
161741502Swpaul	else
161841502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC);
161941502Swpaul
162041502Swpaul	/* Set capture broadcast bit to capture broadcast frames. */
162141502Swpaul	if (ifp->if_flags & IFF_BROADCAST)
162241502Swpaul		VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
162341502Swpaul	else
162441502Swpaul		VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD);
162541502Swpaul
162641502Swpaul	/*
162741502Swpaul	 * Program the multicast filter, if necessary.
162841502Swpaul	 */
162941502Swpaul	vr_setmulti(sc);
163041502Swpaul
163141502Swpaul	/*
163241502Swpaul	 * Load the address of the RX list.
163341502Swpaul	 */
163441502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr));
163541502Swpaul
163641502Swpaul	/* Enable receiver and transmitter. */
163741502Swpaul	CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START|
163841502Swpaul				    VR_CMD_TX_ON|VR_CMD_RX_ON|
163941502Swpaul				    VR_CMD_RX_GO);
164041502Swpaul
164141502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0]));
164241502Swpaul
164341502Swpaul	/*
164441502Swpaul	 * Enable interrupts.
164541502Swpaul	 */
164641502Swpaul	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
164741502Swpaul	CSR_WRITE_2(sc, VR_IMR, VR_INTRS);
164841502Swpaul
164951432Swpaul	mii_mediachg(mii);
165041502Swpaul
165141502Swpaul	ifp->if_flags |= IFF_RUNNING;
165241502Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
165341502Swpaul
165451432Swpaul	sc->vr_stat_ch = timeout(vr_tick, sc, hz);
165551432Swpaul
165667087Swpaul	VR_UNLOCK(sc);
165767087Swpaul
165841502Swpaul	return;
165941502Swpaul}
166041502Swpaul
166141502Swpaul/*
166241502Swpaul * Set media options.
166341502Swpaul */
1664102336Salfredstatic int
1665102336Salfredvr_ifmedia_upd(ifp)
166641502Swpaul	struct ifnet		*ifp;
166741502Swpaul{
166841502Swpaul	struct vr_softc		*sc;
166941502Swpaul
167041502Swpaul	sc = ifp->if_softc;
167141502Swpaul
167251432Swpaul	if (ifp->if_flags & IFF_UP)
167351432Swpaul		vr_init(sc);
167441502Swpaul
167541502Swpaul	return(0);
167641502Swpaul}
167741502Swpaul
167841502Swpaul/*
167941502Swpaul * Report current media status.
168041502Swpaul */
1681102336Salfredstatic void
1682102336Salfredvr_ifmedia_sts(ifp, ifmr)
168341502Swpaul	struct ifnet		*ifp;
168441502Swpaul	struct ifmediareq	*ifmr;
168541502Swpaul{
168641502Swpaul	struct vr_softc		*sc;
168751432Swpaul	struct mii_data		*mii;
168841502Swpaul
168941502Swpaul	sc = ifp->if_softc;
169051432Swpaul	mii = device_get_softc(sc->vr_miibus);
169151432Swpaul	mii_pollstat(mii);
169251432Swpaul	ifmr->ifm_active = mii->mii_media_active;
169351432Swpaul	ifmr->ifm_status = mii->mii_media_status;
169441502Swpaul
169541502Swpaul	return;
169641502Swpaul}
169741502Swpaul
1698102336Salfredstatic int
1699102336Salfredvr_ioctl(ifp, command, data)
170041502Swpaul	struct ifnet		*ifp;
170141502Swpaul	u_long			command;
170241502Swpaul	caddr_t			data;
170341502Swpaul{
170441502Swpaul	struct vr_softc		*sc = ifp->if_softc;
170541502Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
170651432Swpaul	struct mii_data		*mii;
170767087Swpaul	int			error = 0;
170841502Swpaul
170967087Swpaul	VR_LOCK(sc);
171041502Swpaul
171141502Swpaul	switch(command) {
171241502Swpaul	case SIOCSIFFLAGS:
171341502Swpaul		if (ifp->if_flags & IFF_UP) {
171441502Swpaul			vr_init(sc);
171541502Swpaul		} else {
171641502Swpaul			if (ifp->if_flags & IFF_RUNNING)
171741502Swpaul				vr_stop(sc);
171841502Swpaul		}
171941502Swpaul		error = 0;
172041502Swpaul		break;
172141502Swpaul	case SIOCADDMULTI:
172241502Swpaul	case SIOCDELMULTI:
172341502Swpaul		vr_setmulti(sc);
172441502Swpaul		error = 0;
172541502Swpaul		break;
172641502Swpaul	case SIOCGIFMEDIA:
172741502Swpaul	case SIOCSIFMEDIA:
172851432Swpaul		mii = device_get_softc(sc->vr_miibus);
172951432Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
173041502Swpaul		break;
173141502Swpaul	default:
1732106936Ssam		error = ether_ioctl(ifp, command, data);
173341502Swpaul		break;
173441502Swpaul	}
173541502Swpaul
173667087Swpaul	VR_UNLOCK(sc);
173741502Swpaul
173841502Swpaul	return(error);
173941502Swpaul}
174041502Swpaul
1741102336Salfredstatic void
1742102336Salfredvr_watchdog(ifp)
174341502Swpaul	struct ifnet		*ifp;
174441502Swpaul{
174541502Swpaul	struct vr_softc		*sc;
174641502Swpaul
174741502Swpaul	sc = ifp->if_softc;
174841502Swpaul
174967087Swpaul	VR_LOCK(sc);
175041502Swpaul	ifp->if_oerrors++;
175141502Swpaul	printf("vr%d: watchdog timeout\n", sc->vr_unit);
175241502Swpaul
175341502Swpaul	vr_stop(sc);
175441502Swpaul	vr_reset(sc);
175541502Swpaul	vr_init(sc);
175641502Swpaul
175741502Swpaul	if (ifp->if_snd.ifq_head != NULL)
175841502Swpaul		vr_start(ifp);
175941502Swpaul
176067087Swpaul	VR_UNLOCK(sc);
176167087Swpaul
176241502Swpaul	return;
176341502Swpaul}
176441502Swpaul
176541502Swpaul/*
176641502Swpaul * Stop the adapter and free any mbufs allocated to the
176741502Swpaul * RX and TX lists.
176841502Swpaul */
1769102336Salfredstatic void
1770102336Salfredvr_stop(sc)
177141502Swpaul	struct vr_softc		*sc;
177241502Swpaul{
177341502Swpaul	register int		i;
177441502Swpaul	struct ifnet		*ifp;
177541502Swpaul
177667087Swpaul	VR_LOCK(sc);
177767087Swpaul
177841502Swpaul	ifp = &sc->arpcom.ac_if;
177941502Swpaul	ifp->if_timer = 0;
178041502Swpaul
178151432Swpaul	untimeout(vr_tick, sc, sc->vr_stat_ch);
178251432Swpaul
178341502Swpaul	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP);
178441502Swpaul	VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON));
178541502Swpaul	CSR_WRITE_2(sc, VR_IMR, 0x0000);
178641502Swpaul	CSR_WRITE_4(sc, VR_TXADDR, 0x00000000);
178741502Swpaul	CSR_WRITE_4(sc, VR_RXADDR, 0x00000000);
178841502Swpaul
178941502Swpaul	/*
179041502Swpaul	 * Free data in the RX lists.
179141502Swpaul	 */
179241502Swpaul	for (i = 0; i < VR_RX_LIST_CNT; i++) {
179341502Swpaul		if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) {
179441502Swpaul			m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf);
179541502Swpaul			sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL;
179641502Swpaul		}
179741502Swpaul	}
179841502Swpaul	bzero((char *)&sc->vr_ldata->vr_rx_list,
179941502Swpaul		sizeof(sc->vr_ldata->vr_rx_list));
180041502Swpaul
180141502Swpaul	/*
180241502Swpaul	 * Free the TX list buffers.
180341502Swpaul	 */
180441502Swpaul	for (i = 0; i < VR_TX_LIST_CNT; i++) {
180541502Swpaul		if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) {
180641502Swpaul			m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf);
180741502Swpaul			sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL;
180841502Swpaul		}
180941502Swpaul	}
181041502Swpaul
181141502Swpaul	bzero((char *)&sc->vr_ldata->vr_tx_list,
181241502Swpaul		sizeof(sc->vr_ldata->vr_tx_list));
181341502Swpaul
181441502Swpaul	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
181567087Swpaul	VR_UNLOCK(sc);
181641502Swpaul
181741502Swpaul	return;
181841502Swpaul}
181941502Swpaul
182041502Swpaul/*
182141502Swpaul * Stop all chip I/O so that the kernel's probe routines don't
182241502Swpaul * get confused by errant DMAs when rebooting.
182341502Swpaul */
1824102336Salfredstatic void
1825102336Salfredvr_shutdown(dev)
182649610Swpaul	device_t		dev;
182741502Swpaul{
182849610Swpaul	struct vr_softc		*sc;
182941502Swpaul
183049610Swpaul	sc = device_get_softc(dev);
183149610Swpaul
183241502Swpaul	vr_stop(sc);
183341502Swpaul
183441502Swpaul	return;
183541502Swpaul}
1836