Source-Changes-HG archive

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

[src/netbsd-7]: src/sys/dev/ic Pull up following revision(s) (requested by ma...



details:   https://anonhg.NetBSD.org/src/rev/1bdfc0412bed
branches:  netbsd-7
changeset: 798519:1bdfc0412bed
user:      snj <snj%NetBSD.org@localhost>
date:      Sun Nov 09 19:06:57 2014 +0000

description:
Pull up following revision(s) (requested by martin in ticket #189):
        sys/dev/ic/dwc_gmac.c: revision 1.1-1.24
        sys/dev/ic/dwc_gmac_reg.h: revision 1.1-1.12
        sys/dev/ic/dwc_gmac_var.h: revision 1.1-1.5
Add support for Synopsis Designware GMAC ethernet core, as found on
various Allwiner boards and used by the awge(4) driver.

diffstat:

 sys/dev/ic/dwc_gmac.c     |  1381 +++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/ic/dwc_gmac_reg.h |   198 ++++++
 sys/dev/ic/dwc_gmac_var.h |    94 +++
 3 files changed, 1673 insertions(+), 0 deletions(-)

diffs (truncated from 1685 to 300 lines):

diff -r b1f9c3d2db49 -r 1bdfc0412bed sys/dev/ic/dwc_gmac.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/ic/dwc_gmac.c     Sun Nov 09 19:06:57 2014 +0000
@@ -0,0 +1,1381 @@
+/* $NetBSD: dwc_gmac.c,v 1.24.2.2 2014/11/09 19:06:57 snj Exp $ */
+
+/*-
+ * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry and Martin Husemann.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This driver supports the Synopsis Designware GMAC core, as found
+ * on Allwinner A20 cores and others.
+ *
+ * Real documentation seems to not be available, the marketing product
+ * documents could be found here:
+ *
+ *  http://www.synopsys.com/dw/ipdir.php?ds=dwc_ether_mac10_100_1000_unive
+ */
+
+#include <sys/cdefs.h>
+
+__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.24.2.2 2014/11/09 19:06:57 snj Exp $");
+
+/* #define     DWC_GMAC_DEBUG  1 */
+
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+#include <net/bpf.h>
+#ifdef INET
+#include <netinet/if_inarp.h>
+#endif
+
+#include <dev/mii/miivar.h>
+
+#include <dev/ic/dwc_gmac_reg.h>
+#include <dev/ic/dwc_gmac_var.h>
+
+static int dwc_gmac_miibus_read_reg(device_t, int, int);
+static void dwc_gmac_miibus_write_reg(device_t, int, int, int);
+static void dwc_gmac_miibus_statchg(struct ifnet *);
+
+static int dwc_gmac_reset(struct dwc_gmac_softc *sc);
+static void dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc,
+                        uint8_t enaddr[ETHER_ADDR_LEN]);
+static int dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc);
+static void dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc);
+static int dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
+static void dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
+static void dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
+static int dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
+static void dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
+static void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
+static void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops);
+static int dwc_gmac_init(struct ifnet *ifp);
+static void dwc_gmac_stop(struct ifnet *ifp, int disable);
+static void dwc_gmac_start(struct ifnet *ifp);
+static int dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0);
+static int dwc_gmac_ioctl(struct ifnet *, u_long, void *);
+static void dwc_gmac_tx_intr(struct dwc_gmac_softc *sc);
+static void dwc_gmac_rx_intr(struct dwc_gmac_softc *sc);
+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);
+
+#define        TX_DESC_OFFSET(N)       ((AWGE_RX_RING_COUNT+(N)) \
+                                   *sizeof(struct dwc_gmac_dev_dmadesc))
+#define        TX_NEXT(N)              (((N)+1) & (AWGE_TX_RING_COUNT-1))
+
+#define RX_DESC_OFFSET(N)      ((N)*sizeof(struct dwc_gmac_dev_dmadesc))
+#define        RX_NEXT(N)              (((N)+1) & (AWGE_RX_RING_COUNT-1))
+
+
+
+#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)
+
+#define        GMAC_DMA_INT_ERRORS     (GMAC_DMA_INT_AIE|GMAC_DMA_INT_ERE| \
+                               GMAC_DMA_INT_FBE|       \
+                               GMAC_DMA_INT_RWE|GMAC_DMA_INT_RUE| \
+                               GMAC_DMA_INT_UNE|GMAC_DMA_INT_OVE| \
+                               GMAC_DMA_INT_TJE)
+
+#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)
+
+
+#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);
+static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt);
+#endif
+
+void
+dwc_gmac_attach(struct dwc_gmac_softc *sc, uint32_t mii_clk)
+{
+       uint8_t enaddr[ETHER_ADDR_LEN];
+       uint32_t maclo, machi;
+       struct mii_data * const mii = &sc->sc_mii;
+       struct ifnet * const ifp = &sc->sc_ec.ec_if;
+       prop_dictionary_t dict;
+       int s;
+
+       mutex_init(&sc->sc_mdio_lock, MUTEX_DEFAULT, IPL_NET);
+       sc->sc_mii_clk = mii_clk & 7;
+
+       dict = device_properties(sc->sc_dev);
+       prop_data_t ea = dict ? prop_dictionary_get(dict, "mac-address") : NULL;
+       if (ea != NULL) {
+               /*
+                * If the MAC address is overriden by a device property,
+                * use that.
+                */
+               KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
+               KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
+               memcpy(enaddr, prop_data_data_nocopy(ea), ETHER_ADDR_LEN);
+       } else {
+               /*
+                * If we did not get an externaly configure address,
+                * try to read one from the current filter setup,
+                * before resetting the chip.
+                */
+               maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+                   AWIN_GMAC_MAC_ADDR0LO);
+               machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
+                   AWIN_GMAC_MAC_ADDR0HI);
+
+               if (maclo == 0xffffffff && (machi & 0xffff) == 0xffff) {
+                       aprint_error_dev(sc->sc_dev,
+                           "couldn't read MAC address\n");
+                       return;
+               }
+
+               enaddr[0] = maclo & 0x0ff;
+               enaddr[1] = (maclo >> 8) & 0x0ff;
+               enaddr[2] = (maclo >> 16) & 0x0ff;
+               enaddr[3] = (maclo >> 24) & 0x0ff;
+               enaddr[4] = machi & 0x0ff;
+               enaddr[5] = (machi >> 8) & 0x0ff;
+       }
+
+       /*
+        * Init chip and do initial setup
+        */
+       if (dwc_gmac_reset(sc) != 0)
+               return; /* not much to cleanup, haven't attached yet */
+       dwc_gmac_write_hwaddr(sc, enaddr);
+       aprint_normal_dev(sc->sc_dev, "Ethernet address: %s\n",
+           ether_sprintf(enaddr));
+
+       /*
+        * Allocate Tx and Rx rings
+        */
+       if (dwc_gmac_alloc_dma_rings(sc) != 0) {
+               aprint_error_dev(sc->sc_dev, "could not allocate DMA rings\n");
+               goto fail;
+       }
+               
+       if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) {
+               aprint_error_dev(sc->sc_dev, "could not allocate Tx ring\n");
+               goto fail;
+       }
+
+       mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET);
+       if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) {
+               aprint_error_dev(sc->sc_dev, "could not allocate Rx ring\n");
+               goto fail;
+       }
+
+       /*
+        * Prepare interface data
+        */
+       ifp->if_softc = sc;
+       strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_ioctl = dwc_gmac_ioctl;
+       ifp->if_start = dwc_gmac_start;
+       ifp->if_init = dwc_gmac_init;
+       ifp->if_stop = dwc_gmac_stop;
+       IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+       IFQ_SET_READY(&ifp->if_snd);
+
+       /*
+        * Attach MII subdevices
+        */
+       sc->sc_ec.ec_mii = &sc->sc_mii;
+       ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
+        mii->mii_ifp = ifp;
+        mii->mii_readreg = dwc_gmac_miibus_read_reg;
+        mii->mii_writereg = dwc_gmac_miibus_write_reg;
+        mii->mii_statchg = dwc_gmac_miibus_statchg;
+        mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+
+        if (LIST_EMPTY(&mii->mii_phys)) { 
+                aprint_error_dev(sc->sc_dev, "no PHY found!\n");
+                ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
+                ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_MANUAL);
+        } else {
+                ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO);
+        }
+
+       /*
+        * Ready, attach interface
+        */
+       if_attach(ifp);
+       ether_ifattach(ifp, enaddr);
+       ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb);
+
+       /*
+        * Enable interrupts
+        */
+       s = splnet();
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR,
+           AWIN_DEF_MAC_INTRMASK);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE,
+           GMAC_DEF_DMA_INT_MASK);
+       splx(s);
+
+       return;
+
+fail:
+       dwc_gmac_free_rx_ring(sc, &sc->sc_rxq);
+       dwc_gmac_free_tx_ring(sc, &sc->sc_txq);
+}
+
+
+
+static int
+dwc_gmac_reset(struct dwc_gmac_softc *sc)
+{
+       size_t cnt;
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE,
+           bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) | GMAC_BUSMODE_RESET);
+       for (cnt = 0; cnt < 3000; cnt++) {
+               if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)
+                   & GMAC_BUSMODE_RESET) == 0)
+                       return 0;
+               delay(10);
+       }
+
+       aprint_error_dev(sc->sc_dev, "reset timed out\n");
+       return EIO;
+}
+
+static void
+dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc,
+    uint8_t enaddr[ETHER_ADDR_LEN])
+{
+       uint32_t lo, hi;
+
+       lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16)
+           | (enaddr[3] << 24);
+       hi = enaddr[4] | (enaddr[5] << 8);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO, lo);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI, hi);
+}
+
+static int
+dwc_gmac_miibus_read_reg(device_t self, int phy, int reg)
+{



Home | Main Index | Thread Index | Old Index