Date: Mon, 6 Sep 2010 04:14:59 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r212246 - user/nwhitehorn/ps3/powerpc/ps3 Message-ID: <201009060414.o864Exu9011096@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Mon Sep 6 04:14:59 2010 New Revision: 212246 URL: http://svn.freebsd.org/changeset/base/212246 Log: Add a watchdog timer and correct a misunderstaning about busdma that was causing random bits of the ring buffer to be overwritten. The PS3's network interface now runs stably even at high transfer rates. 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 Mon Sep 6 03:00:54 2010 (r212245) +++ user/nwhitehorn/ps3/powerpc/ps3/if_glc.c Mon Sep 6 04:14:59 2010 (r212246) @@ -70,6 +70,7 @@ static int glc_encap(struct glc_softc *s bus_addr_t *pktdesc); static int glc_intr_filter(void *xsc); static void glc_intr(void *xsc); +static void glc_tick(void *xsc); static MALLOC_DEFINE(M_GLC, "gelic", "PS3 GELIC ethernet"); @@ -151,7 +152,9 @@ glc_attach(device_t dev) mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); + callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0); sc->next_txdma_slot = 0; + sc->bsy_txdma_slots = 0; sc->first_used_txdma_slot = -1; /* @@ -318,6 +321,7 @@ glc_init_locked(struct glc_softc *sc) { int i; struct glc_rxsoft *rxs; + struct glc_txsoft *txs; mtx_assert(&sc->sc_mtx, MA_OWNED); @@ -342,12 +346,22 @@ glc_init_locked(struct glc_softc *sc) BUS_DMASYNC_PREREAD); } + txs = STAILQ_FIRST(&sc->sc_txdirtyq); + if (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); + } + lv1_net_start_rx_dma(sc->sc_bus, sc->sc_dev, sc->sc_rxsoft[0].rxs_desc, 0); sc->sc_ifp->if_drv_flags |= IFF_DRV_RUNNING; sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->sc_ifpflags = sc->sc_ifp->if_flags; + + sc->sc_wdog_timer = 0; + callout_reset(&sc->sc_tick_ch, hz, glc_tick, sc); } static void @@ -361,6 +375,24 @@ glc_init(void *xsc) } static void +glc_tick(void *xsc) +{ + struct glc_softc *sc = xsc; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) { + callout_reset(&sc->sc_tick_ch, hz, glc_tick, sc); + return; + } + + /* Problems */ + device_printf(sc->sc_self, "device timeout\n"); + + glc_init_locked(sc); +} + +static void glc_start_locked(struct ifnet *ifp) { struct glc_softc *sc = ifp->if_softc; @@ -371,6 +403,10 @@ glc_start_locked(struct ifnet *ifp) mtx_assert(&sc->sc_mtx, MA_OWNED); first = 0; + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + return; + if (STAILQ_EMPTY(&sc->sc_txdirtyq)) kickstart = 1; @@ -380,15 +416,21 @@ glc_start_locked(struct ifnet *ifp) if (mb_head == NULL) break; + /* Check if the ring buffer is full */ + if (sc->bsy_txdma_slots > 125) { + /* Put the packet back and stop */ + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + IFQ_DRV_PREPEND(&ifp->if_snd, mb_head); + break; + } + BPF_MTAP(ifp, mb_head); if (sc->sc_tx_vlan >= 0) mb_head = ether_vlanencap(mb_head, sc->sc_tx_vlan); if (glc_encap(sc, &mb_head, &pktdesc)) { - /* Put the packet back and stop */ ifp->if_drv_flags |= IFF_DRV_OACTIVE; - IFQ_DRV_PREPEND(&ifp->if_snd, mb_head); break; } @@ -396,9 +438,6 @@ glc_start_locked(struct ifnet *ifp) first = pktdesc; } - bus_dmamap_sync(sc->sc_dmadesc_tag, sc->sc_txdmadesc_map, - BUS_DMASYNC_PREREAD); - if (kickstart && first != 0) { lv1_net_start_tx_dma(sc->sc_bus, sc->sc_dev, first, 0); sc->sc_wdog_timer = 5; @@ -516,50 +555,46 @@ glc_encap(struct glc_softc *sc, struct m struct glc_txsoft *txs; struct mbuf *m; bus_addr_t firstslotphys; - int i, idx; - int nsegs = 16; + int i, idx, nsegs, nsegs_max; int err = 0; - /* Check if the ring buffer is full */ - if (sc->next_txdma_slot == sc->first_used_txdma_slot) - return (-1); - /* Max number of segments is the number of free DMA slots */ - if (sc->next_txdma_slot >= sc->first_used_txdma_slot) - nsegs = 128 - sc->next_txdma_slot + sc->first_used_txdma_slot; - else - nsegs = sc->first_used_txdma_slot - sc->next_txdma_slot; + nsegs_max = 128 - sc->bsy_txdma_slots; - if (nsegs > 16) - nsegs = 16; + if (nsegs_max > 16 || sc->first_used_txdma_slot < 0) + nsegs_max = 16; /* Get a work queue entry. */ if ((txs = STAILQ_FIRST(&sc->sc_txfreeq)) == NULL) { /* Ran out of descriptors. */ return (ENOBUFS); } - - err = bus_dmamap_load_mbuf_sg(sc->sc_txdma_tag, txs->txs_dmamap, - *m_head, segs, &nsegs, BUS_DMA_NOWAIT); - if (err == EFBIG) { - m = m_collapse(*m_head, M_DONTWAIT, nsegs); + nsegs = 0; + for (m = *m_head; m != NULL; m = m->m_next) + nsegs++; + + if (nsegs > nsegs_max) { + m = m_collapse(*m_head, M_DONTWAIT, nsegs_max); if (m == NULL) { m_freem(*m_head); *m_head = NULL; return (ENOBUFS); } *m_head = m; - - err = bus_dmamap_load_mbuf_sg(sc->sc_txdma_tag, - txs->txs_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT); - if (err != 0) { - m_freem(*m_head); - *m_head = NULL; - return (err); - } - } else if (err != 0) + } + + err = bus_dmamap_load_mbuf_sg(sc->sc_txdma_tag, txs->txs_dmamap, + *m_head, segs, &nsegs, BUS_DMA_NOWAIT); + if (err != 0) { + m_freem(*m_head); + *m_head = NULL; return (err); + } + + KASSERT(nsegs <= 128 - sc->bsy_txdma_slots, + ("GLC: Mapped too many (%d) DMA segments with %d available", + nsegs, 128 - sc->bsy_txdma_slots)); if (nsegs == 0) { m_freem(*m_head); @@ -594,21 +629,23 @@ glc_encap(struct glc_softc *sc, struct m idx = (idx + 1) % GLC_MAX_TX_PACKETS; } sc->next_txdma_slot = idx; - idx = (txs->txs_firstdesc - 1) % GLC_MAX_TX_PACKETS; - sc->sc_txdmadesc[idx].next = firstslotphys; + sc->bsy_txdma_slots += nsegs; + if (txs->txs_firstdesc != 0) + idx = txs->txs_firstdesc - 1; + else + idx = GLC_MAX_TX_PACKETS - 1; if (sc->first_used_txdma_slot < 0) sc->first_used_txdma_slot = txs->txs_firstdesc; bus_dmamap_sync(sc->sc_txdma_tag, txs->txs_dmamap, BUS_DMASYNC_PREWRITE); + sc->sc_txdmadesc[idx].next = firstslotphys; STAILQ_REMOVE_HEAD(&sc->sc_txfreeq, txs_q); STAILQ_INSERT_TAIL(&sc->sc_txdirtyq, txs, txs_q); txs->txs_mbuf = *m_head; - - if (pktdesc != NULL) - *pktdesc = firstslotphys; + *pktdesc = firstslotphys; return (0); } @@ -677,6 +714,7 @@ glc_txintr(struct glc_softc *sc) STAILQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q); bus_dmamap_unload(sc->sc_txdma_tag, txs->txs_dmamap); + sc->bsy_txdma_slots -= txs->txs_ndescs; if (txs->txs_mbuf != NULL) { m_freem(txs->txs_mbuf); Modified: user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h ============================================================================== --- user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h Mon Sep 6 03:00:54 2010 (r212245) +++ user/nwhitehorn/ps3/powerpc/ps3/if_glcreg.h Mon Sep 6 04:14:59 2010 (r212246) @@ -84,7 +84,7 @@ struct glc_softc { bus_dma_tag_t sc_txdma_tag; struct glc_txsoft sc_txsoft[GLC_MAX_TX_PACKETS]; struct glc_dmadesc *sc_txdmadesc; - int next_txdma_slot, first_used_txdma_slot; + int next_txdma_slot, first_used_txdma_slot, bsy_txdma_slots; bus_dmamap_t sc_txdmadesc_map; bus_addr_t sc_txdmadesc_phys; @@ -102,6 +102,7 @@ struct glc_softc { int sc_bus, sc_dev; int sc_wdog_timer; + struct callout sc_tick_ch; }; #define GELIC_GET_MAC_ADDRESS 0x0001
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009060414.o864Exu9011096>