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/0bb91b417ce5
branches: trunk
changeset: 433506:0bb91b417ce5
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 6e07f790d617 -r 0bb91b417ce5 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