emx: Allow user to specify RX/TX processing CPU's offset
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 22 Sep 2012 13:45:43 +0000 (21:45 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 22 Sep 2012 13:45:43 +0000 (21:45 +0800)
sys/dev/netif/emx/if_emx.c
sys/dev/netif/emx/if_emx.h

index c9c95cd..efb709b 100644 (file)
@@ -242,6 +242,10 @@ static int emx_sysctl_stats(SYSCTL_HANDLER_ARGS);
 static int     emx_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
 static int     emx_sysctl_int_throttle(SYSCTL_HANDLER_ARGS);
 static int     emx_sysctl_int_tx_nsegs(SYSCTL_HANDLER_ARGS);
+#ifdef IFPOLL_ENABLE
+static int     emx_sysctl_npoll_rxoff(SYSCTL_HANDLER_ARGS);
+static int     emx_sysctl_npoll_txoff(SYSCTL_HANDLER_ARGS);
+#endif
 static void    emx_add_sysctl(struct emx_softc *);
 
 static void    emx_serialize_skipmain(struct emx_softc *);
@@ -413,6 +417,9 @@ emx_attach(device_t dev)
        u_int intr_flags;
        uint16_t eeprom_data, device_id, apme_mask;
        driver_intr_t *intr_func;
+#ifdef IFPOLL_ENABLE
+       int offset, offset_def;
+#endif
 
        lwkt_serialize_init(&sc->main_serialize);
        lwkt_serialize_init(&sc->tx_serialize);
@@ -689,6 +696,37 @@ emx_attach(device_t dev)
        /* XXX disable wol */
        sc->wol = 0;
 
+#ifdef IFPOLL_ENABLE
+       /*
+        * NPOLLING RX CPU offset
+        */
+       if (sc->rx_ring_cnt == ncpus2) {
+               offset = 0;
+       } else {
+               offset_def = (sc->rx_ring_cnt * device_get_unit(dev)) % ncpus2;
+               offset = device_getenv_int(dev, "npoll.rxoff", offset_def);
+               if (offset >= ncpus2 ||
+                   offset % sc->rx_ring_cnt != 0) {
+                       device_printf(dev, "invalid npoll.rxoff %d, use %d\n",
+                           offset, offset_def);
+                       offset = offset_def;
+               }
+       }
+       sc->rx_npoll_off = offset;
+
+       /*
+        * NPOLLING TX CPU offset
+        */
+       offset_def = sc->rx_npoll_off;
+       offset = device_getenv_int(dev, "npoll.txoff", offset_def);
+       if (offset >= ncpus2) {
+               device_printf(dev, "invalid npoll.txoff %d, use %d\n",
+                   offset, offset_def);
+               offset = offset_def;
+       }
+       sc->tx_npoll_off = offset;
+#endif
+
        /* Setup OS specific network interface */
        emx_setup_ifp(sc);
 
@@ -3406,6 +3444,17 @@ emx_add_sysctl(struct emx_softc *sc)
                       OID_AUTO, "rx_ring_cnt", CTLFLAG_RD,
                       &sc->rx_ring_cnt, 0, "RX ring count");
 
+#ifdef IFPOLL_ENABLE
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
+                       OID_AUTO, "npoll_rxoff", CTLTYPE_INT|CTLFLAG_RW,
+                       sc, 0, emx_sysctl_npoll_rxoff, "I",
+                       "NPOLLING RX cpu offset");
+       SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
+                       OID_AUTO, "npoll_txoff", CTLTYPE_INT|CTLFLAG_RW,
+                       sc, 0, emx_sysctl_npoll_txoff, "I",
+                       "NPOLLING TX cpu offset");
+#endif
+
 #ifdef EMX_RSS_DEBUG
        SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
                       OID_AUTO, "rss_debug", CTLFLAG_RW, &sc->rss_debug,
@@ -3502,6 +3551,62 @@ emx_sysctl_int_tx_nsegs(SYSCTL_HANDLER_ARGS)
        return error;
 }
 
+#ifdef IFPOLL_ENABLE
+
+static int
+emx_sysctl_npoll_rxoff(SYSCTL_HANDLER_ARGS)
+{
+       struct emx_softc *sc = (void *)arg1;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       int error, off;
+
+       off = sc->rx_npoll_off;
+       error = sysctl_handle_int(oidp, &off, 0, req);
+       if (error || req->newptr == NULL)
+               return error;
+       if (off < 0)
+               return EINVAL;
+
+       ifnet_serialize_all(ifp);
+       if (off >= ncpus2 || off % sc->rx_ring_cnt != 0) {
+               error = EINVAL;
+       } else {
+               error = 0;
+               sc->rx_npoll_off = off;
+       }
+       ifnet_deserialize_all(ifp);
+
+       return error;
+}
+
+static int
+emx_sysctl_npoll_txoff(SYSCTL_HANDLER_ARGS)
+{
+       struct emx_softc *sc = (void *)arg1;
+       struct ifnet *ifp = &sc->arpcom.ac_if;
+       int error, off;
+
+       off = sc->tx_npoll_off;
+       error = sysctl_handle_int(oidp, &off, 0, req);
+       if (error || req->newptr == NULL)
+               return error;
+       if (off < 0)
+               return EINVAL;
+
+       ifnet_serialize_all(ifp);
+       if (off >= ncpus2) {
+               error = EINVAL;
+       } else {
+               error = 0;
+               sc->tx_npoll_off = off;
+       }
+       ifnet_deserialize_all(ifp);
+
+       return error;
+}
+
+#endif /* IFPOLL_ENABLE */
+
 static int
 emx_dma_alloc(struct emx_softc *sc)
 {
@@ -3663,25 +3768,31 @@ emx_npoll(struct ifnet *ifp, struct ifpoll_info *info)
        ASSERT_IFNET_SERIALIZED_ALL(ifp);
 
        if (info) {
-               int i;
+               int i, off;
 
                info->ifpi_status.status_func = emx_npoll_status;
                info->ifpi_status.serializer = &sc->main_serialize;
 
-               info->ifpi_tx[0].poll_func = emx_npoll_tx;
-               info->ifpi_tx[0].arg = NULL;
-               info->ifpi_tx[0].serializer = &sc->tx_serialize;
+               off = sc->tx_npoll_off;
+               KKASSERT(off < ncpus2);
+               info->ifpi_tx[off].poll_func = emx_npoll_tx;
+               info->ifpi_tx[off].arg = NULL;
+               info->ifpi_tx[off].serializer = &sc->tx_serialize;
 
+               off = sc->rx_npoll_off;
                for (i = 0; i < sc->rx_ring_cnt; ++i) {
-                       info->ifpi_rx[i].poll_func = emx_npoll_rx;
-                       info->ifpi_rx[i].arg = &sc->rx_data[i];
-                       info->ifpi_rx[i].serializer =
-                               &sc->rx_data[i].rx_serialize;
+                       struct emx_rxdata *rdata = &sc->rx_data[i];
+                       int idx = i + off;
+
+                       KKASSERT(idx < ncpus2);
+                       info->ifpi_rx[idx].poll_func = emx_npoll_rx;
+                       info->ifpi_rx[idx].arg = rdata;
+                       info->ifpi_rx[idx].serializer = &rdata->rx_serialize;
                }
 
                if (ifp->if_flags & IFF_RUNNING)
                        emx_disable_intr(sc);
-               ifp->if_npoll_cpuid = 0; /* XXX */
+               ifp->if_npoll_cpuid = sc->tx_npoll_off;
        } else {
                if (ifp->if_flags & IFF_RUNNING)
                        emx_enable_intr(sc);
index d57e4c9..7f913f7 100644 (file)
@@ -276,6 +276,9 @@ struct emx_softc {
        uint32_t                smartspeed;
        int                     int_throttle_ceil;
 
+       int                     rx_npoll_off;
+       int                     tx_npoll_off;
+
        struct lwkt_serialize   main_serialize;
        struct lwkt_serialize   tx_serialize;
        struct lwkt_serialize   *serializes[EMX_NSERIALIZE];