PERFORCE change 128941 for review

Oleksandr Tymoshenko gonzo at FreeBSD.org
Sun Nov 11 11:37:31 PST 2007


http://perforce.freebsd.org/chv.cgi?CH=128941

Change 128941 by gonzo at gonzo_jeeves on 2007/11/11 19:37:03

	o Merge yongari's version of if_vr with newbus stuff.
	o During reset wait while reset bit is cleared instead of
	    DELAY(200);

Affected files ...

.. //depot/projects/mips2/src/sys/pci/if_vr.c#7 edit
.. //depot/projects/mips2/src/sys/pci/if_vrreg.h#6 edit

Differences ...

==== //depot/projects/mips2/src/sys/pci/if_vr.c#7 (text+ko) ====

@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/pci/if_vr.c,v 1.127 2007/10/12 03:32:55 yongari Exp $");
+__FBSDID("$FreeBSD: src/sys/pci/if_vr.c,v 1.126 2007/04/23 12:19:02 phk Exp $");
 
 /*
  * VIA Rhine fast ethernet PCI NIC driver
@@ -65,6 +65,7 @@
 #endif
 
 #include <sys/param.h>
+#include <sys/endian.h>
 #include <sys/systm.h>
 #include <sys/sockio.h>
 #include <sys/mbuf.h>
@@ -72,22 +73,24 @@
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
 
 #include <net/if.h>
 #include <net/ethernet.h>
 #include <net/if_dl.h>
 #include <net/if_media.h>
 #include <net/if_types.h>
+#include <net/if_vlan_var.h>
 
 #include <net/bpf.h>
 
-#include <vm/vm.h>		/* for vtophys */
-#include <vm/pmap.h>		/* for vtophys */
 #include <machine/bus.h>
 #include <machine/resource.h>
 #include <sys/bus.h>
 #include <sys/rman.h>
 
+#include <dev/mii/mii.h>
 #include <dev/mii/miivar.h>
 
 #include <dev/pci/pcireg.h>
@@ -95,7 +98,11 @@
 
 #define VR_USEIOSPACE
 
+#if 0
 #include <pci/if_vrreg.h>
+#else
+#include "if_vrreg.h"
+#endif
 
 MODULE_DEPEND(vr, pci, 1, 1, 1);
 MODULE_DEPEND(vr, ether, 1, 1, 1);
@@ -104,12 +111,18 @@
 /* "device miibus" required.  See GENERIC if you get errors here. */
 #include "miibus_if.h"
 
+/* Show Rx/Tx error status */
+#define	VR_SHOW_ERRORS
+
+#define	VR_CSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP)
+
 /*
  * Various supported device vendors/types, their names & quirks
  */
 
 #define VR_Q_NEEDALIGN		(1<<0)
 #define VR_Q_CSUM		(1<<1)
+#define VR_Q_CAM		(1<<2)
 
 static struct vr_type {
 	u_int16_t		vr_vid;
@@ -130,7 +143,7 @@
 	    0,
 	    "VIA VT6105 Rhine III 10/100BaseTX" },
 	{ VIA_VENDORID, VIA_DEVICEID_RHINE_III_M,
-	    VR_Q_CSUM,
+	    VR_Q_CSUM | VR_Q_CAM,
 	    "VIA VT6105M Rhine III 10/100BaseTX" },
 	{ DELTA_VENDORID, DELTA_DEVICEID_RHINE_II,
 	    VR_Q_NEEDALIGN,
@@ -141,81 +154,86 @@
 	{ 0, 0, 0, NULL }
 };
 
-struct vr_list_data {
-	struct vr_desc		vr_rx_list[VR_RX_LIST_CNT];
-	struct vr_desc		vr_tx_list[VR_TX_LIST_CNT];
-};
-
-struct vr_softc {
-	struct ifnet		*vr_ifp;	/* interface info */
-	device_t		vr_dev;
-	struct resource		*vr_res;
-	struct resource		*vr_irq;
-	void			*vr_intrhand;
-	device_t		vr_miibus;
-	u_int8_t		vr_revid;	/* Rhine chip revision */
-	u_int8_t                vr_flags;       /* See VR_F_* below */
-	struct vr_list_data	*vr_ldata;
-	struct callout		vr_stat_callout;
-	struct mtx		vr_mtx;
-	int			vr_suspended;	/* if 1, sleeping/detaching */
-	int			vr_quirks;
-	struct vr_desc		*vr_rx_head;
-	struct vr_desc		*vr_tx_cons;
-	struct vr_desc		*vr_tx_prod;
-#ifdef DEVICE_POLLING
-	int			rxcycles;
-#endif
-};
-
 static int vr_probe(device_t);
 static int vr_attach(device_t);
 static int vr_detach(device_t);
+static void vr_shutdown(device_t);
+static int vr_suspend(device_t);
+static int vr_resume(device_t);
 
-static int vr_newbuf(struct vr_desc *, struct mbuf *);
+static void vr_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int vr_dma_alloc(struct vr_softc *);
+static void vr_dma_free(struct vr_softc *);
+static __inline void vr_discard_rxbuf(struct vr_rxdesc *);
+static int vr_newbuf(struct vr_softc *, int);
 
+#ifndef __NO_STRICT_ALIGNMENT
+static __inline void vr_fixup_rx(struct mbuf *);
+#endif
 static void vr_rxeof(struct vr_softc *);
-static void vr_rxeoc(struct vr_softc *);
 static void vr_txeof(struct vr_softc *);
 static void vr_tick(void *);
+static int vr_error(struct vr_softc *, uint16_t);
+static void vr_tx_underrun(struct vr_softc *);
 static void vr_intr(void *);
 static void vr_start(struct ifnet *);
 static void vr_start_locked(struct ifnet *);
+static struct mbuf *vr_defrag(struct mbuf *, int, int);
+static int vr_encap(struct vr_softc *, struct mbuf **);
 static int vr_ioctl(struct ifnet *, u_long, caddr_t);
 static void vr_init(void *);
 static void vr_init_locked(struct vr_softc *);
+static void vr_vlan_setup(struct vr_softc *);
+static void vr_tx_start(struct vr_softc *);
+static void vr_rx_start(struct vr_softc *);
+static int vr_tx_stop(struct vr_softc *);
+static int vr_rx_stop(struct vr_softc *);
 static void vr_stop(struct vr_softc *);
-static void vr_watchdog(struct ifnet *);
-static void vr_shutdown(device_t);
+static void vr_watchdog(struct vr_softc *);
 static int vr_ifmedia_upd(struct ifnet *);
 static void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
 
-static int vr_mii_readreg(const struct vr_softc *, struct vr_mii_frame *);
-static int vr_mii_writereg(const struct vr_softc *, const struct vr_mii_frame *);
-static int vr_miibus_readreg(device_t, uint16_t, uint16_t);
-static int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t);
+static int vr_miibus_readreg(device_t, int, int);
+static int vr_miibus_writereg(device_t, int, int, int);
 static void vr_miibus_statchg(device_t);
 
-static void vr_setcfg(struct vr_softc *, int);
-static void vr_setmulti(struct vr_softc *);
+static void vr_link_task(void *, int);
+static int vr_setperf(struct vr_softc *, int, uint8_t *);
+static void vr_set_filter(struct vr_softc *);
 static void vr_reset(const struct vr_softc *);
-static int vr_list_rx_init(struct vr_softc *);
-static int vr_list_tx_init(struct vr_softc *);
+static int vr_tx_ring_init(struct vr_softc *);
+static int vr_rx_ring_init(struct vr_softc *);
+static int vr_sysctl_stats(SYSCTL_HANDLER_ARGS);
 
 #ifdef VR_USEIOSPACE
 #define VR_RES			SYS_RES_IOPORT
-#define VR_RID			VR_PCI_LOIO
+#define VR_RID			PCIR_BAR(0)
 #else
 #define VR_RES			SYS_RES_MEMORY
-#define VR_RID			VR_PCI_LOMEM
+#define VR_RID			PCIR_BAR(1)
 #endif
 
+static struct vr_tx_threshold_table {
+	int tx_cfg;
+	int bcr_cfg;
+	int value;
+} vr_tx_threshold_tables[] = {
+	{ VR_TXTHRESH_64BYTES, VR_BCR1_TXTHRESH64BYTES,	64 },
+	{ VR_TXTHRESH_128BYTES, VR_BCR1_TXTHRESH128BYTES, 128 },
+	{ VR_TXTHRESH_256BYTES, VR_BCR1_TXTHRESH256BYTES, 256 },
+	{ VR_TXTHRESH_512BYTES, VR_BCR1_TXTHRESH512BYTES, 512 },
+	{ VR_TXTHRESH_1024BYTES, VR_BCR1_TXTHRESH1024BYTES, 1024 },
+	{ VR_TXTHRESH_STORENFWD, VR_BCR1_TXTHRESHSTORENFWD, 2048 }
+};
+
 static device_method_t vr_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		vr_probe),
 	DEVMETHOD(device_attach,	vr_attach),
 	DEVMETHOD(device_detach, 	vr_detach),
 	DEVMETHOD(device_shutdown,	vr_shutdown),
+	DEVMETHOD(device_suspend,	vr_suspend),
+	DEVMETHOD(device_resume,	vr_resume),
 
 	/* bus interface */
 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
@@ -225,8 +243,9 @@
 	DEVMETHOD(miibus_readreg,	vr_miibus_readreg),
 	DEVMETHOD(miibus_writereg,	vr_miibus_writereg),
 	DEVMETHOD(miibus_statchg,	vr_miibus_statchg),
+	DEVMETHOD(miibus_linkchg,	vr_miibus_statchg),
 
-	{ 0, 0 }
+	{ NULL, NULL }
 };
 
 static driver_t vr_driver = {
@@ -239,132 +258,167 @@
 
 DRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0);
 DRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0);
-#define VR_F_RESTART		0x01		/* Restart unit on next tick */
-
-#define	VR_LOCK(_sc)		mtx_lock(&(_sc)->vr_mtx)
-#define	VR_UNLOCK(_sc)		mtx_unlock(&(_sc)->vr_mtx)
-#define	VR_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->vr_mtx, MA_OWNED)
-
-/*
- * register space access macros
- */
-#define CSR_WRITE_4(sc, reg, val)	bus_write_4(sc->vr_res, reg, val)
-#define CSR_WRITE_2(sc, reg, val)	bus_write_2(sc->vr_res, reg, val)
-#define CSR_WRITE_1(sc, reg, val)	bus_write_1(sc->vr_res, reg, val)
-
-#define CSR_READ_2(sc, reg)		bus_read_2(sc->vr_res, reg)
-#define CSR_READ_1(sc, reg)		bus_read_1(sc->vr_res, reg)
 
-#define VR_SETBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | (x))
-#define VR_CLRBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~(x))
-
-#define VR_SETBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | (x))
-#define VR_CLRBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~(x))
-
-
-/*
- * Read an PHY register through the MII.
- */
 static int
-vr_mii_readreg(const struct vr_softc *sc, struct vr_mii_frame *frame)
+vr_miibus_readreg(device_t dev, int phy, int reg)
 {
-	int	i;
+	struct vr_softc		*sc;
+	int			i;
+
+	sc = device_get_softc(dev);
+	if (sc->vr_phyaddr != phy)
+		return (0);
 
 	/* Set the PHY address. */
-	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
-	    frame->mii_phyaddr);
-
+	CSR_WRITE_1(sc, VR_PHYADDR, phy);
 	/* Set the register address. */
-	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
+	CSR_WRITE_1(sc, VR_MIIADDR, reg);
 	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB);
 
-	for (i = 0; i < 10000; i++) {
+	for (i = 0; i < VR_MII_TIMEOUT; i++) {
+		DELAY(1);
 		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0)
 			break;
-		DELAY(1);
 	}
-	frame->mii_data = CSR_READ_2(sc, VR_MIIDATA);
+	if (i == VR_MII_TIMEOUT)
+		device_printf(sc->vr_dev, "phy read fail %d:%d\n", phy, reg);
 
-	return (0);
+	return (CSR_READ_2(sc, VR_MIIDATA));
 }
 
-
-/*
- * Write to a PHY register through the MII.
- */
 static int
-vr_mii_writereg(const struct vr_softc *sc, const struct vr_mii_frame *frame)
+vr_miibus_writereg(device_t dev, int phy, int reg, int data)
 {
-	int	i;
+	struct vr_softc		*sc;
+	int			i;
+
+	sc = device_get_softc(dev);
+	if (sc->vr_phyaddr != phy)
+		return (0);
 
 	/* Set the PHY address. */
-	CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)|
-	    frame->mii_phyaddr);
-
+	CSR_WRITE_1(sc, VR_PHYADDR, phy);
 	/* Set the register address and data to write. */
-	CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr);
-	CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data);
-
+	CSR_WRITE_1(sc, VR_MIIADDR, reg);
+	CSR_WRITE_2(sc, VR_MIIDATA, data);
 	VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB);
 
-	for (i = 0; i < 10000; i++) {
+	for (i = 0; i < VR_MII_TIMEOUT; i++) {
+		DELAY(1);
 		if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0)
 			break;
-		DELAY(1);
 	}
+	if (i == VR_MII_TIMEOUT)
+		device_printf(sc->vr_dev, "phy write fail %d:%d\n", phy, reg);
 
 	return (0);
 }
 
-static int
-vr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg)
+static void
+vr_miibus_statchg(device_t dev)
 {
-	struct vr_mii_frame	frame;
-	struct vr_softc		*sc = device_get_softc(dev);
+	struct vr_softc		*sc;
 
-	if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1)
-		return (0);
-
-	bzero((char *)&frame, sizeof(frame));
-	frame.mii_phyaddr = phy;
-	frame.mii_regaddr = reg;
-	vr_mii_readreg(sc, &frame);
-	return (frame.mii_data);
+	sc = device_get_softc(dev);
+	taskqueue_enqueue(taskqueue_swi, &sc->vr_link_task);
 }
 
-static int
-vr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data)
+/*
+ * In order to fiddle with the
+ * 'full-duplex' and '100Mbps' bits in the netconfig register, we
+ * first have to put the transmit and/or receive logic in the idle state.
+ */
+static void
+vr_link_task(void *arg, int pending)
 {
-	struct vr_mii_frame	frame;
-	struct vr_softc		*sc = device_get_softc(dev);
+	struct vr_softc		*sc;
+	struct mii_data		*mii;
+	struct ifnet		*ifp;
+	int			lfdx, mfdx;
+	uint8_t			cr0, cr1;
+
+	sc = (struct vr_softc *)arg;
 
-	if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1)
-		return (0);
+	VR_LOCK(sc);
+	mii = device_get_softc(sc->vr_miibus);
+	ifp = sc->vr_ifp;
+	if (mii == NULL || ifp == NULL ||
+	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+		VR_UNLOCK(sc);
+		return;
+	}
 
-	bzero((char *)&frame, sizeof(frame));
-	frame.mii_phyaddr = phy;
-	frame.mii_regaddr = reg;
-	frame.mii_data = data;
-	vr_mii_writereg(sc, &frame);
+	if (mii->mii_media_status & IFM_ACTIVE) {
+		if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+			sc->vr_link = 1;
+	} else
+		sc->vr_link = 0;
 
-	return (0);
+	if (sc->vr_link) {
+		/* XXX flow control */
+		cr0 = CSR_READ_1(sc, VR_CR0);
+		cr1 = CSR_READ_1(sc, VR_CR1);
+		mfdx = (cr1 & VR_CR1_FULLDUPLEX) != 0;
+		lfdx = (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0;
+		if (mfdx != lfdx) {
+			if ((cr0 & (VR_CR0_TX_ON | VR_CR0_RX_ON)) != 0) {
+				if (vr_tx_stop(sc) < 0 || vr_rx_stop(sc) < 0) {
+					printf("T1\n");
+					sc->vr_flags |= VR_F_RESTART;
+					VR_UNLOCK(sc);
+					return;
+				}
+			}
+			if (lfdx)
+				cr1 |= VR_CR1_FULLDUPLEX;
+			else
+				cr1 &= ~VR_CR1_FULLDUPLEX;
+			CSR_WRITE_1(sc, VR_CR1, cr1);
+		}
+		vr_rx_start(sc);
+		vr_tx_start(sc);
+	} else {
+		if (vr_tx_stop(sc) < 0 || vr_rx_stop(sc) < 0) {
+			printf("T2\n");
+			sc->vr_flags |= VR_F_RESTART;
+			VR_UNLOCK(sc);
+			return;
+		}
+	}
+	VR_UNLOCK(sc);
 }
 
-static void
-vr_miibus_statchg(device_t dev)
+/*
+ * Copy the address 'mac' into the perfect RX filter entry at
+ * offset 'idx.' The perfect filter only has 32 entries so do
+ * some sanity tests.
+ */
+static int
+vr_setperf(struct vr_softc *sc, int idx, uint8_t *mac)
 {
-	struct mii_data		*mii;
-	struct vr_softc		*sc = device_get_softc(dev);
+	int	i;
+
+	if (idx < 0 || idx >= VR_CAM_MCAST_CNT || mac == NULL)
+		return (EINVAL);
+
+	/* Set CAM entry address. */
+	CSR_WRITE_1(sc, VR_CAMADDR, idx);
+	/* Set CAM entry data. */
+	for (i = 0; i < ETHER_ADDR_LEN; i++)
+		CSR_WRITE_1(sc, VR_MAR0 + i, mac[i]);
+	DELAY(10);
+	/* Set CAM write. */
+	CSR_WRITE_1(sc, VR_CAMCTL, VR_CAMCTL_ENA | VR_CAMCTL_WRITE);
+	DELAY(10);
 
-	mii = device_get_softc(sc->vr_miibus);
-	vr_setcfg(sc, mii->mii_media_active);
+	return(0);
 }
 
 /*
  * Program the 64-bit multicast hash filter.
  */
 static void
-vr_setmulti(struct vr_softc *sc)
+vr_set_filter(struct vr_softc *sc)
 {
 	struct ifnet		*ifp = sc->vr_ifp;
 	int			h = 0;
@@ -372,13 +426,19 @@
 	struct ifmultiaddr	*ifma;
 	uint8_t			rxfilt;
 	int			mcnt = 0;
+	uint32_t		cam_mask;
 
 	VR_LOCK_ASSERT(sc);
 
 	rxfilt = CSR_READ_1(sc, VR_RXCFG);
 
+	rxfilt = ~(VR_RXCFG_RX_PROMISC | VR_RXCFG_RX_BROAD | VR_RXCFG_RX_MULTI);
+	if (ifp->if_flags & IFF_BROADCAST)
+		rxfilt |= VR_RXCFG_RX_BROAD;
 	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
 		rxfilt |= VR_RXCFG_RX_MULTI;
+		if (ifp->if_flags & IFF_PROMISC)
+			rxfilt |= VR_RXCFG_RX_PROMISC;
 		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
 		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
 		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
@@ -389,11 +449,26 @@
 	CSR_WRITE_4(sc, VR_MAR0, 0);
 	CSR_WRITE_4(sc, VR_MAR1, 0);
 
+	if (sc->vr_quirks & VR_Q_CAM)
+		CSR_WRITE_1(sc, VR_CAMCTL, VR_CAMCTL_ENA | VR_CAMCTL_MCAST);
+	cam_mask = 0;
 	/* Now program new ones. */
 	IF_ADDR_LOCK(ifp);
 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
 		if (ifma->ifma_addr->sa_family != AF_LINK)
 			continue;
+		/*
+		 * Program the first VR_CAM_MCAST_CNT multicast
+		 * groups into the perfect filter. For all others,
+		 * use the hash table.
+		 */
+		if (sc->vr_quirks & VR_Q_CAM && mcnt < VR_CAM_MCAST_CNT) {
+			vr_setperf(sc, mcnt,
+			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+			cam_mask |= 1 << mcnt;
+			mcnt++;
+			continue;
+		}
 		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
 		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
 		if (h < 32)
@@ -404,68 +479,57 @@
 	}
 	IF_ADDR_UNLOCK(ifp);
 
+	if (sc->vr_quirks & VR_Q_CAM) {
+		/* Set CAM mask. */
+		CSR_WRITE_1(sc, VR_CAMMASK, cam_mask);
+		CSR_WRITE_1(sc, VR_CAMCTL, 0);
+		/* Disable VLAN CAM. */
+		CSR_WRITE_1(sc, VR_CAMCTL, VR_CAMCTL_ENA | VR_CAMCTL_VLAN);
+		CSR_WRITE_1(sc, VR_CAMMASK, 0);
+		CSR_WRITE_1(sc, VR_CAMCTL, 0);
+	}
+
 	if (mcnt)
 		rxfilt |= VR_RXCFG_RX_MULTI;
-	else
-		rxfilt &= ~VR_RXCFG_RX_MULTI;
 
 	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
 	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
 	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
 }
 
-/*
- * In order to fiddle with the
- * 'full-duplex' and '100Mbps' bits in the netconfig register, we
- * first have to put the transmit and/or receive logic in the idle state.
- */
-static void
-vr_setcfg(struct vr_softc *sc, int media)
-{
-	int	restart = 0;
-
-	VR_LOCK_ASSERT(sc);
-
-	if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) {
-		restart = 1;
-		VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON));
-	}
-
-	if ((media & IFM_GMASK) == IFM_FDX)
-		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
-	else
-		VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX);
-
-	if (restart)
-		VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON);
-}
-
 static void
 vr_reset(const struct vr_softc *sc)
 {
-	register int	i;
+	int		i;
 
 	/*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during attach w/o lock. */
 
-	VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET);
-
+	CSR_WRITE_1(sc, VR_CR1, VR_CR1_RESET);
+	if (sc->vr_revid < REV_ID_VT6102_A) {
+		/* VT86C100A needs more delay after reset. */
+		DELAY(100);
+	}
 	for (i = 0; i < VR_TIMEOUT; i++) {
 		DELAY(10);
-		if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET))
+		if (!(CSR_READ_1(sc, VR_CR1) & VR_CR1_RESET))
 			break;
 	}
 	if (i == VR_TIMEOUT) {
-		if (sc->vr_revid < REV_ID_VT3065_A)
+		if (sc->vr_revid < REV_ID_VT6102_A)
 			device_printf(sc->vr_dev, "reset never completed!\n");
 		else {
 			/* Use newer force reset command */
-			device_printf(sc->vr_dev, "Using force reset command.\n");
+			device_printf(sc->vr_dev,
+			    "Using force reset command.\n");
 			VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST);
+			/*
+			 * Wait a little while for the chip to get its brains
+			 * in order.
+			 */
+			DELAY(2000);
 		}
 	}
 
-	/* Wait a little while for the chip to get its brains in order. */
-	DELAY(1000);
 }
 
 /*
@@ -526,12 +590,18 @@
 	mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
 	    MTX_DEF);
 	callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0);
+	TASK_INIT(&sc->vr_link_task, 0, vr_link_task, sc);
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+	    vr_sysctl_stats, "I", "Statistics");
 
 	/*
 	 * Map control/status registers.
 	 */
 	pci_enable_busmaster(dev);
-	sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF;
+	sc->vr_revid = pci_get_revid(dev);
+	device_printf(dev, "Revision: 0x%x\n", sc->vr_revid);
 
 	rid = VR_RID;
 	sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE);
@@ -556,34 +626,40 @@
 	/* Allocate ifnet structure. */
 	ifp = sc->vr_ifp = if_alloc(IFT_ETHER);
 	if (ifp == NULL) {
-		device_printf(dev, "can not if_alloc()\n");
+		device_printf(dev, "couldn't allocate ifnet structure\n");
 		error = ENOSPC;
 		goto fail;
 	}
 	ifp->if_softc = sc;
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
-	ifp->if_mtu = ETHERMTU;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = vr_ioctl;
 	ifp->if_start = vr_start;
-	ifp->if_watchdog = vr_watchdog;
 	ifp->if_init = vr_init;
-	IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1);
-	ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_RING_CNT - 1);
+	ifp->if_snd.ifq_maxlen = VR_TX_RING_CNT - 1;
 	IFQ_SET_READY(&ifp->if_snd);
 
+	/* Configure Tx FIFO threshold */
+	sc->vr_txthresh = VR_TXTHRESH_MIN;
 	if (sc->vr_quirks & VR_Q_CSUM) {
-		ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
+		ifp->if_hwassist = VR_CSUM_FEATURES;
 		ifp->if_capabilities |= IFCAP_HWCSUM;
+		/*
+		 * To update checksum field the hardware may need to
+		 * store entire frames into FIFO before transmitting.
+		 */
+		sc->vr_txthresh = VR_TXTHRESH_MAX;
 	}
 
 	ifp->if_capabilities |= IFCAP_VLAN_MTU;
+	if (sc->vr_revid >= REV_ID_VT6105M_A0) {
+		/* 6105M supports HW VLAN tag insertion/extraction. */
+		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
+		if (sc->vr_quirks & VR_Q_CSUM)
+			ifp->if_capabilities |= IFCAP_VLAN_HWCSUM;
+	}
 	ifp->if_capenable = ifp->if_capabilities;
-	if (ifp->if_capenable & IFCAP_TXCSUM)
-		ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP);
-	else
-		ifp->if_hwassist = 0;
-		
 #ifdef DEVICE_POLLING
 	ifp->if_capabilities |= IFCAP_POLLING;
 #endif
@@ -598,7 +674,13 @@
 
 	/* Reset the adapter. */
 	vr_reset(sc);
+	/* Ack intr & disable further interrupts. */
+	CSR_WRITE_2(sc, VR_ISR, 0xFFFF);
+	CSR_WRITE_2(sc, VR_IMR, 0);
+	if (sc->vr_revid >= REV_ID_VT6102_A)
+		CSR_WRITE_2(sc, VR_MII_IMR, 0);
 
+#if 0
 	/*
 	 * Turn on bit2 (MIION) in PCI configuration register 0x53 during
 	 * initialization and disable AUTOPOLL.
@@ -606,6 +688,35 @@
 	pci_write_config(dev, VR_PCI_MODE,
 	    pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4);
 	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
+#else
+	if (sc->vr_revid < REV_ID_VT6102_A) {
+		pci_write_config(dev, VR_PCI_MODE2,
+		    pci_read_config(dev, VR_PCI_MODE2, 1) |
+		    VR_MODE2_MODE10T, 1);
+	} else {
+		/* Report error instead of retrying forever. */
+		pci_write_config(dev, VR_PCI_MODE2,
+		    pci_read_config(dev, VR_PCI_MODE2, 1) |
+		    VR_MODE2_PCEROPT, 1);
+        	/* Detect MII coding error. */
+		pci_write_config(dev, VR_PCI_MODE3,
+		    pci_read_config(dev, VR_PCI_MODE3, 1) |
+		    VR_MODE3_MIION, 1);
+		if (sc->vr_revid >= REV_ID_VT6105_LOM &&
+		    sc->vr_revid < REV_ID_VT6105M_A0)
+			pci_write_config(dev, VR_PCI_MODE2,
+			    pci_read_config(dev, VR_PCI_MODE2, 1) |
+			    VR_MODE2_MODE10T, 1);
+		/* Enable Memory-Read-Multiple. */
+		if (sc->vr_revid >= REV_ID_VT6107_A1 &&
+		    sc->vr_revid < REV_ID_VT6105M_A0)
+			pci_write_config(dev, VR_PCI_MODE2,
+			    pci_read_config(dev, VR_PCI_MODE2, 1) |
+			    VR_MODE2_MRDPL, 1);
+	}
+	/* Disable MII AUTOPOLL. */
+	VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL);
+#endif
 
 	/*
 	 * Get station address. The way the Rhine chips work,
@@ -615,19 +726,23 @@
 	 * registers.
 	 */
 	VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD);
-	DELAY(200);
+	while ((CSR_READ_4(sc, VR_EECSR) & VR_EECSR_LOAD)) {
+		DELAY(10);
+	}
+
 	for (i = 0; i < ETHER_ADDR_LEN; i++)
 		eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i);
 
-	sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF,
-	    M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
-
-	if (sc->vr_ldata == NULL) {
-		device_printf(dev, "no memory for list buffers!\n");
+	if (vr_dma_alloc(sc) != 0) {
 		error = ENXIO;
 		goto fail;
 	}
 
+	/* Save PHY address. */
+	if (sc->vr_revid >= REV_ID_VT6105_A0)
+		sc->vr_phyaddr = 1;
+	else
+		sc->vr_phyaddr = CSR_READ_1(sc, VR_PHYADDR) & VR_PHYADDR_MASK;
 	/* Do MII setup. */
 	if (mii_phy_probe(dev, &sc->vr_miibus,
 	    vr_ifmedia_upd, vr_ifmedia_sts)) {
@@ -638,8 +753,12 @@
 
 	/* Call MI attach routine. */
 	ether_ifattach(ifp, eaddr);
-
-	sc->vr_suspended = 0;
+	/*
+	 * Tell the upper layer(s) we support long frames.
+	 * Must appear after the call to ether_ifattach() because
+	 * ether_ifattach() sets ifi_hdrlen to the default value.
+	 */
+	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
 
 	/* Hook interrupt last to avoid having to lock softc */
 	error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE,
@@ -674,7 +793,7 @@
 	KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized"));
 
 #ifdef DEVICE_POLLING
-	if (ifp->if_capenable & IFCAP_POLLING)
+	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
 		ether_poll_deregister(ifp);
 #endif
 
@@ -682,9 +801,11 @@
 	if (device_is_attached(dev)) {
 		VR_LOCK(sc);
 		sc->vr_suspended = 1;
+		sc->vr_detach = 1;
 		vr_stop(sc);
 		VR_UNLOCK(sc);
 		callout_drain(&sc->vr_stat_callout);
+		taskqueue_drain(taskqueue_swi, &sc->vr_link_task);
 		ether_ifdetach(ifp);
 	}
 	if (sc->vr_miibus)
@@ -701,78 +822,366 @@
 	if (ifp)
 		if_free(ifp);
 
-	if (sc->vr_ldata)
-		contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF);
+	vr_dma_free(sc);
 
 	mtx_destroy(&sc->vr_mtx);
 
 	return (0);
 }
 
+struct vr_dmamap_arg {
+	bus_addr_t	vr_busaddr;
+};
+
+static void
+vr_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	struct vr_dmamap_arg	*ctx;
+
+	if (error != 0)
+		return;
+	ctx = arg;
+	ctx->vr_busaddr = segs[0].ds_addr;
+}
+
+static int
+vr_dma_alloc(struct vr_softc *sc)
+{
+	struct vr_dmamap_arg	ctx;
+	struct vr_txdesc	*txd;
+	struct vr_rxdesc	*rxd;
+	bus_size_t		alignment;
+	int			error, i;
+
+	/* Create parent DMA tag. */
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->vr_dev),	/* parent */
+	    1, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
+	    0,				/* nsegments */
+	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->vr_cdata.vr_parent_tag);
+	if (error != 0) {
+		device_printf(sc->vr_dev, "failed to create parent DMA tag\n");
+		goto fail;
+	}
+	/* Create tag for Tx ring. */
+	error = bus_dma_tag_create(
+	    sc->vr_cdata.vr_parent_tag,	/* parent */
+	    VR_RING_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    VR_TX_RING_SIZE,		/* maxsize */
+	    1,				/* nsegments */
+	    VR_TX_RING_SIZE,		/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->vr_cdata.vr_tx_ring_tag);
+	if (error != 0) {
+		device_printf(sc->vr_dev, "failed to create Tx ring DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Rx ring. */
+	error = bus_dma_tag_create(
+	    sc->vr_cdata.vr_parent_tag,	/* parent */
+	    VR_RING_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    VR_RX_RING_SIZE,		/* maxsize */
+	    1,				/* nsegments */
+	    VR_RX_RING_SIZE,		/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->vr_cdata.vr_rx_ring_tag);
+	if (error != 0) {
+		device_printf(sc->vr_dev, "failed to create Rx ring DMA tag\n");
+		goto fail;
+	}
+
+	if ((sc->vr_quirks & VR_Q_NEEDALIGN) != 0)
+		alignment = sizeof(uint32_t);
+	else
+		alignment = 1;
+	/* Create tag for Tx buffers. */
+	error = bus_dma_tag_create(
+	    sc->vr_cdata.vr_parent_tag,	/* parent */
+	    alignment, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    MCLBYTES * VR_MAXFRAGS,	/* maxsize */
+	    VR_MAXFRAGS,		/* nsegments */
+	    MCLBYTES,			/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->vr_cdata.vr_tx_tag);
+	if (error != 0) {
+		device_printf(sc->vr_dev, "failed to create Tx DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Rx buffers. */
+	error = bus_dma_tag_create(
+	    sc->vr_cdata.vr_parent_tag,	/* parent */
+	    VR_RX_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    MCLBYTES,			/* maxsize */
+	    1,				/* nsegments */
+	    MCLBYTES,			/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->vr_cdata.vr_rx_tag);
+	if (error != 0) {
+		device_printf(sc->vr_dev, "failed to create Rx DMA tag\n");
+		goto fail;
+	}
+
+	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
+	error = bus_dmamem_alloc(sc->vr_cdata.vr_tx_ring_tag,
+	    (void **)&sc->vr_rdata.vr_tx_ring, BUS_DMA_WAITOK |
+	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->vr_cdata.vr_tx_ring_map);
+	if (error != 0) {
+		device_printf(sc->vr_dev,
+		    "failed to allocate DMA'able memory for Tx ring\n");
+		goto fail;
+	}
+
+	ctx.vr_busaddr = 0;
+	error = bus_dmamap_load(sc->vr_cdata.vr_tx_ring_tag,
+	    sc->vr_cdata.vr_tx_ring_map, sc->vr_rdata.vr_tx_ring,
+	    VR_TX_RING_SIZE, vr_dmamap_cb, &ctx, 0);
+	if (error != 0 || ctx.vr_busaddr == 0) {
+		device_printf(sc->vr_dev,
+		    "failed to load DMA'able memory for Tx ring\n");
+		goto fail;
+	}
+	sc->vr_rdata.vr_tx_ring_paddr = ctx.vr_busaddr;
+
+	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
+	error = bus_dmamem_alloc(sc->vr_cdata.vr_rx_ring_tag,
+	    (void **)&sc->vr_rdata.vr_rx_ring, BUS_DMA_WAITOK |
+	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->vr_cdata.vr_rx_ring_map);
+	if (error != 0) {
+		device_printf(sc->vr_dev,
+		    "failed to allocate DMA'able memory for Rx ring\n");
+		goto fail;
+	}
+
+	ctx.vr_busaddr = 0;
+	error = bus_dmamap_load(sc->vr_cdata.vr_rx_ring_tag,
+	    sc->vr_cdata.vr_rx_ring_map, sc->vr_rdata.vr_rx_ring,
+	    VR_RX_RING_SIZE, vr_dmamap_cb, &ctx, 0);
+	if (error != 0 || ctx.vr_busaddr == 0) {
+		device_printf(sc->vr_dev,
+		    "failed to load DMA'able memory for Rx ring\n");
+		goto fail;
+	}
+	sc->vr_rdata.vr_rx_ring_paddr = ctx.vr_busaddr;
+
+	/* Create DMA maps for Tx buffers. */
+	for (i = 0; i < VR_TX_RING_CNT; i++) {
+		txd = &sc->vr_cdata.vr_txdesc[i];
+		txd->tx_m = NULL;
+		txd->tx_dmamap = NULL;
+		error = bus_dmamap_create(sc->vr_cdata.vr_tx_tag, 0,
+		    &txd->tx_dmamap);
+		if (error != 0) {
+			device_printf(sc->vr_dev,
+			    "failed to create Tx dmamap\n");
+			goto fail;
+		}
+	}

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list