Date: Sat, 21 Jan 2012 03:05:47 GMT From: Jakub Wojciech Klama <jceel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 204933 for review Message-ID: <201201210305.q0L35lov052003@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@204933?ac=10 Change 204933 by jceel@jceel_cyclone on 2012/01/21 03:05:31 Introduce RX filtering based on built-in hash filter. Turn off promiscuous mode by default. Affected files ... .. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpe.c#10 edit .. //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpereg.h#6 edit Differences ... ==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpe.c#10 (text+ko) ==== @@ -133,8 +133,8 @@ bus_space_handle_t lpe_bsh; #define LPE_FLAG_LINK (1 << 0) uint32_t lpe_flags; + int lpe_watchdog_timer; struct callout lpe_tick; - struct lpe_chain_data lpe_cdata; struct lpe_ring_data lpe_rdata; }; @@ -154,16 +154,20 @@ static void lpe_stop(struct lpe_softc *); static void lpe_stop_locked(struct lpe_softc *); static int lpe_ioctl(struct ifnet *, u_long, caddr_t); +static void lpe_set_rxmode(struct lpe_softc *); +static void lpe_set_rxfilter(struct lpe_softc *); 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_watchdog(struct lpe_softc *); 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_discard_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 *); @@ -177,6 +181,13 @@ #define lpe_write_4(_sc, _reg, _val) \ bus_space_write_4((_sc)->lpe_bst, (_sc)->lpe_bsh, (_reg), (_val)) +#define LPE_HWDESC_RXERRS (LPE_HWDESC_CRCERROR | LPE_HWDESC_SYMBOLERROR | \ + LPE_HWDESC_LENGTHERROR | LPE_HWDESC_ALIGNERROR | LPE_HWDESC_OVERRUN | \ + LPE_HWDESC_RXNODESCR) + +#define LPE_HWDESC_TXERRS (LPE_HWDESC_EXCDEFER | LPE_HWDESC_EXCCOLL | \ + LPE_HWDESC_LATECOLL | LPE_HWDESC_UNDERRUN | LPE_HWDESC_TXNODESCR) + static int lpe_probe(device_t dev) { @@ -305,6 +316,12 @@ struct lpe_softc *sc = device_get_softc(dev); lpe_stop(sc); + + if_free(sc->lpe_ifp); + bus_teardown_intr(dev, sc->lpe_irq_res, sc->lpe_intrhand); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lpe_irq_res); + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lpe_mem_res); + return (0); } @@ -313,6 +330,7 @@ { struct lpe_softc *sc = device_get_softc(dev); uint32_t val; + int result; lpe_write_4(sc, LPE_MCMD, LPE_MCMD_READ); lpe_write_4(sc, LPE_MADR, @@ -331,12 +349,10 @@ return (0); lpe_write_4(sc, LPE_MCMD, 0); + result = (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK); + debugf("phy=%d reg=%d result=0x%04x\n", phy, reg, result); - int x = (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK); - - - debugf("phy=%d reg=%d result=0x%04x\n", phy, reg, x); - return (x); + return (result); } static int @@ -397,9 +413,9 @@ LPE_COMMAND_TXRESET | LPE_COMMAND_RXRESET); /* Set station address */ - lpe_write_4(sc, LPE_SA0, sc->lpe_enaddr[0] << 8 | sc->lpe_enaddr[1]); - lpe_write_4(sc, LPE_SA1, sc->lpe_enaddr[2] << 8 | sc->lpe_enaddr[3]); - lpe_write_4(sc, LPE_SA2, sc->lpe_enaddr[4] << 8 | sc->lpe_enaddr[5]); + lpe_write_4(sc, LPE_SA2, sc->lpe_enaddr[1] << 8 | sc->lpe_enaddr[0]); + lpe_write_4(sc, LPE_SA1, sc->lpe_enaddr[3] << 8 | sc->lpe_enaddr[2]); + lpe_write_4(sc, LPE_SA0, sc->lpe_enaddr[5] << 8 | sc->lpe_enaddr[4]); /* Leave soft reset mode */ mac1 = lpe_read_4(sc, LPE_MAC1); @@ -433,8 +449,7 @@ /* 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_COMMAND_PASSRUNTFRAME | - LPE_COMMAND_PASSRXFILTER); + LPE_COMMAND_TXENABLE | LPE_COMMAND_PASSRUNTFRAME); /* Enable receive */ mac1 = lpe_read_4(sc, LPE_MAC1); @@ -446,7 +461,7 @@ lpe_write_4(sc, LPE_MCFG, LPE_MCFG_CLKSEL(7)); /* Set up Rx filter */ - lpe_write_4(sc, LPE_RXFILTER_CTRL, 0xffffffff); + lpe_set_rxmode(sc); /* Enable interrupts */ lpe_write_4(sc, LPE_INTENABLE, LPE_INT_RXOVERRUN | LPE_INT_RXERROR | @@ -503,8 +518,6 @@ lpe_lock_assert(sc); - debugf("entry"); - while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { if (lpe_read_4(sc, LPE_TXDESC_PROD) == lpe_read_4(sc, LPE_TXDESC_CONS) - 5) @@ -523,6 +536,7 @@ /* Submit new descriptor list */ if (encap) { lpe_write_4(sc, LPE_TXDESC_PROD, sc->lpe_cdata.lpe_tx_prod); + sc->lpe_watchdog_timer = 5; } } @@ -541,7 +555,7 @@ prod = sc->lpe_cdata.lpe_tx_prod; txd = &sc->lpe_cdata.lpe_tx_desc[prod]; - debugf("lpe_encap: starting with prod=%d\n", prod); + debugf("starting with prod=%d\n", prod); err = bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT); @@ -599,6 +613,19 @@ lpe_stop_locked(struct lpe_softc *sc) { lpe_lock_assert(sc); + + callout_stop(&sc->lpe_tick); + + /* Disable interrupts */ + lpe_write_4(sc, LPE_INTCLEAR, 0xffffffff); + + /* Stop EMAC */ + lpe_write_4(sc, LPE_MAC1, 0); + lpe_write_4(sc, LPE_MAC2, 0); + lpe_write_4(sc, LPE_COMMAND, 0); + + sc->lpe_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + sc->lpe_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; } static int @@ -607,9 +634,29 @@ 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; + int err = 0; switch (cmd) { + case SIOCSIFFLAGS: + lpe_lock(sc); + if (ifp->if_flags & IFF_UP) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + lpe_set_rxmode(sc); + lpe_set_rxfilter(sc); + } else + lpe_init_locked(sc); + } else + lpe_stop(sc); + lpe_unlock(sc); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + lpe_lock(sc); + lpe_set_rxfilter(sc); + lpe_unlock(sc); + } + break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: err = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); @@ -622,6 +669,57 @@ return (err); } +static void lpe_set_rxmode(struct lpe_softc *sc) +{ + struct ifnet *ifp = sc->lpe_ifp; + uint32_t rxfilt; + + rxfilt = LPE_RXFILTER_UNIHASH | LPE_RXFILTER_MULTIHASH | LPE_RXFILTER_PERFECT; + + if (ifp->if_flags & IFF_BROADCAST) + rxfilt |= LPE_RXFILTER_BROADCAST; + + if (ifp->if_flags & IFF_PROMISC) + rxfilt |= LPE_RXFILTER_UNICAST | LPE_RXFILTER_MULTICAST; + + if (ifp->if_flags & IFF_ALLMULTI) + rxfilt |= LPE_RXFILTER_MULTICAST; + + lpe_write_4(sc, LPE_RXFILTER_CTRL, rxfilt); +} + +static void lpe_set_rxfilter(struct lpe_softc *sc) +{ + struct ifnet *ifp = sc->lpe_ifp; + struct ifmultiaddr *ifma; + int index; + uint32_t hashl, hashh; + + hashl = 0; + hashh = 0; + + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + + device_printf(sc->lpe_dev, "rx filter add: %6D\n", LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ":"); + + index = ether_crc32_be(LLADDR((struct sockaddr_dl *) + ifma->ifma_addr), ETHER_ADDR_LEN) >> 23 & 0x3f; + + if (index > 31) + hashh |= (1 << (index - 32)); + else + hashl |= (1 << index); + } + if_maddr_runlock(ifp); + + /* Program new hash filter */ + lpe_write_4(sc, LPE_HASHFILTER_L, hashl); + lpe_write_4(sc, LPE_HASHFILTER_H, hashh); +} + static void lpe_intr(void *arg) { @@ -666,16 +764,26 @@ hwd = &sc->lpe_rdata.lpe_rx_ring[cons]; hws = &sc->lpe_rdata.lpe_rx_status[cons]; + /* Check received frame for errors */ + if (hws->lhs_info & LPE_HWDESC_RXERRS) { + ifp->if_ierrors++; + lpe_discard_rxbuf(sc, cons); + lpe_init_rxbuf(sc, cons); + goto skip; + } + m = rxd->lpe_rxdesc_mbuf; m->m_pkthdr.rcvif = ifp; m->m_data += 2; + ifp->if_ipackets++; + lpe_unlock(sc); (*ifp->if_input)(ifp, m); lpe_lock(sc); lpe_init_rxbuf(sc, cons); - +skip: LPE_INC(cons, LPE_RXDESC_NUM); lpe_write_4(sc, LPE_RXDESC_CONS, cons); } @@ -684,13 +792,12 @@ static void lpe_txintr(struct lpe_softc *sc) { + struct ifnet *ifp = sc->lpe_ifp; struct lpe_hwdesc *hwd; struct lpe_hwstatus *hws; struct lpe_txdesc *txd; int cons, last; - debugf("transmit interrupt\n"); - for (;;) { cons = lpe_read_4(sc, LPE_TXDESC_CONS); last = sc->lpe_cdata.lpe_tx_last; @@ -705,6 +812,14 @@ bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap, BUS_DMASYNC_POSTWRITE); + ifp->if_collisions += LPE_HWDESC_COLLISIONS(hws->lhs_info); + + /* XXX tylko dla ostatniego fragmentu */ + if (hws->lhs_info & LPE_HWDESC_TXERRS) + ifp->if_oerrors++; + else + ifp->if_opackets++; + if (txd->lpe_txdesc_first) { bus_dmamap_unload(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap); @@ -714,8 +829,12 @@ txd->lpe_txdesc_first = 0; } + sc->lpe_cdata.lpe_tx_used--; LPE_INC(sc->lpe_cdata.lpe_tx_last, LPE_TXDESC_NUM); } + + if (!sc->lpe_cdata.lpe_tx_used) + sc->lpe_watchdog_timer = 0; } static void @@ -725,11 +844,33 @@ struct mii_data *mii = device_get_softc(sc->lpe_miibus); lpe_lock_assert(sc); + mii_tick(mii); + lpe_watchdog(sc); callout_reset(&sc->lpe_tick, hz, lpe_tick, sc); } +static void +lpe_watchdog(struct lpe_softc *sc) +{ + struct ifnet *ifp = sc->lpe_ifp; + + lpe_lock_assert(sc); + + if (sc->lpe_watchdog_timer == 0 || sc->lpe_watchdog_timer--) + return; + + /* Chip has stopped responding */ + device_printf(sc->lpe_dev, "WARNING: chip hangup, restarting...\n"); + lpe_stop_locked(sc); + lpe_init_locked(sc); + + /* Try to resend packets */ + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + lpe_start_locked(ifp); +} + static int lpe_dma_alloc(struct lpe_softc *sc) { @@ -1022,7 +1163,6 @@ return (0); } -#if 0 static void lpe_discard_rxbuf(struct lpe_softc *sc, int n) { @@ -1032,16 +1172,16 @@ 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); + bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap); - hwd->hw_flagslen = 0; + hwd->lhr_data = 0; + hwd->lhr_control = 0; - if (rxd->dve_rxdesc_mbuf) { - m_freem(rxd->dve_rxdesc_mbuf); - rxd->dve_rxdesc_mbuf = NULL; + if (rxd->lpe_rxdesc_mbuf) { + m_freem(rxd->lpe_rxdesc_mbuf); + rxd->lpe_rxdesc_mbuf = NULL; } } -#endif static void lpe_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) ==== //depot/projects/soc2011/jceel_lpc/sys/arm/lpc/if_lpereg.h#6 (text+ko) ==== @@ -116,6 +116,14 @@ #define LPE_FLOWCONTROL_COUNTER 0x170 #define LPE_FLOWCONTROL_STATUS 0x174 #define LPE_RXFILTER_CTRL 0x200 +#define LPE_RXFILTER_UNICAST (1 << 0) +#define LPE_RXFILTER_BROADCAST (1 << 1) +#define LPE_RXFILTER_MULTICAST (1 << 2) +#define LPE_RXFILTER_UNIHASH (1 << 3) +#define LPE_RXFILTER_MULTIHASH (1 << 4) +#define LPE_RXFILTER_PERFECT (1 << 5) +#define LPE_RXFILTER_WOL (1 << 12) +#define LPE_RXFILTER_FILTWOL (1 << 13) #define LPE_RXFILTER_WOL_STATUS 0x204 #define LPE_RXFILTER_WOL_CLEAR 0x208 #define LPE_HASHFILTER_L 0x210 @@ -159,13 +167,26 @@ /* These are valid for both Rx and Tx descriptors */ #define LPE_HWDESC_SIZE_MASK (1 << 10) +#define LPE_HWDESC_INTERRUPT (1 << 31) -/* These are valid for Tx descriptors only */ -#define LPE_HWDESC_INTERRUPT (1 << 31) +/* These are valid for Tx descriptors */ +#define LPE_HWDESC_LAST (1 << 30) #define LPE_HWDESC_CRC (1 << 29) #define LPE_HWDESC_PAD (1 << 28) +#define LPE_HWDESC_HUGE (1 << 27) +#define LPE_HWDESC_OVERRIDE (1 << 26) -/* These are valid for Rx descriptors only */ +/* These are valid for Tx status descriptors */ +#define LPE_HWDESC_COLLISIONS(_n) (((_n) >> 21) & 0x7) +#define LPE_HWDESC_DEFER (1 << 25) +#define LPE_HWDESC_EXCDEFER (1 << 26) +#define LPE_HWDESC_EXCCOLL (1 << 27) +#define LPE_HWDESC_LATECOLL (1 << 28) +#define LPE_HWDESC_UNDERRUN (1 << 29) +#define LPE_HWDESC_TXNODESCR (1 << 30) +#define LPE_HWDESC_ERROR (1 << 31) + +/* These are valid for Rx status descriptors */ #define LPE_HWDESC_CONTROL (1 << 18) #define LPE_HWDESC_VLAN (1 << 19) #define LPE_HWDESC_FAILFILTER (1 << 20) @@ -177,7 +198,7 @@ #define LPE_HWDESC_RANGEERROR (1 << 26) #define LPE_HWDESC_ALIGNERROR (1 << 27) #define LPE_HWDESC_OVERRUN (1 << 28) -#define LPE_HWDESC_NODESCR (1 << 29) +#define LPE_HWDESC_RXNODESCR (1 << 29) #define LPE_HWDESC_LASTFLAG (1 << 30) #define LPE_HWDESC_ERROR (1 << 31)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201210305.q0L35lov052003>