Index: if_nfe.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/nfe/if_nfe.c,v
retrieving revision 1.21.2.4
diff -u -p -r1.21.2.4 if_nfe.c
--- if_nfe.c	18 Mar 2008 00:42:26 -0000	1.21.2.4
+++ if_nfe.c	26 Apr 2008 16:46:04 -0000
@@ -1050,15 +1050,11 @@ nfe_alloc_rx_ring(struct nfe_softc *sc, 
 	void *desc;
 	int i, error, descsize;
 
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->desc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->desc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
+	desc = ring->desc;
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
 
-	ring->cur = ring->next = 0;
+	ring->cur = 0;
 
 	error = bus_dma_tag_create(sc->nfe_parent_tag,
 	    NFE_RING_ALIGN, 0,			/* alignment, boundary */
@@ -1075,17 +1071,14 @@ nfe_alloc_rx_ring(struct nfe_softc *sc, 
 		goto fail;
 	}
 
-	/* allocate memory to desc */
+	/* allocate memory to desc - XXX do we need a temporary desc ? */
 	error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK |
 	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map);
 	if (error != 0) {
 		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
 		goto fail;
 	}
-	if (sc->nfe_flags & NFE_40BIT_ADDR)
-		ring->desc64 = desc;
-	else
-		ring->desc32 = desc;
+	ring->desc = desc;
 
 	/* map desc to device visible address space */
 	ctx.nfe_busaddr = 0;
@@ -1158,15 +1151,11 @@ nfe_alloc_jrx_ring(struct nfe_softc *sc,
 		return;
 	}
 
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->jdesc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->jdesc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
+	desc = ring->jdesc;
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
 
-	ring->jcur = ring->jnext = 0;
+	ring->jcur = 0;
 
 	/* Create DMA tag for jumbo Rx ring. */
 	error = bus_dma_tag_create(sc->nfe_parent_tag,
@@ -1230,10 +1219,7 @@ nfe_alloc_jrx_ring(struct nfe_softc *sc,
 		    "could not allocate DMA'able memory for jumbo Rx ring\n");
 		goto fail;
 	}
-	if (sc->nfe_flags & NFE_40BIT_ADDR)
-		ring->jdesc64 = desc;
-	else
-		ring->jdesc32 = desc;
+	ring->jdesc = desc;
 
 	ctx.nfe_busaddr = 0;
 	error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc,
@@ -1323,19 +1309,13 @@ fail:
 static int
 nfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
 {
-	void *desc;
 	size_t descsize;
 	int i;
 
-	ring->cur = ring->next = 0;
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->desc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->desc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
-	bzero(desc, descsize * NFE_RX_RING_COUNT);
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
+	ring->cur = 0;
+	bzero(ring->desc, descsize * NFE_RX_RING_COUNT);
 	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
 		if (nfe_newbuf(sc, i) != 0)
 			return (ENOBUFS);
@@ -1351,19 +1331,13 @@ nfe_init_rx_ring(struct nfe_softc *sc, s
 static int
 nfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring)
 {
-	void *desc;
 	size_t descsize;
 	int i;
 
-	ring->jcur = ring->jnext = 0;
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->jdesc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->jdesc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
-	bzero(desc, descsize * NFE_RX_RING_COUNT);
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
+	ring->jcur = 0;
+	bzero(ring->jdesc, descsize * NFE_RX_RING_COUNT);
 	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
 		if (nfe_jnewbuf(sc, i) != 0)
 			return (ENOBUFS);
@@ -1380,16 +1354,10 @@ static void
 nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring)
 {
 	struct nfe_rx_data *data;
-	void *desc;
 	int i, descsize;
 
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->desc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->desc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
 
 	for (i = 0; i < NFE_RX_RING_COUNT; i++) {
 		data = &ring->data[i];
@@ -1413,11 +1381,10 @@ nfe_free_rx_ring(struct nfe_softc *sc, s
 		ring->rx_data_tag = NULL;
 	}
 
-	if (desc != NULL) {
+	if (ring->desc != NULL) {
 		bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map);
-		bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map);
-		ring->desc64 = NULL;
-		ring->desc32 = NULL;
+		bus_dmamem_free(ring->rx_desc_tag, ring->desc, ring->rx_desc_map);
+		ring->desc = NULL;
 		ring->rx_desc_map = NULL;
 	}
 	if (ring->rx_desc_tag != NULL) {
@@ -1432,7 +1399,6 @@ nfe_free_jrx_ring(struct nfe_softc *sc, 
 {
 	struct nfe_jpool_entry *entry;
 	struct nfe_rx_data *data;
-	void *desc;
 	int i, descsize;
 
 	if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0)
@@ -1454,13 +1420,8 @@ nfe_free_jrx_ring(struct nfe_softc *sc, 
 	}
         NFE_JLIST_UNLOCK(sc);
 
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->jdesc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->jdesc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
 
 	for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) {
 		data = &ring->jdata[i];
@@ -1484,11 +1445,10 @@ nfe_free_jrx_ring(struct nfe_softc *sc, 
 		ring->jrx_data_tag = NULL;
 	}
 
-	if (desc != NULL) {
+	if (ring->jdesc != NULL) {
 		bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map);
-		bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map);
-		ring->jdesc64 = NULL;
-		ring->jdesc32 = NULL;
+		bus_dmamem_free(ring->jrx_desc_tag, ring->jdesc, ring->jrx_desc_map);
+		ring->jdesc = NULL;
 		ring->jrx_desc_map = NULL;
 	}
 	/* Destroy jumbo buffer block. */
@@ -1515,13 +1475,9 @@ nfe_alloc_tx_ring(struct nfe_softc *sc, 
 	void *desc;
 	int descsize;
 
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->desc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->desc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
+	desc = ring->desc;
 
 	ring->queued = 0;
 	ring->cur = ring->next = 0;
@@ -1547,10 +1503,7 @@ nfe_alloc_tx_ring(struct nfe_softc *sc, 
 		device_printf(sc->nfe_dev, "could not create desc DMA map\n");
 		goto fail;
 	}
-	if (sc->nfe_flags & NFE_40BIT_ADDR)
-		ring->desc64 = desc;
-	else
-		ring->desc32 = desc;
+	ring->desc = desc;
 
 	ctx.nfe_busaddr = 0;
 	error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc,
@@ -1595,20 +1548,14 @@ fail:
 static void
 nfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
 {
-	void *desc;
 	size_t descsize;
 
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
 	sc->nfe_force_tx = 0;
 	ring->queued = 0;
 	ring->cur = ring->next = 0;
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->desc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->desc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
-	bzero(desc, descsize * NFE_TX_RING_COUNT);
+	bzero(ring->desc, descsize * NFE_TX_RING_COUNT);
 
 	bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
@@ -1619,16 +1566,10 @@ static void
 nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring)
 {
 	struct nfe_tx_data *data;
-	void *desc;
 	int i, descsize;
 
-	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc = ring->desc64;
-		descsize = sizeof (struct nfe_desc64);
-	} else {
-		desc = ring->desc32;
-		descsize = sizeof (struct nfe_desc32);
-	}
+	descsize = (sc->nfe_flags & NFE_40BIT_ADDR) ?
+		sizeof (struct nfe_desc64) : sizeof (struct nfe_desc32);
 
 	for (i = 0; i < NFE_TX_RING_COUNT; i++) {
 		data = &ring->data[i];
@@ -1652,13 +1593,12 @@ nfe_free_tx_ring(struct nfe_softc *sc, s
 		ring->tx_data_tag = NULL;
 	}
 
-	if (desc != NULL) {
+	if (ring->desc != NULL) {
 		bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map,
 		    BUS_DMASYNC_POSTWRITE);
 		bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map);
-		bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map);
-		ring->desc64 = NULL;
-		ring->desc32 = NULL;
+		bus_dmamem_free(ring->tx_desc_tag, ring->desc, ring->tx_desc_map);
+		ring->desc = NULL;
 		ring->tx_desc_map = NULL;
 		bus_dma_tag_destroy(ring->tx_desc_tag);
 		ring->tx_desc_tag = NULL;
@@ -1902,23 +1842,30 @@ nfe_intr(void *arg)
 	return (FILTER_HANDLED);
 }
 
-
 static void
 nfe_int_task(void *arg, int pending)
 {
 	struct nfe_softc *sc = arg;
 	struct ifnet *ifp = sc->nfe_ifp;
 	uint32_t r;
-	int domore;
 
 	NFE_LOCK(sc);
 
-	if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) {
-		nfe_enable_intr(sc);
-		NFE_UNLOCK(sc);
-		return;	/* not for us */
+	r = NFE_READ(sc, sc->nfe_irq_status);
+	if (r == 0 && sc->domore == 0)
+		goto done;	/* not for us, or no more work to do */
+	if (r) {
+		NFE_WRITE(sc, sc->nfe_irq_status, r);
+		if (r & (NFE_IRQ_RXERR | NFE_IRQ_RX_NOBUF)) {
+			/*
+			 * Potential stall in the receiver. Record the
+			 * irq_status in sc->needreset and later call
+			 * nfe_intr_locked() to restart the receiver.
+			 */
+			sc->nfe_rxringfull++;
+			sc->needreset = r;
+		}
 	}
-	NFE_WRITE(sc, sc->nfe_irq_status, r);
 
 	DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r);
 
@@ -1935,41 +1882,62 @@ nfe_int_task(void *arg, int pending)
 		DPRINTF(sc, "link state changed\n");
 	}
 
-	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
-		NFE_UNLOCK(sc);
-		nfe_enable_intr(sc);
-		return;
-	}
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		goto done;
 
-	domore = 0;
 	/* check Rx ring */
 	if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN)
-		domore = nfe_jrxeof(sc, sc->nfe_process_limit);
+		sc->domore = nfe_jrxeof(sc, sc->nfe_process_limit);
 	else
-		domore = nfe_rxeof(sc, sc->nfe_process_limit);
+		sc->domore = nfe_rxeof(sc, sc->nfe_process_limit);
 	/* check Tx ring */
 	nfe_txeof(sc);
 
 	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task);
 
-	NFE_UNLOCK(sc);
-
-	if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) {
+	if (sc->domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) {
 		taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task);
+		NFE_UNLOCK(sc);
 		return;
 	}
 
-	/* Reenable interrupts. */
+done:
+	/* Reenable interrupts, check if need reset, and unlock */
 	nfe_enable_intr(sc);
+	if (sc->needreset) {
+		if (1)
+			printf("%s reset, error 0x%x\n",
+				__FUNCTION__, sc->needreset);
+		/*
+		 * We only need to restart the receiver. nfe_init_locked()
+		 * does a lot more than that, but we don't have yet a better
+		 * way to deal with just the receiver.
+		 * In particular, clearing and setting NFE_RX_START
+		 * in NFE_RX_CTL does not restart the receiver correctly.
+		 */
+#if 1
+		ifp->if_drv_flags &= ~IFF_DRV_RUNNING; /* force init_locked */
+		nfe_init_locked(sc);
+#else
+		/* The code in this #else block does not help. */
+		sc->needreset = 0;
+		r = NFE_READ(sc, NFE_RX_CTL);
+		NFE_WRITE(sc, NFE_RX_CTL, r & ~NFE_RX_START);
+		DELAY(30);
+		r = NFE_READ(sc, NFE_RX_CTL);
+		DELAY(30);
+		NFE_WRITE(sc, NFE_RX_CTL, r | NFE_RX_START);
+		DELAY(30);
+#endif
+	}
+	NFE_UNLOCK(sc);
 }
 
 
 static __inline void
 nfe_discard_rxbuf(struct nfe_softc *sc, int idx)
 {
-	struct nfe_desc32 *desc32;
-	struct nfe_desc64 *desc64;
 	struct nfe_rx_data *data;
 	struct mbuf *m;
 
@@ -1977,14 +1945,14 @@ nfe_discard_rxbuf(struct nfe_softc *sc, 
 	m = data->m;
 
 	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc64 = &sc->rxq.desc64[idx];
+		struct nfe_desc64 *desc64 = ((struct nfe_desc64 *)sc->rxq.desc) + idx;
 		/* VLAN packet may have overwritten it. */
 		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
 		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
 		desc64->length = htole16(m->m_len);
 		desc64->flags = htole16(NFE_RX_READY);
 	} else {
-		desc32 = &sc->rxq.desc32[idx];
+		struct nfe_desc32 *desc32 = ((struct nfe_desc32 *)sc->rxq.desc) + idx;
 		desc32->length = htole16(m->m_len);
 		desc32->flags = htole16(NFE_RX_READY);
 	}
@@ -1994,8 +1962,6 @@ nfe_discard_rxbuf(struct nfe_softc *sc, 
 static __inline void
 nfe_discard_jrxbuf(struct nfe_softc *sc, int idx)
 {
-	struct nfe_desc32 *desc32;
-	struct nfe_desc64 *desc64;
 	struct nfe_rx_data *data;
 	struct mbuf *m;
 
@@ -2003,14 +1969,14 @@ nfe_discard_jrxbuf(struct nfe_softc *sc,
 	m = data->m;
 
 	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc64 = &sc->jrxq.jdesc64[idx];
+		struct nfe_desc64 *desc64 = ((struct nfe_desc64 *)sc->jrxq.jdesc) + idx;
 		/* VLAN packet may have overwritten it. */
 		desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr));
 		desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr));
 		desc64->length = htole16(m->m_len);
 		desc64->flags = htole16(NFE_RX_READY);
 	} else {
-		desc32 = &sc->jrxq.jdesc32[idx];
+		struct nfe_desc32 *desc32 = ((struct nfe_desc32 *)sc->jrxq.jdesc) + idx;
 		desc32->length = htole16(m->m_len);
 		desc32->flags = htole16(NFE_RX_READY);
 	}
@@ -2021,8 +1987,6 @@ static int
 nfe_newbuf(struct nfe_softc *sc, int idx)
 {
 	struct nfe_rx_data *data;
-	struct nfe_desc32 *desc32;
-	struct nfe_desc64 *desc64;
 	struct mbuf *m;
 	bus_dma_segment_t segs[1];
 	bus_dmamap_t map;
@@ -2057,13 +2021,13 @@ nfe_newbuf(struct nfe_softc *sc, int idx
 	data->m = m;
 	/* update mapping address in h/w descriptor */
 	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc64 = &sc->rxq.desc64[idx];
+		struct nfe_desc64 *desc64 = ((struct nfe_desc64 *)sc->rxq.desc) + idx;
 		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
 		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
 		desc64->length = htole16(segs[0].ds_len);
 		desc64->flags = htole16(NFE_RX_READY);
 	} else {
-		desc32 = &sc->rxq.desc32[idx];
+		struct nfe_desc32 *desc32 = ((struct nfe_desc32 *)sc->rxq.desc) + idx;
 		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
 		desc32->length = htole16(segs[0].ds_len);
 		desc32->flags = htole16(NFE_RX_READY);
@@ -2077,8 +2041,6 @@ static int
 nfe_jnewbuf(struct nfe_softc *sc, int idx)
 {
 	struct nfe_rx_data *data;
-	struct nfe_desc32 *desc32;
-	struct nfe_desc64 *desc64;
 	struct mbuf *m;
 	bus_dma_segment_t segs[1];
 	bus_dmamap_t map;
@@ -2125,13 +2087,13 @@ nfe_jnewbuf(struct nfe_softc *sc, int id
 	data->m = m;
 	/* update mapping address in h/w descriptor */
 	if (sc->nfe_flags & NFE_40BIT_ADDR) {
-		desc64 = &sc->jrxq.jdesc64[idx];
+		struct nfe_desc64 *desc64 = ((struct nfe_desc64 *)sc->jrxq.jdesc) + idx;
 		desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr));
 		desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr));
 		desc64->length = htole16(segs[0].ds_len);
 		desc64->flags = htole16(NFE_RX_READY);
 	} else {
-		desc32 = &sc->jrxq.jdesc32[idx];
+		struct nfe_desc32 *desc32 = ((struct nfe_desc32 *)sc->jrxq.jdesc) + idx;
 		desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr));
 		desc32->length = htole16(segs[0].ds_len);
 		desc32->flags = htole16(NFE_RX_READY);
@@ -2145,33 +2107,34 @@ static int
 nfe_rxeof(struct nfe_softc *sc, int count)
 {
 	struct ifnet *ifp = sc->nfe_ifp;
-	struct nfe_desc32 *desc32;
-	struct nfe_desc64 *desc64;
 	struct nfe_rx_data *data;
 	struct mbuf *m;
 	uint16_t flags;
 	int len, prog;
-	uint32_t vtag = 0;
 
 	NFE_LOCK_ASSERT(sc);
 
 	bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map,
 	    BUS_DMASYNC_POSTREAD);
 
-	for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) {
+	for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT)) {
+		uint32_t vtag;
+		int idx = sc->rxq.cur;
+
 		if (count <= 0)
 			break;
 		count--;
-
-		data = &sc->rxq.data[sc->rxq.cur];
+		
+		data = &sc->rxq.data[idx];
 
 		if (sc->nfe_flags & NFE_40BIT_ADDR) {
-			desc64 = &sc->rxq.desc64[sc->rxq.cur];
+			struct nfe_desc64 *desc64 = ((struct nfe_desc64 *)sc->rxq.desc) + idx;
 			vtag = le32toh(desc64->physaddr[1]);
 			flags = le16toh(desc64->flags);
 			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
 		} else {
-			desc32 = &sc->rxq.desc32[sc->rxq.cur];
+			struct nfe_desc32 *desc32 = ((struct nfe_desc32 *)sc->rxq.desc) + idx;
+			vtag = 0;
 			flags = le16toh(desc32->flags);
 			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
 		}
@@ -2182,7 +2145,7 @@ nfe_rxeof(struct nfe_softc *sc, int coun
 		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
 			if (!(flags & NFE_RX_VALID_V1)) {
 				ifp->if_ierrors++;
-				nfe_discard_rxbuf(sc, sc->rxq.cur);
+				nfe_discard_rxbuf(sc, idx);
 				continue;
 			}
 			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
@@ -2192,7 +2155,7 @@ nfe_rxeof(struct nfe_softc *sc, int coun
 		} else {
 			if (!(flags & NFE_RX_VALID_V2)) {
 				ifp->if_ierrors++;
-				nfe_discard_rxbuf(sc, sc->rxq.cur);
+				nfe_discard_rxbuf(sc, idx);
 				continue;
 			}
 
@@ -2204,14 +2167,14 @@ nfe_rxeof(struct nfe_softc *sc, int coun
 
 		if (flags & NFE_RX_ERROR) {
 			ifp->if_ierrors++;
-			nfe_discard_rxbuf(sc, sc->rxq.cur);
+			nfe_discard_rxbuf(sc, idx);
 			continue;
 		}
 
 		m = data->m;
-		if (nfe_newbuf(sc, sc->rxq.cur) != 0) {
+		if (nfe_newbuf(sc, idx) != 0) {
 			ifp->if_iqdrops++;
-			nfe_discard_rxbuf(sc, sc->rxq.cur);
+			nfe_discard_rxbuf(sc, idx);
 			continue;
 		}
 
@@ -2256,21 +2219,19 @@ static int
 nfe_jrxeof(struct nfe_softc *sc, int count)
 {
 	struct ifnet *ifp = sc->nfe_ifp;
-	struct nfe_desc32 *desc32;
-	struct nfe_desc64 *desc64;
 	struct nfe_rx_data *data;
 	struct mbuf *m;
 	uint16_t flags;
 	int len, prog;
-	uint32_t vtag = 0;
 
 	NFE_LOCK_ASSERT(sc);
 
 	bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map,
 	    BUS_DMASYNC_POSTREAD);
 
-	for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT),
-	    vtag = 0) {
+	for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT)) {
+		uint32_t vtag;
+	    	int idx = sc->jrxq.jcur;
 		if (count <= 0)
 			break;
 		count--;
@@ -2278,12 +2239,13 @@ nfe_jrxeof(struct nfe_softc *sc, int cou
 		data = &sc->jrxq.jdata[sc->jrxq.jcur];
 
 		if (sc->nfe_flags & NFE_40BIT_ADDR) {
-			desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur];
+			struct nfe_desc64 *desc64 = ((struct nfe_desc64 *)sc->jrxq.jdesc) + idx;
 			vtag = le32toh(desc64->physaddr[1]);
 			flags = le16toh(desc64->flags);
 			len = le16toh(desc64->length) & NFE_RX_LEN_MASK;
 		} else {
-			desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur];
+			struct nfe_desc32 *desc32 = ((struct nfe_desc32 *)sc->jrxq.jdesc) + idx;
+			vtag = 0;
 			flags = le16toh(desc32->flags);
 			len = le16toh(desc32->length) & NFE_RX_LEN_MASK;
 		}
@@ -2294,7 +2256,7 @@ nfe_jrxeof(struct nfe_softc *sc, int cou
 		if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) {
 			if (!(flags & NFE_RX_VALID_V1)) {
 				ifp->if_ierrors++;
-				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
+				nfe_discard_jrxbuf(sc, idx);
 				continue;
 			}
 			if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) {
@@ -2304,7 +2266,7 @@ nfe_jrxeof(struct nfe_softc *sc, int cou
 		} else {
 			if (!(flags & NFE_RX_VALID_V2)) {
 				ifp->if_ierrors++;
-				nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
+				nfe_discard_jrxbuf(sc, idx);
 				continue;
 			}
 
@@ -2316,14 +2278,14 @@ nfe_jrxeof(struct nfe_softc *sc, int cou
 
 		if (flags & NFE_RX_ERROR) {
 			ifp->if_ierrors++;
-			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
+			nfe_discard_jrxbuf(sc, idx);
 			continue;
 		}
 
 		m = data->m;
-		if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) {
+		if (nfe_jnewbuf(sc, idx) != 0) {
 			ifp->if_iqdrops++;
-			nfe_discard_jrxbuf(sc, sc->jrxq.jcur);
+			nfe_discard_jrxbuf(sc, idx);
 			continue;
 		}
 
@@ -2368,10 +2330,6 @@ static void
 nfe_txeof(struct nfe_softc *sc)
 {
 	struct ifnet *ifp = sc->nfe_ifp;
-	struct nfe_desc32 *desc32;
-	struct nfe_desc64 *desc64;
-	struct nfe_tx_data *data = NULL;
-	uint16_t flags;
 	int cons, prog;
 
 	NFE_LOCK_ASSERT(sc);
@@ -2382,11 +2340,14 @@ nfe_txeof(struct nfe_softc *sc)
 	prog = 0;
 	for (cons = sc->txq.next; cons != sc->txq.cur;
 	    NFE_INC(cons, NFE_TX_RING_COUNT)) {
+		struct nfe_tx_data *data;
+		uint16_t flags;
+
 		if (sc->nfe_flags & NFE_40BIT_ADDR) {
-			desc64 = &sc->txq.desc64[cons];
+			struct nfe_desc64 *desc64 = ((struct nfe_desc64 *)sc->txq.desc) + cons;
 			flags = le16toh(desc64->flags);
 		} else {
-			desc32 = &sc->txq.desc32[cons];
+			struct nfe_desc32 *desc32 = ((struct nfe_desc32 *)sc->txq.desc) + cons;
 			flags = le16toh(desc32->flags);
 		}
 
@@ -2439,8 +2400,8 @@ nfe_txeof(struct nfe_softc *sc)
 static int
 nfe_encap(struct nfe_softc *sc, struct mbuf **m_head)
 {
-	struct nfe_desc32 *desc32 = NULL;
-	struct nfe_desc64 *desc64 = NULL;
+	struct nfe_desc32 *desc32 = NULL; /* silence compiler, but desc32/64 */
+	struct nfe_desc64 *desc64 = NULL; /* are correctly set later. */
 	bus_dmamap_t map;
 	bus_dma_segment_t segs[NFE_MAX_SCATTER];
 	int error, i, nsegs, prod, si;
@@ -2448,6 +2409,7 @@ nfe_encap(struct nfe_softc *sc, struct m
 	uint16_t cflags, flags;
 	struct mbuf *m;
 
+	/* si is the starting index */
 	prod = si = sc->txq.cur;
 	map = sc->txq.data[prod].tx_data_map;
 
@@ -2501,7 +2463,7 @@ nfe_encap(struct nfe_softc *sc, struct m
 
 	for (i = 0; i < nsegs; i++) {
 		if (sc->nfe_flags & NFE_40BIT_ADDR) {
-			desc64 = &sc->txq.desc64[prod];
+			desc64 = ((struct nfe_desc64 *)sc->txq.desc) + prod;
 			desc64->physaddr[0] =
 			    htole32(NFE_ADDR_HI(segs[i].ds_addr));
 			desc64->physaddr[1] =
@@ -2510,7 +2472,7 @@ nfe_encap(struct nfe_softc *sc, struct m
 			desc64->length = htole16(segs[i].ds_len - 1);
 			desc64->flags = htole16(flags);
 		} else {
-			desc32 = &sc->txq.desc32[prod];
+			desc32 = ((struct nfe_desc32 *)sc->txq.desc) + prod;
 			desc32->physaddr =
 			    htole32(NFE_ADDR_LO(segs[i].ds_addr));
 			desc32->length = htole16(segs[i].ds_len - 1);
@@ -2533,7 +2495,7 @@ nfe_encap(struct nfe_softc *sc, struct m
 	 */
 	if (sc->nfe_flags & NFE_40BIT_ADDR) {
 		desc64->flags |= htole16(NFE_TX_LASTFRAG_V2);
-		desc64 = &sc->txq.desc64[si];
+		desc64 = ((struct nfe_desc64 *)sc->txq.desc) + si;
 		if ((m->m_flags & M_VLANTAG) != 0)
 			desc64->vtag = htole32(NFE_TX_VTAG |
 			    m->m_pkthdr.ether_vtag);
@@ -2556,7 +2518,7 @@ nfe_encap(struct nfe_softc *sc, struct m
 			desc32->flags |= htole16(NFE_TX_LASTFRAG_V2);
 		else
 			desc32->flags |= htole16(NFE_TX_LASTFRAG_V1);
-		desc32 = &sc->txq.desc32[si];
+		desc32 = ((struct nfe_desc32 *)sc->txq.desc) + si;
 		if (tso_segsz != 0) {
 			/*
 			 * XXX
@@ -2710,6 +2672,32 @@ static void
 nfe_watchdog(struct ifnet *ifp)
 {
 	struct nfe_softc *sc = ifp->if_softc;
+	/*
+	 * Some hardware has stats counters for various events.
+	 * Most if not all of them are 'reset-on'read' so we need to
+	 * accumulate totals in the 'sc'.
+	 * To read and report these numbers (e.g. for debugging purposes)
+	 * change the 'if (0)' to 'if (1)'.
+	 */
+    if (0) {
+	uint32_t a, b, rx, drop, err, ov;
+
+	a = NFE_READ(sc, NFE_RX_CTL);
+	b = NFE_READ(sc, NFE_RX_STATUS);
+	rx = NFE_READ(sc, 0x02dc); /* rx receive count (bytes) */
+	drop = NFE_READ(sc, 0x02e8); /* rx drop frames */
+	err = NFE_READ(sc, 0x02a4); /* rx frame error */
+	ov = NFE_READ(sc, 0x02b8); /* rx overflows */
+	sc->nfe_rxbytes += rx;
+	sc->nfe_rxdrop += drop;
+	sc->nfe_rxerr += err;
+	sc->nfe_rxoverflow += ov;
+	
+	printf("%s rx ctl 0x%x stat 0x%x count %llu/0x%x drop %d err %d ov %d ringfull %d\n",
+		__FUNCTION__, a, b, sc->nfe_rxbytes, rx,
+		sc->nfe_rxdrop, sc->nfe_rxerr,
+		sc->nfe_rxoverflow, sc->nfe_rxringfull);
+    }
 
 	if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer)
 		return;
@@ -2772,6 +2760,7 @@ nfe_init_locked(void *xsc)
 
 	nfe_stop(ifp);
 
+	sc->needreset = 0;
 	sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS;
 
 	nfe_init_tx_ring(sc, &sc->txq);
@@ -2888,8 +2877,10 @@ nfe_init_locked(void *xsc)
 		nfe_disable_intr(sc);
 	else
 #endif
-	nfe_set_intr(sc);
-	nfe_enable_intr(sc); /* enable interrupts */
+	{
+		nfe_set_intr(sc);
+		nfe_enable_intr(sc); /* enable interrupts */
+	}
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
Index: if_nfevar.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/nfe/if_nfevar.h,v
retrieving revision 1.5
diff -u -p -r1.5 if_nfevar.h
--- if_nfevar.h	24 Jul 2007 01:11:00 -0000	1.5
+++ if_nfevar.h	26 Apr 2008 08:42:47 -0000
@@ -27,8 +27,7 @@ struct nfe_tx_ring {
 	bus_dma_tag_t		tx_desc_tag;
 	bus_dmamap_t		tx_desc_map;
 	bus_addr_t		physaddr;
-	struct nfe_desc32	*desc32;
-	struct nfe_desc64	*desc64;
+	void			*desc; /* either nfe_desc32 or nfe_desc64 */
 	bus_dma_tag_t		tx_data_tag;
 	struct nfe_tx_data	data[NFE_TX_RING_COUNT];
 	int			queued;
@@ -51,13 +50,11 @@ struct nfe_rx_ring {
 	bus_dma_tag_t		rx_desc_tag;
 	bus_dmamap_t		rx_desc_map;
 	bus_addr_t		physaddr;
-	struct nfe_desc32	*desc32;
-	struct nfe_desc64	*desc64;
+	void			*desc; /* either nfe_desc32 or nfe_desc64 */
 	bus_dma_tag_t		rx_data_tag;
 	bus_dmamap_t		rx_spare_map;
 	struct nfe_rx_data	data[NFE_RX_RING_COUNT];
 	int			cur;
-	int			next;
 };
 
 struct nfe_jrx_ring {
@@ -68,13 +65,11 @@ struct nfe_jrx_ring {
 	void			*jpool;
 	caddr_t			jslots[NFE_JSLOTS];
 	bus_addr_t		jphysaddr;
-	struct nfe_desc32	*jdesc32;
-	struct nfe_desc64	*jdesc64;
+	void			*jdesc; /* either nfe_desc32 or nfe_desc64 */
 	bus_dma_tag_t		jrx_data_tag;
 	bus_dmamap_t		jrx_spare_map;
 	struct nfe_rx_data	jdata[NFE_JUMBO_RX_RING_COUNT];
 	int			jcur;
-	int			jnext;
 };
 
 struct nfe_softc {
@@ -123,6 +118,16 @@ struct nfe_softc {
 	uint32_t		nfe_msi;
 	uint32_t		nfe_msix;
 
+	uint32_t		needreset;	/* stall detected in int_task */
+	uint32_t		domore;		/* pending work for int_task */
+
+	/* stats fields */
+	uint32_t		nfe_rxringfull;	/* how many times the rx ring was full */
+	uint64_t		nfe_rxbytes;	/* received bytes */
+	uint32_t		nfe_rxdrop;	/* dropped packets */
+	uint32_t		nfe_rxoverflow;	/* overflows ? */
+	uint32_t		nfe_rxerr;	/* rx errors */
+
 	struct nfe_tx_ring	txq;
 	struct nfe_rx_ring	rxq;
 	struct nfe_jrx_ring	jrxq;
