Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/ic Greatly simplify ioctl handling by fully relying ...



details:   https://anonhg.NetBSD.org/src/rev/a8d33b8ad4ae
branches:  trunk
changeset: 803414:a8d33b8ad4ae
user:      martin <martin%NetBSD.org@localhost>
date:      Sun Oct 26 17:39:16 2014 +0000

description:
Greatly simplify ioctl handling by fully relying on ether_ioctl and a
ifflags-change callback, together with a shadow copy of the last active
interface flags.
Fix ALLMULTI vs. PROMISC handling.
Fix mac hash filter calculation by reversing the crc bits (pointed out
by Jared).

diffstat:

 sys/dev/ic/dwc_gmac.c     |  184 +++++++++++++++++++++++++++------------------
 sys/dev/ic/dwc_gmac_var.h |    3 +-
 2 files changed, 111 insertions(+), 76 deletions(-)

diffs (truncated from 305 to 300 lines):

diff -r eb4e967541f6 -r a8d33b8ad4ae sys/dev/ic/dwc_gmac.c
--- a/sys/dev/ic/dwc_gmac.c     Sun Oct 26 16:21:59 2014 +0000
+++ b/sys/dev/ic/dwc_gmac.c     Sun Oct 26 17:39:16 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_gmac.c,v 1.21 2014/10/25 18:00:25 joerg Exp $ */
+/* $NetBSD: dwc_gmac.c,v 1.22 2014/10/26 17:39:16 martin 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.21 2014/10/25 18:00:25 joerg Exp $");
+__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.22 2014/10/26 17:39:16 martin Exp $");
 
 /* #define     DWC_GMAC_DEBUG  1 */
 
@@ -91,6 +91,8 @@
 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))
@@ -122,6 +124,7 @@
 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
@@ -237,6 +240,7 @@
         */
        if_attach(ifp);
        ether_ifattach(ifp, enaddr);
+       ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb);
 
        /*
         * Enable interrupts
@@ -897,78 +901,51 @@
        return 0;
 }
 
+/*
+ * If the interface is up and running, only modify the receive
+ * filter when setting promiscuous or debug mode.  Otherwise fall
+ * through to ether_ioctl, which will reset the chip.
+ */
+static int
+dwc_gmac_ifflags_cb(struct ethercom *ec)
+{
+       struct ifnet *ifp = &ec->ec_if;
+       struct dwc_gmac_softc *sc = ifp->if_softc;
+       int change = ifp->if_flags ^ sc->sc_if_flags;
+
+       if ((change & ~(IFF_CANTCHANGE|IFF_DEBUG)) != 0)
+               return ENETRESET;
+       if ((change & IFF_PROMISC) != 0)
+               dwc_gmac_setmulti(sc);
+       return 0;
+}
+
 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;
 
        s = splnet();
 
-       switch (cmd) {
-       case SIOCINITIFADDR:
-               ifp->if_flags |= IFF_UP;
-               dwc_gmac_init(ifp);
-               switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
-               case AF_INET:
-                       arp_ifinit(ifp, ifa);
-                       break;
-#endif
-               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;
+       if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
                error = 0;
                if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
                        ;
-               else if (ifp->if_flags & IFF_RUNNING)
+               else if (ifp->if_flags & IFF_RUNNING) {
+                       /*
+                        * Multicast list has changed; set the hardware filter
+                        * accordingly.
+                        */
                        dwc_gmac_setmulti(sc);
-               break;
+               }
        }
 
+       /* Try to get things going again */
+       if (ifp->if_flags & IFF_UP)
+               dwc_gmac_start(ifp);
+       sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
        splx(s);
-
        return error;
 }
 
@@ -1134,6 +1111,20 @@
 
 }
 
+/*
+ * Revers order of bits - http://aggregate.org/MAGIC/#Bit%20Reversal
+ */
+static uint32_t
+bitrev32(uint32_t x)
+{
+       x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
+       x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
+       x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
+       x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
+
+       return (x >> 16) | (x << 16);
+}
+
 static void
 dwc_gmac_setmulti(struct dwc_gmac_softc *sc)
 {
@@ -1141,26 +1132,20 @@
        struct ether_multi *enm;
        struct ether_multistep step;
        uint32_t hashes[2] = { 0, 0 };
-       uint32_t ffilt;
-       int h, mcnt;
+       uint32_t ffilt, h;
+       int mcnt, s;
+
+       s = splnet();
 
        ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT);
        
        if (ifp->if_flags & IFF_PROMISC) {
-allmulti:
-               ifp->if_flags |= IFF_ALLMULTI;
-               ffilt |= AWIN_GMAC_MAC_FFILT_PM;
-               bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT,
-                   ffilt);
-               bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW,
-                   0xffffffff);
-               bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
-                   0xffffffff);
-               return;
+               ffilt |= AWIN_GMAC_MAC_FFILT_PR;
+               goto special_filter;
        }
 
        ifp->if_flags &= ~IFF_ALLMULTI;
-       ffilt &= ~AWIN_GMAC_MAC_FFILT_PM;
+       ffilt &= ~(AWIN_GMAC_MAC_FFILT_PM|AWIN_GMAC_MAC_FFILT_PR);
 
        bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0);
        bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0);
@@ -1169,10 +1154,15 @@
        mcnt = 0;
        while (enm != NULL) {
                if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
-                   ETHER_ADDR_LEN) != 0)
-                       goto allmulti;
+                   ETHER_ADDR_LEN) != 0) {
+                       ffilt |= AWIN_GMAC_MAC_FFILT_PM;
+                       ifp->if_flags |= IFF_ALLMULTI;
+                       goto special_filter;
+               }
 
-               h = (~ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN)) >> 26;
+               h = bitrev32(
+                       ~ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN)
+                   ) >> 26;
                hashes[h >> 5] |= (1 << (h & 0x1f));
 
                mcnt++;
@@ -1189,6 +1179,28 @@
            hashes[0]);
        bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
            hashes[1]);
+       sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
+
+       splx(s);
+
+#ifdef DWC_GMAC_DEBUG
+       dwc_gmac_dump_ffilt(sc, ffilt);
+#endif
+       return;
+
+special_filter:
+#ifdef DWC_GMAC_DEBUG
+       dwc_gmac_dump_ffilt(sc, ffilt);
+#endif
+       /* no MAC hashes, ALLMULTI or PROMISC */
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT,
+           ffilt);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW,
+           0xffffffff);
+       bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
+           0xffffffff);
+       sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
+       splx(s);
 }
 
 int
@@ -1338,10 +1350,32 @@
 dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg)
 {
        dwc_dump_status(sc);
+       dwc_gmac_dump_ffilt(sc,
+           bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT));
        dwc_gmac_dump_dma(sc);
        dwc_gmac_dump_tx_desc(sc);
        dwc_gmac_dump_rx_desc(sc);
 
        panic("%s", msg);
 }
+
+static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt)
+{
+       char buf[200];
+
+       /* print filter setup */
+       snprintb(buf, sizeof(buf), "\177\20"
+           "b\x1f""RA\0"
+           "b\x0a""HPF\0"
+           "b\x09""SAF\0"
+           "b\x08""SAIF\0"
+           "b\x05""DBF\0"
+           "b\x04""PM\0"
+           "b\x03""DAIF\0"
+           "b\x02""HMC\0"
+           "b\x01""HUC\0"
+           "b\x00""PR\0"
+           "\0", ffilt);
+       aprint_normal_dev(sc->sc_dev, "FFILT: %s\n", buf);
+}
 #endif
diff -r eb4e967541f6 -r a8d33b8ad4ae sys/dev/ic/dwc_gmac_var.h
--- a/sys/dev/ic/dwc_gmac_var.h Sun Oct 26 16:21:59 2014 +0000
+++ b/sys/dev/ic/dwc_gmac_var.h Sun Oct 26 17:39:16 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_gmac_var.h,v 1.4 2014/10/20 20:10:05 jmcneill Exp $ */
+/* $NetBSD: dwc_gmac_var.h,v 1.5 2014/10/26 17:39:16 martin Exp $ */
 
 /*-
  * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
@@ -86,6 +86,7 @@
        bus_dma_segment_t sc_dma_ring_seg;      /* and TX ring */
        struct dwc_gmac_rx_ring sc_rxq;



Home | Main Index | Thread Index | Old Index