Date: Thu, 9 Jun 2011 08:54:38 GMT From: Jakub Wojciech Klama <jceel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 194491 for review Message-ID: <201106090854.p598scbK027607@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@194491?ac=10 Change 194491 by jceel@jceel_cyclone on 2011/06/09 08:54:06 Ethernet driver update: working correctly in trivial scenarios. Affected files ... .. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpe.c#2 edit .. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpereg.h#2 edit Differences ... ==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpe.c#2 (text+ko) ==== @@ -94,6 +94,7 @@ struct lpe_txdesc lpe_tx_desc[LPE_TXDESC_NUM]; int lpe_tx_prod; int lpe_tx_cons; + int lpe_tx_used; int lpe_rx_cons; }; @@ -120,8 +121,8 @@ bus_space_tag_t lpe_bst; bus_space_handle_t lpe_bsh; uint32_t lpe_flags; + struct callout lpe_tick; - struct lpe_chain_data lpe_cdata; struct lpe_ring_data lpe_rdata; }; @@ -144,11 +145,13 @@ static void lpe_intr(void *); static void lpe_rxintr(struct lpe_softc *); static void lpe_txintr(struct lpe_softc *); -//static void lpe_tick(void *); +static void lpe_tick(void *); static int lpe_encap(struct lpe_softc *, struct mbuf **); static int lpe_dma_alloc(struct lpe_softc *); static int lpe_dma_alloc_rx(struct lpe_softc *); static int lpe_dma_alloc_tx(struct lpe_softc *); +static int lpe_init_rx(struct lpe_softc *); +static int lpe_init_rxbuf(struct lpe_softc *, int); static void lpe_dmamap_cb(void *, bus_dma_segment_t *, int, int); static int lpe_ifmedia_upd(struct ifnet *); static void lpe_ifmedia_sts(struct ifnet *, struct ifmediareq *); @@ -194,6 +197,8 @@ mtx_init(&sc->lpe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); + callout_init_mtx(&sc->lpe_tick, &sc->lpe_mtx, 0); + rid = 0; sc->lpe_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -287,8 +292,6 @@ struct lpe_softc *sc = device_get_softc(dev); uint32_t val; - device_printf(dev, "mii read: phy=%d reg=%d\n", phy, reg); - lpe_write_4(sc, LPE_MCMD, LPE_MCMD_READ); lpe_write_4(sc, LPE_MADR, (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT | @@ -305,7 +308,11 @@ if (val & LPE_MIND_INVALID) return (0); - return (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK); + lpe_write_4(sc, LPE_MCMD, 0); + + int x = (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK); +// printf("mii read: phy=%d reg=%d result=0x%04x\n", phy, reg, x); + return (x); } static int @@ -314,6 +321,8 @@ struct lpe_softc *sc = device_get_softc(dev); uint32_t val; +// printf("mii write: phy=%d reg=%d data=0x%04x\n", phy, reg, data); + lpe_write_4(sc, LPE_MCMD, LPE_MCMD_WRITE); lpe_write_4(sc, LPE_MADR, (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT | @@ -393,11 +402,20 @@ /* Enable Tx and Rx */ cmd = lpe_read_4(sc, LPE_COMMAND); - lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE | LPE_COMMAND_TXENABLE); + lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE | + LPE_COMMAND_TXENABLE | LPE_COMMAND_PASSRUNTFRAME | + LPE_COMMAND_PASSRXFILTER); /* Enable receive */ mac1 = lpe_read_4(sc, LPE_MAC1); - lpe_write_4(sc, LPE_MAC1, mac1 | LPE_MAC1_RXENABLE); + lpe_write_4(sc, LPE_MAC1, /*mac1 |*/ LPE_MAC1_RXENABLE | LPE_MAC1_PASSALL); + + /* XXX */ + lpe_write_4(sc, LPE_MAC2, LPE_MAC2_CRCENABLE | LPE_MAC2_PADCRCENABLE | + LPE_MAC2_FULLDUPLEX); + + /* XXX */ + lpe_write_4(sc, LPE_MCFG, (((7) & 0x7) << 2)); /* Set up Rx filter */ lpe_write_4(sc, LPE_RXFILTER_CTRL, 0xffffffff); @@ -407,20 +425,36 @@ LPE_INT_RXFINISH | LPE_INT_RXDONE | LPE_INT_TXUNDERRUN | LPE_INT_TXERROR | LPE_INT_TXFINISH | LPE_INT_TXDONE); + sc->lpe_cdata.lpe_tx_prod = 0; + sc->lpe_cdata.lpe_tx_cons = 0; + sc->lpe_cdata.lpe_tx_used = 0; + sc->lpe_cdata.lpe_rx_cons = 0; + + lpe_init_rx(sc); + /* Initialize Rx packet and status descriptor heads */ lpe_write_4(sc, LPE_RXDESC, sc->lpe_rdata.lpe_rx_ring_phys); lpe_write_4(sc, LPE_RXSTATUS, sc->lpe_rdata.lpe_rx_status_phys); - lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM); + lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM - 1); lpe_write_4(sc, LPE_RXDESC_CONS, 0); + + device_printf(sc->lpe_dev, "rx ring: %p, rx status: %p\n", + sc->lpe_rdata.lpe_rx_ring, sc->lpe_rdata.lpe_rx_status); + /* Initialize Tx packet and status descriptor heads */ lpe_write_4(sc, LPE_TXDESC, sc->lpe_rdata.lpe_tx_ring_phys); lpe_write_4(sc, LPE_TXSTATUS, sc->lpe_rdata.lpe_tx_status_phys); - lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM); + lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM - 1); lpe_write_4(sc, LPE_TXDESC_PROD, 0); - + + device_printf(sc->lpe_dev, "tx ring: %p, tx status: %p\n", + sc->lpe_rdata.lpe_tx_ring, sc->lpe_rdata.lpe_tx_status); + ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + callout_reset(&sc->lpe_tick, hz, lpe_tick, sc); } static void @@ -442,7 +476,7 @@ lpe_lock_assert(sc); - device_printf(sc->lpe_dev, "lpe_start_locked()\n"); +// device_printf(sc->lpe_dev, "lpe_start_locked()\n"); while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { /* Dequeue first packet */ @@ -451,11 +485,13 @@ break; lpe_encap(sc, &m_head); + + encap++; } /* Submit new descriptor list */ if (encap) { - + lpe_write_4(sc, LPE_TXDESC_PROD, sc->lpe_cdata.lpe_tx_prod); } } @@ -465,13 +501,21 @@ { struct lpe_txdesc *txd; struct lpe_hwdesc *hwd; - struct lpe_hwstatus *hws; + //struct lpe_hwstatus *hws; bus_dma_segment_t segs[LPE_MAXFRAGS]; - int i, err, nsegs; + int i, err, nsegs, prod; lpe_lock_assert(sc); M_ASSERTPKTHDR((*m_head)); + prod = sc->lpe_cdata.lpe_tx_prod; + txd = &sc->lpe_cdata.lpe_tx_desc[prod]; + +// device_printf(sc->lpe_dev, "lpe_encap: starting with prod=%d\n", prod); + +// device_printf(sc->lpe_dev, "lpe_encap: packet data: %16D\n", +// mtod(*m_head, const char *), " "); + err = bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT); @@ -484,12 +528,34 @@ return (EIO); } + bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap, + BUS_DMASYNC_PREREAD); + bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + for (i = 0; i < nsegs; i++) { - hwd = &sc->lpe_rdata.lpe_tx_desc[prod]; - + hwd = &sc->lpe_rdata.lpe_tx_ring[prod]; + hwd->lhr_data = segs[i].ds_addr; + hwd->lhr_control = segs[i].ds_len - 1;// & LPE_HWDESC_SIZE_MASK; + + if (i == nsegs - 1) { + hwd->lhr_control |= LPE_HWDESC_LASTFLAG; + hwd->lhr_control |= LPE_HWDESC_INTERRUPT; + hwd->lhr_control |= (1 << 28) | (1 << 29); + } + LPE_INC(prod, LPE_TXDESC_NUM); + +// device_printf(sc->lpe_dev, "lpe_encap: 1 segment done @ %p, size: %ld\n", +// hwd, segs[i].ds_len); } + bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + sc->lpe_cdata.lpe_tx_used += nsegs; + sc->lpe_cdata.lpe_tx_prod = prod; + return (0); } @@ -510,9 +576,16 @@ static int lpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { + struct lpe_softc *sc = ifp->if_softc; + struct mii_data *mii = device_get_softc(sc->lpe_miibus); + struct ifreq *ifr = (struct ifreq *)data; int err; switch (cmd) { + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + err = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); + break; default: err = ether_ioctl(ifp, cmd, data); break; @@ -527,14 +600,16 @@ struct lpe_softc *sc = (struct lpe_softc *)arg; uint32_t intstatus; - device_printf(sc->lpe_dev, "intr(): 0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS)); +// device_printf(sc->lpe_dev, "intr(): 0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS)); while ((intstatus = lpe_read_4(sc, LPE_INTSTATUS))) { - if (intstatus & LPE_INT_RXFINISH) + if (intstatus & LPE_INT_RXDONE) lpe_rxintr(sc); - if (intstatus & LPE_INT_TXFINISH) + if (intstatus & LPE_INT_TXDONE) lpe_txintr(sc); + + lpe_write_4(sc, LPE_INTCLEAR, 0xffff); } @@ -543,22 +618,62 @@ static void lpe_rxintr(struct lpe_softc *sc) { + struct ifnet *ifp = sc->lpe_ifp; + struct lpe_hwdesc *hwd; + struct lpe_hwstatus *hws; + struct lpe_rxdesc *rxd; + struct mbuf *m; + int prod, cons; +// device_printf(sc->lpe_dev, "receive interrupt\n"); + + for (;;) { + prod = lpe_read_4(sc, LPE_RXDESC_PROD); + cons = lpe_read_4(sc, LPE_RXDESC_CONS); + if (prod == cons) + break; + + rxd = &sc->lpe_cdata.lpe_rx_desc[cons]; + hwd = &sc->lpe_rdata.lpe_rx_ring[cons]; + hws = &sc->lpe_rdata.lpe_rx_status[cons]; + +// device_printf(sc->lpe_dev, "incoming packet: idx=%d len=%d data=%16D\n", +// cons, hws->lhs_info & 0x7ff, +// mtod(rxd->lpe_rxdesc_mbuf, const char *), " "); + + + m = rxd->lpe_rxdesc_mbuf; + m->m_pkthdr.rcvif = ifp; + m->m_data += 2; + + (*ifp->if_input)(ifp, m); + + lpe_init_rxbuf(sc, cons); + + LPE_INC(cons, LPE_RXDESC_NUM); + lpe_write_4(sc, LPE_RXDESC_CONS, cons); + } + +// device_printf(sc->lpe_dev, "rx: prod=%d cons=%d\n", prod, cons); } static void lpe_txintr(struct lpe_softc *sc) { - +/// device_printf(sc->lpe_dev, "transmit interrupt\n"); } -#if 0 static void lpe_tick(void *arg) { + struct lpe_softc *sc = (struct lpe_softc *)arg; + //struct mii_data *mii = device_get_softc(sc->lpe_miibus); + + lpe_lock_assert(sc); + //mii_tick(mii); + callout_reset(&sc->lpe_tick, hz, lpe_tick, sc); } -#endif static int lpe_dma_alloc(struct lpe_softc *sc) @@ -797,6 +912,84 @@ return (err); } +static int +lpe_init_rx(struct lpe_softc *sc) +{ + int i, err; + + for (i = 0; i < LPE_RXDESC_NUM; i++) { + err = lpe_init_rxbuf(sc, i); + if (err) + return (err); + } + + return (0); +} + +static int +lpe_init_rxbuf(struct lpe_softc *sc, int n) +{ + struct lpe_rxdesc *rxd; + struct lpe_hwdesc *hwd; + struct lpe_hwstatus *hws; + struct mbuf *m; + bus_dma_segment_t segs[1]; + int nsegs; + + rxd = &sc->lpe_cdata.lpe_rx_desc[n]; + hwd = &sc->lpe_rdata.lpe_rx_ring[n]; + hws = &sc->lpe_rdata.lpe_rx_status[n]; + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + + if (!m) { + device_printf(sc->lpe_dev, "WARNING: mbufs exhausted!\n"); + return (ENOBUFS); + } + + m->m_len = m->m_pkthdr.len = MCLBYTES; + + bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap); + +// printf("i=%d sc=%p lpe_rx_buf_tag=%p lpe_rxdesc_dmamap=%p m=%p\n", +// n, sc, sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap, m); + + if (bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_rx_buf_tag, + rxd->lpe_rxdesc_dmamap, m, segs, &nsegs, 0)) { + m_freem(m); + return (ENOBUFS); + } + + bus_dmamap_sync(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap, + BUS_DMASYNC_PREREAD); + + rxd->lpe_rxdesc_mbuf = m; + hwd->lhr_data = segs[0].ds_addr + 2; + hwd->lhr_control = (segs[0].ds_len - 1) | LPE_HWDESC_INTERRUPT; + + return (0); +} + +#if 0 +static void +lpe_discard_rxbuf(struct lpe_softc *sc, int n) +{ + struct lpe_rxdesc *rxd; + struct lpe_hwdesc *hwd; + + rxd = &sc->lpe_cdata.lpe_rx_desc[n]; + hwd = &sc->lpe_rdata.lpe_rx_ring[n]; + + bus_dmamap_unload(rxch->dve_rx_buf_tag, rxd->dve_rxdesc_dmamap); + + hwd->hw_flagslen = 0; + + if (rxd->dve_rxdesc_mbuf) { + m_freem(rxd->dve_rxdesc_mbuf); + rxd->dve_rxdesc_mbuf = NULL; + } +} +#endif + static void lpe_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) { @@ -854,6 +1047,6 @@ DRIVER_MODULE(lpe, simplebus, lpe_driver, lpe_devclass, 0, 0); DRIVER_MODULE(miibus, lpe, miibus_driver, miibus_devclass, 0, 0); -MODULE_DEPEND(dve, obio, 1, 1, 1); -MODULE_DEPEND(dve, miibus, 1, 1, 1); -MODULE_DEPEND(dve, ether, 1, 1, 1); +MODULE_DEPEND(lpe, obio, 1, 1, 1); +MODULE_DEPEND(lpe, miibus, 1, 1, 1); +MODULE_DEPEND(lpe, ether, 1, 1, 1); ==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpereg.h#2 (text+ko) ==== @@ -151,6 +151,8 @@ uint32_t lhs_crc; }; +#define LPE_INC(x, y) (x) = ((x) == ((y)-1)) ? 0 : (x)+1 + /* These are valid for both Rx and Tx descriptors */ #define LPE_HWDESC_SIZE_MASK (1 << 10)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106090854.p598scbK027607>