svn commit: r212237 - user/nwhitehorn/ps3/powerpc/ps3

Nathan Whitehorn nwhitehorn at FreeBSD.org
Sun Sep 5 18:56:24 UTC 2010


Author: nwhitehorn
Date: Sun Sep  5 18:56:24 2010
New Revision: 212237
URL: http://svn.freebsd.org/changeset/base/212237

Log:
  Improve performance by only restarting TX DMA when it is really
  necessary. This brings up TX performance to 100 Mbit. There is still an
  issue where outbound traffic will hang the controller under very heavy
  TX load. I haven't debugged that one yet.

Modified:
  user/nwhitehorn/ps3/powerpc/ps3/if_glc.c
  user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h

Modified: user/nwhitehorn/ps3/powerpc/ps3/if_glc.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/if_glc.c	Sun Sep  5 18:47:04 2010	(r212236)
+++ user/nwhitehorn/ps3/powerpc/ps3/if_glc.c	Sun Sep  5 18:56:24 2010	(r212237)
@@ -68,6 +68,7 @@ static int	glc_add_rxbuf(struct glc_soft
 static int	glc_add_rxbuf_dma(struct glc_softc *sc, int idx);
 static int	glc_encap(struct glc_softc *sc, struct mbuf **m_head,
 		    bus_addr_t *pktdesc);
+static int	glc_intr_filter(void *xsc);
 static void	glc_intr(void *xsc);
 
 static MALLOC_DEFINE(M_GLC, "gelic", "PS3 GELIC ethernet");
@@ -193,15 +194,15 @@ glc_attach(device_t dev) 
 	}
 
 	bus_setup_intr(dev, sc->sc_irq,
-	    INTR_TYPE_MISC | INTR_MPSAFE | INTR_ENTROPY, NULL, glc_intr,
-	    sc, &sc->sc_irqctx);
-	sc->sc_interrupt_status = (uint64_t *)contigmalloc(8, M_GLC, M_ZERO, 0,
+	    INTR_TYPE_MISC | INTR_MPSAFE | INTR_ENTROPY,
+	    glc_intr_filter, glc_intr, sc, &sc->sc_irqctx);
+	sc->sc_hwirq_status = (uint64_t *)contigmalloc(8, M_GLC, M_ZERO, 0,
 	    BUS_SPACE_MAXADDR_32BIT, 8, PAGE_SIZE);
 	lv1_net_set_interrupt_status_indicator(sc->sc_bus, sc->sc_dev,
-	    vtophys(sc->sc_interrupt_status), 0);
+	    vtophys(sc->sc_hwirq_status), 0);
 	lv1_net_set_interrupt_mask(sc->sc_bus, sc->sc_dev,
 	    GELIC_INT_RXDONE | GELIC_INT_TXDONE | GELIC_INT_RXFRAME |
-	    GELIC_INT_PHY, 0);
+	    GELIC_INT_PHY | GELIC_INT_TX_CHAIN_END, 0);
 
 	/*
 	 * Set up DMA.
@@ -398,12 +399,9 @@ glc_start_locked(struct ifnet *ifp)
 	bus_dmamap_sync(sc->sc_dmadesc_tag, sc->sc_txdmadesc_map,
 	    BUS_DMASYNC_PREREAD);
 
-	/* XXX: kickstart always until problems are sorted out */
-	kickstart = 1;
-
 	if (kickstart && first != 0) {
-		lv1_net_stop_tx_dma(sc->sc_bus, sc->sc_dev, 0);
 		lv1_net_start_tx_dma(sc->sc_bus, sc->sc_dev, first, 0);
+		sc->sc_wdog_timer = 5;
 	}
 }
 
@@ -577,9 +575,6 @@ glc_encap(struct glc_softc *sc, struct m
 	    txs->txs_firstdesc*sizeof(struct glc_dmadesc));
 
 	for (i = 0; i < nsegs; i++) {
-		if (i+1 == nsegs)
-			txs->txs_lastdesc = sc->next_txdma_slot;
-
 		bzero(&sc->sc_txdmadesc[idx], sizeof(sc->sc_txdmadesc[idx]));
 		sc->sc_txdmadesc[idx].paddr = glc_map_addr(sc, segs[i].ds_addr);
 		sc->sc_txdmadesc[idx].len = segs[i].ds_len;
@@ -589,7 +584,7 @@ glc_encap(struct glc_softc *sc, struct m
 		sc->sc_txdmadesc[idx].cmd_stat |= GELIC_CMDSTAT_NOIPSEC;
 
 		if (i+1 == nsegs) {
-			txs->txs_lastdesc = sc->next_txdma_slot;
+			txs->txs_lastdesc = idx;
 			sc->sc_txdmadesc[idx].next = 0;
 			sc->sc_txdmadesc[idx].cmd_stat |= GELIC_CMDSTAT_LAST;
 		}
@@ -659,7 +654,7 @@ glc_rxintr(struct glc_softc *sc)
 		mtx_lock(&sc->sc_mtx);
 
 	    requeue:
-		if (sc->sc_rxdmadesc[i].cmd_stat & GELIC_CMDSTAT_RX_END)
+		if (sc->sc_rxdmadesc[i].cmd_stat & GELIC_CMDSTAT_CHAIN_END)
 			restart_rxdma = 1;
 		glc_add_rxbuf_dma(sc, i);	
 		if (restart_rxdma)
@@ -673,7 +668,7 @@ glc_txintr(struct glc_softc *sc)
 {
 	struct ifnet *ifp = sc->sc_ifp;
 	struct glc_txsoft *txs;
-	int progress = 0;
+	int progress = 0, kickstart = 0;
 
 	while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) {
 		if (sc->sc_txdmadesc[txs->txs_lastdesc].cmd_stat
@@ -688,8 +683,18 @@ glc_txintr(struct glc_softc *sc)
 			txs->txs_mbuf = NULL;
 		}
 
-		STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);
+		if ((sc->sc_txdmadesc[txs->txs_lastdesc].cmd_stat & 0xf0000000)
+		    != 0) {
+			lv1_net_stop_tx_dma(sc->sc_bus, sc->sc_dev, 0);
+			kickstart = 1;
+			ifp->if_oerrors++;
+		}
+
+		if (sc->sc_txdmadesc[txs->txs_lastdesc].cmd_stat &
+		    GELIC_CMDSTAT_CHAIN_END)
+			kickstart = 1;
 
+		STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);
 		ifp->if_opackets++;
 		progress = 1;
 	}
@@ -699,15 +704,19 @@ glc_txintr(struct glc_softc *sc)
 	else
 		sc->first_used_txdma_slot = -1;
 
+	if (kickstart && txs != NULL) {
+		lv1_net_start_tx_dma(sc->sc_bus, sc->sc_dev,
+		    glc_map_addr(sc, sc->sc_txdmadesc_phys +
+		    txs->txs_firstdesc*sizeof(struct glc_dmadesc)), 0);
+	}
+
 	if (progress) {
 		/*
 		 * We freed some descriptors, so reset IFF_DRV_OACTIVE
 		 * and restart.
 		 */
 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-#if 0
 		sc->sc_wdog_timer = STAILQ_EMPTY(&sc->sc_txdirtyq) ? 0 : 5;
-#endif
 
 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) &&
 		    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
@@ -715,25 +724,37 @@ glc_txintr(struct glc_softc *sc)
 	}
 }
 
+static int
+glc_intr_filter(void *xsc)
+{
+	struct glc_softc *sc = xsc; 
+
+	powerpc_sync();
+	atomic_set_64(&sc->sc_interrupt_status, *sc->sc_hwirq_status);
+	return (FILTER_SCHEDULE_THREAD);
+}
+
 static void
 glc_intr(void *xsc)
 {
 	struct glc_softc *sc = xsc; 
+	uint64_t status;
 
 	mtx_lock(&sc->sc_mtx);
-	powerpc_sync();
 
-	if (*sc->sc_interrupt_status == 0) {
-		device_printf(sc->sc_self, "stray interrupt!\n");
+	status = atomic_readandclear_64(&sc->sc_interrupt_status);
+
+	if (status == 0) {
 		mtx_unlock(&sc->sc_mtx);
 		return;
 	}
 
-	if (*sc->sc_interrupt_status & (GELIC_INT_RXDONE | GELIC_INT_RXFRAME))
+	if (status & (GELIC_INT_RXDONE | GELIC_INT_RXFRAME))
 		glc_rxintr(sc);
 
-	if (*sc->sc_interrupt_status & GELIC_INT_TXDONE)
+	if (status & (GELIC_INT_TXDONE | GELIC_INT_TX_CHAIN_END))
 		glc_txintr(sc);
 
 	mtx_unlock(&sc->sc_mtx);
 }
+

Modified: user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h	Sun Sep  5 18:47:04 2010	(r212236)
+++ user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h	Sun Sep  5 18:56:24 2010	(r212237)
@@ -76,7 +76,8 @@ struct glc_softc {
 	int		sc_irqid;
 	struct resource	*sc_irq;
 	void		*sc_irqctx;
-	uint64_t	*sc_interrupt_status;
+	uint64_t	*sc_hwirq_status;
+	volatile uint64_t sc_interrupt_status;
 
 	/* Transmission */
 
@@ -100,6 +101,7 @@ struct glc_softc {
 	bus_addr_t	sc_rxdmadesc_phys;
 
 	int		sc_bus, sc_dev;
+	int		sc_wdog_timer;
 };
 
 #define GELIC_GET_MAC_ADDRESS   0x0001
@@ -119,7 +121,7 @@ struct glc_softc {
 /* Command status code */
 #define	GELIC_DESCR_OWNED	0xa0000000
 #define	GELIC_CMDSTAT_DMA_DONE	0x00000000
-#define	GELIC_CMDSTAT_RX_END	0x00000002
+#define	GELIC_CMDSTAT_CHAIN_END	0x00000002
 #define GELIC_CMDSTAT_NOIPSEC	0x00080000
 #define GELIC_CMDSTAT_LAST	0x00040000
 #define GELIC_RXERRORS		0x7def8000
@@ -128,6 +130,7 @@ struct glc_softc {
 #define GELIC_INT_RXDONE	0x0000000000004000UL
 #define GELIC_INT_RXFRAME	0x1000000000000000UL
 #define GELIC_INT_TXDONE	0x0080000000000000UL
+#define GELIC_INT_TX_CHAIN_END	0x0100000000000000UL
 #define GELIC_INT_PHY		0x0000000020000000UL
 
 /* Hardware DMA descriptor. Must be 32-byte aligned */


More information about the svn-src-user mailing list