Add ifpoll, which support hardware TX/RX queues based polling.
[dragonfly.git] / sys / dev / netif / emx / if_emx.c
index 63c4834..662a023 100644 (file)
@@ -64,7 +64,7 @@
  * SUCH DAMAGE.
  */
 
-#include "opt_polling.h"
+#include "opt_ifpoll.h"
 #include "opt_serializer.h"
 #include "opt_rss.h"
 #include "opt_emx.h"
@@ -80,6 +80,7 @@
 #include <sys/proc.h>
 #include <sys/rman.h>
 #include <sys/serialize.h>
+#include <sys/serialize2.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/sysctl.h>
@@ -96,6 +97,7 @@
 #include <net/toeplitz2.h>
 #include <net/vlan/if_vlan_var.h>
 #include <net/vlan/if_vlan_ether.h>
+#include <net/if_poll.h>
 
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
@@ -173,8 +175,8 @@ static void emx_init(void *);
 static void    emx_stop(struct emx_softc *);
 static int     emx_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
 static void    emx_start(struct ifnet *);
-#ifdef DEVICE_POLLING
-static void    emx_poll(struct ifnet *, enum poll_cmd, int);
+#ifdef IFPOLL_ENABLE
+static void    emx_qpoll(struct ifnet *, struct ifpoll_info *);
 #endif
 static void    emx_watchdog(struct ifnet *);
 static void    emx_media_status(struct ifnet *, struct ifmediareq *);
@@ -236,6 +238,9 @@ static void emx_add_sysctl(struct emx_softc *);
 
 static void    emx_serialize_skipmain(struct emx_softc *);
 static void    emx_deserialize_skipmain(struct emx_softc *);
+#ifdef IFPOLL_ENABLE
+static int     emx_tryserialize_skipmain(struct emx_softc *);
+#endif
 
 /* Management and WOL Support */
 static void    emx_get_mgmt(struct emx_softc *);
@@ -403,9 +408,6 @@ emx_attach(device_t dev)
        for (i = 0; i < EMX_NRX_RING; ++i)
                lwkt_serialize_init(&sc->rx_data[i].rx_serialize);
 
-       lwkt_serialize_init(&sc->panic_serialize);
-       lwkt_serialize_enter(&sc->panic_serialize);
-
        i = 0;
        sc->serializes[i++] = &sc->main_serialize;
        sc->serializes[i++] = &sc->tx_serialize;
@@ -903,8 +905,8 @@ emx_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
                if (ifp->if_flags & IFF_RUNNING) {
                        emx_disable_intr(sc);
                        emx_set_multi(sc);
-#ifdef DEVICE_POLLING
-                       if (!(ifp->if_flags & IFF_POLLING))
+#ifdef IFPOLL_ENABLE
+                       if (!(ifp->if_flags & IFF_NPOLLING))
 #endif
                                emx_enable_intr(sc);
                }
@@ -1138,66 +1140,21 @@ emx_init(void *xsc)
                E1000_WRITE_REG(&sc->hw, E1000_IVAR, 0x800A0908);
        }
 
-#ifdef DEVICE_POLLING
+#ifdef IFPOLL_ENABLE
        /*
         * Only enable interrupts if we are not polling, make sure
         * they are off otherwise.
         */
-       if (ifp->if_flags & IFF_POLLING)
+       if (ifp->if_flags & IFF_NPOLLING)
                emx_disable_intr(sc);
        else
-#endif /* DEVICE_POLLING */
+#endif /* IFPOLL_ENABLE */
                emx_enable_intr(sc);
 
        /* Don't reset the phy next time init gets called */
        sc->hw.phy.reset_disable = TRUE;
 }
 
-#ifdef DEVICE_POLLING
-
-static void
-emx_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
-{
-       struct emx_softc *sc = ifp->if_softc;
-       uint32_t reg_icr;
-
-       ASSERT_IFNET_SERIALIZED_ALL(ifp);
-
-       switch (cmd) {
-       case POLL_REGISTER:
-               emx_disable_intr(sc);
-               break;
-
-       case POLL_DEREGISTER:
-               emx_enable_intr(sc);
-               break;
-
-       case POLL_AND_CHECK_STATUS:
-               reg_icr = E1000_READ_REG(&sc->hw, E1000_ICR);
-               if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
-                       callout_stop(&sc->timer);
-                       sc->hw.mac.get_link_status = 1;
-                       emx_update_link_status(sc);
-                       callout_reset(&sc->timer, hz, emx_timer, sc);
-               }
-               /* FALL THROUGH */
-       case POLL_ONLY:
-               if (ifp->if_flags & IFF_RUNNING) {
-                       int i;
-
-                       for (i = 0; i < sc->rx_ring_inuse; ++i)
-                               emx_rxeof(sc, i, count);
-
-                       emx_txeof(sc);
-                       if (!ifq_is_empty(&ifp->if_snd))
-                               if_devstart(ifp);
-               }
-               break;
-       }
-}
-
-#endif /* DEVICE_POLLING */
-
 static void
 emx_intr(void *xsc)
 {
@@ -1802,8 +1759,8 @@ emx_setup_ifp(struct emx_softc *sc)
        ifp->if_init =  emx_init;
        ifp->if_ioctl = emx_ioctl;
        ifp->if_start = emx_start;
-#ifdef DEVICE_POLLING
-       ifp->if_poll = emx_poll;
+#ifdef IFPOLL_ENABLE
+       ifp->if_qpoll = emx_qpoll;
 #endif
        ifp->if_watchdog = emx_watchdog;
        ifp->if_serialize = emx_serialize;
@@ -1815,7 +1772,7 @@ emx_setup_ifp(struct emx_softc *sc)
        ifq_set_maxlen(&ifp->if_snd, sc->num_tx_desc - 1);
        ifq_set_ready(&ifp->if_snd);
 
-       ether_ifattach(ifp, sc->hw.mac.addr, &sc->panic_serialize);
+       ether_ifattach(ifp, sc->hw.mac.addr, NULL);
 
        ifp->if_capabilities = IFCAP_HWCSUM |
                               IFCAP_VLAN_HWTAGGING |
@@ -3633,6 +3590,10 @@ emx_serialize(struct ifnet *ifp, enum ifnet_serialize slz)
                lwkt_serialize_array_enter(sc->serializes, EMX_NSERIALIZE, 0);
                break;
 
+       case IFNET_SERIALIZE_MAIN:
+               lwkt_serialize_enter(&sc->main_serialize);
+               break;
+
        case IFNET_SERIALIZE_TX:
                lwkt_serialize_enter(&sc->tx_serialize);
                break;
@@ -3660,6 +3621,10 @@ emx_deserialize(struct ifnet *ifp, enum ifnet_serialize slz)
                lwkt_serialize_array_exit(sc->serializes, EMX_NSERIALIZE, 0);
                break;
 
+       case IFNET_SERIALIZE_MAIN:
+               lwkt_serialize_exit(&sc->main_serialize);
+               break;
+
        case IFNET_SERIALIZE_TX:
                lwkt_serialize_exit(&sc->tx_serialize);
                break;
@@ -3687,6 +3652,9 @@ emx_tryserialize(struct ifnet *ifp, enum ifnet_serialize slz)
                return lwkt_serialize_array_try(sc->serializes,
                                                EMX_NSERIALIZE, 0);
 
+       case IFNET_SERIALIZE_MAIN:
+               return lwkt_serialize_try(&sc->main_serialize);
+
        case IFNET_SERIALIZE_TX:
                return lwkt_serialize_try(&sc->tx_serialize);
 
@@ -3707,6 +3675,14 @@ emx_serialize_skipmain(struct emx_softc *sc)
        lwkt_serialize_array_enter(sc->serializes, EMX_NSERIALIZE, 1);
 }
 
+#ifdef IFPOLL_ENABLE
+static int
+emx_tryserialize_skipmain(struct emx_softc *sc)
+{
+       return lwkt_serialize_array_try(sc->serializes, EMX_NSERIALIZE, 1);
+}
+#endif
+
 static void
 emx_deserialize_skipmain(struct emx_softc *sc)
 {
@@ -3733,6 +3709,13 @@ emx_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz,
                }
                break;
 
+       case IFNET_SERIALIZE_MAIN:
+               if (serialized)
+                       ASSERT_SERIALIZED(&sc->main_serialize);
+               else
+                       ASSERT_NOT_SERIALIZED(&sc->main_serialize);
+               break;
+
        case IFNET_SERIALIZE_TX:
                if (serialized)
                        ASSERT_SERIALIZED(&sc->tx_serialize);
@@ -3760,3 +3743,81 @@ emx_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz,
 }
 
 #endif /* INVARIANTS */
+
+#ifdef IFPOLL_ENABLE
+
+static void
+emx_qpoll_status(struct ifnet *ifp, int pollhz __unused)
+{
+       struct emx_softc *sc = ifp->if_softc;
+       uint32_t reg_icr;
+
+       ASSERT_SERIALIZED(&sc->main_serialize);
+
+       reg_icr = E1000_READ_REG(&sc->hw, E1000_ICR);
+       if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+               if (emx_tryserialize_skipmain(sc)) {
+                       callout_stop(&sc->timer);
+                       sc->hw.mac.get_link_status = 1;
+                       emx_update_link_status(sc);
+                       callout_reset(&sc->timer, hz, emx_timer, sc);
+                       emx_deserialize_skipmain(sc);
+               }
+       }
+}
+
+static void
+emx_qpoll_tx(struct ifnet *ifp, void *arg __unused, int cycle __unused)
+{
+       struct emx_softc *sc = ifp->if_softc;
+
+       ASSERT_SERIALIZED(&sc->tx_serialize);
+
+       emx_txeof(sc);
+       if (!ifq_is_empty(&ifp->if_snd))
+               if_devstart(ifp);
+}
+
+static void
+emx_qpoll_rx(struct ifnet *ifp, void *arg, int cycle)
+{
+       struct emx_softc *sc = ifp->if_softc;
+       struct emx_rxdata *rdata = arg;
+
+       ASSERT_SERIALIZED(&rdata->rx_serialize);
+
+       emx_rxeof(sc, rdata - sc->rx_data, cycle);
+}
+
+static void
+emx_qpoll(struct ifnet *ifp, struct ifpoll_info *info)
+{
+       struct emx_softc *sc = ifp->if_softc;
+
+       ASSERT_IFNET_SERIALIZED_ALL(ifp);
+
+       if (info) {
+               int i;
+
+               info->ifpi_status.status_func = emx_qpoll_status;
+               info->ifpi_status.serializer = &sc->main_serialize;
+
+               info->ifpi_tx[0].poll_func = emx_qpoll_tx;
+               info->ifpi_tx[0].arg = NULL;
+               info->ifpi_tx[0].serializer = &sc->tx_serialize;
+
+               for (i = 0; i < sc->rx_ring_cnt; ++i) {
+                       info->ifpi_rx[i].poll_func = emx_qpoll_rx;
+                       info->ifpi_rx[i].arg = &sc->rx_data[i];
+                       info->ifpi_rx[i].serializer =
+                               &sc->rx_data[i].rx_serialize;
+               }
+
+               if (ifp->if_flags & IFF_RUNNING)
+                       emx_disable_intr(sc);
+       } else if (ifp->if_flags & IFF_RUNNING) {
+               emx_enable_intr(sc);
+       }
+}
+
+#endif /* IFPOLL_ENABLE */