if: Add subqueue watchdog helper functions for driver use
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 25 Jan 2013 03:29:47 +0000 (11:29 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 25 Jan 2013 03:31:55 +0000 (11:31 +0800)
Ease driver's multiple TX queue support

sys/net/if.c
sys/net/ifq_var.h

index 1cf740d..39e38a2 100644 (file)
@@ -119,6 +119,9 @@ static void if_slowtimo(void *);
 static void    link_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
 static int     if_rtdel(struct radix_node *, void *);
 
+/* Helper functions */
+static void    ifsq_watchdog_reset(struct ifsubq_watchdog *);
+
 #ifdef INET6
 /*
  * XXX: declare here to avoid to include many inet6 related files..
@@ -3025,3 +3028,55 @@ ifq_mapsubq_default(struct ifaltq *ifq __unused, int cpuid __unused)
 {
        return ALTQ_SUBQ_INDEX_DEFAULT;
 }
+
+static void
+ifsq_watchdog(void *arg)
+{
+       struct ifsubq_watchdog *wd = arg;
+       struct ifnet *ifp;
+
+       if (__predict_true(wd->wd_timer == 0 || --wd->wd_timer))
+               goto done;
+
+       ifp = ifsq_get_ifp(wd->wd_subq);
+       if (ifnet_tryserialize_all(ifp)) {
+               wd->wd_watchdog(wd->wd_subq);
+               ifnet_deserialize_all(ifp);
+       } else {
+               /* try again next timeout */
+               wd->wd_timer = 1;
+       }
+done:
+       ifsq_watchdog_reset(wd);
+}
+
+static void
+ifsq_watchdog_reset(struct ifsubq_watchdog *wd)
+{
+       callout_reset_bycpu(&wd->wd_callout, hz, ifsq_watchdog, wd,
+           ifsq_get_cpuid(wd->wd_subq));
+}
+
+void
+ifsq_watchdog_init(struct ifsubq_watchdog *wd, struct ifaltq_subque *ifsq,
+    ifsq_watchdog_t watchdog)
+{
+       callout_init_mp(&wd->wd_callout);
+       wd->wd_timer = 0;
+       wd->wd_subq = ifsq;
+       wd->wd_watchdog = watchdog;
+}
+
+void
+ifsq_watchdog_start(struct ifsubq_watchdog *wd)
+{
+       wd->wd_timer = 0;
+       ifsq_watchdog_reset(wd);
+}
+
+void
+ifsq_watchdog_stop(struct ifsubq_watchdog *wd)
+{
+       wd->wd_timer = 0;
+       callout_stop(&wd->wd_callout);
+}
index 5f43a0e..b343bea 100644 (file)
            ("not ifp's default subqueue"));
 
 struct ifaltq;
+struct ifaltq_subque;
+
+typedef void   (*ifsq_watchdog_t)(struct ifaltq_subque *);
+
+struct ifsubq_watchdog {
+       struct callout  wd_callout;
+       int             wd_timer;
+       struct ifaltq_subque *wd_subq;
+       ifsq_watchdog_t wd_watchdog;
+};
 
 /*
  * Support for "classic" ALTQ interfaces.
@@ -82,6 +92,11 @@ int          ifq_mapsubq_default(struct ifaltq *, int);
 void           ifsq_devstart(struct ifaltq_subque *ifsq);
 void           ifsq_devstart_sched(struct ifaltq_subque *ifsq);
 
+void           ifsq_watchdog_init(struct ifsubq_watchdog *,
+                   struct ifaltq_subque *, ifsq_watchdog_t);
+void           ifsq_watchdog_start(struct ifsubq_watchdog *);
+void           ifsq_watchdog_stop(struct ifsubq_watchdog *);
+
 /*
  * Dispatch a packet to an interface.
  */