Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ic Add support for the enhanced descriptors feature.



details:   https://anonhg.NetBSD.org/src/rev/8eb504c3cd07
branches:  trunk
changeset: 835945:8eb504c3cd07
user:      aymeric <aymeric%NetBSD.org@localhost>
date:      Mon Sep 17 20:25:49 2018 +0000

description:
Add support for the enhanced descriptors feature.

This makes "recent" dwc gmac controllers, as found e.g. on the Cyclone V, work.
The change was also tested working on an Allwinner A20 which doesn't have the
feature.

No negative reaction on port-arm.

diffstat:

 sys/dev/ic/dwc_gmac.c     |  233 +++++++++++++++++++++++++++++++++++++--------
 sys/dev/ic/dwc_gmac_reg.h |   30 +++++-
 sys/dev/ic/dwc_gmac_var.h |   19 +++-
 3 files changed, 236 insertions(+), 46 deletions(-)

diffs (truncated from 497 to 300 lines):

diff -r e8598d64a33e -r 8eb504c3cd07 sys/dev/ic/dwc_gmac.c
--- a/sys/dev/ic/dwc_gmac.c     Mon Sep 17 16:52:28 2018 +0000
+++ b/sys/dev/ic/dwc_gmac.c     Mon Sep 17 20:25:49 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_gmac.c,v 1.52 2018/07/18 23:10:27 sevan Exp $ */
+/* $NetBSD: dwc_gmac.c,v 1.53 2018/09/17 20:25:49 aymeric Exp $ */
 
 /*-
  * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.52 2018/07/18 23:10:27 sevan Exp $");
+__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.53 2018/09/17 20:25:49 aymeric Exp $");
 
 /* #define     DWC_GMAC_DEBUG  1 */
 
@@ -100,6 +100,53 @@
 static void dwc_gmac_setmulti(struct dwc_gmac_softc *sc);
 static int dwc_gmac_ifflags_cb(struct ethercom *);
 static uint32_t        bitrev32(uint32_t x);
+static void dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *);
+static int  dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *, int);
+static int  dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *);
+static int  dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *, int);
+static int  dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *);
+static void dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *);
+static int  dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *);
+
+static const struct dwc_gmac_desc_methods desc_methods_standard = {
+       .tx_init_flags = dwc_gmac_desc_std_tx_init_flags,
+       .tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev,
+       .tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev,
+       .tx_set_len = dwc_gmac_desc_std_set_len,
+       .tx_set_first_frag = dwc_gmac_desc_std_tx_set_first_frag,
+       .tx_set_last_frag = dwc_gmac_desc_std_tx_set_last_frag,
+       .rx_init_flags = dwc_gmac_desc_std_rx_init_flags,
+       .rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev,
+       .rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev,
+       .rx_set_len = dwc_gmac_desc_std_set_len,
+       .rx_get_len = dwc_gmac_desc_std_get_len,
+       .rx_has_error = dwc_gmac_desc_std_rx_has_error
+};
+
+static const struct dwc_gmac_desc_methods desc_methods_enhanced = {
+       .tx_init_flags = dwc_gmac_desc_enh_tx_init_flags,
+       .tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev,
+       .tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev,
+       .tx_set_len = dwc_gmac_desc_enh_set_len,
+       .tx_set_first_frag = dwc_gmac_desc_enh_tx_set_first_frag,
+       .tx_set_last_frag = dwc_gmac_desc_enh_tx_set_last_frag,
+       .rx_init_flags = dwc_gmac_desc_enh_rx_init_flags,
+       .rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev,
+       .rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev,
+       .rx_set_len = dwc_gmac_desc_enh_set_len,
+       .rx_get_len = dwc_gmac_desc_enh_get_len,
+       .rx_has_error = dwc_gmac_desc_enh_rx_has_error
+};
+
 
 #define        TX_DESC_OFFSET(N)       ((AWGE_RX_RING_COUNT+(N)) \
                                    *sizeof(struct dwc_gmac_dev_dmadesc))
@@ -122,7 +169,7 @@
 
 #define        AWIN_DEF_MAC_INTRMASK   \
        (AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG |       \
-       AWIN_GMAC_MAC_INT_LINKCHG | AWIN_GMAC_MAC_INT_RGSMII)
+       AWIN_GMAC_MAC_INT_LINKCHG)
 
 #ifdef DWC_GMAC_DEBUG
 static void dwc_gmac_dump_dma(struct dwc_gmac_softc *sc);
@@ -194,6 +241,12 @@
        aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n",
            ether_sprintf(enaddr));
 
+       if (bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_HWFEATURES) &
+           GMAC_DMA_FEAT_ENHANCED_DESC)
+               sc->sc_descm = &desc_methods_enhanced;
+       else
+               sc->sc_descm = &desc_methods_standard;
+
        /*
         * Allocate Tx and Rx rings
         */
@@ -444,10 +497,9 @@
                next = RX_NEXT(i);
                desc->ddesc_next = htole32(ring->r_physaddr
                    + next * sizeof(*desc));
-               desc->ddesc_cntl = htole32(
-                   __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
-                   DDESC_CNTL_RXCHAIN);
-               desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
+               sc->sc_descm->rx_init_flags(desc);
+               sc->sc_descm->rx_set_len(desc, AWGE_MAX_PACKET);
+               sc->sc_descm->rx_set_owned_by_dev(desc);
        }
 
        bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
@@ -473,10 +525,9 @@
        mutex_enter(&ring->r_mtx);
        for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
                desc = &sc->sc_rxq.r_desc[i];
-               desc->ddesc_cntl = htole32(
-                   __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
-                   DDESC_CNTL_RXCHAIN);
-               desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
+               sc->sc_descm->rx_init_flags(desc);
+               sc->sc_descm->rx_set_len(desc, AWGE_MAX_PACKET);
+               sc->sc_descm->rx_set_owned_by_dev(desc);
        }
 
        bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
@@ -891,11 +942,11 @@
                dwc_gmac_txdesc_sync(sc, start, sc->sc_txq.t_cur,
                    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
 
-               bus_space_write_4(sc->sc_bst, sc->sc_bsh,
-                   AWIN_GMAC_DMA_TXPOLL, ~0U);
 #ifdef DWC_GMAC_DEBUG
                dwc_dump_status(sc);
 #endif
+               bus_space_write_4(sc->sc_bst, sc->sc_bsh,
+                   AWIN_GMAC_DMA_TXPOLL, ~0U);
        }
 }
 
@@ -942,7 +993,6 @@
        struct dwc_gmac_dev_dmadesc *desc = NULL;
        struct dwc_gmac_tx_data *data = NULL;
        bus_dmamap_t map;
-       uint32_t flags, len, status;
        int error, i, first;
 
 #ifdef DWC_GMAC_DEBUG
@@ -966,38 +1016,37 @@
                return ENOBUFS;
        }
 
-       flags = DDESC_CNTL_TXFIRST|DDESC_CNTL_TXCHAIN;
-       status = 0;
        for (i = 0; i < map->dm_nsegs; i++) {
                data = &sc->sc_txq.t_data[sc->sc_txq.t_cur];
                desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur];
 
                desc->ddesc_data = htole32(map->dm_segs[i].ds_addr);
-               len = __SHIFTIN(map->dm_segs[i].ds_len, DDESC_CNTL_SIZE1MASK);
 
 #ifdef DWC_GMAC_DEBUG
                aprint_normal_dev(sc->sc_dev, "enqueing desc #%d data %08lx "
-                   "len %lu (flags: %08x, len: %08x)\n", sc->sc_txq.t_cur,
+                   "len %lu\n", sc->sc_txq.t_cur,
                    (unsigned long)map->dm_segs[i].ds_addr,
-                   (unsigned long)map->dm_segs[i].ds_len,
-                   flags, len);
+                   (unsigned long)map->dm_segs[i].ds_len);
 #endif
 
-               desc->ddesc_cntl = htole32(len|flags);
-               flags &= ~DDESC_CNTL_TXFIRST;
+               sc->sc_descm->tx_init_flags(desc);
+               sc->sc_descm->tx_set_len(desc, map->dm_segs[i].ds_len);
+
+               if (i == 0)
+                       sc->sc_descm->tx_set_first_frag(desc);
 
                /*
                 * Defer passing ownership of the first descriptor
                 * until we are done.
                 */
-               desc->ddesc_status = htole32(status);
-               status |= DDESC_STATUS_OWNEDBYDEV;
+               if (i != 0)
+                       sc->sc_descm->tx_set_owned_by_dev(desc);
 
                sc->sc_txq.t_queued++;
                sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur);
        }
 
-       desc->ddesc_cntl |= htole32(DDESC_CNTL_TXLAST|DDESC_CNTL_TXINT);
+       sc->sc_descm->tx_set_last_frag(desc);
 
        data->td_m = m0;
        data->td_active = map;
@@ -1006,8 +1055,10 @@
            BUS_DMASYNC_PREWRITE);
 
        /* Pass first to device */
-       sc->sc_txq.t_desc[first].ddesc_status =
-           htole32(DDESC_STATUS_OWNEDBYDEV);
+       sc->sc_descm->tx_set_owned_by_dev(&sc->sc_txq.t_desc[first]);
+
+       bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
+           BUS_DMASYNC_PREWRITE);
 
        return 0;
 }
@@ -1087,7 +1138,6 @@
        struct ifnet *ifp = &sc->sc_ec.ec_if;
        struct dwc_gmac_tx_data *data;
        struct dwc_gmac_dev_dmadesc *desc;
-       uint32_t status;
        int i, nsegs;
 
        mutex_enter(&sc->sc_txq.t_mtx);
@@ -1108,8 +1158,7 @@
                    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
 
                desc = &sc->sc_txq.t_desc[i];
-               status = le32toh(desc->ddesc_status);
-               if (status & DDESC_STATUS_OWNEDBYDEV)
+               if (sc->sc_descm->tx_is_owned_by_dev(desc))
                        break;
 
                data = &sc->sc_txq.t_data[i];
@@ -1149,7 +1198,6 @@
        struct dwc_gmac_dev_dmadesc *desc;
        struct dwc_gmac_rx_data *data;
        bus_addr_t physaddr;
-       uint32_t status;
        struct mbuf *m, *mnew;
        int i, len, error;
 
@@ -1161,21 +1209,20 @@
                desc = &sc->sc_rxq.r_desc[i];
                data = &sc->sc_rxq.r_data[i];
 
-               status = le32toh(desc->ddesc_status);
-               if (status & DDESC_STATUS_OWNEDBYDEV)
+               if (sc->sc_descm->rx_is_owned_by_dev(desc))
                        break;
 
-               if (status & (DDESC_STATUS_RXERROR|DDESC_STATUS_RXTRUNCATED)) {
+               if (sc->sc_descm->rx_has_error(desc)) {
 #ifdef DWC_GMAC_DEBUG
                        aprint_normal_dev(sc->sc_dev,
                            "RX error: descriptor status %08x, skipping\n",
-                           status);
+                           le32toh(desc->ddesc_status0));
 #endif
                        ifp->if_ierrors++;
                        goto skip;
                }
 
-               len = __SHIFTOUT(status, DDESC_STATUS_FRMLENMSK);
+               len = sc->sc_descm->rx_get_len(desc);
 
 #ifdef DWC_GMAC_DEBUG
                aprint_normal_dev(sc->sc_dev,
@@ -1241,10 +1288,11 @@
 skip:
                bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
                    data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD);
-               desc->ddesc_cntl = htole32(
-                   __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
-                   DDESC_CNTL_RXCHAIN);
-               desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
+
+               sc->sc_descm->rx_init_flags(desc);
+               sc->sc_descm->rx_set_len(desc, AWGE_MAX_PACKET);
+               sc->sc_descm->rx_set_owned_by_dev(desc);
+
                bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
                    RX_DESC_OFFSET(i), sizeof(*desc),
                    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
@@ -1398,6 +1446,107 @@
        return rv;
 }
 
+static void
+dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc) {
+       desc->ddesc_status0 |= DDESC_STATUS_OWNEDBYDEV;
+}
+
+static int
+dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc) {
+       return !!(desc->ddesc_status0 & DDESC_STATUS_OWNEDBYDEV);
+}
+
+static void
+dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *desc, int len) {
+       uint32_t cntl = le32toh(desc->ddesc_cntl1);
+
+       desc->ddesc_cntl1 = htole32((cntl & ~DDESC_CNTL_SIZE1MASK) |
+               __SHIFTIN(len, DDESC_CNTL_SIZE1MASK));
+}
+
+static int
+dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *desc) {
+       return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_STATUS_FRMLENMSK);
+}



Home | Main Index | Thread Index | Old Index