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 more MAC filter setup, some DMA burst configu...
details: https://anonhg.NetBSD.org/src/rev/c3ac16f1ecd5
branches: trunk
changeset: 333103:c3ac16f1ecd5
user: martin <martin%NetBSD.org@localhost>
date: Sun Oct 19 11:45:01 2014 +0000
description:
Add more MAC filter setup, some DMA burst configuration (from jmcneill),
actually enable RX interrupts (spotted by jmcneill), add RX handling
code and debug code.
diffstat:
sys/dev/ic/dwc_gmac.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 194 insertions(+), 9 deletions(-)
diffs (truncated from 308 to 300 lines):
diff -r 77ab42f5fcef -r c3ac16f1ecd5 sys/dev/ic/dwc_gmac.c
--- a/sys/dev/ic/dwc_gmac.c Sun Oct 19 11:37:17 2014 +0000
+++ b/sys/dev/ic/dwc_gmac.c Sun Oct 19 11:45:01 2014 +0000
@@ -39,7 +39,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.10 2014/10/13 09:07:26 martin Exp $");
+__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.11 2014/10/19 11:45:01 martin Exp $");
/* #define DWC_GMAC_DEBUG 1 */
@@ -98,7 +98,7 @@
-#define GMAC_DEF_DMA_INT_MASK (GMAC_DMA_INT_TIE| \
+#define GMAC_DEF_DMA_INT_MASK (GMAC_DMA_INT_TIE|GMAC_DMA_INT_RIE| \
GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE| \
GMAC_DMA_INT_FBE|GMAC_DMA_INT_UNE)
@@ -116,6 +116,7 @@
#ifdef DWC_GMAC_DEBUG
static void dwc_gmac_dump_dma(struct dwc_gmac_softc *sc);
static void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc);
+static void dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc);
static void dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg);
static void dwc_dump_status(struct dwc_gmac_softc *sc);
#endif
@@ -389,7 +390,8 @@
desc->ddesc_next = htole32(ring->r_physaddr
+ next * sizeof(*desc));
desc->ddesc_cntl = htole32(
- __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK));
+ __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
+ DDESC_CNTL_RXCHAIN | DDESC_CNTL_RXINT);
desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
}
@@ -425,6 +427,9 @@
BUS_DMASYNC_PREWRITE);
ring->r_cur = ring->r_next = 0;
+ /* reset DMA address to start of ring */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
+ sc->sc_rxq.r_physaddr);
}
static int
@@ -654,8 +659,10 @@
conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF);
conf &= ~(AWIN_GMAC_MAC_CONF_FES100|AWIN_GMAC_MAC_CONF_MIISEL
|AWIN_GMAC_MAC_CONF_FULLDPLX);
- conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST | AWIN_GMAC_MAC_CONF_TXENABLE
- | AWIN_GMAC_MAC_CONF_RXENABLE;
+ conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST
+ | AWIN_GMAC_MAC_CONF_DISABLERXOWN
+ | AWIN_GMAC_MAC_CONF_RXENABLE
+ | AWIN_GMAC_MAC_CONF_TXENABLE;
switch (IFM_SUBTYPE(mii->mii_media_active)) {
case IFM_10_T:
break;
@@ -689,6 +696,21 @@
dwc_gmac_stop(ifp, 0);
/*
+ * Configure DMA burst/transfer mode and RX/TX priorities.
+ * XXX - the GMAC_BUSMODE_PRIORXTX bits are undocumented.
+ */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE,
+ GMAC_BUSMODE_FIXEDBURST |
+ __SHIFTIN(GMAC_BUSMODE_PRIORXTX_41, GMAC_BUSMODE_PRIORXTX) |
+ __SHIFTIN(8, GMCA_BUSMODE_PBL));
+
+ /*
+ * Set up address filter (XXX for testing only: promiscous)
+ */
+ bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT,
+ AWIN_GMAC_MAC_FFILT_PR);
+
+ /*
* Set up dma pointer for RX and TX ring
*/
bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
@@ -700,7 +722,8 @@
* Start RX/TX part
*/
bus_space_write_4(sc->sc_bst, sc->sc_bsh,
- AWIN_GMAC_DMA_OPMODE, GMAC_DMA_OP_RXSTART|GMAC_DMA_OP_TXSTART);
+ AWIN_GMAC_DMA_OPMODE, GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART |
+ GMAC_DMA_OP_STOREFORWARD);
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
@@ -846,7 +869,6 @@
static int
dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data)
{
- // struct dwc_gmac_softc *sc = ifp->if_softc;
struct ifaddr *ifa = (struct ifaddr *)data;
int s, error = 0;
@@ -865,6 +887,43 @@
default:
break;
}
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((error = ifioctl_common(ifp, cmd, data)) != 0)
+ break;
+
+ switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
+ case IFF_RUNNING:
+ /*
+ * If interface is marked down and it is running, then
+ * stop it.
+ */
+ dwc_gmac_stop(ifp, 0);
+ ifp->if_flags &= ~IFF_RUNNING;
+ break;
+ case IFF_UP:
+ /*
+ * If interface is marked up and it is stopped, then
+ * start it.
+ */
+ error = dwc_gmac_init(ifp);
+ break;
+ case IFF_UP|IFF_RUNNING:
+ /*
+ * If setting debug or promiscuous mode, do not reset
+ * the chip; for everything else, call dwc_gmac_init()
+ * which will trigger a reset.
+ */
+ /* XXX - for now allways init */
+ error = dwc_gmac_init(ifp);
+ break;
+ case 0:
+ break;
+ }
+
+ break;
+
default:
if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
break;
@@ -902,8 +961,10 @@
dwc_gmac_txdesc_sync(sc, i, i+1,
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
flags = le32toh(desc->ddesc_status);
+
if (flags & DDESC_STATUS_OWNEDBYDEV)
break;
+
data = &sc->sc_txq.t_data[i];
if (data->td_m == NULL)
continue;
@@ -932,10 +993,116 @@
static void
dwc_gmac_rx_intr(struct dwc_gmac_softc *sc)
{
+ struct ifnet *ifp = &sc->sc_ec.ec_if;
+ 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;
+
+ for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) {
+
#ifdef DWC_GMAC_DEBUG
- aprint_normal_dev(sc->sc_dev, "rx intr\n");
- /* XXX */
+printf("rx int: checking desc #%d\n", i);
+#endif
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
+ RX_DESC_OFFSET(i), sizeof(*desc),
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ desc = &sc->sc_rxq.r_desc[i];
+ data = &sc->sc_rxq.r_data[i];
+
+ status = le32toh(desc->ddesc_status);
+ if (status & DDESC_STATUS_OWNEDBYDEV) {
+#ifdef DWC_GMAC_DEBUG
+printf("status %08x, still owned by device\n", status);
+#endif
+ break;
+ }
+
+ if (status & (DDESC_STATUS_RXERROR|DDESC_STATUS_RXTRUNCATED)) {
+#ifdef DWC_GMAC_DEBUG
+printf("status %08x, RX error, skipping\n", status);
+#endif
+ ifp->if_ierrors++;
+ goto skip;
+ }
+
+ len = __SHIFTOUT(status, DDESC_STATUS_FRMLENMSK);
+
+#ifdef DWC_GMAC_DEBUG
+printf("rx int: device is done with #%d, len: %d\n", i, len);
#endif
+
+ /*
+ * Try to get a new mbuf before passing this one
+ * up, if that fails, drop the packet and reuse
+ * the existing one.
+ */
+ MGETHDR(mnew, M_DONTWAIT, MT_DATA);
+ if (mnew == NULL) {
+ ifp->if_ierrors++;
+ goto skip;
+ }
+ MCLGET(mnew, M_DONTWAIT);
+ if ((mnew->m_flags & M_EXT) == 0) {
+ m_freem(mnew);
+ ifp->if_ierrors++;
+ goto skip;
+ }
+
+ /* unload old DMA map */
+ bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
+ data->rd_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmat, data->rd_map);
+
+ /* and reload with new mbuf */
+ error = bus_dmamap_load(sc->sc_dmat, data->rd_map,
+ mtod(mnew, void*), MCLBYTES, NULL,
+ BUS_DMA_READ | BUS_DMA_NOWAIT);
+ if (error != 0) {
+ m_freem(mnew);
+ /* try to reload old mbuf */
+ error = bus_dmamap_load(sc->sc_dmat, data->rd_map,
+ mtod(data->rd_m, void*), MCLBYTES, NULL,
+ BUS_DMA_READ | BUS_DMA_NOWAIT);
+ if (error != 0) {
+ panic("%s: could not load old rx mbuf",
+ device_xname(sc->sc_dev));
+ }
+ ifp->if_ierrors++;
+ goto skip;
+ }
+ physaddr = data->rd_map->dm_segs[0].ds_addr;
+
+ /*
+ * New mbuf loaded, update RX ring and continue
+ */
+ m = data->rd_m;
+ data->rd_m = mnew;
+ desc->ddesc_data = htole32(physaddr);
+
+ /* finalize mbuf */
+ m->m_pkthdr.len = m->m_len = len;
+ m->m_pkthdr.rcvif = ifp;
+
+ bpf_mtap(ifp, m);
+ ifp->if_ipackets++;
+ (*ifp->if_input)(ifp, m);
+
+skip:
+ desc->ddesc_cntl = htole32(
+ __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK));
+ desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
+ RX_DESC_OFFSET(i), sizeof(*desc),
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ }
+
+ /* update RX pointer */
+ sc->sc_rxq.r_cur = i;
+
}
int
@@ -1030,6 +1197,23 @@
}
static void
+dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc)
+{
+ int i;
+
+ aprint_normal_dev(sc->sc_dev, "RX queue: cur=%d, next=%d\n",
+ sc->sc_rxq.r_cur, sc->sc_rxq.r_next);
+ aprint_normal_dev(sc->sc_dev, "RX DMA descriptors:\n");
+ for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
+ struct dwc_gmac_dev_dmadesc *desc = &sc->sc_rxq.r_desc[i];
+ aprint_normal("#%d (%08lx): status: %08x cntl: %08x data: %08x next: %08x\n",
+ i, sc->sc_txq.t_physaddr + i*sizeof(struct dwc_gmac_dev_dmadesc),
+ le32toh(desc->ddesc_status), le32toh(desc->ddesc_cntl),
+ le32toh(desc->ddesc_data), le32toh(desc->ddesc_next));
+ }
+}
+
+static void
dwc_dump_status(struct dwc_gmac_softc *sc)
{
uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
Home |
Main Index |
Thread Index |
Old Index