Support polling(4) on multiple CPUs, i.e. each NIC can be assigned to a
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 30 Sep 2007 04:37:27 +0000 (04:37 +0000)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 30 Sep 2007 04:37:27 +0000 (04:37 +0000)
particular CPU that supports polling(4):
- Tunable kern.polling.cpumask controls which CPU can support polling(4).
- Sysctl nodes under kern.polling.X should be used to tune polling(4)
  parameters on CPU_X.
- 'pollcpu' is added to ifconfig(8), which can be used to assign an NIC
  to a particular CPU.

sbin/ifconfig/ifconfig.c
sys/kern/kern_clock.c
sys/kern/kern_poll.c
sys/net/if.c
sys/net/if.h
sys/net/if_var.h
sys/net/netisr.h
sys/sys/sockio.h

index 825564c..fba84d7 100644 (file)
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.113.2.4 2006/02/09 10:48:43 yar Exp $
- * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.29 2007/01/01 01:42:23 sephe Exp $
+ * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.30 2007/09/30 04:37:27 sephe Exp $
  */
 
 #include <sys/param.h>
@@ -799,6 +799,27 @@ setifname(const char *val, int dummy __unused, int s,
        printname = 0;
 }
 
+static void
+setifpollcpu(const char *val, int dummy __unused, int s, 
+    const struct afswtch *afp)
+{
+       int pollcpu;
+
+       pollcpu = atoi(val);
+       if (pollcpu < 0) {
+               warn("pollcpu < 0");
+               return;
+       }
+
+       setifflags("-polling", -IFF_POLLING, s, afp);
+
+       ifr.ifr_pollcpu = pollcpu;
+       if (ioctl(s, SIOCSIFPOLLCPU, (caddr_t)&ifr) < 0) {
+               warn("ioctl (set pollcpu)");
+               return;
+       }
+}
+
 /*
  * Expand the compacted form of addresses as returned via the
  * configuration read via sysctl().
@@ -912,6 +933,11 @@ status(const struct afswtch *afp, int addrcount, struct    sockaddr_dl *sdl,
        if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
                printf("%s", ifs.ascii);
 
+       if (flags & IFF_POLLING) {
+               if (ioctl(s, SIOCGIFPOLLCPU, &ifr) == 0 && ifr.ifr_pollcpu >= 0)
+                       printf("\tpollcpu: %d\n", ifr.ifr_pollcpu);
+       }
+
        close(s);
        return;
 }
@@ -1063,6 +1089,7 @@ static struct cmd basic_cmds[] = {
        DEF_CMD("noicmp",       IFF_LINK1,      setifflags),
        DEF_CMD_ARG("mtu",                      setifmtu),
        DEF_CMD_ARG("name",                     setifname),
+       DEF_CMD_ARG("pollcpu",                  setifpollcpu)
 };
 
 static __constructor void
index 6f64815..df12595 100644 (file)
@@ -70,7 +70,7 @@
  *
  *     @(#)kern_clock.c        8.5 (Berkeley) 1/21/94
  * $FreeBSD: src/sys/kern/kern_clock.c,v 1.105.2.10 2002/10/17 13:19:40 maxim Exp $
- * $DragonFly: src/sys/kern/kern_clock.c,v 1.60 2007/09/12 12:02:09 sephe Exp $
+ * $DragonFly: src/sys/kern/kern_clock.c,v 1.61 2007/09/30 04:37:27 sephe Exp $
  */
 
 #include "opt_ntp.h"
 #endif
 
 #ifdef DEVICE_POLLING
-extern void init_device_poll(void);
 extern void init_device_poll_pcpu(int);
 #endif
 
@@ -230,9 +229,6 @@ int ntp_leap_insert;        /* whether to insert or remove a second */
 static void
 initclocks(void *dummy)
 {
-#ifdef DEVICE_POLLING
-       init_device_poll();
-#endif
        /*psratio = profhz / stathz;*/
        initclocks_pcpu();
        clocks_running = 1;
index 45325e3..2e38315 100644 (file)
@@ -25,7 +25,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_poll.c,v 1.2.2.4 2002/06/27 23:26:33 luigi Exp $
- * $DragonFly: src/sys/kern/kern_poll.c,v 1.33 2007/09/12 12:02:09 sephe Exp $
+ * $DragonFly: src/sys/kern/kern_poll.c,v 1.34 2007/09/30 04:37:27 sephe Exp $
  */
 
 #include "opt_polling.h"
@@ -41,6 +41,7 @@
 
 #include <net/if.h>                    /* for IFF_* flags              */
 #include <net/netisr.h>                        /* for NETISR_POLL              */
+#include <net/netmsg2.h>
 
 /*
  * Polling support for [network] device drivers.
@@ -132,6 +133,9 @@ struct pollctx {
        struct systimer         pollclock;
        int                     polling_enabled;
        int                     pollhz;
+
+       struct netmsg           poll_netmsg;
+       struct netmsg           poll_more_netmsg;
 };
 
 static struct pollctx  *poll_context[POLLCTX_MAX];
@@ -141,14 +145,16 @@ SYSCTL_NODE(_kern, OID_AUTO, polling, CTLFLAG_RW, 0,
 
 static int     poll_defcpu = -1;
 SYSCTL_INT(_kern_polling, OID_AUTO, defcpu, CTLFLAG_RD,
-       &poll_defcpu, 0, "default CPU# to run device polling");
+       &poll_defcpu, 0, "default CPU to run device polling");
 
-static uint32_t        poll_cpumask = 0x1;
-#ifdef notyet
-TUNABLE_INT("kern.polling.cpumask", &poll_cpumask);
-#endif
+static uint32_t        poll_cpumask0 = 0xffffffff;
+TUNABLE_INT("kern.polling.cpumask", &poll_cpumask0);
 
-static int     polling_enabled = 0;    /* global polling enable */
+static uint32_t        poll_cpumask;
+SYSCTL_INT(_kern_polling, OID_AUTO, cpumask, CTLFLAG_RD,
+       &poll_cpumask, 0, "CPUs that can run device polling");
+
+static int     polling_enabled = 1;    /* global polling enable */
 TUNABLE_INT("kern.polling.enable", &polling_enabled);
 
 static int     pollhz = DEVICE_POLLING_FREQ_DEFAULT;
@@ -158,6 +164,11 @@ TUNABLE_INT("kern.polling.pollhz", &pollhz);
 static void    netisr_poll(struct netmsg *);
 static void    netisr_pollmore(struct netmsg *);
 
+static void    poll_register(struct netmsg *);
+static void    poll_deregister(struct netmsg *);
+static void    poll_sysctl_pollhz(struct netmsg *);
+static void    poll_sysctl_polling(struct netmsg *);
+
 /* Systimer handler */
 static void    pollclock(systimer_t, struct intrframe *);
 
@@ -167,28 +178,27 @@ static int        sysctl_polling(SYSCTL_HANDLER_ARGS);
 static void    poll_add_sysctl(struct sysctl_ctx_list *,
                                struct sysctl_oid_list *, struct pollctx *);
 
-void           init_device_poll(void);         /* init routine */
+static void    schedpoll_oncpu(struct pollctx *, struct netmsg *, netisr_fn_t);
+
 void           init_device_poll_pcpu(int);     /* per-cpu init routine */
 
 /*
- * register relevant netisr. Called from kern_clock.c:
+ * Initialize per-cpu polling(4) context.  Called from kern_clock.c:
  */
-void
-init_device_poll(void)
-{
-       netisr_register(NETISR_POLL, cpu0_portfn, netisr_poll);
-       netisr_register(NETISR_POLLMORE, cpu0_portfn, netisr_pollmore);
-}
-
 void
 init_device_poll_pcpu(int cpuid)
 {
        struct pollctx *pctx;
        char cpuid_str[3];
 
-       if (((1 << cpuid) & poll_cpumask) == 0)
+       if (cpuid >= POLLCTX_MAX)
+               return;
+
+       if (((1 << cpuid) & poll_cpumask0) == 0)
                return;
 
+       poll_cpumask |= (1 << cpuid);
+
        pctx = kmalloc(sizeof(*pctx), M_DEVBUF, M_WAITOK | M_ZERO);
 
        pctx->poll_burst = 5;
@@ -199,6 +209,8 @@ init_device_poll_pcpu(int cpuid)
        pctx->polling_enabled = polling_enabled;
        pctx->pollhz = pollhz;
        pctx->poll_cpuid = cpuid;
+       netmsg_init(&pctx->poll_netmsg, &netisr_adone_rport, 0, NULL);
+       netmsg_init(&pctx->poll_more_netmsg, &netisr_adone_rport, 0, NULL);
 
        KASSERT(cpuid < POLLCTX_MAX, ("cpu id must < %d", cpuid));
        poll_context[cpuid] = pctx;
@@ -228,8 +240,19 @@ init_device_poll_pcpu(int cpuid)
        /*
         * Initialize systimer
         */
-       systimer_init_periodic_nq(&pctx->pollclock, pollclock, pctx,
-                                 pctx->polling_enabled ? pctx->pollhz : 1);
+       systimer_init_periodic_nq(&pctx->pollclock, pollclock, pctx, 1);
+}
+
+static __inline void
+schedpoll(struct pollctx *pctx)
+{
+       schedpoll_oncpu(pctx, &pctx->poll_netmsg, netisr_poll);
+}
+
+static __inline void
+schedpollmore(struct pollctx *pctx)
+{
+       schedpoll_oncpu(pctx, &pctx->poll_more_netmsg, netisr_pollmore);
 }
 
 /*
@@ -239,6 +262,8 @@ static int
 sysctl_pollhz(SYSCTL_HANDLER_ARGS)
 {
        struct pollctx *pctx = arg1;
+       struct netmsg msg;
+       lwkt_port_t port;
        int error, phz;
 
        phz = pctx->pollhz;
@@ -250,11 +275,11 @@ sysctl_pollhz(SYSCTL_HANDLER_ARGS)
        else if (phz > DEVICE_POLLING_FREQ_MAX)
                phz = DEVICE_POLLING_FREQ_MAX;
 
-       crit_enter();
-       pctx->pollhz = phz;
-       if (pctx->polling_enabled)
-               systimer_adjust_periodic(&pctx->pollclock, phz);
-       crit_exit();
+       netmsg_init(&msg, &curthread->td_msgport, 0, poll_sysctl_pollhz);
+       msg.nm_lmsg.u.ms_result = phz;
+
+       port = cpu_portfn(pctx->poll_cpuid);
+       lwkt_domsg(port, &msg.nm_lmsg, 0);
        return 0;
 }
 
@@ -266,6 +291,8 @@ static int
 sysctl_polling(SYSCTL_HANDLER_ARGS)
 {
        struct pollctx *pctx = arg1;
+       struct netmsg msg;
+       lwkt_port_t port;
        int error, enabled;
 
        enabled = pctx->polling_enabled;
@@ -273,13 +300,11 @@ sysctl_polling(SYSCTL_HANDLER_ARGS)
        if (error || req->newptr == NULL)
                return error;
 
-       crit_enter();
-       pctx->polling_enabled = enabled;
-       if (pctx->polling_enabled)
-               systimer_adjust_periodic(&pctx->pollclock, pollhz);
-       else
-               systimer_adjust_periodic(&pctx->pollclock, 1);
-       crit_exit();
+       netmsg_init(&msg, &curthread->td_msgport, 0, poll_sysctl_polling);
+       msg.nm_lmsg.u.ms_result = enabled;
+
+       port = cpu_portfn(pctx->poll_cpuid);
+       lwkt_domsg(port, &msg.nm_lmsg, 0);
        return 0;
 }
 
@@ -330,7 +355,7 @@ pollclock(systimer_t info, struct intrframe *frame __unused)
                if (pctx->phase != 0)
                        pctx->suspect++;
                pctx->phase = 1;
-               schednetisr(NETISR_POLL);
+               schedpoll(pctx);
                pctx->phase = 2;
        }
        if (pctx->pending_polls++ > 0)
@@ -367,14 +392,15 @@ netisr_pollmore(struct netmsg *msg)
        pctx = poll_context[cpuid];
        KKASSERT(pctx != NULL);
        KKASSERT(pctx->poll_cpuid == cpuid);
+       KKASSERT(pctx == msg->nm_lmsg.u.ms_resultp);
 
-       crit_enter();
        lwkt_replymsg(&msg->nm_lmsg, 0);
+
        pctx->phase = 5;
        if (pctx->residual_burst > 0) {
-               schednetisr(NETISR_POLL);
+               schedpoll(pctx);
                /* will run immediately on return, followed by netisrs */
-               goto out;
+               return;
        }
        /* here we can account time spent in netisr's in this tick */
        microuptime(&t);
@@ -401,11 +427,9 @@ netisr_pollmore(struct netmsg *msg)
                pctx->poll_burst -= (pctx->poll_burst / 8);
                if (pctx->poll_burst < 1)
                        pctx->poll_burst = 1;
-               schednetisr(NETISR_POLL);
+               schedpoll(pctx);
                pctx->phase = 6;
        }
-out:
-       crit_exit();
 }
 
 /*
@@ -432,9 +456,10 @@ netisr_poll(struct netmsg *msg)
        pctx = poll_context[cpuid];
        KKASSERT(pctx != NULL);
        KKASSERT(pctx->poll_cpuid == cpuid);
+       KKASSERT(pctx == msg->nm_lmsg.u.ms_resultp);
 
        lwkt_replymsg(&msg->nm_lmsg, 0);
-       crit_enter();
+
        pctx->phase = 3;
        if (pctx->residual_burst == 0) { /* first call in this tick */
                microuptime(&pctx->poll_start_t);
@@ -477,37 +502,97 @@ netisr_poll(struct netmsg *msg)
                for (i = 0 ; i < pctx->poll_handlers ; i++) {
                        struct ifnet *ifp = pctx->pr[i].ifp;
 
+                       if (!lwkt_serialize_try(ifp->if_serializer))
+                               continue;
+
                        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING|IFF_POLLING))
-                           == (IFF_UP|IFF_RUNNING|IFF_POLLING)) {
-                               if (lwkt_serialize_try(ifp->if_serializer)) {
-                                       ifp->if_poll(ifp, arg, cycles);
-                                       lwkt_serialize_exit(ifp->if_serializer);
-                               }
-                       }
+                           == (IFF_UP|IFF_RUNNING|IFF_POLLING))
+                               ifp->if_poll(ifp, arg, cycles);
+
+                       lwkt_serialize_exit(ifp->if_serializer);
                }
        } else {        /* unregister */
                for (i = 0 ; i < pctx->poll_handlers ; i++) {
                        struct ifnet *ifp = pctx->pr[i].ifp;
 
-                       if ((ifp->if_flags & IFF_POLLING) == 0)
+                       lwkt_serialize_enter(ifp->if_serializer);
+
+                       if ((ifp->if_flags & IFF_POLLING) == 0) {
+                               KKASSERT(ifp->if_poll_cpuid < 0);
+                               lwkt_serialize_exit(ifp->if_serializer);
                                continue;
+                       }
+                       ifp->if_flags &= ~IFF_POLLING;
+                       ifp->if_poll_cpuid = -1;
+
                        /*
                         * Only call the interface deregistration
                         * function if the interface is still 
                         * running.
                         */
-                       lwkt_serialize_enter(ifp->if_serializer);
-                       ifp->if_flags &= ~IFF_POLLING;
                        if (ifp->if_flags & IFF_RUNNING)
                                ifp->if_poll(ifp, POLL_DEREGISTER, 1);
+
                        lwkt_serialize_exit(ifp->if_serializer);
                }
                pctx->residual_burst = 0;
                pctx->poll_handlers = 0;
        }
-       schednetisr(NETISR_POLLMORE);
+       schedpollmore(pctx);
        pctx->phase = 4;
-       crit_exit();
+}
+
+static void
+poll_register(struct netmsg *msg)
+{
+       struct ifnet *ifp = msg->nm_lmsg.u.ms_resultp;
+       struct pollctx *pctx;
+       int rc, cpuid;
+
+       cpuid = mycpu->gd_cpuid;
+       KKASSERT(cpuid < POLLCTX_MAX);
+
+       pctx = poll_context[cpuid];
+       KKASSERT(pctx != NULL);
+       KKASSERT(pctx->poll_cpuid == cpuid);
+
+       if (pctx->polling_enabled == 0) {
+               /* Polling disabled, cannot register */
+               rc = EOPNOTSUPP;
+               goto back;
+       }
+
+       /*
+        * Check if there is room.
+        */
+       if (pctx->poll_handlers >= POLL_LIST_LEN) {
+               /*
+                * List full, cannot register more entries.
+                * This should never happen; if it does, it is probably a
+                * broken driver trying to register multiple times. Checking
+                * this at runtime is expensive, and won't solve the problem
+                * anyways, so just report a few times and then give up.
+                */
+               static int verbose = 10;        /* XXX */
+               if (verbose >0) {
+                       kprintf("poll handlers list full, "
+                               "maybe a broken driver ?\n");
+                       verbose--;
+               }
+               rc = ENOMEM;
+       } else {
+               pctx->pr[pctx->poll_handlers].ifp = ifp;
+               pctx->poll_handlers++;
+               rc = 0;
+
+               if (pctx->poll_handlers == 1) {
+                       KKASSERT(pctx->polling_enabled);
+                       systimer_adjust_periodic(&pctx->pollclock,
+                                                pctx->pollhz);
+               }
+       }
+back:
+       lwkt_replymsg(&msg->nm_lmsg, rc);
 }
 
 /*
@@ -519,68 +604,109 @@ netisr_poll(struct netmsg *msg)
 int
 ether_poll_register(struct ifnet *ifp)
 {
-       struct pollctx *pctx;
-       int rc;
-
        if (poll_defcpu < 0)
                return 0;
        KKASSERT(poll_defcpu < POLLCTX_MAX);
 
-       pctx = poll_context[poll_defcpu];
-       KKASSERT(pctx != NULL);
-       KKASSERT(pctx->poll_cpuid == poll_defcpu);
+       return ether_pollcpu_register(ifp, poll_defcpu);
+}
 
-       if (pctx->polling_enabled == 0) /* polling disabled, cannot register */
+int
+ether_pollcpu_register(struct ifnet *ifp, int cpuid)
+{
+       struct netmsg msg;
+       lwkt_port_t port;
+       int rc;
+
+       if (ifp->if_poll == NULL) {
+               /* Device does not support polling */
                return 0;
-       if (ifp->if_flags & IFF_POLLING)        /* already polling      */
+       }
+
+       if (cpuid < 0 || cpuid >= POLLCTX_MAX)
                return 0;
-       if (ifp->if_poll == NULL)               /* no polling support   */
+
+       if (((1 << cpuid) & poll_cpumask) == 0) {
+               /* Polling is not supported on 'cpuid' */
                return 0;
+       }
+       KKASSERT(poll_context[cpuid] != NULL);
 
        /*
         * Attempt to register.  Interlock with IFF_POLLING.
         */
        crit_enter();   /* XXX MP - not mp safe */
+
        lwkt_serialize_enter(ifp->if_serializer);
+       if (ifp->if_flags & IFF_POLLING) {
+               /* Already polling */
+               KKASSERT(ifp->if_poll_cpuid >= 0);
+               lwkt_serialize_exit(ifp->if_serializer);
+               crit_exit();
+               return 0;
+       }
+       KKASSERT(ifp->if_poll_cpuid < 0);
        ifp->if_flags |= IFF_POLLING;
+       ifp->if_poll_cpuid = cpuid;
        if (ifp->if_flags & IFF_RUNNING)
                ifp->if_poll(ifp, POLL_REGISTER, 0);
        lwkt_serialize_exit(ifp->if_serializer);
-       if ((ifp->if_flags & IFF_POLLING) == 0) {
-               crit_exit();
-               return 0;
-       }
 
-       /*
-        * Check if there is room.  If there isn't, deregister.
-        */
-       if (pctx->poll_handlers >= POLL_LIST_LEN) {
-               /*
-                * List full, cannot register more entries.
-                * This should never happen; if it does, it is probably a
-                * broken driver trying to register multiple times. Checking
-                * this at runtime is expensive, and won't solve the problem
-                * anyways, so just report a few times and then give up.
-                */
-               static int verbose = 10;        /* XXX */
-               if (verbose >0) {
-                       kprintf("poll handlers list full, "
-                               "maybe a broken driver ?\n");
-                       verbose--;
-               }
+       netmsg_init(&msg, &curthread->td_msgport, 0, poll_register);
+       msg.nm_lmsg.u.ms_resultp = ifp;
+
+       port = cpu_portfn(cpuid);
+       lwkt_domsg(port, &msg.nm_lmsg, 0);
+
+       if (msg.nm_lmsg.ms_error) {
                lwkt_serialize_enter(ifp->if_serializer);
                ifp->if_flags &= ~IFF_POLLING;
+               ifp->if_poll_cpuid = -1;
                if (ifp->if_flags & IFF_RUNNING)
                        ifp->if_poll(ifp, POLL_DEREGISTER, 0);
                lwkt_serialize_exit(ifp->if_serializer);
                rc = 0;
        } else {
-               pctx->pr[pctx->poll_handlers].ifp = ifp;
-               pctx->poll_handlers++;
                rc = 1;
        }
+
        crit_exit();
-       return (rc);
+       return rc;
+}
+
+static void
+poll_deregister(struct netmsg *msg)
+{
+       struct ifnet *ifp = msg->nm_lmsg.u.ms_resultp;
+       struct pollctx *pctx;
+       int rc, i, cpuid;
+
+       cpuid = mycpu->gd_cpuid;
+       KKASSERT(cpuid < POLLCTX_MAX);
+
+       pctx = poll_context[cpuid];
+       KKASSERT(pctx != NULL);
+       KKASSERT(pctx->poll_cpuid == cpuid);
+
+       for (i = 0 ; i < pctx->poll_handlers ; i++) {
+               if (pctx->pr[i].ifp == ifp) /* Found it */
+                       break;
+       }
+       if (i == pctx->poll_handlers) {
+               kprintf("ether_poll_deregister: ifp not found!!!\n");
+               rc = ENOENT;
+       } else {
+               pctx->poll_handlers--;
+               if (i < pctx->poll_handlers) {
+                       /* Last entry replaces this one. */
+                       pctx->pr[i].ifp = pctx->pr[pctx->poll_handlers].ifp;
+               }
+
+               if (pctx->poll_handlers == 0)
+                       systimer_adjust_periodic(&pctx->pollclock, 1);
+               rc = 0;
+       }
+       lwkt_replymsg(&msg->nm_lmsg, rc);
 }
 
 /*
@@ -590,50 +716,51 @@ ether_poll_register(struct ifnet *ifp)
 int
 ether_poll_deregister(struct ifnet *ifp)
 {
-       struct pollctx *pctx;
-       int i;
+       struct netmsg msg;
+       lwkt_port_t port;
+       int rc, cpuid;
 
        KKASSERT(ifp != NULL);
 
-       if (poll_defcpu < 0)
+       if (ifp->if_poll == NULL)
                return 0;
-       KKASSERT(poll_defcpu < POLLCTX_MAX);
-
-       pctx = poll_context[poll_defcpu];
-       KKASSERT(pctx != NULL);
-       KKASSERT(pctx->poll_cpuid == poll_defcpu);
 
        crit_enter();
+
+       lwkt_serialize_enter(ifp->if_serializer);
        if ((ifp->if_flags & IFF_POLLING) == 0) {
+               KKASSERT(ifp->if_poll_cpuid < 0);
+               lwkt_serialize_exit(ifp->if_serializer);
                crit_exit();
                return 0;
        }
-       for (i = 0 ; i < pctx->poll_handlers ; i++) {
-               if (pctx->pr[i].ifp == ifp) /* found it */
-                       break;
-       }
-       ifp->if_flags &= ~IFF_POLLING; /* found or not... */
-       if (i == pctx->poll_handlers) {
-               crit_exit();
-               kprintf("ether_poll_deregister: ifp not found!!!\n");
-               return 0;
-       }
-       pctx->poll_handlers--;
-       if (i < pctx->poll_handlers) { /* Last entry replaces this one. */
-               pctx->pr[i].ifp = pctx->pr[pctx->poll_handlers].ifp;
-       }
-       crit_exit();
 
-       /*
-        * Only call the deregistration function if the interface is still
-        * in a run state.
-        */
-       if (ifp->if_flags & IFF_RUNNING) {
+       cpuid = ifp->if_poll_cpuid;
+       KKASSERT(cpuid >= 0);
+       KKASSERT(poll_context[cpuid] != NULL);
+
+       ifp->if_flags &= ~IFF_POLLING;
+       ifp->if_poll_cpuid = -1;
+       lwkt_serialize_exit(ifp->if_serializer);
+
+       netmsg_init(&msg, &curthread->td_msgport, 0, poll_deregister);
+       msg.nm_lmsg.u.ms_resultp = ifp;
+
+       port = cpu_portfn(cpuid);
+       lwkt_domsg(port, &msg.nm_lmsg, 0);
+
+       if (!msg.nm_lmsg.ms_error) {
                lwkt_serialize_enter(ifp->if_serializer);
-               ifp->if_poll(ifp, POLL_DEREGISTER, 1);
+               if (ifp->if_flags & IFF_RUNNING)
+                       ifp->if_poll(ifp, POLL_DEREGISTER, 1);
                lwkt_serialize_exit(ifp->if_serializer);
+               rc = 1;
+       } else {
+               rc = 0;
        }
-       return (1);
+
+       crit_exit();
+       return rc;
 }
 
 static void
@@ -693,3 +820,58 @@ poll_add_sysctl(struct sysctl_ctx_list *ctx, struct sysctl_oid_list *parent,
                        &pctx->poll_handlers, 0,
                        "Number of registered poll handlers");
 }
+
+static void
+schedpoll_oncpu(struct pollctx *pctx, struct netmsg *msg, netisr_fn_t handler)
+{
+       if (msg->nm_lmsg.ms_flags & MSGF_DONE) {
+               lwkt_port_t port;
+
+               netmsg_init(msg, &netisr_adone_rport, 0, handler);
+#ifdef INVARIANTS
+               msg->nm_lmsg.u.ms_resultp = pctx;
+#endif
+               port = cpu_portfn(mycpu->gd_cpuid);
+               lwkt_sendmsg(port, &msg->nm_lmsg);
+       }
+}
+
+static void
+poll_sysctl_pollhz(struct netmsg *msg)
+{
+       struct pollctx *pctx;
+       int cpuid;
+
+       cpuid = mycpu->gd_cpuid;
+       KKASSERT(cpuid < POLLCTX_MAX);
+
+       pctx = poll_context[cpuid];
+       KKASSERT(pctx != NULL);
+       KKASSERT(pctx->poll_cpuid == cpuid);
+
+       pctx->pollhz = msg->nm_lmsg.u.ms_result;
+       if (pctx->polling_enabled && pctx->poll_handlers)
+               systimer_adjust_periodic(&pctx->pollclock, pctx->pollhz);
+       lwkt_replymsg(&msg->nm_lmsg, 0);
+}
+
+static void
+poll_sysctl_polling(struct netmsg *msg)
+{
+       struct pollctx *pctx;
+       int cpuid;
+
+       cpuid = mycpu->gd_cpuid;
+       KKASSERT(cpuid < POLLCTX_MAX);
+
+       pctx = poll_context[cpuid];
+       KKASSERT(pctx != NULL);
+       KKASSERT(pctx->poll_cpuid == cpuid);
+
+       pctx->polling_enabled = msg->nm_lmsg.u.ms_result;
+       if (pctx->polling_enabled && pctx->poll_handlers)
+               systimer_adjust_periodic(&pctx->pollclock, pctx->pollhz);
+       else
+               systimer_adjust_periodic(&pctx->pollclock, 1);
+       lwkt_replymsg(&msg->nm_lmsg, 0);
+}
index 97e87cd..3f03d65 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)if.c        8.3 (Berkeley) 1/4/94
  * $FreeBSD: src/sys/net/if.c,v 1.185 2004/03/13 02:35:03 brooks Exp $
- * $DragonFly: src/sys/net/if.c,v 1.55 2007/08/27 16:15:42 hasso Exp $
+ * $DragonFly: src/sys/net/if.c,v 1.56 2007/09/30 04:37:27 sephe Exp $
  */
 
 #include "opt_compat.h"
@@ -196,6 +196,11 @@ if_attach(struct ifnet *ifp, lwkt_serialize_t serializer)
        }
        ifp->if_serializer = serializer;
 
+#ifdef DEVICE_POLLING
+       /* Device is not in polling mode by default */
+       ifp->if_poll_cpuid = -1;
+#endif
+
        TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
        ifp->if_index = ++if_index;
        /*
@@ -1131,6 +1136,21 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct ucred *cred)
                ifr->ifr_phys = ifp->if_physical;
                break;
 
+       case SIOCGIFPOLLCPU:
+#ifdef DEVICE_POLLING
+               ifr->ifr_pollcpu = ifp->if_poll_cpuid;
+#else
+               ifr->ifr_pollcpu = -1;
+#endif
+               break;
+
+       case SIOCSIFPOLLCPU:
+#ifdef DEVICE_POLLING
+               if ((ifp->if_flags & IFF_POLLING) == 0)
+                       ether_pollcpu_register(ifp, ifr->ifr_pollcpu);
+#endif
+               break;
+
        case SIOCSIFFLAGS:
                error = suser_cred(cred, 0);
                if (error)
index 1aa16de..2e0ab18 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)if.h        8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/net/if.h,v 1.58.2.9 2002/08/30 14:23:38 sobomax Exp $
- * $DragonFly: src/sys/net/if.h,v 1.18 2007/03/24 05:57:49 sephe Exp $
+ * $DragonFly: src/sys/net/if.h,v 1.19 2007/09/30 04:37:27 sephe Exp $
  */
 
 #ifndef _NET_IF_H_
@@ -259,6 +259,7 @@ struct      ifreq {
                int     ifru_media;
                void   *ifru_data;
                int     ifru_cap[2];
+               int     ifru_pollcpu;
        } ifr_ifru;
 #define        ifr_addr        ifr_ifru.ifru_addr      /* address */
 #define        ifr_dstaddr     ifr_ifru.ifru_dstaddr   /* other end of p-to-p link */
@@ -272,6 +273,7 @@ struct      ifreq {
 #define        ifr_data        ifr_ifru.ifru_data      /* for use by interface */
 #define        ifr_reqcap      ifr_ifru.ifru_cap[0]    /* requested capabilities */
 #define        ifr_curcap      ifr_ifru.ifru_cap[1]    /* current capabilities */
+#define ifr_pollcpu    ifr_ifru.ifru_pollcpu   /* polling(4) cpu */
 };
 
 #define        _SIZEOF_ADDR_IFREQ(ifr) \
index f9577ef..25d8ca8 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     From: @(#)if.h  8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/net/if_var.h,v 1.18.2.16 2003/04/15 18:11:19 fjoe Exp $
- * $DragonFly: src/sys/net/if_var.h,v 1.40 2007/09/09 03:51:25 sephe Exp $
+ * $DragonFly: src/sys/net/if_var.h,v 1.41 2007/09/30 04:37:27 sephe Exp $
  */
 
 #ifndef        _NET_IF_VAR_H_
@@ -210,8 +210,11 @@ struct ifnet {
 #ifdef DEVICE_POLLING
        void    (*if_poll)              /* IFF_POLLING support */
                (struct ifnet *, enum poll_cmd, int);
+       int     if_poll_cpuid;
 #else
-       void    (*if_poll_unused)(void); /* placeholder */
+       /* Place holders */
+       void    (*if_poll_unused)(void);
+       int     if_poll_cpuid_used;
 #endif
        struct  ifaltq if_snd;          /* output queue (includes altq) */
        struct  ifprefixhead if_prefixhead; /* list of prefixes per if */
@@ -502,6 +505,7 @@ int if_clone_destroy(const char *);
 typedef        void poll_handler_t (struct ifnet *ifp, enum poll_cmd cmd, int count);
 int    ether_poll_register(struct ifnet *);
 int    ether_poll_deregister(struct ifnet *);
+int    ether_pollcpu_register(struct ifnet *, int);
 #endif /* DEVICE_POLLING */
 #endif /* _KERNEL */
 
index 2432e6f..440fc8c 100644 (file)
@@ -65,7 +65,7 @@
  *
  *     @(#)netisr.h    8.1 (Berkeley) 6/10/93
  * $FreeBSD: src/sys/net/netisr.h,v 1.21.2.5 2002/02/09 23:02:39 luigi Exp $
- * $DragonFly: src/sys/net/netisr.h,v 1.27 2007/06/16 15:27:27 sephe Exp $
+ * $DragonFly: src/sys/net/netisr.h,v 1.28 2007/09/30 04:37:27 sephe Exp $
  */
 
 #ifndef _NET_NETISR_H_
@@ -87,7 +87,6 @@
  * on the lowest level routine of each protocol.
  */
 #define NETISR_RESERVED0 0             /* cannot be used */
-#define        NETISR_POLL     1               /* polling callback */
 #define        NETISR_IP       2               /* same as AF_INET */
 #define        NETISR_NS       6               /* same as AF_NS */
 #define        NETISR_AARP     15              /* Appletalk ARP */
 #define        NETISR_IPV6     28              /* same as AF_INET6 */
 #define        NETISR_NATM     29              /* same as AF_NATM */
 #define        NETISR_NETGRAPH 30              /* same as AF_NETGRAPH */
-#define        NETISR_POLLMORE 31              /* check if we need more polling */
 
 #define        NETISR_MAX      32
 
@@ -216,6 +214,7 @@ struct netisr {
 
 #ifdef _KERNEL
 
+extern lwkt_port netisr_adone_rport;
 extern lwkt_port netisr_afree_rport;
 extern lwkt_port netisr_apanic_rport;
 
index 4f42a1a..5ef5a50 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)sockio.h    8.1 (Berkeley) 3/28/94
  * $FreeBSD: src/sys/sys/sockio.h,v 1.14.2.6 2002/02/07 15:12:37 ambrisko Exp $
- * $DragonFly: src/sys/sys/sockio.h,v 1.4 2005/12/21 16:40:25 corecode Exp $
+ * $DragonFly: src/sys/sys/sockio.h,v 1.5 2007/09/30 04:37:27 sephe Exp $
  */
 
 #ifndef        _SYS_SOCKIO_H_
 #define SIOCIFDESTROY   _IOW('i', 121, struct ifreq)   /* destroy clone if */
 #define SIOCIFGCLONERS _IOWR('i', 120, struct if_clonereq) /* get cloners */
 
+#define SIOCSIFPOLLCPU  _IOW('i', 125, struct ifreq)   /* set polling(4) cpu */
+#define SIOCGIFPOLLCPU _IOWR('i', 126, struct ifreq)   /* set polling(4) cpu */
+
 #endif /* !_SYS_SOCKIO_H_ */