commit bb35ab5a919cea8e39e67f85e5db0da866775b2c
Author: Ryota Ozaki <ozaki-r@iij.ad.jp>
Date:   Tue Feb 2 17:51:04 2016 +0900

    Tweak API

diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c
index 15e5033..26667bb 100644
--- a/sys/dev/pci/if_iwm.c
+++ b/sys/dev/pci/if_iwm.c
@@ -6832,8 +6832,8 @@ iwm_attach(device_t parent, device_t self, void *aux)
 	ether_ifattach(ifp, ic->ic_myaddr);	/* XXX */
 #endif
 	if_register(ifp);
-	/* XXX should provide its own softint handler */
-	ifp->if_percpuq = if_percpuq_create(if_percpuq_softint, ifp);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
 
 	callout_init(&sc->sc_calib_to, 0);
 	callout_setfunc(&sc->sc_calib_to, iwm_calib_timeout, sc);
diff --git a/sys/dev/pci/if_rtwn.c b/sys/dev/pci/if_rtwn.c
index 6f61bac..5551ebca 100644
--- a/sys/dev/pci/if_rtwn.c
+++ b/sys/dev/pci/if_rtwn.c
@@ -358,8 +358,8 @@ rtwn_attach(device_t parent, device_t self, void *aux)
 	if_initialize(ifp);
 	ieee80211_ifattach(ic);
 	if_register(ifp);
-	/* XXX should provide its own softint handler */
-	ifp->if_percpuq = if_percpuq_create(if_percpuq_softint, ifp);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
 
 	/* override default methods */
 	ic->ic_newassoc = rtwn_newassoc;
diff --git a/sys/dev/pci/if_wm.c b/sys/dev/pci/if_wm.c
index 6a19ffe..b9f4b10 100644
--- a/sys/dev/pci/if_wm.c
+++ b/sys/dev/pci/if_wm.c
@@ -442,6 +442,8 @@ struct wm_softc {
 	krndsource_t rnd_source;	/* random source */
 
 	kmutex_t *sc_core_lock;		/* lock for softc operations */
+
+	struct if_percpuq *sc_ipq;	/* softint-based input queues */
 };
 
 #define WM_TX_LOCK(_txq)	if ((_txq)->txq_lock) mutex_enter((_txq)->txq_lock)
@@ -2444,8 +2446,10 @@ alloc_retry:
 #endif
 
 	/* Attach the interface. */
-	if_attach(ifp);
+	if_initialize(ifp);
+	sc->sc_ipq = if_percpuq_create(&sc->sc_ethercom.ec_if);
 	ether_ifattach(ifp, enaddr);
+	if_register(ifp);
 	ether_set_ifflags_cb(&sc->sc_ethercom, wm_ifflags_cb);
 	rnd_attach_source(&sc->rnd_source, xname, RND_TYPE_NET,
 			  RND_FLAG_DEFAULT);
@@ -2559,7 +2563,7 @@ wm_detach(device_t self, int flags __unused)
 
 	ether_ifdetach(ifp);
 	if_detach(ifp);
-
+	if_percpuq_destroy(sc->sc_ipq);
 
 	/* Unload RX dmamaps and free mbufs */
 	for (i = 0; i < sc->sc_nrxqueues; i++) {
@@ -7121,7 +7125,7 @@ wm_rxeof(struct wm_rxqueue *rxq)
 		bpf_mtap(ifp, m);
 
 		/* Pass it on. */
-		if_input(ifp, m);
+		if_percpuq_enqueue(sc->sc_ipq, m);
 
 		WM_RX_LOCK(rxq);
 
diff --git a/sys/net/if.c b/sys/net/if.c
index dfd622f..506331c 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -650,6 +650,20 @@ if_register(ifnet_t *ifp)
 }
 
 static void
+if_percpuq_softint(void *arg)
+{
+	struct if_percpuq *ipq = arg;
+	struct ifnet *ifp = ipq->ipq_ifp;
+	struct mbuf *m;
+	int s;
+
+	s = splnet();
+	while ((m = if_percpuq_dequeue(ipq)) != NULL)
+		ifp->_if_input(ifp, m);
+	splx(s);
+}
+
+static void
 if_percpuq_init_ifq(void *p, void *arg __unused, struct cpu_info *ci __unused)
 {
 	struct ifqueue *const ifq = p;
@@ -659,7 +673,7 @@ if_percpuq_init_ifq(void *p, void *arg __unused, struct cpu_info *ci __unused)
 }
 
 struct if_percpuq *
-if_percpuq_create(void (*sih)(void *), void *arg)
+if_percpuq_create(struct ifnet *ifp)
 {
 	struct if_percpuq *ipq;
 
@@ -667,30 +681,26 @@ if_percpuq_create(void (*sih)(void *), void *arg)
 	if (ipq == NULL)
 		panic("kmem_zalloc failed");
 
+	ipq->ipq_ifp = ifp;
 	ipq->ipq_si = softint_establish(SOFTINT_NET|SOFTINT_MPSAFE,
-	    sih, arg);
+	    if_percpuq_softint, ipq);
 	ipq->ipq_ifqs = percpu_alloc(sizeof(struct ifqueue));
 	percpu_foreach(ipq->ipq_ifqs, &if_percpuq_init_ifq, NULL);
 
 	return ipq;
 }
 
-void
-if_percpuq_softint(void *arg)
+struct mbuf *
+if_percpuq_dequeue(struct if_percpuq *ipq)
 {
-	struct ifnet *ifp = arg;
 	struct mbuf *m;
 	struct ifqueue *ifq;
-	int s;
 
-	s = splnet();
-	ifq = percpu_getref(ifp->if_percpuq->ipq_ifqs);
-	while (!IF_IS_EMPTY(ifq)) {
-		IF_DEQUEUE(ifq, m);
-		ifp->_if_input(ifp, m);
-	}
-	percpu_putref(ifp->if_percpuq->ipq_ifqs);
-	splx(s);
+	ifq = percpu_getref(ipq->ipq_ifqs);
+	IF_DEQUEUE(ifq, m);
+	percpu_putref(ipq->ipq_ifqs);
+
+	return m;
 }
 
 static void
@@ -705,9 +715,47 @@ void
 if_percpuq_destroy(struct if_percpuq *ipq)
 {
 
+	softint_disestablish(ipq->ipq_si);
 	percpu_foreach(ipq->ipq_ifqs, &if_percpuq_purge_ifq, NULL);
 	percpu_free(ipq->ipq_ifqs, sizeof(struct ifqueue));
-	softint_disestablish(ipq->ipq_si);
+}
+
+void
+if_percpuq_enqueue(struct if_percpuq *ipq, struct mbuf *m)
+{
+	struct ifqueue *ifq = percpu_getref(ipq->ipq_ifqs);
+	int s;
+
+	s = splnet();
+	if (IF_QFULL(ifq)) {
+		IF_DROP(ifq);
+		m_freem(m);
+		goto out;
+	}
+	IF_ENQUEUE(ifq, m);
+	percpu_putref(ipq->ipq_ifqs);
+
+	softint_schedule(ipq->ipq_si);
+out:
+	splx(s);
+}
+
+/*
+ * The common interface input routine that is called by device drivers.
+ * We ensure that the upper layer routines, e.g., ether_input and bridge_input,
+ * aren't run in hardware interrupt context.
+ */
+void
+if_input(struct ifnet *ifp, struct mbuf *m)
+{
+
+	if (ifp->if_percpuq) {
+		if_percpuq_enqueue(ifp->if_percpuq, m);
+	} else {
+		KASSERT(!cpu_intr_p());
+
+		ifp->_if_input(ifp, m);
+	}
 }
 
 /*
@@ -717,8 +765,9 @@ if_percpuq_destroy(struct if_percpuq *ipq)
 void
 if_attach(ifnet_t *ifp)
 {
+
 	if_initialize(ifp);
-	ifp->if_percpuq = if_percpuq_create(if_percpuq_softint, ifp);
+	ifp->if_percpuq = if_percpuq_create(ifp);
 	if_register(ifp);
 }
 
@@ -988,13 +1037,8 @@ again:
 	xc = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
 	xc_wait(xc);
 
-	if (ifp->if_percpuq != NULL) {
-		struct if_percpuq *ipq = ifp->if_percpuq;
-
-		percpu_foreach(ipq->ipq_ifqs, &if_percpuq_purge_ifq, NULL);
-		percpu_free(ipq->ipq_ifqs, sizeof(struct ifqueue));
-		softint_disestablish(ipq->ipq_si);
-	}
+	if (ifp->if_percpuq != NULL)
+		if_percpuq_destroy(ifp->if_percpuq);
 
 	splx(s);
 }
@@ -2512,42 +2556,6 @@ if_mcast_op(ifnet_t *ifp, const unsigned long cmd, const struct sockaddr *sa)
 	return rc;
 }
 
-void
-if_percpuq_enqueue(struct if_percpuq *ipq, struct mbuf *m)
-{
-	struct ifqueue *ifq = percpu_getref(ipq->ipq_ifqs);
-
-	if (IF_QFULL(ifq)) {
-		IF_DROP(ifq);
-		m_freem(m);
-		return;
-	}
-	IF_ENQUEUE(ifq, m);
-	percpu_putref(ipq->ipq_ifqs);
-
-	softint_schedule(ipq->ipq_si);
-}
-
-/*
- * The common interface input routine that is called by device drivers.
- * We ensure that the upper layer routines, e.g., ether_input and bridge_input,
- * aren't run in hardware interrupt context.
- */
-void
-if_input(struct ifnet *ifp, struct mbuf *m)
-{
-
-	if (ifp->if_percpuq) {
-		KASSERT(cpu_intr_p());
-
-		if_percpuq_enqueue(ifp->if_percpuq, m);
-	} else {
-		KASSERT(!cpu_intr_p());
-
-		ifp->_if_input(ifp, m);
-	}
-}
-
 static void
 sysctl_sndq_setup(struct sysctllog **clog, const char *ifname,
     struct ifaltq *ifq)
diff --git a/sys/net/if.h b/sys/net/if.h
index 5f2e185..bf619ec 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -252,11 +252,7 @@ struct bridge_softc;
 struct bridge_iflist;
 struct callout;
 struct krwlock;
-
-struct if_percpuq {
-	void		*ipq_si;
-	struct percpu	*ipq_ifqs;	/* struct ifqueue */
-};
+struct if_percpuq;
 
 typedef struct ifnet {
 	void	*if_softc;		/* lower-level data for this if */
@@ -956,11 +952,18 @@ int	if_clone_list(int, char *, int *);
 
 void	if_input(struct ifnet *, struct mbuf *);
 
+struct if_percpuq {
+	struct ifnet	*ipq_ifp;
+	void		*ipq_si;
+	struct percpu	*ipq_ifqs;	/* struct ifqueue */
+};
+
 struct if_percpuq *
-	if_percpuq_create(void (*)(void *), void *);
+	if_percpuq_create(struct ifnet *);
 void	if_percpuq_destroy(struct if_percpuq *);
 void	if_percpuq_enqueue(struct if_percpuq *, struct mbuf *);
-void	if_percpuq_softint(void *);
+struct mbuf *
+	if_percpuq_dequeue(struct if_percpuq *);
 
 void ifa_insert(struct ifnet *, struct ifaddr *);
 void ifa_remove(struct ifnet *, struct ifaddr *);