diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-10-07 15:10:20 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-01-10 09:53:31 +0100 |
commit | c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch) | |
tree | ad4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sys/dev/dwc/if_dwc.c | |
parent | userspace-header-gen.py: Simplify program ports (diff) | |
download | rtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2 |
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sys/dev/dwc/if_dwc.c')
-rw-r--r-- | freebsd/sys/dev/dwc/if_dwc.c | 736 |
1 files changed, 303 insertions, 433 deletions
diff --git a/freebsd/sys/dev/dwc/if_dwc.c b/freebsd/sys/dev/dwc/if_dwc.c index a3716a15..c7284ee1 100644 --- a/freebsd/sys/dev/dwc/if_dwc.c +++ b/freebsd/sys/dev/dwc/if_dwc.c @@ -44,24 +44,16 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/sys/param.h> #include <sys/systm.h> #include <sys/bus.h> +#include <sys/gpio.h> #include <sys/kernel.h> -#include <sys/module.h> -#include <sys/malloc.h> -#include <sys/rman.h> -#include <sys/endian.h> #include <rtems/bsd/sys/lock.h> +#include <sys/malloc.h> #include <sys/mbuf.h> +#include <sys/module.h> #include <sys/mutex.h> +#include <sys/rman.h> #include <sys/socket.h> #include <sys/sockio.h> -#include <sys/sysctl.h> - -#ifndef __rtems__ -#include <dev/fdt/fdt_common.h> -#include <dev/ofw/openfirm.h> -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> -#endif /* __rtems__ */ #include <net/bpf.h> #include <net/if.h> @@ -70,21 +62,27 @@ __FBSDID("$FreeBSD$"); #include <net/if_media.h> #include <net/if_types.h> #include <net/if_var.h> -#include <net/if_vlan_var.h> #include <machine/bus.h> -#ifndef __rtems__ -#include <machine/fdt.h> -#endif /* __rtems__ */ +#include <dev/dwc/if_dwc.h> +#include <dev/dwc/if_dwcvar.h> #include <dev/mii/mii.h> #include <dev/mii/miivar.h> -#include <rtems/bsd/local/miibus_if.h> -#ifdef __rtems__ -#pragma GCC diagnostic ignored "-Wpointer-sign" -#include <rtems/bsd/bsd.h> +#ifndef __rtems__ +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> #endif /* __rtems__ */ +#ifdef EXT_RESOURCES +#include <dev/extres/clk/clk.h> +#include <dev/extres/hwreset/hwreset.h> +#endif + +#include <rtems/bsd/local/if_dwc_if.h> +#include <rtems/bsd/local/gpio_if.h> +#include <rtems/bsd/local/miibus_if.h> + #define READ4(_sc, _reg) \ bus_read_4((_sc)->res[0], _reg) #define WRITE4(_sc, _reg, _val) \ @@ -93,128 +91,53 @@ __FBSDID("$FreeBSD$"); #define MAC_RESET_TIMEOUT 100 #define WATCHDOG_TIMEOUT_SECS 5 #define STATS_HARVEST_INTERVAL 2 -#define MII_CLK_VAL 2 - -#include <dev/dwc/if_dwc.h> #define DWC_LOCK(sc) mtx_lock(&(sc)->mtx) #define DWC_UNLOCK(sc) mtx_unlock(&(sc)->mtx) -#define DWC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED); -#define DWC_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED); - -#define DDESC_TDES0_OWN (1 << 31) -#define DDESC_TDES0_TXINT (1 << 30) -#define DDESC_TDES0_TXLAST (1 << 29) -#define DDESC_TDES0_TXFIRST (1 << 28) -#define DDESC_TDES0_TXCRCDIS (1 << 27) -#define DDESC_TDES0_CIC_IP_HDR (0x1 << 22) -#define DDESC_TDES0_CIC_IP_HDR_PYL (0x2 << 22) -#define DDESC_TDES0_CIC_IP_HDR_PYL_PHDR (0x3 << 22) -#define DDESC_TDES0_TXRINGEND (1 << 21) -#define DDESC_TDES0_TXCHAIN (1 << 20) - -#define DDESC_RDES0_OWN (1 << 31) +#define DWC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) +#define DWC_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED) + +#define DDESC_TDES0_OWN (1U << 31) +#define DDESC_TDES0_TXINT (1U << 30) +#define DDESC_TDES0_TXLAST (1U << 29) +#define DDESC_TDES0_TXFIRST (1U << 28) +#define DDESC_TDES0_TXCRCDIS (1U << 27) +#define DDESC_TDES0_TXRINGEND (1U << 21) +#define DDESC_TDES0_TXCHAIN (1U << 20) + +#define DDESC_RDES0_OWN (1U << 31) #define DDESC_RDES0_FL_MASK 0x3fff #define DDESC_RDES0_FL_SHIFT 16 /* Frame Length */ -#define DDESC_RDES0_ESA (1 << 0) -#define DDESC_RDES1_CHAINED (1 << 14) -#define DDESC_RDES4_IP_PYL_ERR (1 << 4) -#define DDESC_RDES4_IP_HDR_ERR (1 << 3) -#define DDESC_RDES4_IP_PYL_TYPE_MSK 0x7 -#define DDESC_RDES4_IP_PYL_UDP 1 -#define DDESC_RDES4_IP_PYL_TCP 2 - -struct dwc_bufmap { -#ifndef __rtems__ - bus_dmamap_t map; -#endif /* __rtems__ */ - struct mbuf *mbuf; -}; +#define DDESC_RDES1_CHAINED (1U << 14) + +/* Alt descriptor bits. */ +#define DDESC_CNTL_TXINT (1U << 31) +#define DDESC_CNTL_TXLAST (1U << 30) +#define DDESC_CNTL_TXFIRST (1U << 29) +#define DDESC_CNTL_TXCRCDIS (1U << 26) +#define DDESC_CNTL_TXRINGEND (1U << 25) +#define DDESC_CNTL_TXCHAIN (1U << 24) + +#define DDESC_CNTL_CHAINED (1U << 24) /* * A hardware buffer descriptor. Rx and Tx buffers have the same descriptor - * layout, but the bits in the flags field have different meanings. + * layout, but the bits in the fields have different meanings. */ struct dwc_hwdesc { - uint32_t tdes0; - uint32_t tdes1; + uint32_t tdes0; /* status for alt layout */ + uint32_t tdes1; /* cntl for alt layout */ uint32_t addr; /* pointer to buffer data */ uint32_t addr_next; /* link to next descriptor */ - uint32_t tdes4; - uint32_t tdes5; - uint32_t timestamp_low; - uint32_t timestamp_high; }; /* - * Driver data and defines. - */ -#ifndef __rtems__ -#define RX_DESC_COUNT 1024 -#else /* __rtems__ */ -#define RX_DESC_COUNT 256 -#endif /* __rtems__ */ -#define RX_DESC_SIZE (sizeof(struct dwc_hwdesc) * RX_DESC_COUNT) -#define TX_DESC_COUNT 1024 -#define TX_DESC_SIZE (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT) -#define TX_MAX_DMA_SEGS 8 /* maximum segs in a tx mbuf dma */ - -/* * The hardware imposes alignment restrictions on various objects involved in * DMA transfers. These values are expressed in bytes (not bits). */ #define DWC_DESC_RING_ALIGN 2048 -#define DWC_CKSUM_ASSIST (CSUM_IP | CSUM_TCP | CSUM_UDP | \ - CSUM_TCP_IPV6 | CSUM_UDP_IPV6) - -struct dwc_softc { - struct resource *res[2]; - bus_space_tag_t bst; - bus_space_handle_t bsh; - device_t dev; - int mii_clk; - device_t miibus; - struct mii_data * mii_softc; - struct ifnet *ifp; - int if_flags; - struct mtx mtx; - void * intr_cookie; - struct callout dwc_callout; - uint8_t phy_conn_type; - uint8_t mactype; - boolean_t link_is_up; - boolean_t is_attached; - boolean_t is_detaching; - int tx_watchdog_count; - int stats_harvest_count; - - /* RX */ - bus_dma_tag_t rxdesc_tag; - bus_dmamap_t rxdesc_map; - struct dwc_hwdesc *rxdesc_ring; -#ifndef __rtems__ - bus_addr_t rxdesc_ring_paddr; - bus_dma_tag_t rxbuf_tag; -#endif /* __rtems__ */ - struct dwc_bufmap rxbuf_map[RX_DESC_COUNT]; - uint32_t rx_idx; - - /* TX */ - bus_dma_tag_t txdesc_tag; - bus_dmamap_t txdesc_map; - struct dwc_hwdesc *txdesc_ring; -#ifndef __rtems__ - bus_addr_t txdesc_ring_paddr; - bus_dma_tag_t txbuf_tag; -#endif /* __rtems__ */ - struct dwc_bufmap txbuf_map[TX_DESC_COUNT]; - uint32_t tx_idx_head; - uint32_t tx_idx_tail; - int txcount; -}; - static struct resource_spec dwc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, @@ -234,13 +157,12 @@ next_rxidx(struct dwc_softc *sc, uint32_t curidx) } static inline uint32_t -next_txidx(struct dwc_softc *sc, uint32_t curidx, int inc) +next_txidx(struct dwc_softc *sc, uint32_t curidx) { - return ((curidx + (uint32_t)inc) % TX_DESC_COUNT); + return ((curidx + 1) % TX_DESC_COUNT); } -#ifndef __rtems__ static void dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { @@ -249,130 +171,75 @@ dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) return; *(bus_addr_t *)arg = segs[0].ds_addr; } -#endif /* __rtems__ */ -static void -dwc_setup_txdesc(struct dwc_softc *sc, int csum_flags, int idx, - bus_dma_segment_t segs[TX_MAX_DMA_SEGS], int nsegs) +inline static uint32_t +dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr, + uint32_t len) { - int i; - - sc->txcount += nsegs; + uint32_t flags; + uint32_t nidx; - idx = next_txidx(sc, idx, nsegs); - sc->tx_idx_head = idx; + nidx = next_txidx(sc, idx); - /* - * Fill in the TX descriptors back to front so that OWN bit in first - * descriptor is set last. - */ - for (i = nsegs - 1; i >= 0; i--) { - uint32_t tdes0; + /* Addr/len 0 means we're clearing the descriptor after xmit done. */ + if (paddr == 0 || len == 0) { + flags = 0; + --sc->txcount; + } else { + if (sc->mactype == DWC_GMAC_ALT_DESC) + flags = DDESC_CNTL_TXCHAIN | DDESC_CNTL_TXFIRST + | DDESC_CNTL_TXLAST | DDESC_CNTL_TXINT; + else + flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXFIRST + | DDESC_TDES0_TXLAST | DDESC_TDES0_TXINT; + ++sc->txcount; + } - idx = next_txidx(sc, idx, -1); + sc->txdesc_ring[idx].addr = (uint32_t)(paddr); + if (sc->mactype == DWC_GMAC_ALT_DESC) { + sc->txdesc_ring[idx].tdes0 = 0; + sc->txdesc_ring[idx].tdes1 = flags | len; + } else { + sc->txdesc_ring[idx].tdes0 = flags; + sc->txdesc_ring[idx].tdes1 = len; + } - sc->txdesc_ring[idx].addr = segs[i].ds_addr; - sc->txdesc_ring[idx].tdes1 = segs[i].ds_len; + if (paddr && len) { wmb(); - - tdes0 = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXINT | - DDESC_TDES0_OWN; - - if (i == 0) { - tdes0 |= DDESC_TDES0_TXFIRST; - - if ((csum_flags & (CSUM_TCP | CSUM_UDP | - CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) != 0) - tdes0 |= DDESC_TDES0_CIC_IP_HDR_PYL_PHDR; - else if ((csum_flags & CSUM_IP) != 0) - tdes0 |= DDESC_TDES0_CIC_IP_HDR; - } - - if (i == nsegs - 1) - tdes0 |= DDESC_TDES0_TXLAST; - - sc->txdesc_ring[idx].tdes0 = tdes0; + sc->txdesc_ring[idx].tdes0 |= DDESC_TDES0_OWN; wmb(); - - if (i != 0) - sc->txbuf_map[idx].mbuf = NULL; } + + return (nidx); } -#ifdef __rtems__ static int -dwc_get_segs_for_tx(struct mbuf *m, bus_dma_segment_t segs[TX_MAX_DMA_SEGS], - int *nsegs) +dwc_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp) { - int i = 0; - - do { - if (m->m_len > 0) { - segs[i].ds_addr = mtod(m, bus_addr_t); - segs[i].ds_len = m->m_len; - rtems_cache_flush_multiple_data_lines(m->m_data, m->m_len); - ++i; - } - - m = m->m_next; - - if (m == NULL) { - *nsegs = i; - - return (0); - } - } while (i < TX_MAX_DMA_SEGS); + struct bus_dma_segment seg; + int error, nsegs; + struct mbuf * m; - return (EFBIG); -} -#endif /* __rtems__ */ -static void -dwc_setup_txbuf(struct dwc_softc *sc, struct mbuf *m, int *start_tx) -{ - bus_dma_segment_t segs[TX_MAX_DMA_SEGS]; - int error, nsegs, idx; + if ((m = m_defrag(*mp, M_NOWAIT)) == NULL) + return (ENOMEM); + *mp = m; - idx = sc->tx_idx_head; -#ifndef __rtems__ error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map, - m, &seg, &nsegs, BUS_DMA_NOWAIT); - -#else /* __rtems__ */ - error = dwc_get_segs_for_tx(m, segs, &nsegs); -#endif /* __rtems__ */ - if (error == EFBIG) { - /* Too many segments! Defrag and try again. */ - struct mbuf *m2 = m_defrag(m, M_NOWAIT); - - if (m2 == NULL) { - m_freem(m); - return; - } - m = m2; -#ifndef __rtems__ - error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, - sc->txbuf_map[idx].map, m, &seg, &nsegs, BUS_DMA_NOWAIT); -#else /* __rtems__ */ - error = dwc_get_segs_for_tx(m, segs, &nsegs); -#endif /* __rtems__ */ - } + m, &seg, &nsegs, 0); if (error != 0) { - /* Give up. */ - m_freem(m); - return; + return (ENOMEM); } - sc->txbuf_map[idx].mbuf = m; + KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); -#ifndef __rtems__ bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map, BUS_DMASYNC_PREWRITE); -#endif /* __rtems__ */ - dwc_setup_txdesc(sc, m->m_pkthdr.csum_flags, idx, segs, nsegs); + sc->txbuf_map[idx].mbuf = m; + + dwc_setup_txdesc(sc, idx, seg.ds_addr, seg.ds_len); - ETHER_BPF_MTAP(sc->ifp, m); - *start_tx = 1; + return (0); } static void @@ -380,7 +247,7 @@ dwc_txstart_locked(struct dwc_softc *sc) { struct ifnet *ifp; struct mbuf *m; - int start_tx; + int enqueued; DWC_ASSERT_LOCKED(sc); @@ -389,10 +256,14 @@ dwc_txstart_locked(struct dwc_softc *sc) ifp = sc->ifp; - start_tx = 0; + if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { + return; + } + + enqueued = 0; for (;;) { - if (sc->txcount >= (TX_DESC_COUNT - 1 - TX_MAX_DMA_SEGS)) { + if (sc->txcount == (TX_DESC_COUNT-1)) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } @@ -400,11 +271,16 @@ dwc_txstart_locked(struct dwc_softc *sc) IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; - - dwc_setup_txbuf(sc, m, &start_tx); + if (dwc_setup_txbuf(sc, sc->tx_idx_head, &m) != 0) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + break; + } + BPF_MTAP(ifp, m); + sc->tx_idx_head = next_txidx(sc, sc->tx_idx_head); + ++enqueued; } - if (start_tx != 0) { + if (enqueued != 0) { WRITE4(sc, TRANSMIT_POLL_DEMAND, 0x1); sc->tx_watchdog_count = WATCHDOG_TIMEOUT_SECS; } @@ -416,8 +292,7 @@ dwc_txstart(struct ifnet *ifp) struct dwc_softc *sc = ifp->if_softc; DWC_LOCK(sc); - if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) - dwc_txstart_locked(sc); + dwc_txstart_locked(sc); DWC_UNLOCK(sc); } @@ -425,7 +300,7 @@ static void dwc_stop_locked(struct dwc_softc *sc) { struct ifnet *ifp; - int reg; + uint32_t reg; DWC_ASSERT_LOCKED(sc); @@ -459,7 +334,7 @@ dwc_stop_locked(struct dwc_softc *sc) static void dwc_clear_stats(struct dwc_softc *sc) { - int reg; + uint32_t reg; reg = READ4(sc, MMC_CONTROL); reg |= (MMC_CONTROL_CNTRST); @@ -478,7 +353,6 @@ dwc_harvest_stats(struct dwc_softc *sc) sc->stats_harvest_count = 0; ifp = sc->ifp; -#ifndef __rtems__ if_inc_counter(ifp, IFCOUNTER_IPACKETS, READ4(sc, RXFRAMECOUNT_GB)); if_inc_counter(ifp, IFCOUNTER_IMCASTS, READ4(sc, RXMULTICASTFRAMES_G)); if_inc_counter(ifp, IFCOUNTER_IERRORS, @@ -495,24 +369,6 @@ dwc_harvest_stats(struct dwc_softc *sc) if_inc_counter(ifp, IFCOUNTER_COLLISIONS, READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL)); -#else /* __rtems__ */ - ifp->if_ipackets += READ4(sc, RXFRAMECOUNT_GB); - ifp->if_imcasts += READ4(sc, RXMULTICASTFRAMES_G); - ifp->if_ierrors += - READ4(sc, RXOVERSIZE_G) + READ4(sc, RXUNDERSIZE_G) + - READ4(sc, RXCRCERROR) + READ4(sc, RXALIGNMENTERROR) + - READ4(sc, RXRUNTERROR) + READ4(sc, RXJABBERERROR) + - READ4(sc, RXLENGTHERROR); - - ifp->if_opackets += READ4(sc, TXFRAMECOUNT_G); - ifp->if_omcasts += READ4(sc, TXMULTICASTFRAMES_G); - ifp->if_oerrors += - READ4(sc, TXOVERSIZE_G) + READ4(sc, TXEXCESSDEF) + - READ4(sc, TXCARRIERERR) + READ4(sc, TXUNDERFLOWERROR); - - ifp->if_collisions += - READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL); -#endif /* __rtems__ */ dwc_clear_stats(sc); } @@ -561,7 +417,7 @@ static void dwc_init_locked(struct dwc_softc *sc) { struct ifnet *ifp = sc->ifp; - int reg; + uint32_t reg; DWC_ASSERT_LOCKED(sc); @@ -588,7 +444,6 @@ dwc_init_locked(struct dwc_softc *sc) /* Enable transmitters */ reg = READ4(sc, MAC_CONFIGURATION); - reg |= (CONF_IPC); reg |= (CONF_JD | CONF_ACS | CONF_BE); reg |= (CONF_TE | CONF_RE); WRITE4(sc, MAC_CONFIGURATION, reg); @@ -618,13 +473,12 @@ dwc_setup_rxdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr) sc->rxdesc_ring[idx].addr = (uint32_t)paddr; nidx = next_rxidx(sc, idx); -#ifndef __rtems__ sc->rxdesc_ring[idx].addr_next = sc->rxdesc_ring_paddr + \ (nidx * sizeof(struct dwc_hwdesc)); -#else /* __rtems__ */ - sc->rxdesc_ring[idx].addr_next = (uint32_t)&sc->rxdesc_ring[nidx]; -#endif /* __rtems__ */ - sc->rxdesc_ring[idx].tdes1 = DDESC_RDES1_CHAINED | MCLBYTES; + if (sc->mactype == DWC_GMAC_ALT_DESC) + sc->rxdesc_ring[idx].tdes1 = DDESC_CNTL_CHAINED | RX_MAX_PACKET; + else + sc->rxdesc_ring[idx].tdes1 = DDESC_RDES1_CHAINED | MCLBYTES; wmb(); sc->rxdesc_ring[idx].tdes0 = DDESC_RDES0_OWN; @@ -636,14 +490,11 @@ dwc_setup_rxdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr) static int dwc_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m) { - bus_dma_segment_t seg; -#ifndef __rtems__ + struct bus_dma_segment seg; int error, nsegs; -#endif /* __rtems__ */ m_adj(m, ETHER_ALIGN); -#ifndef __rtems__ error = bus_dmamap_load_mbuf_sg(sc->rxbuf_tag, sc->rxbuf_map[idx].map, m, &seg, &nsegs, 0); if (error != 0) { @@ -654,10 +505,6 @@ dwc_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m) bus_dmamap_sync(sc->rxbuf_tag, sc->rxbuf_map[idx].map, BUS_DMASYNC_PREREAD); -#else /* __rtems__ */ - rtems_cache_invalidate_multiple_data_lines(m->m_data, m->m_len); - seg.ds_addr = mtod(m, bus_addr_t); -#endif /* __rtems__ */ sc->rxbuf_map[idx].mbuf = m; dwc_setup_rxdesc(sc, idx, seg.ds_addr); @@ -743,27 +590,26 @@ dwc_setup_rxfilter(struct dwc_softc *sc) { struct ifmultiaddr *ifma; struct ifnet *ifp; - uint8_t *eaddr; - uint32_t crc; - uint8_t val; - int hashbit; - int hashreg; - int ffval; - int reg; - int lo; - int hi; + uint8_t *eaddr, val; + uint32_t crc, ffval, hashbit, hashreg, hi, lo, hash[8]; + int nhash, i; DWC_ASSERT_LOCKED(sc); ifp = sc->ifp; + nhash = sc->mactype == DWC_GMAC_ALT_DESC ? 2 : 8; /* * Set the multicast (group) filter hash. */ - if ((ifp->if_flags & IFF_ALLMULTI)) + if ((ifp->if_flags & IFF_ALLMULTI) != 0) { ffval = (FRAME_FILTER_PM); - else { + for (i = 0; i < nhash; i++) + hash[i] = ~0; + } else { ffval = (FRAME_FILTER_HMC); + for (i = 0; i < nhash; i++) + hash[i] = 0; if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) @@ -773,12 +619,11 @@ dwc_setup_rxfilter(struct dwc_softc *sc) /* Take lower 8 bits and reverse it */ val = bitreverse(~crc & 0xff); + if (sc->mactype == DWC_GMAC_ALT_DESC) + val >>= nhash; /* Only need lower 6 bits */ hashreg = (val >> 5); hashbit = (val & 31); - - reg = READ4(sc, HASH_TABLE_REG(hashreg)); - reg |= (1 << hashbit); - WRITE4(sc, HASH_TABLE_REG(hashreg), reg); + hash[hashreg] |= (1 << hashbit); } if_maddr_runlock(ifp); } @@ -799,6 +644,13 @@ dwc_setup_rxfilter(struct dwc_softc *sc) WRITE4(sc, MAC_ADDRESS_LOW(0), lo); WRITE4(sc, MAC_ADDRESS_HIGH(0), hi); WRITE4(sc, MAC_FRAME_FILTER, ffval); + if (sc->mactype == DWC_GMAC_ALT_DESC) { + WRITE4(sc, GMAC_MAC_HTLOW, hash[0]); + WRITE4(sc, GMAC_MAC_HTHIGH, hash[1]); + } else { + for (i = 0; i < nhash; i++) + WRITE4(sc, HASH_TABLE_REG(i), hash[i]); + } } static int @@ -866,28 +718,27 @@ dwc_txfinish_locked(struct dwc_softc *sc) { struct dwc_bufmap *bmap; struct dwc_hwdesc *desc; + struct ifnet *ifp; DWC_ASSERT_LOCKED(sc); + ifp = sc->ifp; while (sc->tx_idx_tail != sc->tx_idx_head) { desc = &sc->txdesc_ring[sc->tx_idx_tail]; if ((desc->tdes0 & DDESC_TDES0_OWN) != 0) break; bmap = &sc->txbuf_map[sc->tx_idx_tail]; -#ifndef __rtems__ bus_dmamap_sync(sc->txbuf_tag, bmap->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->txbuf_tag, bmap->map); -#endif /* __rtems__ */ m_freem(bmap->mbuf); bmap->mbuf = NULL; - --sc->txcount; - sc->tx_idx_tail = next_txidx(sc, sc->tx_idx_tail, 1); + dwc_setup_txdesc(sc, sc->tx_idx_tail, 0, 0); + sc->tx_idx_tail = next_txidx(sc, sc->tx_idx_tail); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } - sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - dwc_txstart_locked(sc); - /* If there are no buffers outstanding, muzzle the watchdog. */ if (sc->tx_idx_tail == sc->tx_idx_head) { sc->tx_watchdog_count = 0; @@ -900,11 +751,8 @@ dwc_rxfinish_locked(struct dwc_softc *sc) struct ifnet *ifp; struct mbuf *m0; struct mbuf *m; - int error; + int error, idx, len; uint32_t rdes0; - uint32_t rdes4; - int idx; - int len; ifp = sc->ifp; @@ -915,78 +763,20 @@ dwc_rxfinish_locked(struct dwc_softc *sc) if ((rdes0 & DDESC_RDES0_OWN) != 0) break; - sc->rx_idx = next_rxidx(sc, idx); - - m = sc->rxbuf_map[idx].mbuf; - - m0 = dwc_alloc_mbufcl(sc); - if (m0 == NULL) { - m0 = m; - - /* Account for m_adj() in dwc_setup_rxbuf() */ - m0->m_data = m0->m_ext.ext_buf; - } - - if ((error = dwc_setup_rxbuf(sc, idx, m0)) != 0) { - /* - * XXX Now what? - * We've got a hole in the rx ring. - */ - } - - if (m0 == m) { - /* Discard frame and continue */ -#ifndef __rtems__ - if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1); -#else /* __rtems__ */ - ++ifp->if_iqdrops; -#endif /* __rtems__ */ - continue; - } - -#ifndef __rtems__ bus_dmamap_sync(sc->rxbuf_tag, sc->rxbuf_map[idx].map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->rxbuf_tag, sc->rxbuf_map[idx].map); -#endif /* __rtems__ */ len = (rdes0 >> DDESC_RDES0_FL_SHIFT) & DDESC_RDES0_FL_MASK; if (len != 0) { + m = sc->rxbuf_map[idx].mbuf; m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = len; m->m_len = len; - - /* Check checksum offload flags. */ - if ((rdes0 & DDESC_RDES0_ESA) != 0) { - rdes4 = sc->rxdesc_ring[idx].tdes4; - - /* TCP or UDP checks out, IP checks out too. */ - if ((rdes4 & DDESC_RDES4_IP_PYL_TYPE_MSK) == - DDESC_RDES4_IP_PYL_UDP || - (rdes4 & DDESC_RDES4_IP_PYL_TYPE_MSK) == - DDESC_RDES4_IP_PYL_TCP) { - m->m_pkthdr.csum_flags |= - CSUM_IP_CHECKED | - CSUM_IP_VALID | - CSUM_DATA_VALID | - CSUM_PSEUDO_HDR; - m->m_pkthdr.csum_data = 0xffff; - } else if ((rdes4 & (DDESC_RDES4_IP_PYL_ERR | - DDESC_RDES4_IP_HDR_ERR)) == 0) { - /* Only IP checks out. */ - m->m_pkthdr.csum_flags |= - CSUM_IP_CHECKED | - CSUM_IP_VALID; - m->m_pkthdr.csum_data = 0xffff; - } - } - -#ifndef __rtems__ if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); -#else /* __rtems__ */ - ++ifp->if_ipackets; - rtems_cache_invalidate_multiple_data_lines(m->m_data, m->m_len); -#endif /* __rtems__ */ + + /* Remove trailing FCS */ + m_adj(m, -ETHER_CRC_LEN); DWC_UNLOCK(sc); (*ifp->if_input)(ifp, m); @@ -994,6 +784,18 @@ dwc_rxfinish_locked(struct dwc_softc *sc) } else { /* XXX Zero-length packet ? */ } + + if ((m0 = dwc_alloc_mbufcl(sc)) != NULL) { + if ((error = dwc_setup_rxbuf(sc, idx, m0)) != 0) { + /* + * XXX Now what? + * We've got a hole in the rx ring. + */ + } + } else + if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1); + + sc->rx_idx = next_rxidx(sc, sc->rx_idx); } } @@ -1008,28 +810,31 @@ dwc_intr(void *arg) DWC_LOCK(sc); reg = READ4(sc, INTERRUPT_STATUS); - if (reg) { - mii_mediachg(sc->mii_softc); + if (reg) READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS); - } reg = READ4(sc, DMA_STATUS); - WRITE4(sc, DMA_STATUS, reg & DMA_STATUS_INTR_MASK); - - if (reg & (DMA_STATUS_RI | DMA_STATUS_RU)) - dwc_rxfinish_locked(sc); + if (reg & DMA_STATUS_NIS) { + if (reg & DMA_STATUS_RI) + dwc_rxfinish_locked(sc); - if (reg & DMA_STATUS_TI) - dwc_txfinish_locked(sc); + if (reg & DMA_STATUS_TI) { + dwc_txfinish_locked(sc); + dwc_txstart_locked(sc); + } + } - if (reg & DMA_STATUS_FBI) { - /* Fatal bus error */ - device_printf(sc->dev, - "Ethernet DMA error, restarting controller.\n"); - dwc_stop_locked(sc); - dwc_init_locked(sc); + if (reg & DMA_STATUS_AIS) { + if (reg & DMA_STATUS_FBI) { + /* Fatal bus error */ + device_printf(sc->dev, + "Ethernet DMA error, restarting controller.\n"); + dwc_stop_locked(sc); + dwc_init_locked(sc); + } } + WRITE4(sc, DMA_STATUS, reg & DMA_STATUS_INTR_MASK); DWC_UNLOCK(sc); } @@ -1070,7 +875,6 @@ setup_dma(struct dwc_softc *sc) goto out; } -#ifndef __rtems__ error = bus_dmamap_load(sc->txdesc_tag, sc->txdesc_map, sc->txdesc_ring, TX_DESC_SIZE, dwc_get1paddr, &sc->txdesc_ring_paddr, 0); @@ -1079,30 +883,20 @@ setup_dma(struct dwc_softc *sc) "could not load TX descriptor ring map.\n"); goto out; } -#endif /* __rtems__ */ for (idx = 0; idx < TX_DESC_COUNT; idx++) { - sc->txdesc_ring[idx].addr = 0; - sc->txdesc_ring[idx].tdes0 = DDESC_TDES0_TXCHAIN; - sc->txdesc_ring[idx].tdes1 = 0; - nidx = next_txidx(sc, idx, 1); -#ifndef __rtems__ - sc->txdesc_ring[idx].addr_next = sc->txdesc_ring_paddr + \ + nidx = next_txidx(sc, idx); + sc->txdesc_ring[idx].addr_next = sc->txdesc_ring_paddr + (nidx * sizeof(struct dwc_hwdesc)); -#else /* __rtems__ */ - sc->txdesc_ring[idx].addr_next = - (uint32_t)&sc->txdesc_ring[nidx]; -#endif /* __rtems__ */ } -#ifndef __rtems__ error = bus_dma_tag_create( bus_get_dma_tag(sc->dev), /* Parent tag. */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - MCLBYTES, TX_MAX_DMA_SEGS, /* maxsize, nsegments */ + MCLBYTES, 1, /* maxsize, nsegments */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ @@ -1112,10 +906,8 @@ setup_dma(struct dwc_softc *sc) "could not create TX ring DMA tag.\n"); goto out; } -#endif /* __rtems__ */ for (idx = 0; idx < TX_DESC_COUNT; idx++) { -#ifndef __rtems__ error = bus_dmamap_create(sc->txbuf_tag, BUS_DMA_COHERENT, &sc->txbuf_map[idx].map); if (error != 0) { @@ -1123,7 +915,7 @@ setup_dma(struct dwc_softc *sc) "could not create TX buffer DMA map.\n"); goto out; } -#endif /* __rtems__ */ + dwc_setup_txdesc(sc, idx, 0, 0); } /* @@ -1155,7 +947,6 @@ setup_dma(struct dwc_softc *sc) goto out; } -#ifndef __rtems__ error = bus_dmamap_load(sc->rxdesc_tag, sc->rxdesc_map, sc->rxdesc_ring, RX_DESC_SIZE, dwc_get1paddr, &sc->rxdesc_ring_paddr, 0); @@ -1181,10 +972,8 @@ setup_dma(struct dwc_softc *sc) "could not create RX buf DMA tag.\n"); goto out; } -#endif /* __rtems__ */ for (idx = 0; idx < RX_DESC_COUNT; idx++) { -#ifndef __rtems__ error = bus_dmamap_create(sc->rxbuf_tag, BUS_DMA_COHERENT, &sc->rxbuf_map[idx].map); if (error != 0) { @@ -1192,7 +981,6 @@ setup_dma(struct dwc_softc *sc) "could not create RX buffer DMA map.\n"); goto out; } -#endif /* __rtems__ */ if ((m = dwc_alloc_mbufcl(sc)) == NULL) { device_printf(sc->dev, "Could not alloc mbuf\n"); error = ENOMEM; @@ -1203,7 +991,6 @@ setup_dma(struct dwc_softc *sc) "could not create new RX buffer.\n"); goto out; } - sc->rxdesc_ring[idx].tdes4 = 0; } out: @@ -1216,11 +1003,7 @@ out: static int dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) { -#ifndef __rtems__ - int rnd; -#endif /* __rtems__ */ - int lo; - int hi; + uint32_t hi, lo, rnd; /* * Try to recover a MAC address from the running hardware. If there's @@ -1241,7 +1024,6 @@ dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) hwaddr[4] = (hi >> 0) & 0xff; hwaddr[5] = (hi >> 8) & 0xff; } else { -#ifndef __rtems__ rnd = arc4random() & 0x00ffffff; hwaddr[0] = 'b'; hwaddr[1] = 's'; @@ -1249,14 +1031,98 @@ dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) hwaddr[3] = rnd >> 16; hwaddr[4] = rnd >> 8; hwaddr[5] = rnd >> 0; -#else /* __rtems__ */ - rtems_bsd_get_mac_address(device_get_name(sc->dev), - device_get_unit(sc->dev), hwaddr); + } + + return (0); +} + +#define GPIO_ACTIVE_LOW 1 + +static int +dwc_reset(device_t dev) +{ +#ifndef __rtems__ + pcell_t gpio_prop[4]; + pcell_t delay_prop[3]; + phandle_t node, gpio_node; + device_t gpio; + uint32_t pin, flags; + uint32_t pin_value; + + node = ofw_bus_get_node(dev); + if (OF_getencprop(node, "snps,reset-gpio", + gpio_prop, sizeof(gpio_prop)) <= 0) + return (0); + + if (OF_getencprop(node, "snps,reset-delays-us", + delay_prop, sizeof(delay_prop)) <= 0) { + device_printf(dev, + "Wrong property for snps,reset-delays-us"); + return (ENXIO); + } + + gpio_node = OF_node_from_xref(gpio_prop[0]); + if ((gpio = OF_device_from_xref(gpio_prop[0])) == NULL) { + device_printf(dev, + "Can't find gpio controller for phy reset\n"); + return (ENXIO); + } + + if (GPIO_MAP_GPIOS(gpio, node, gpio_node, + nitems(gpio_prop) - 1, + gpio_prop + 1, &pin, &flags) != 0) { + device_printf(dev, "Can't map gpio for phy reset\n"); + return (ENXIO); + } + + pin_value = GPIO_PIN_LOW; + if (OF_hasprop(node, "snps,reset-active-low")) + pin_value = GPIO_PIN_HIGH; + + if (flags & GPIO_ACTIVE_LOW) + pin_value = !pin_value; + + GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT); + GPIO_PIN_SET(gpio, pin, pin_value); + DELAY(delay_prop[0]); + GPIO_PIN_SET(gpio, pin, !pin_value); + DELAY(delay_prop[1]); + GPIO_PIN_SET(gpio, pin, pin_value); + DELAY(delay_prop[2]); #endif /* __rtems__ */ + + return (0); +} + +#ifdef EXT_RESOURCES +static int +dwc_clock_init(device_t dev) +{ + hwreset_t rst; + clk_t clk; + int error; + + /* Enable clock */ + if (clk_get_by_ofw_name(dev, 0, "stmmaceth", &clk) == 0) { + error = clk_enable(clk); + if (error != 0) { + device_printf(dev, "could not enable main clock\n"); + return (error); + } + } + + /* De-assert reset */ + if (hwreset_get_by_ofw_name(dev, 0, "stmmaceth", &rst) == 0) { + error = hwreset_deassert(rst); + if (error != 0) { + device_printf(dev, "could not de-assert reset\n"); + return (error); + } } return (0); } +#endif static int dwc_probe(device_t dev) @@ -1280,15 +1146,23 @@ dwc_attach(device_t dev) uint8_t macaddr[ETHER_ADDR_LEN]; struct dwc_softc *sc; struct ifnet *ifp; - int error; - int reg; - int i; + int error, i; + uint32_t reg; sc = device_get_softc(dev); sc->dev = dev; - sc->mii_clk = MII_CLK_VAL; sc->rx_idx = 0; - sc->txcount = 0; + sc->txcount = TX_DESC_COUNT; + sc->mii_clk = IF_DWC_MII_CLK(dev); + sc->mactype = IF_DWC_MAC_TYPE(dev); + + if (IF_DWC_INIT(dev) != 0) + return (ENXIO); + +#ifdef EXT_RESOURCES + if (dwc_clock_init(dev) != 0) + return (ENXIO); +#endif if (bus_alloc_resources(dev, dwc_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); @@ -1305,6 +1179,12 @@ dwc_attach(device_t dev) return (ENXIO); } + /* Reset the PHY if needed */ + if (dwc_reset(dev) != 0) { + device_printf(dev, "Can't reset the PHY\n"); + return (ENXIO); + } + /* Reset */ reg = READ4(sc, BUS_MODE); reg |= (BUS_MODE_SWR); @@ -1320,9 +1200,11 @@ dwc_attach(device_t dev) return (ENXIO); } - reg = READ4(sc, BUS_MODE); - reg |= (BUS_MODE_ATDS); - reg |= (BUS_MODE_EIGHTXPBL); + if (sc->mactype == DWC_GMAC_ALT_DESC) { + reg = BUS_MODE_FIXEDBURST; + reg |= (BUS_MODE_PRIORXTX_41 << BUS_MODE_PRIORXTX_SHIFT); + } else + reg = (BUS_MODE_EIGHTXPBL); reg |= (BUS_MODE_PBL_BEATS_8 << BUS_MODE_PBL_SHIFT); WRITE4(sc, BUS_MODE, reg); @@ -1337,36 +1219,36 @@ dwc_attach(device_t dev) return (ENXIO); /* Setup addresses */ -#ifndef __rtems__ WRITE4(sc, RX_DESCR_LIST_ADDR, sc->rxdesc_ring_paddr); WRITE4(sc, TX_DESCR_LIST_ADDR, sc->txdesc_ring_paddr); -#else /* __rtems__ */ - WRITE4(sc, RX_DESCR_LIST_ADDR, (uint32_t)&sc->rxdesc_ring[0]); - WRITE4(sc, TX_DESCR_LIST_ADDR, (uint32_t)&sc->txdesc_ring[0]); -#endif /* __rtems__ */ mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_NETWORK_LOCK, MTX_DEF); callout_init_mtx(&sc->dwc_callout, &sc->mtx, 0); + /* Setup interrupt handler. */ + error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, + NULL, dwc_intr, sc, &sc->intr_cookie); + if (error != 0) { + device_printf(dev, "could not setup interrupt handler.\n"); + return (ENXIO); + } + /* Set up the ethernet interface. */ sc->ifp = ifp = if_alloc(IFT_ETHER); ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 | - IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM; + ifp->if_capabilities = IFCAP_VLAN_MTU; ifp->if_capenable = ifp->if_capabilities; - ifp->if_hwassist = DWC_CKSUM_ASSIST; ifp->if_start = dwc_txstart; ifp->if_ioctl = dwc_ioctl; ifp->if_init = dwc_init; IFQ_SET_MAXLEN(&ifp->if_snd, TX_DESC_COUNT - 1); ifp->if_snd.ifq_drv_maxlen = TX_DESC_COUNT - 1; IFQ_SET_READY(&ifp->if_snd); - ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* Attach the mii driver. */ error = mii_attach(dev, &sc->miibus, ifp, dwc_media_change, @@ -1379,14 +1261,6 @@ dwc_attach(device_t dev) } sc->mii_softc = device_get_softc(sc->miibus); - /* Setup interrupt handler. */ - error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, - NULL, dwc_intr, sc, &sc->intr_cookie); - if (error != 0) { - device_printf(dev, "could not setup interrupt handler.\n"); - return (ENXIO); - } - /* All ready to run, attach the ethernet interface. */ ether_ifattach(ifp, macaddr); sc->is_attached = true; @@ -1454,7 +1328,7 @@ dwc_miibus_statchg(device_t dev) { struct dwc_softc *sc; struct mii_data *mii; - int reg; + uint32_t reg; /* * Called by the MII bus driver when the PHY establishes @@ -1513,7 +1387,7 @@ static device_method_t dwc_methods[] = { { 0, 0 } }; -static driver_t dwc_driver = { +driver_t dwc_driver = { "dwc", dwc_methods, sizeof(struct dwc_softc), @@ -1521,11 +1395,7 @@ static driver_t dwc_driver = { static devclass_t dwc_devclass; -#ifndef __rtems__ DRIVER_MODULE(dwc, simplebus, dwc_driver, dwc_devclass, 0, 0); -#else /* __rtems__ */ -DRIVER_MODULE(dwc, nexus, dwc_driver, dwc_devclass, 0, 0); -#endif /* __rtems__ */ DRIVER_MODULE(miibus, dwc, miibus_driver, miibus_devclass, 0, 0); MODULE_DEPEND(dwc, ether, 1, 1, 1); |