Module Name:    src
Committed By:   martin
Date:           Wed Oct  8 18:24:21 UTC 2014

Modified Files:
        src/sys/dev/ic: dwc_gmac.c

Log Message:
More interrupt handling, more debug code, less magic numbers.


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/ic/dwc_gmac.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/dwc_gmac.c
diff -u src/sys/dev/ic/dwc_gmac.c:1.7 src/sys/dev/ic/dwc_gmac.c:1.8
--- src/sys/dev/ic/dwc_gmac.c:1.7	Sun Sep 14 18:28:37 2014
+++ src/sys/dev/ic/dwc_gmac.c	Wed Oct  8 18:24:21 2014
@@ -39,7 +39,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.7 2014/09/14 18:28:37 martin Exp $");
+__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.8 2014/10/08 18:24:21 martin Exp $");
 
 /* #define	DWC_GMAC_DEBUG	1 */
 
@@ -86,17 +86,37 @@ static void dwc_gmac_stop(struct ifnet *
 static void dwc_gmac_start(struct ifnet *ifp);
 static int dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0);
 static int dwc_gmac_ioctl(struct ifnet *, u_long, void *);
-
+static void dwc_gmac_tx_intr(struct dwc_gmac_softc *sc);
+static void dwc_gmac_rx_intr(struct dwc_gmac_softc *sc);
 
 #define	TX_DESC_OFFSET(N)	((AWGE_RX_RING_COUNT+(N)) \
 				    *sizeof(struct dwc_gmac_dev_dmadesc))
+#define	TX_NEXT(N)		(((N)+1) & (AWGE_TX_RING_COUNT-1))
 
 #define RX_DESC_OFFSET(N)	((N)*sizeof(struct dwc_gmac_dev_dmadesc))
+#define	RX_NEXT(N)		(((N)+1) & (AWGE_RX_RING_COUNT-1))
+
+
+
+#define	GMAC_DEF_DMA_INT_MASK	(GMAC_DMA_INT_TIE|GMAC_DMA_INT_RIE| \
+				GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE| \
+				GMAC_DMA_INT_FBE|GMAC_DMA_INT_UNE)
+
+#define	GMAC_DMA_INT_ERRORS	(GMAC_DMA_INT_AIE|GMAC_DMA_INT_ERE| \
+				GMAC_DMA_INT_FBE|GMAC_DMA_INT_ETE| \
+				GMAC_DMA_INT_RWE|GMAC_DMA_INT_RUE| \
+				GMAC_DMA_INT_UNE|GMAC_DMA_INT_OVE| \
+				GMAC_DMA_INT_TJE|GMAC_DMA_INT_TUE)
+
+#define	AWIN_DEF_MAC_INTRMASK	\
+	(AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG |	\
+	AWIN_GMAC_MAC_INT_LINKCHG | AWIN_GMAC_MAC_INT_RGSMII)
 
 
 #ifdef DWC_GMAC_DEBUG
 static void dwc_gmac_dump_dma(struct dwc_gmac_softc *sc);
 static void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc);
+static void dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg);
 #endif
 
 void
@@ -127,8 +147,10 @@ dwc_gmac_attach(struct dwc_gmac_softc *s
 		 * try to read one from the current filter setup,
 		 * before resetting the chip.
 		 */
-		maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO);
-		machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI);
+		maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+		    AWIN_GMAC_MAC_ADDR0LO);
+		machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+		    AWIN_GMAC_MAC_ADDR0HI);
 		enaddr[0] = maclo & 0x0ff;
 		enaddr[1] = (maclo >> 8) & 0x0ff;
 		enaddr[2] = (maclo >> 16) & 0x0ff;
@@ -137,10 +159,6 @@ dwc_gmac_attach(struct dwc_gmac_softc *s
 		enaddr[5] = (machi >> 8) & 0x0ff;
 	}
 
-#ifdef DWC_GMAC_DEBUG
-	dwc_gmac_dump_dma(sc);
-#endif
-
 	/*
 	 * Init chip and do intial setup
 	 */
@@ -210,8 +228,10 @@ dwc_gmac_attach(struct dwc_gmac_softc *s
 	/*
 	 * Enable interrupts
 	 */
-	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR, AWIN_DEF_MAC_INTRMASK);
-	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE, GMAC_DEF_DMA_INT_MASK);
+	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR,
+	    AWIN_DEF_MAC_INTRMASK);
+	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE,
+	    GMAC_DEF_DMA_INT_MASK);
 
 	return;
 
@@ -364,7 +384,7 @@ dwc_gmac_alloc_rx_ring(struct dwc_gmac_s
 
 		desc = &sc->sc_rxq.r_desc[i];
 		desc->ddesc_data = htole32(physaddr);
-		next = (i+1) % AWGE_RX_RING_COUNT;
+		next = RX_NEXT(i);
 		desc->ddesc_next = htole32(ring->r_physaddr 
 		    + next * sizeof(*desc));
 		desc->ddesc_cntl = htole32(
@@ -528,7 +548,7 @@ dwc_gmac_alloc_tx_ring(struct dwc_gmac_s
 		}
 		ring->t_desc[i].ddesc_next = htole32(
 		    ring->t_physaddr + sizeof(struct dwc_gmac_dev_dmadesc)
-		    *((i+1)%AWGE_TX_RING_COUNT));
+		    *TX_NEXT(i));
 	}
 
 	return 0;
@@ -706,11 +726,6 @@ dwc_gmac_start(struct ifnet *ifp)
 		    bus_space_read_4(sc->sc_bst, sc->sc_bsh,
 		        AWIN_GMAC_DMA_OPMODE) | GMAC_DMA_OP_TXSTART);
 	}
-
-#ifdef DWC_GMAC_DEBUG
-	dwc_gmac_dump_dma(sc);
-	dwc_gmac_dump_tx_desc(sc);
-#endif
 }
 
 static void
@@ -745,6 +760,11 @@ dwc_gmac_queue(struct dwc_gmac_softc *sc
 	uint32_t flags, len;
 	int error, i, first;
 
+#ifdef DWC_GMAC_DEBUG
+	aprint_normal_dev(sc->sc_dev,
+	    "dwc_gmac_queue: adding mbuf chain %p\n", m0);
+#endif
+
 	first = sc->sc_txq.t_cur;
 	map = sc->sc_txq.t_data[first].td_map;
 	flags = 0;
@@ -763,23 +783,24 @@ dwc_gmac_queue(struct dwc_gmac_softc *sc
 	}
 
 	data = NULL;
-	flags = DDESC_CNTL_TXFIRST|DDESC_CNTL_TXINT|DDESC_CNTL_TXCHAIN;
+	flags = DDESC_CNTL_TXFIRST|DDESC_CNTL_TXCHAIN;
 	for (i = 0; i < map->dm_nsegs; i++) {
 		data = &sc->sc_txq.t_data[sc->sc_txq.t_cur];
+		desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur];
+
+		desc->ddesc_data = htole32(map->dm_segs[i].ds_addr);
+		len = __SHIFTIN(map->dm_segs[i].ds_len,DDESC_CNTL_SIZE1MASK);
+		if (i == map->dm_nsegs-1)
+			flags |= DDESC_CNTL_TXLAST|DDESC_CNTL_TXINT;
 
 #ifdef DWC_GMAC_DEBUG
 		aprint_normal_dev(sc->sc_dev, "enqueing desc #%d data %08lx "
-		    "len %lu\n", sc->sc_txq.t_cur,
+		    "len %lu (flags: %08x, len: %08x)\n", sc->sc_txq.t_cur,
 		    (unsigned long)map->dm_segs[i].ds_addr,
-		    (unsigned long)map->dm_segs[i].ds_len);
+		    (unsigned long)map->dm_segs[i].ds_len,
+		    flags, len);
 #endif
 
-		desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur];
-
-		desc->ddesc_data = htole32(map->dm_segs[i].ds_addr);
-		len = __SHIFTIN(map->dm_segs[i].ds_len,DDESC_CNTL_SIZE1MASK);
-		if (i == map->dm_nsegs-1)
-			flags |= DDESC_CNTL_TXLAST;
 		desc->ddesc_cntl = htole32(len|flags);
 		flags &= ~DDESC_CNTL_TXFIRST;
 
@@ -789,10 +810,9 @@ dwc_gmac_queue(struct dwc_gmac_softc *sc
 		 */
 		if (i)
 			desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
-		sc->sc_txq.t_queued++;
 
-		sc->sc_txq.t_cur = (sc->sc_txq.t_cur + 1)
-		    & (AWGE_TX_RING_COUNT-1);
+		sc->sc_txq.t_queued++;
+		sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur);
 	}
 
 	/* Pass first to device */
@@ -846,29 +866,105 @@ dwc_gmac_ioctl(struct ifnet *ifp, u_long
 	return error;
 }
 
+static void
+dwc_gmac_tx_intr(struct dwc_gmac_softc *sc)
+{
+	struct dwc_gmac_tx_data *data;
+	struct dwc_gmac_dev_dmadesc *desc;
+	uint32_t flags;
+	int i;
+
+	for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0;
+	    i = TX_NEXT(i), sc->sc_txq.t_queued--) {
+
+#ifdef DWC_GMAC_DEBUG
+		aprint_normal_dev(sc->sc_dev,
+		    "dwc_gmac_tx_intr: checking desc #%d (t_queued: %d)\n",
+		    i, sc->sc_txq.t_queued);
+#endif
+
+		desc = &sc->sc_txq.t_desc[i];
+		dwc_gmac_txdesc_sync(sc, i, i+1,
+		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+		flags = le32toh(desc->ddesc_status);
+		if (flags & DDESC_STATUS_OWNEDBYDEV)
+			break;
+		data = &sc->sc_txq.t_data[i];
+		if (data->td_m == NULL)
+			continue;
+		sc->sc_ec.ec_if.if_opackets++;
+		bus_dmamap_sync(sc->sc_dmat, data->td_active, 0,
+		    data->td_active->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(sc->sc_dmat, data->td_active);
+
+#ifdef DWC_GMAC_DEBUG
+		aprint_normal_dev(sc->sc_dev,
+		    "dwc_gmac_tx_intr: done with packet at desc #%d, "
+		    "freeing mbuf %p\n", i, data->td_m);
+#endif
+
+		m_freem(data->td_m);
+		data->td_m = NULL;
+	}
+
+	sc->sc_txq.t_next = i;
+
+	if (sc->sc_txq.t_queued < AWGE_TX_RING_COUNT) {
+		sc->sc_ec.ec_if.if_flags &= ~IFF_OACTIVE;
+	}
+}
+
+static void
+dwc_gmac_rx_intr(struct dwc_gmac_softc *sc)
+{
+#ifdef DWC_GMAC_DEBUG
+	aprint_normal_dev(sc->sc_dev, "rx intr\n");
+	/* XXX */
+#endif
+}
+
 int
 dwc_gmac_intr(struct dwc_gmac_softc *sc)
 {
 	uint32_t status, dma_status;
+	int rv = 0;
 
 	status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR);
 	if (status & AWIN_GMAC_MII_IRQ) {
 		(void)bus_space_read_4(sc->sc_bst, sc->sc_bsh,
 		    AWIN_GMAC_MII_STATUS);
+		rv = 1;
 		mii_pollstat(&sc->sc_mii);
 	}
 
 	dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
 	    AWIN_GMAC_DMA_STATUS);
 
-printf("%s: INTR status: %08x, DMA status: %08x\n", device_xname(sc->sc_dev),
-    status, dma_status);
+	if (dma_status & (GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE))
+		rv = 1;
 
-static size_t cnt = 0;
-if (++cnt > 20)
-	panic("enough now");
+	if (dma_status & GMAC_DMA_INT_TIE)
+		dwc_gmac_tx_intr(sc);
 
-	return 1;
+	if (dma_status & GMAC_DMA_INT_RIE)
+		dwc_gmac_rx_intr(sc);
+
+	/*
+	 * Check error conditions
+	 */
+	if (dma_status & GMAC_DMA_INT_ERRORS) {
+		sc->sc_ec.ec_if.if_oerrors++;
+#ifdef DWC_GMAC_DEBUG
+		dwc_dump_and_abort(sc, "interrupt error condition");
+#endif
+	}
+
+	/* ack interrupt */
+	if (dma_status)
+		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
+		    AWIN_GMAC_DMA_STATUS, dma_status & GMAC_DMA_INT_MASK);
+
+	return rv;
 }
 
 #ifdef DWC_GMAC_DEBUG
@@ -906,7 +1002,9 @@ dwc_gmac_dump_tx_desc(struct dwc_gmac_so
 {
 	int i;
 
-	aprint_normal_dev(sc->sc_dev, " TX DMA descriptors:\n");
+	aprint_normal_dev(sc->sc_dev, "TX queue: cur=%d, next=%d, queued=%d\n",
+	    sc->sc_txq.t_cur, sc->sc_txq.t_next, sc->sc_txq.t_queued);
+	aprint_normal_dev(sc->sc_dev, "TX DMA descriptors:\n");
 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
 		struct dwc_gmac_dev_dmadesc *desc = &sc->sc_txq.t_desc[i];
 		aprint_normal("#%d (%08lx): status: %08x cntl: %08x data: %08x next: %08x\n",
@@ -916,4 +1014,41 @@ dwc_gmac_dump_tx_desc(struct dwc_gmac_so
 
 	}
 }
+
+static void
+dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg)
+{
+	uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+	     AWIN_GMAC_MAC_INTR);
+	uint32_t dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+	     AWIN_GMAC_DMA_STATUS);
+	char buf[200];
+
+	/* print interrupt state */
+	snprintb(buf, sizeof(buf), "\177\20"
+	    "b\x10""NIE\0"
+	    "b\x0f""AIE\0"
+	    "b\x0e""ERE\0"
+	    "b\x0d""FBE\0"
+	    "b\x0a""ETE\0"
+	    "b\x09""RWE\0"
+	    "b\x08""RSE\0"
+	    "b\x07""RUE\0"
+	    "b\x06""RIE\0"
+	    "b\x05""UNE\0"
+	    "b\x04""OVE\0"
+	    "b\x03""TJE\0"
+	    "b\x02""TUE\0"
+	    "b\x01""TSE\0"
+	    "b\x00""TIE\0"
+	    "\0", dma_status);
+	printf("%s: INTR status: %08x, DMA status: %s\n",
+	    device_xname(sc->sc_dev),
+	    status, buf);
+
+	dwc_gmac_dump_dma(sc);
+	dwc_gmac_dump_tx_desc(sc);
+
+	panic(msg);
+}
 #endif

Reply via email to