Module Name:    src
Committed By:   nonaka
Date:           Thu Feb  2 10:05:35 UTC 2017

Modified Files:
        src/sys/dev/ic: an.c anvar.h arn5008.c arn9003.c ath.c ath_netbsd.h
            athn.c athnvar.h atw.c atwvar.h awi.c awivar.h bwi.c bwivar.h
            malo.c malovar.h rt2560.c rt2560var.h rt2661.c rt2661var.h rt2860.c
            rt2860var.h rtw.c rtwvar.h wi.c wivar.h
        src/sys/dev/pci: if_ipw.c if_ipwvar.h if_iwi.c if_iwivar.h if_iwm.c
            if_iwmvar.h if_iwn.c if_iwnvar.h if_malo_pci.c if_rtwn.c
            if_rtwnreg.h if_wpi.c if_wpivar.h
        src/sys/dev/pcmcia: if_malo_pcmcia.c if_malo_pcmciavar.h
        src/sys/net80211: ieee80211_input.c ieee80211_proto.c

Log Message:
wlan interfaces make interrupt routine running on softint context.

see http://mail-index.netbsd.org/tech-kern/2016/12/06/msg021281.html

tested device:
 * ath at pci: AR5212, AR5424
 * athn at pci: AR9287
 * ipw at pci: 2100BG
 * iwi at pci: 2915ABG
 * iwm at pci: 3165, 7260, 8260
 * iwn at pci: 4945, 6235
 * ral at pci: RT2560
 * rtwn at pci: RTL8192CE


To generate a diff of this commit:
cvs rdiff -u -r1.63 -r1.64 src/sys/dev/ic/an.c
cvs rdiff -u -r1.20 -r1.21 src/sys/dev/ic/anvar.h
cvs rdiff -u -r1.11 -r1.12 src/sys/dev/ic/arn5008.c \
    src/sys/dev/ic/rt2661var.h
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/ic/arn9003.c src/sys/dev/ic/bwivar.h \
    src/sys/dev/ic/rt2560var.h
cvs rdiff -u -r1.122 -r1.123 src/sys/dev/ic/ath.c
cvs rdiff -u -r1.15 -r1.16 src/sys/dev/ic/ath_netbsd.h
cvs rdiff -u -r1.14 -r1.15 src/sys/dev/ic/athn.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/ic/athnvar.h
cvs rdiff -u -r1.160 -r1.161 src/sys/dev/ic/atw.c
cvs rdiff -u -r1.37 -r1.38 src/sys/dev/ic/atwvar.h
cvs rdiff -u -r1.90 -r1.91 src/sys/dev/ic/awi.c
cvs rdiff -u -r1.27 -r1.28 src/sys/dev/ic/awivar.h
cvs rdiff -u -r1.30 -r1.31 src/sys/dev/ic/bwi.c
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/ic/malo.c
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/ic/malovar.h
cvs rdiff -u -r1.28 -r1.29 src/sys/dev/ic/rt2560.c
cvs rdiff -u -r1.33 -r1.34 src/sys/dev/ic/rt2661.c
cvs rdiff -u -r1.24 -r1.25 src/sys/dev/ic/rt2860.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/ic/rt2860var.h
cvs rdiff -u -r1.124 -r1.125 src/sys/dev/ic/rtw.c
cvs rdiff -u -r1.44 -r1.45 src/sys/dev/ic/rtwvar.h
cvs rdiff -u -r1.241 -r1.242 src/sys/dev/ic/wi.c
cvs rdiff -u -r1.65 -r1.66 src/sys/dev/ic/wivar.h
cvs rdiff -u -r1.62 -r1.63 src/sys/dev/pci/if_ipw.c
cvs rdiff -u -r1.17 -r1.18 src/sys/dev/pci/if_ipwvar.h
cvs rdiff -u -r1.101 -r1.102 src/sys/dev/pci/if_iwi.c
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/pci/if_iwivar.h \
    src/sys/dev/pci/if_iwnvar.h
cvs rdiff -u -r1.69 -r1.70 src/sys/dev/pci/if_iwm.c
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/pci/if_iwmvar.h
cvs rdiff -u -r1.83 -r1.84 src/sys/dev/pci/if_iwn.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/pci/if_malo_pci.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/pci/if_rtwn.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/pci/if_rtwnreg.h
cvs rdiff -u -r1.76 -r1.77 src/sys/dev/pci/if_wpi.c
cvs rdiff -u -r1.20 -r1.21 src/sys/dev/pci/if_wpivar.h
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/pcmcia/if_malo_pcmcia.c
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/pcmcia/if_malo_pcmciavar.h
cvs rdiff -u -r1.86 -r1.87 src/sys/net80211/ieee80211_input.c
cvs rdiff -u -r1.33 -r1.34 src/sys/net80211/ieee80211_proto.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/an.c
diff -u src/sys/dev/ic/an.c:1.63 src/sys/dev/ic/an.c:1.64
--- src/sys/dev/ic/an.c:1.63	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/an.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: an.c,v 1.63 2016/06/10 13:27:13 ozaki-r Exp $	*/
+/*	$NetBSD: an.c,v 1.64 2017/02/02 10:05:35 nonaka Exp $	*/
 /*
  * Copyright (c) 1997, 1998, 1999
  *	Bill Paul <wp...@ctr.columbia.edu>.  All rights reserved.
@@ -77,7 +77,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: an.c,v 1.63 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: an.c,v 1.64 2017/02/02 10:05:35 nonaka Exp $");
 
 
 #include <sys/param.h>
@@ -96,6 +96,7 @@ __KERNEL_RCSID(0, "$NetBSD: an.c,v 1.63 
 #include <sys/kauth.h>
 
 #include <sys/bus.h>
+#include <sys/intr.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -116,6 +117,7 @@ __KERNEL_RCSID(0, "$NetBSD: an.c,v 1.63 
 
 static int	an_reset(struct an_softc *);
 static void	an_wait(struct an_softc *);
+static void	an_softintr(void *);
 static int	an_init(struct ifnet *);
 static void	an_stop(struct ifnet *, int);
 static void	an_start(struct ifnet *);
@@ -178,6 +180,13 @@ an_attach(struct an_softc *sc)
 		return 1;
 	}
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, an_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		splx(s);
+		aprint_error_dev(sc->sc_dev, "failed to establish softint\n");
+		return 1;
+	}
+
 	/* Load factory config */
 	if (an_cmd(sc, AN_CMD_READCFG, 0) != 0) {
 		splx(s);
@@ -308,8 +317,10 @@ an_attach(struct an_softc *sc)
 	/*
 	 * Call MI attach routine.
 	 */
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	sc->sc_newstate = ic->ic_newstate;
 	ic->ic_newstate = an_newstate;
@@ -409,7 +420,10 @@ an_detach(struct an_softc *sc)
 	an_stop(ifp, 1);
 	ieee80211_ifdetach(ic);
 	if_detach(ifp);
+	if (sc->sc_soft_ih != NULL)
+		softint_disestablish(sc->sc_soft_ih);
 	splx(s);
+
 	return 0;
 }
 
@@ -432,8 +446,6 @@ an_intr(void *arg)
 {
 	struct an_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
-	int i;
-	u_int16_t status;
 
 	if (!sc->sc_enabled || !device_is_active(sc->sc_dev) ||
 	    (ifp->if_flags & IFF_RUNNING) == 0)
@@ -445,15 +457,39 @@ an_intr(void *arg)
 		return 1;
 	}
 
+	/* Disable interrupts */
+	CSR_WRITE_2(sc, AN_INT_EN, 0);
+
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+an_softintr(void *arg)
+{
+	struct an_softc *sc = arg;
+	struct ifnet *ifp = &sc->sc_if;
+	int i, s;
+	uint16_t status;
+
+	if (!sc->sc_enabled || !device_is_active(sc->sc_dev) ||
+	    (ifp->if_flags & IFF_RUNNING) == 0)
+		return;
+
+	if ((ifp->if_flags & IFF_UP) == 0) {
+		CSR_WRITE_2(sc, AN_EVENT_ACK, ~0);
+		return;
+	}
+
 	/* maximum 10 loops per interrupt */
 	for (i = 0; i < 10; i++) {
 		if (!sc->sc_enabled || !device_is_active(sc->sc_dev))
-			return 1;
+			return;
 		if (CSR_READ_2(sc, AN_SW0) != AN_MAGIC) {
 			DPRINTF(("an_intr: magic number changed: %x\n",
 			    CSR_READ_2(sc, AN_SW0)));
 			config_deactivate(sc->sc_dev);
-			return 1;
+			return;
 		}
 		status = CSR_READ_2(sc, AN_EVENT_STAT);
 		CSR_WRITE_2(sc, AN_EVENT_ACK, status & ~(AN_INTRS));
@@ -471,11 +507,17 @@ an_intr(void *arg)
 
 		if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
 		    sc->sc_ic.ic_state == IEEE80211_S_RUN &&
-		    !IFQ_IS_EMPTY(&ifp->if_snd))
+		    !IFQ_IS_EMPTY(&ifp->if_snd)) {
+			s = splnet();
 			an_start(ifp);
+			splx(s);
+		}
 	}
+	if (i == 10)
+		softint_schedule(sc->sc_soft_ih);
 
-	return 1;
+	/* Re-enable interrupts */
+	CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);
 }
 
 static int
@@ -1328,7 +1370,7 @@ an_rx_intr(struct an_softc *sc)
 	struct an_rxframe frmhdr;
 	struct mbuf *m;
 	u_int16_t status;
-	int fid, gaplen, len, off;
+	int fid, gaplen, len, off, s;
 	uint8_t *gap;
 
 	fid = CSR_READ_2(sc, AN_RX_FID);
@@ -1441,6 +1483,8 @@ an_rx_intr(struct an_softc *sc)
 	m_set_rcvif(m, ifp);
 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
 
+	s = splnet();
+
 	if (sc->sc_drvbpf) {
 		struct an_rx_radiotap_header *tap = &sc->sc_rxtap;
 
@@ -1473,13 +1517,17 @@ an_rx_intr(struct an_softc *sc)
 	ieee80211_input(ic, m, ni, frmhdr.an_rx_signal_strength,
 	    le32toh(frmhdr.an_rx_time));
 	ieee80211_free_node(ni);
+
+	splx(s);
 }
 
 static void
 an_tx_intr(struct an_softc *sc, int status)
 {
 	struct ifnet *ifp = &sc->sc_if;
-	int cur, fid;
+	int cur, fid, s;
+
+	s = splnet();
 
 	sc->sc_tx_timer = 0;
 	ifp->if_flags &= ~IFF_OACTIVE;
@@ -1513,7 +1561,7 @@ an_tx_intr(struct an_softc *sc, int stat
 			    fid, cur);
 	}
 
-	return;
+	splx(s);
 }
 
 static void
@@ -1521,11 +1569,13 @@ an_linkstat_intr(struct an_softc *sc)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
 	u_int16_t status;
+	int s;
 
 	status = CSR_READ_2(sc, AN_LINKSTAT);
 	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
 	DPRINTF(("an_linkstat_intr: status 0x%x\n", status));
 
+	s = splnet();
 	if (status == AN_LINKSTAT_ASSOCIATED) {
 		if (ic->ic_state != IEEE80211_S_RUN ||
 		    ic->ic_opmode == IEEE80211_M_IBSS)
@@ -1534,6 +1584,7 @@ an_linkstat_intr(struct an_softc *sc)
 		if (ic->ic_opmode == IEEE80211_M_STA)
 			ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 	}
+	splx(s);
 }
 
 /* Must be called at proper protection level! */

Index: src/sys/dev/ic/anvar.h
diff -u src/sys/dev/ic/anvar.h:1.20 src/sys/dev/ic/anvar.h:1.21
--- src/sys/dev/ic/anvar.h:1.20	Sun Jan 17 19:45:06 2010
+++ src/sys/dev/ic/anvar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: anvar.h,v 1.20 2010/01/17 19:45:06 pooka Exp $	*/
+/*	$NetBSD: anvar.h,v 1.21 2017/02/02 10:05:35 nonaka Exp $	*/
 /*
  * Copyright (c) 1997, 1998, 1999
  *	Bill Paul <wp...@ctr.columbia.edu>.  All rights reserved.
@@ -108,6 +108,7 @@ struct an_softc	{
 	struct ieee80211com	sc_ic;
 	bus_space_tag_t		sc_iot;
 	bus_space_handle_t	sc_ioh;
+	void			*sc_soft_ih;
 	int			(*sc_enable)(struct an_softc *);
 	void			(*sc_disable)(struct an_softc *);
 	int			(*sc_newstate)(struct ieee80211com *,

Index: src/sys/dev/ic/arn5008.c
diff -u src/sys/dev/ic/arn5008.c:1.11 src/sys/dev/ic/arn5008.c:1.12
--- src/sys/dev/ic/arn5008.c:1.11	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/arn5008.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: arn5008.c,v 1.11 2016/06/10 13:27:13 ozaki-r Exp $	*/
+/*	$NetBSD: arn5008.c,v 1.12 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: ar5008.c,v 1.21 2012/08/25 12:14:31 kettenis Exp $	*/
 
 /*-
@@ -24,7 +24,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: arn5008.c,v 1.11 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: arn5008.c,v 1.12 2017/02/02 10:05:35 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/sockio.h>
@@ -88,6 +88,7 @@ Static void	ar5008_hw_init(struct athn_s
 		    struct ieee80211_channel *);
 Static void	ar5008_init_baseband(struct athn_softc *);
 Static void	ar5008_init_chains(struct athn_softc *);
+Static int	ar5008_intr_status(struct athn_softc *);
 Static int	ar5008_intr(struct athn_softc *);
 Static void	ar5008_next_calib(struct athn_softc *);
 Static int	ar5008_read_eep_word(struct athn_softc *, uint32_t,
@@ -175,6 +176,7 @@ ar5008_attach(struct athn_softc *sc)
 	ops->dma_alloc = ar5008_dma_alloc;
 	ops->dma_free = ar5008_dma_free;
 	ops->rx_enable = ar5008_rx_enable;
+	ops->intr_status = ar5008_intr_status;
 	ops->intr = ar5008_intr;
 	ops->tx = ar5008_tx;
 
@@ -797,7 +799,7 @@ ar5008_rx_process(struct athn_softc *sc)
 	struct ieee80211_node *ni;
 	struct mbuf *m, *m1;
 	u_int32_t rstamp;
-	int error, len, rssi;
+	int error, len, rssi, s;
 
 	bf = SIMPLEQ_FIRST(&rxq->head);
 	if (__predict_false(bf == NULL)) {	/* Should not happen. */
@@ -908,6 +910,8 @@ ar5008_rx_process(struct athn_softc *sc)
 	m_set_rcvif(m, ifp);
 	m->m_pkthdr.len = m->m_len = len;
 
+	s = splnet();
+
 	/* Grab a reference to the source node. */
 	wh = mtod(m, struct ieee80211_frame *);
 	ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
@@ -934,6 +938,8 @@ ar5008_rx_process(struct athn_softc *sc)
 	/* Node is no longer needed. */
 	ieee80211_free_node(ni);
 
+	splx(s);
+
  skip:
 	/* Unlink this descriptor from head. */
 	SIMPLEQ_REMOVE_HEAD(&rxq->head, bf_list);
@@ -1031,7 +1037,9 @@ ar5008_tx_intr(struct athn_softc *sc)
 	struct ifnet *ifp = &sc->sc_if;
 	uint16_t mask = 0;
 	uint32_t reg;
-	int qid;
+	int qid, s;
+
+	s = splnet();
 
 	reg = AR_READ(sc, AR_ISR_S0_S);
 	mask |= MS(reg, AR_ISR_S0_QCU_TXOK);
@@ -1050,6 +1058,8 @@ ar5008_tx_intr(struct athn_softc *sc)
 		ifp->if_flags &= ~IFF_OACTIVE;
 		ifp->if_start(ifp);
 	}
+
+	splx(s);
 }
 
 #ifndef IEEE80211_STA_ONLY
@@ -1177,10 +1187,10 @@ ar5008_swba_intr(struct athn_softc *sc)
 }
 #endif
 
-Static int
-ar5008_intr(struct athn_softc *sc)
+static int
+ar5008_get_intr_status(struct athn_softc *sc, uint32_t *intrp, uint32_t *syncp)
 {
-	uint32_t intr, intr5, sync;
+	uint32_t intr, sync;
 
 	/* Get pending interrupts. */
 	intr = AR_READ(sc, AR_INTR_ASYNC_CAUSE);
@@ -1199,6 +1209,31 @@ ar5008_intr(struct athn_softc *sc)
 	if (intr == 0 && sync == 0)
 		return 0;	/* Not for us. */
 
+	*intrp = intr;
+	*syncp = sync;
+	return 1;
+}
+
+
+Static int
+ar5008_intr_status(struct athn_softc *sc)
+{
+	uint32_t intr, sync;
+
+	return ar5008_get_intr_status(sc, &intr, &sync);
+}
+
+Static int
+ar5008_intr(struct athn_softc *sc)
+{
+	uint32_t intr, intr5, sync;
+#ifndef IEEE80211_STA_ONLY
+	int s;
+#endif
+
+	if (!ar5008_get_intr_status(sc, &intr, &sync))
+		return 0;
+
 	if (intr != 0) {
 		if (intr & AR_ISR_BCNMISC) {
 			uint32_t intr2 = AR_READ(sc, AR_ISR_S2);
@@ -1216,8 +1251,11 @@ ar5008_intr(struct athn_softc *sc)
 			return 1;
 
 #ifndef IEEE80211_STA_ONLY
-		if (intr & AR_ISR_SWBA)
+		if (intr & AR_ISR_SWBA) {
+			s = splnet();
 			ar5008_swba_intr(sc);
+			splx(s);
+		}
 #endif
 		if (intr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
 			ar5008_rx_intr(sc);
Index: src/sys/dev/ic/rt2661var.h
diff -u src/sys/dev/ic/rt2661var.h:1.11 src/sys/dev/ic/rt2661var.h:1.12
--- src/sys/dev/ic/rt2661var.h:1.11	Sat Feb 18 13:38:36 2012
+++ src/sys/dev/ic/rt2661var.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rt2661var.h,v 1.11 2012/02/18 13:38:36 drochner Exp $	*/
+/*	$NetBSD: rt2661var.h,v 1.12 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: rt2661var.h,v 1.4 2006/02/25 12:56:47 damien Exp $	*/
 
 /*-
@@ -101,6 +101,7 @@ struct rt2661_softc {
 	bus_dma_tag_t			sc_dmat;
 	bus_space_tag_t			sc_st;
 	bus_space_handle_t		sc_sh;
+	void				*sc_soft_ih;
 
 	struct ethercom			sc_ec;
 

Index: src/sys/dev/ic/arn9003.c
diff -u src/sys/dev/ic/arn9003.c:1.9 src/sys/dev/ic/arn9003.c:1.10
--- src/sys/dev/ic/arn9003.c:1.9	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/arn9003.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: arn9003.c,v 1.9 2016/06/10 13:27:13 ozaki-r Exp $	*/
+/*	$NetBSD: arn9003.c,v 1.10 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: ar9003.c,v 1.25 2012/10/20 09:53:32 stsp Exp $	*/
 
 /*-
@@ -24,7 +24,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: arn9003.c,v 1.9 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: arn9003.c,v 1.10 2017/02/02 10:05:35 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/sockio.h>
@@ -91,6 +91,7 @@ Static void	ar9003_hw_init(struct athn_s
 		    struct ieee80211_channel *);
 Static void	ar9003_init_baseband(struct athn_softc *);
 Static void	ar9003_init_chains(struct athn_softc *);
+Static int	ar9003_intr_status(struct athn_softc *);
 Static int	ar9003_intr(struct athn_softc *);
 Static void	ar9003_next_calib(struct athn_softc *);
 Static void	ar9003_paprd_enable(struct athn_softc *);
@@ -193,6 +194,7 @@ ar9003_attach(struct athn_softc *sc)
 	ops->dma_alloc = ar9003_dma_alloc;
 	ops->dma_free = ar9003_dma_free;
 	ops->rx_enable = ar9003_rx_enable;
+	ops->intr_status = ar9003_intr_status;
 	ops->intr = ar9003_intr;
 	ops->tx = ar9003_tx;
 
@@ -949,7 +951,7 @@ ar9003_rx_process(struct athn_softc *sc,
 	struct mbuf *m, *m1;
 	size_t len;
 	u_int32_t rstamp;
-	int error, rssi;
+	int error, rssi, s;
 
 	bf = SIMPLEQ_FIRST(&rxq->head);
 	if (__predict_false(bf == NULL)) {	/* Should not happen. */
@@ -1041,6 +1043,8 @@ ar9003_rx_process(struct athn_softc *sc,
 	m->m_data = (void *)&ds[1];
 	m->m_pkthdr.len = m->m_len = len;
 
+	s = splnet();
+
 	/* Grab a reference to the source node. */
 	wh = mtod(m, struct ieee80211_frame *);
 	ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
@@ -1066,6 +1070,8 @@ ar9003_rx_process(struct athn_softc *sc,
 	/* Node is no longer needed. */
 	ieee80211_free_node(ni);
 
+	splx(s);
+
  skip:
 	/* Unlink this descriptor from head. */
 	SIMPLEQ_REMOVE_HEAD(&rxq->head, bf_list);
@@ -1189,13 +1195,19 @@ Static void
 ar9003_tx_intr(struct athn_softc *sc)
 {
 	struct ifnet *ifp = &sc->sc_if;
+	int s;
 
-	while (ar9003_tx_process(sc) == 0);
+	s = splnet();
+
+	while (ar9003_tx_process(sc) == 0)
+		continue;
 
 	if (!SIMPLEQ_EMPTY(&sc->sc_txbufs)) {
 		ifp->if_flags &= ~IFF_OACTIVE;
 		ifp->if_start(ifp);
 	}
+
+	splx(s);
 }
 
 #ifndef IEEE80211_STA_ONLY
@@ -1336,8 +1348,8 @@ ar9003_swba_intr(struct athn_softc *sc)
 }
 #endif
 
-Static int
-ar9003_intr(struct athn_softc *sc)
+static int
+ar9003_get_intr_status(struct athn_softc *sc, uint32_t *intrp, uint32_t *syncp)
 {
 	uint32_t intr, sync;
 
@@ -1358,6 +1370,30 @@ ar9003_intr(struct athn_softc *sc)
 	if (intr == 0 && sync == 0)
 		return 0;	/* Not for us. */
 
+	*intrp = intr;
+	*syncp = sync;
+	return 1;
+}
+
+Static int
+ar9003_intr_status(struct athn_softc *sc)
+{
+	uint32_t intr, sync;
+
+	return ar9003_get_intr_status(sc, &intr, &sync);
+}
+
+Static int
+ar9003_intr(struct athn_softc *sc)
+{
+	uint32_t intr, sync;
+#ifndef IEEE80211_STA_ONLY
+	int s;
+#endif
+
+	if (!ar9003_get_intr_status(sc, &intr, &sync))
+		return 0;
+
 	if (intr != 0) {
 		if (intr & AR_ISR_BCNMISC) {
 			uint32_t intr2 = AR_READ(sc, AR_ISR_S2);
@@ -1377,8 +1413,11 @@ ar9003_intr(struct athn_softc *sc)
 			return 1;
 
 #ifndef IEEE80211_STA_ONLY
-		if (intr & AR_ISR_SWBA)
+		if (intr & AR_ISR_SWBA) {
+			s = splnet();
 			ar9003_swba_intr(sc);
+			splx(s);
+		}
 #endif
 		if (intr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
 			ar9003_rx_intr(sc, ATHN_QID_LP);
Index: src/sys/dev/ic/bwivar.h
diff -u src/sys/dev/ic/bwivar.h:1.9 src/sys/dev/ic/bwivar.h:1.10
--- src/sys/dev/ic/bwivar.h:1.9	Thu Apr 12 12:52:58 2012
+++ src/sys/dev/ic/bwivar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: bwivar.h,v 1.9 2012/04/12 12:52:58 nakayama Exp $	*/
+/*	$NetBSD: bwivar.h,v 1.10 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: bwivar.h,v 1.23 2008/02/25 20:36:54 mglocker Exp $	*/
 
 /*
@@ -529,6 +529,7 @@ struct bwi_softc {
 #define sc_if sc_ec.ec_if
 	uint32_t		 sc_flags;	/* BWI_F_ */
 	void			*sc_ih;		/* [TRC: interrupt handler] */
+	void			*sc_soft_ih;
 
 	uint32_t		 sc_cap;	/* BWI_CAP_ */
 	uint16_t		 sc_bbp_id;	/* BWI_BBPID_ */
Index: src/sys/dev/ic/rt2560var.h
diff -u src/sys/dev/ic/rt2560var.h:1.9 src/sys/dev/ic/rt2560var.h:1.10
--- src/sys/dev/ic/rt2560var.h:1.9	Sat Feb 18 13:38:36 2012
+++ src/sys/dev/ic/rt2560var.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rt2560var.h,v 1.9 2012/02/18 13:38:36 drochner Exp $	*/
+/*	$NetBSD: rt2560var.h,v 1.10 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: rt2560var.h,v 1.2 2006/01/14 12:43:27 damien Exp $  */
 
 /*-
@@ -109,6 +109,7 @@ struct rt2560_softc {
 	bus_dma_tag_t		sc_dmat;
 	bus_space_tag_t		sc_st;
 	bus_space_handle_t	sc_sh;
+	void			*sc_soft_ih;
 
 	struct sysctllog	*sc_sysctllog;
 

Index: src/sys/dev/ic/ath.c
diff -u src/sys/dev/ic/ath.c:1.122 src/sys/dev/ic/ath.c:1.123
--- src/sys/dev/ic/ath.c:1.122	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/ath.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ath.c,v 1.122 2016/06/10 13:27:13 ozaki-r Exp $	*/
+/*	$NetBSD: ath.c,v 1.123 2017/02/02 10:05:35 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@@ -41,7 +41,7 @@
 __FBSDID("$FreeBSD: src/sys/dev/ath/if_ath.c,v 1.104 2005/09/16 10:09:23 ru Exp $");
 #endif
 #ifdef __NetBSD__
-__KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.122 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.123 2017/02/02 10:05:35 nonaka Exp $");
 #endif
 
 /*
@@ -198,6 +198,23 @@ static void	ath_setcurmode(struct ath_so
 static void	ath_bpfattach(struct ath_softc *);
 static void	ath_announce(struct ath_softc *);
 
+#ifdef __NetBSD__
+#define	ATH_TASK_FUNC(__func)						\
+static void __CONCAT(__func, _si)(void *arg)				\
+{									\
+	__func(arg, 1);							\
+}
+ATH_TASK_FUNC(ath_rx_proc);
+ATH_TASK_FUNC(ath_rxorn_proc);
+ATH_TASK_FUNC(ath_fatal_proc);
+ATH_TASK_FUNC(ath_bmiss_proc);
+ATH_TASK_FUNC(ath_bstuck_proc);
+ATH_TASK_FUNC(ath_radar_proc);
+ATH_TASK_FUNC(ath_tx_proc_q0);
+ATH_TASK_FUNC(ath_tx_proc_q0123);
+ATH_TASK_FUNC(ath_tx_proc);
+#endif
+
 int ath_dwelltime = 200;		/* 5 channels/second */
 int ath_calinterval = 30;		/* calibrate every 30 secs */
 int ath_outdoor = AH_TRUE;		/* outdoor operation */
@@ -856,9 +873,18 @@ ath_fatal_proc(void *arg, int pending)
 {
 	struct ath_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
+#ifdef __NetBSD__
+	int s;
+#endif
 
 	if_printf(ifp, "hardware error; resetting\n");
+#ifdef __NetBSD__
+	s = splnet();
+#endif
 	ath_reset(ifp);
+#ifdef __NetBSD__
+	splx(s);
+#endif
 }
 
 static void
@@ -866,9 +892,18 @@ ath_rxorn_proc(void *arg, int pending)
 {
 	struct ath_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
+#ifdef __NetBSD__
+	int s;
+#endif
 
 	if_printf(ifp, "rx FIFO overrun; resetting\n");
+#ifdef __NetBSD__
+	s = splnet();
+#endif
 	ath_reset(ifp);
+#ifdef __NetBSD__
+	splx(s);
+#endif
 }
 
 static void
@@ -876,6 +911,7 @@ ath_bmiss_proc(void *arg, int pending)
 {
 	struct ath_softc *sc = arg;
 	struct ieee80211com *ic = &sc->sc_ic;
+	NET_LOCK_GIANT_FUNC_INIT();
 
 	DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending);
 	KASSERTMSG(ic->ic_opmode == IEEE80211_M_STA,
@@ -2374,10 +2410,19 @@ ath_bstuck_proc(void *arg, int pending)
 {
 	struct ath_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
+#ifdef __NetBSD__
+	int s;
+#endif
 
 	if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n",
 		sc->sc_bmisscount);
+#ifdef __NetBSD__
+	s = splnet();
+#endif
 	ath_reset(ifp);
+#ifdef __NetBSD__
+	splx(s);
+#endif
 }
 
 /*
@@ -3011,6 +3056,7 @@ ath_rx_proc(void *arg, int npending)
 	int16_t nf;
 	u_int64_t tsf;
 	uint8_t rxerr_tap, rxerr_mon;
+	NET_LOCK_GIANT_FUNC_INIT();
 
 	NET_LOCK_GIANT();		/* XXX */
 
@@ -4186,6 +4232,9 @@ ath_tx_proc_q0(void *arg, int npending)
 {
 	struct ath_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
+#ifdef __NetBSD__
+	int s;
+#endif
 
 	if (txqactive(sc->sc_ah, 0) && ath_tx_processq(sc, &sc->sc_txq[0]) > 0){
 		sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah);
@@ -4196,7 +4245,13 @@ ath_tx_proc_q0(void *arg, int npending)
 	if (sc->sc_softled)
 		ath_led_event(sc, ATH_LED_TX);
 
+#ifdef __NetBSD__
+	s = splnet();
+#endif
 	ath_start(ifp);
+#ifdef __NetBSD__
+	splx(s);
+#endif
 }
 
 /*
@@ -4209,6 +4264,9 @@ ath_tx_proc_q0123(void *arg, int npendin
 	struct ath_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
 	int nacked;
+#ifdef __NetBSD__
+	int s;
+#endif
 
 	/*
 	 * Process each active queue.
@@ -4231,7 +4289,13 @@ ath_tx_proc_q0123(void *arg, int npendin
 	if (sc->sc_softled)
 		ath_led_event(sc, ATH_LED_TX);
 
+#ifdef __NetBSD__
+	s = splnet();
+#endif
 	ath_start(ifp);
+#ifdef __NetBSD__
+	splx(s);
+#endif
 }
 
 /*
@@ -4243,6 +4307,9 @@ ath_tx_proc(void *arg, int npending)
 	struct ath_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
 	int i, nacked;
+#ifdef __NetBSD__
+	int s;
+#endif
 
 	/*
 	 * Process each active queue.
@@ -4258,7 +4325,13 @@ ath_tx_proc(void *arg, int npending)
 	if (sc->sc_softled)
 		ath_led_event(sc, ATH_LED_TX);
 
+#ifdef __NetBSD__
+	s = splnet();
+#endif
 	ath_start(ifp);
+#ifdef __NetBSD__
+	splx(s);
+#endif
 }
 
 static void

Index: src/sys/dev/ic/ath_netbsd.h
diff -u src/sys/dev/ic/ath_netbsd.h:1.15 src/sys/dev/ic/ath_netbsd.h:1.16
--- src/sys/dev/ic/ath_netbsd.h:1.15	Sun Jan 27 12:48:56 2013
+++ src/sys/dev/ic/ath_netbsd.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ath_netbsd.h,v 1.15 2013/01/27 12:48:56 jmcneill Exp $ */
+/*	$NetBSD: ath_netbsd.h,v 1.16 2017/02/02 10:05:35 nonaka Exp $ */
 
 /*-
  * Copyright (c) 2003, 2004 David Young
@@ -28,22 +28,25 @@
 #define _ATH_NETBSD_H
 
 #include <sys/sysctl.h>
+#include <sys/intr.h>
 
 typedef struct ath_task {
-	void	(*t_func)(void*, int);
-	void	*t_context;
+	void	*t_soft_ih;
 } ath_task_t;
 
 #define ATH_CALLOUT_INIT(__ch, __mpsafe) callout_init((__ch), 0)
 
 #define TASK_INIT(__task, __zero, __func, __context)	\
 	do {						\
-		(__task)->t_func = (__func);		\
-		(__task)->t_context = (__context);	\
+		(__task)->t_soft_ih = 			\
+		    softint_establish(SOFTINT_NET,	\
+		      __CONCAT(__func, _si),		\
+		      (__context));			\
+		KASSERT((__task)->t_soft_ih);		\
 	} while (0)
 
 #define TASK_RUN_OR_ENQUEUE(__task)	\
-	((*(__task)->t_func)((__task)->t_context, 1))
+	softint_schedule((__task)->t_soft_ih);
 
 typedef kmutex_t ath_txq_lock_t;
 #define	ATH_TXQ_LOCK_INIT(_sc, _tq)	mutex_init(&(_tq)->axq_lock, MUTEX_DEFAULT, IPL_NET)
@@ -59,8 +62,9 @@ typedef kmutex_t ath_txbuf_lock_t;
 #define	ATH_TXBUF_UNLOCK(_sc)		mutex_exit(&(_sc)->sc_txbuflock)
 #define	ATH_TXBUF_LOCK_ASSERT(_sc)	do { KASSERTMSG(mutex_owned(&(_sc)->sc_txbuflock), "txbuf lock unheld"); } while (/*CONSTCOND*/true)
 
-#define	NET_LOCK_GIANT()
-#define	NET_UNLOCK_GIANT()
+#define	NET_LOCK_GIANT_FUNC_INIT()	int s
+#define	NET_LOCK_GIANT()		s = splnet()
+#define	NET_UNLOCK_GIANT()		splx(s)
 
 #define	SYSCTL_INT_SUBR(__rw, __name, __descr)				     \
 	sysctl_createv(log, 0, &rnode, &cnode, CTLFLAG_PERMANENT|(__rw),     \

Index: src/sys/dev/ic/athn.c
diff -u src/sys/dev/ic/athn.c:1.14 src/sys/dev/ic/athn.c:1.15
--- src/sys/dev/ic/athn.c:1.14	Sat Jan 21 12:45:22 2017
+++ src/sys/dev/ic/athn.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: athn.c,v 1.14 2017/01/21 12:45:22 skrll Exp $	*/
+/*	$NetBSD: athn.c,v 1.15 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: athn.c,v 1.83 2014/07/22 13:12:11 mpi Exp $	*/
 
 /*-
@@ -23,7 +23,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: athn.c,v 1.14 2017/01/21 12:45:22 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: athn.c,v 1.15 2017/02/02 10:05:35 nonaka Exp $");
 
 #ifndef _MODULE
 #include "athn_usb.h"		/* for NATHN_USB */
@@ -118,6 +118,7 @@ Static void	athn_tx_reclaim(struct athn_
 Static void	athn_watchdog(struct ifnet *);
 Static void	athn_write_serdes(struct athn_softc *,
 		    const struct athn_serdes *);
+Static void	athn_softintr(void *);
 
 #ifdef ATHN_BT_COEXISTENCE
 Static void	athn_btcoex_disable(struct athn_softc *);
@@ -188,6 +189,14 @@ athn_attach(struct athn_softc *sc)
 	athn_set_power_sleep(sc);
 
 	if (!(sc->sc_flags & ATHN_FLAG_USB)) {
+		sc->sc_soft_ih = softint_establish(SOFTINT_NET, athn_softintr,
+		    sc);
+		if (sc->sc_soft_ih == NULL) {
+			aprint_error_dev(sc->sc_dev,
+			    "could not establish softint\n");
+			return EINVAL;
+		}
+
 		error = sc->sc_ops.dma_alloc(sc);
 		if (error != 0) {
 			aprint_error_dev(sc->sc_dev,
@@ -340,8 +349,11 @@ athn_attach(struct athn_softc *sc)
 	IFQ_SET_READY(&ifp->if_snd);
 	memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
 
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	ic->ic_node_alloc = athn_node_alloc;
 	ic->ic_newassoc = athn_newassoc;
@@ -382,6 +394,11 @@ athn_detach(struct athn_softc *sc)
 
 		/* Free Tx/Rx DMA resources. */
 		sc->sc_ops.dma_free(sc);
+
+		if (sc->sc_soft_ih != NULL) {
+			softint_disestablish(sc->sc_soft_ih);
+			sc->sc_soft_ih = NULL;
+		}
 	}
 	/* Free ROM copy. */
 	if (sc->sc_eep != NULL) {
@@ -537,7 +554,30 @@ athn_intr(void *xsc)
 		 */
 		return 0;
 
-	return sc->sc_ops.intr(sc);
+	if (!sc->sc_ops.intr_status(sc))
+		return 0;
+
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+Static void
+athn_softintr(void *xsc)
+{
+	struct athn_softc *sc = xsc;
+	struct ifnet *ifp = &sc->sc_if;
+
+	if (!IS_UP_AND_RUNNING(ifp))
+		return;
+
+	if (!device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER))
+		/*
+		 * The hardware is not ready/present, don't touch anything.
+		 * Note this can happen early on if the IRQ is shared.
+		 */
+		return;
+
+	sc->sc_ops.intr(sc);
 }
 
 Static void

Index: src/sys/dev/ic/athnvar.h
diff -u src/sys/dev/ic/athnvar.h:1.5 src/sys/dev/ic/athnvar.h:1.6
--- src/sys/dev/ic/athnvar.h:1.5	Fri Nov 27 21:16:17 2015
+++ src/sys/dev/ic/athnvar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: athnvar.h,v 1.5 2015/11/27 21:16:17 jmcneill Exp $	*/
+/*	$NetBSD: athnvar.h,v 1.6 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: athnvar.h,v 1.34 2013/10/21 16:13:49 stsp Exp $	*/
 
 /*-
@@ -416,6 +416,7 @@ struct athn_ops {
 	int	(*dma_alloc)(struct athn_softc *);
 	void	(*dma_free)(struct athn_softc *);
 	void	(*rx_enable)(struct athn_softc *);
+	int	(*intr_status)(struct athn_softc *);
 	int	(*intr)(struct athn_softc *);
 	int	(*tx)(struct athn_softc *, struct mbuf *,
 		    struct ieee80211_node *, int);
@@ -457,6 +458,7 @@ struct athn_softc {
 	struct ieee80211com		sc_ic;
 	struct ethercom			sc_ec;
 #define sc_if	sc_ec.ec_if
+	void				*sc_soft_ih;
 
 #if 0
 	int				(*sc_enable)(struct athn_softc *);

Index: src/sys/dev/ic/atw.c
diff -u src/sys/dev/ic/atw.c:1.160 src/sys/dev/ic/atw.c:1.161
--- src/sys/dev/ic/atw.c:1.160	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/atw.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atw.c,v 1.160 2016/06/10 13:27:13 ozaki-r Exp $  */
+/*	$NetBSD: atw.c,v 1.161 2017/02/02 10:05:35 nonaka Exp $  */
 
 /*-
  * Copyright (c) 1998, 1999, 2000, 2002, 2003, 2004 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: atw.c,v 1.160 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atw.c,v 1.161 2017/02/02 10:05:35 nonaka Exp $");
 
 
 #include <sys/param.h>
@@ -50,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: atw.c,v 1.16
 #include <sys/kauth.h>
 #include <sys/time.h>
 #include <sys/proc.h>
+#include <sys/atomic.h>
 #include <lib/libkern/libkern.h>
 
 #include <machine/endian.h>
@@ -201,6 +202,7 @@ void	atw_txdrain(struct atw_softc *);
 void	atw_reset(struct atw_softc *);
 
 /* Interrupt handlers */
+void	atw_softintr(void *);
 void	atw_linkintr(struct atw_softc *, u_int32_t);
 void	atw_rxintr(struct atw_softc *);
 void	atw_txintr(struct atw_softc *, uint32_t);
@@ -519,6 +521,12 @@ atw_attach(struct atw_softc *sc)
 
 	pmf_self_suspensor_init(sc->sc_dev, &sc->sc_suspensor, &sc->sc_qual);
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, atw_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(sc->sc_dev, "unable to establish softint\n");
+		goto fail_0;
+	}
+
 	sc->sc_txth = atw_txthresh_tab_lo;
 
 	SIMPLEQ_INIT(&sc->sc_txfreeq);
@@ -783,8 +791,11 @@ atw_attach(struct atw_softc *sc)
 	 * Call MI attach routines.
 	 */
 
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	atw_evcnt_attach(sc);
 
@@ -853,7 +864,10 @@ atw_attach(struct atw_softc *sc)
  fail_1:
 	bus_dmamem_free(sc->sc_dmat, &sc->sc_cdseg, sc->sc_cdnseg);
  fail_0:
-	return;
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
 }
 
 static struct ieee80211_node *
@@ -2721,6 +2735,11 @@ atw_detach(struct atw_softc *sc)
 
 	atw_evcnt_detach(sc);
 
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
+
 	return (0);
 }
 
@@ -2763,8 +2782,7 @@ atw_intr(void *arg)
 {
 	struct atw_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
-	u_int32_t status, rxstatus, txstatus, linkstatus;
-	int handled = 0, txthresh;
+	uint32_t status;
 
 #ifdef DEBUG
 	if (!device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER))
@@ -2779,6 +2797,34 @@ atw_intr(void *arg)
 	    !device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER))
 		return (0);
 
+	status = ATW_READ(sc, ATW_STSR);
+	if (status == 0)
+		return 0;
+
+	if ((status & sc->sc_inten) == 0) {
+		ATW_WRITE(sc, ATW_STSR, status);
+		return 0;
+	}
+
+	/* Disable interrupts */
+	ATW_WRITE(sc, ATW_IER, 0);
+
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+void
+atw_softintr(void *arg)
+{
+	struct atw_softc *sc = arg;
+	struct ifnet *ifp = &sc->sc_if;
+	uint32_t status, rxstatus, txstatus, linkstatus;
+	int txthresh, s;
+
+	if ((ifp->if_flags & IFF_RUNNING) == 0 ||
+	    !device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER))
+		return;
+
 	for (;;) {
 		status = ATW_READ(sc, ATW_STSR);
 
@@ -2825,8 +2871,6 @@ atw_intr(void *arg)
 		if ((status & sc->sc_inten) == 0)
 			break;
 
-		handled = 1;
-
 		rxstatus = status & sc->sc_rxint_mask;
 		txstatus = status & sc->sc_txint_mask;
 		linkstatus = status & sc->sc_linkint_mask;
@@ -2898,13 +2942,17 @@ atw_intr(void *arg)
 			if (status & ATW_INTR_RPS)
 				printf("%s: receive process stopped\n",
 				    device_xname(sc->sc_dev));
+			s = splnet();
 			(void)atw_init(ifp);
+			splx(s);
 			break;
 		}
 
 		if (status & ATW_INTR_FBE) {
 			aprint_error_dev(sc->sc_dev, "fatal bus error\n");
+			s = splnet();
 			(void)atw_init(ifp);
+			splx(s);
 			break;
 		}
 
@@ -2924,9 +2972,12 @@ atw_intr(void *arg)
 	}
 
 	/* Try to get more packets going. */
+	s = splnet();
 	atw_start(ifp);
+	splx(s);
 
-	return (handled);
+	/* Enable interrupts */
+	ATW_WRITE(sc, ATW_IER, sc->sc_inten);
 }
 
 /*
@@ -3053,7 +3104,7 @@ atw_rxintr(struct atw_softc *sc)
 	struct atw_rxsoft *rxs;
 	struct mbuf *m;
 	u_int32_t rxstat;
-	int i, len, rate, rate0;
+	int i, s, len, rate, rate0;
 	u_int32_t rssi, ctlrssi;
 
 	for (i = sc->sc_rxptr;; i = sc->sc_rxptr) {
@@ -3157,6 +3208,8 @@ atw_rxintr(struct atw_softc *sc)
 		else
 			rssi = ctlrssi;
 
+		s = splnet();
+
 		/* Pass this up to any BPF listeners. */
 		if (sc->sc_radiobpf != NULL) {
 			struct atw_rx_radiotap_header *tap = &sc->sc_rxtap;
@@ -3192,6 +3245,7 @@ atw_rxintr(struct atw_softc *sc)
 				sc->sc_sige_ev.ev_count++;
 			ifp->if_ierrors++;
 			m_freem(m);
+			splx(s);
 			continue;
 		}
 
@@ -3208,6 +3262,7 @@ atw_rxintr(struct atw_softc *sc)
 #endif
 		ieee80211_input(ic, m, ni, (int)rssi, 0);
 		ieee80211_free_node(ni);
+		splx(s);
 	}
 }
 
@@ -3223,10 +3278,13 @@ atw_txintr(struct atw_softc *sc, uint32_
 	struct ifnet *ifp = &sc->sc_if;
 	struct atw_txsoft *txs;
 	u_int32_t txstat;
+	int s;
 
 	DPRINTF3(sc, ("%s: atw_txintr: sc_flags 0x%08x\n",
 	    device_xname(sc->sc_dev), sc->sc_flags));
 
+	s = splnet();
+
 	/*
 	 * Go through our Tx list and free mbufs for those
 	 * frames that have been transmitted.
@@ -3318,6 +3376,8 @@ atw_txintr(struct atw_softc *sc, uint32_
 	}
 
 	KASSERT(txs != NULL || (ifp->if_flags & IFF_OACTIVE) == 0);
+
+	splx(s);
 }
 
 /*

Index: src/sys/dev/ic/atwvar.h
diff -u src/sys/dev/ic/atwvar.h:1.37 src/sys/dev/ic/atwvar.h:1.38
--- src/sys/dev/ic/atwvar.h:1.37	Sun Mar 14 21:25:59 2010
+++ src/sys/dev/ic/atwvar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atwvar.h,v 1.37 2010/03/14 21:25:59 dyoung Exp $	*/
+/*	$NetBSD: atwvar.h,v 1.38 2017/02/02 10:05:35 nonaka Exp $	*/
 
 /*
  * Copyright (c) 2003, 2004 The NetBSD Foundation, Inc.  All rights reserved.
@@ -181,6 +181,8 @@ struct atw_softc {
 	struct ieee80211_node	*(*sc_node_alloc)(struct ieee80211_node_table*);
 	void			(*sc_node_free)(struct ieee80211_node *);
 
+	void			*sc_soft_ih;
+
 	int			sc_tx_timer;
 	int			sc_rescan_timer;
 

Index: src/sys/dev/ic/awi.c
diff -u src/sys/dev/ic/awi.c:1.90 src/sys/dev/ic/awi.c:1.91
--- src/sys/dev/ic/awi.c:1.90	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/awi.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: awi.c,v 1.90 2016/06/10 13:27:13 ozaki-r Exp $	*/
+/*	$NetBSD: awi.c,v 1.91 2017/02/02 10:05:35 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc.
@@ -78,7 +78,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.90 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.91 2017/02/02 10:05:35 nonaka Exp $");
 
 #include "opt_inet.h"
 
@@ -113,6 +113,7 @@ __KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.90
 #include <dev/ic/awireg.h>
 #include <dev/ic/awivar.h>
 
+static void awi_softintr(void *);
 static int  awi_init(struct ifnet *);
 static void awi_stop(struct ifnet *, int);
 static void awi_start(struct ifnet *);
@@ -198,6 +199,12 @@ awi_attach(struct awi_softc *sc)
 	sc->sc_busy = 1;
 	sc->sc_attached = 0;
 	sc->sc_substate = AWI_ST_NONE;
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, awi_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		config_deactivate(sc->sc_dev);
+		splx(s);
+		return ENOMEM;
+	}
 	if ((error = awi_hw_init(sc)) != 0) {
 		config_deactivate(sc->sc_dev);
 		splx(s);
@@ -311,6 +318,7 @@ awi_detach(struct awi_softc *sc)
 	if_detach(ifp);
 	shutdownhook_disestablish(sc->sc_sdhook);
 	powerhook_disestablish(sc->sc_powerhook);
+	softint_disestablish(sc->sc_soft_ih);
 	splx(s);
 	return 0;
 }
@@ -349,7 +357,7 @@ awi_power(int why, void *arg)
 	case PWR_RESUME:
 		if (ifp->if_flags & IFF_UP) {
 			awi_init(ifp);
-			(void)awi_intr(sc);	/* make sure */
+			awi_softintr(sc);	/* make sure */
 		}
 		break;
 	case PWR_SOFTSUSPEND:
@@ -375,16 +383,6 @@ int
 awi_intr(void *arg)
 {
 	struct awi_softc *sc = arg;
-	u_int16_t status;
-	int handled = 0, ocansleep;
-#ifdef AWI_DEBUG
-	static const char *intname[] = {
-	    "CMD", "RX", "TX", "SCAN_CMPLT",
-	    "CFP_START", "DTIM", "CFP_ENDING", "GROGGY",
-	    "TXDATA", "TXBCAST", "TXPS", "TXCF",
-	    "TXMGT", "#13", "RXDATA", "RXMGT"
-	};
-#endif
 
 	if (!sc->sc_enabled || !sc->sc_enab_intr ||
 	    !device_is_active(sc->sc_dev)) {
@@ -395,6 +393,27 @@ awi_intr(void *arg)
 		return 0;
 	}
 
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+awi_softintr(void *arg)
+{
+	struct awi_softc *sc = arg;
+	u_int16_t status;
+	int ocansleep;
+	int s;
+#ifdef AWI_DEBUG
+	static const char *intname[] = {
+	    "CMD", "RX", "TX", "SCAN_CMPLT",
+	    "CFP_START", "DTIM", "CFP_ENDING", "GROGGY",
+	    "TXDATA", "TXBCAST", "TXPS", "TXCF",
+	    "TXMGT", "#13", "RXDATA", "RXMGT"
+	};
+#endif
+
+	s = splnet();
 	am79c930_gcr_setbits(&sc->sc_chip,
 	    AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT);
 	awi_write_1(sc, AWI_DIS_PWRDN, 1);
@@ -428,7 +447,6 @@ awi_intr(void *arg)
 			printf("\n");
 		}
 #endif
-		handled = 1;
 		if (status & AWI_INT_RX)
 			awi_rx_int(sc);
 		if (status & AWI_INT_TX)
@@ -441,10 +459,11 @@ awi_intr(void *arg)
 				ieee80211_next_scan(&sc->sc_ic);
 		}
 	}
+
 	sc->sc_cansleep = ocansleep;
 	am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN);
 	awi_write_1(sc, AWI_DIS_PWRDN, 0);
-	return handled;
+	splx(s);
 }
 
 

Index: src/sys/dev/ic/awivar.h
diff -u src/sys/dev/ic/awivar.h:1.27 src/sys/dev/ic/awivar.h:1.28
--- src/sys/dev/ic/awivar.h:1.27	Sat Oct 27 17:18:19 2012
+++ src/sys/dev/ic/awivar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: awivar.h,v 1.27 2012/10/27 17:18:19 chs Exp $	*/
+/*	$NetBSD: awivar.h,v 1.28 2017/02/02 10:05:35 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc.
@@ -83,6 +83,7 @@ struct awi_softc {
 	int			(*sc_send_mgmt)(struct ieee80211com *,
 				    struct ieee80211_node *, int, int);
 
+	void			*sc_soft_ih;
 	void			*sc_sdhook;	/* shutdown hook */
 	void			*sc_powerhook;	/* power management hook */
 	unsigned int		sc_attached:1,

Index: src/sys/dev/ic/bwi.c
diff -u src/sys/dev/ic/bwi.c:1.30 src/sys/dev/ic/bwi.c:1.31
--- src/sys/dev/ic/bwi.c:1.30	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/bwi.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: bwi.c,v 1.30 2016/06/10 13:27:13 ozaki-r Exp $	*/
+/*	$NetBSD: bwi.c,v 1.31 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: bwi.c,v 1.74 2008/02/25 21:13:30 mglocker Exp $	*/
 
 /*
@@ -48,7 +48,7 @@
 
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bwi.c,v 1.30 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bwi.c,v 1.31 2017/02/02 10:05:35 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/callout.h>
@@ -61,6 +61,7 @@ __KERNEL_RCSID(0, "$NetBSD: bwi.c,v 1.30
 #include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
+#include <sys/intr.h>
 
 #include <machine/endian.h>
 
@@ -693,131 +694,151 @@ int
 bwi_intr(void *arg)
 {
 	struct bwi_softc *sc = arg;
+	struct ifnet *ifp = &sc->sc_if;
+
+	if (!device_is_active(sc->sc_dev) ||
+	    (ifp->if_flags & IFF_RUNNING) == 0)
+		return (0);
+
+	/* Disable all interrupts */
+	bwi_disable_intrs(sc, BWI_ALL_INTRS);
+
+	softint_schedule(sc->sc_soft_ih);
+	return (1);
+}
+
+static void
+bwi_softintr(void *arg)
+{
+	struct bwi_softc *sc = arg;
 	struct bwi_mac *mac;
 	struct ifnet *ifp = &sc->sc_if;
 	uint32_t intr_status;
 	uint32_t txrx_intr_status[BWI_TXRX_NRING];
-	int i, txrx_error, tx = 0, rx_data = -1;
+	int i, s, txrx_error, tx = 0, rx_data = -1;
 
 	if (!device_is_active(sc->sc_dev) ||
 	    (ifp->if_flags & IFF_RUNNING) == 0)
-		return (0);
+		return;
 
-	/*
-	 * Get interrupt status
-	 */
-	intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS);
-	if (intr_status == 0xffffffff)	/* Not for us */
-		return (0);
+	for (;;) {
+		/*
+		 * Get interrupt status
+		 */
+		intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS);
+		if (intr_status == 0xffffffff)	/* Not for us */
+			goto out;
 
-	intr_status &= CSR_READ_4(sc, BWI_MAC_INTR_MASK);
-	if (intr_status == 0)		/* Nothing is interesting */
-		return (0);
+		intr_status &= CSR_READ_4(sc, BWI_MAC_INTR_MASK);
+		if (intr_status == 0)		/* Nothing is interesting */
+			goto out;
 
-	DPRINTF(sc, BWI_DBG_INTR, "intr status 0x%08x\n", intr_status);
+		DPRINTF(sc, BWI_DBG_INTR, "intr status 0x%08x\n", intr_status);
 
-	KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC);
-	mac = (struct bwi_mac *)sc->sc_cur_regwin;
+		KASSERT(sc->sc_cur_regwin->rw_type == BWI_REGWIN_T_MAC);
+		mac = (struct bwi_mac *)sc->sc_cur_regwin;
 
-	txrx_error = 0;
+		txrx_error = 0;
 
-	for (i = 0; i < BWI_TXRX_NRING; ++i) {
-		uint32_t mask;
+		for (i = 0; i < BWI_TXRX_NRING; ++i) {
+			uint32_t mask;
 
-		if (BWI_TXRX_IS_RX(i))
-			mask = BWI_TXRX_RX_INTRS;
-		else
-			mask = BWI_TXRX_TX_INTRS;
+			if (BWI_TXRX_IS_RX(i))
+				mask = BWI_TXRX_RX_INTRS;
+			else
+				mask = BWI_TXRX_TX_INTRS;
 
-		txrx_intr_status[i] =
-		    CSR_READ_4(sc, BWI_TXRX_INTR_STATUS(i)) & mask;
+			txrx_intr_status[i] =
+			    CSR_READ_4(sc, BWI_TXRX_INTR_STATUS(i)) & mask;
 
-		if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) {
-			aprint_error_dev(sc->sc_dev,
-			    "intr fatal TX/RX (%d) error 0x%08x\n",
-			    i, txrx_intr_status[i]);
-			txrx_error = 1;
+			if (txrx_intr_status[i] & BWI_TXRX_INTR_ERROR) {
+				aprint_error_dev(sc->sc_dev,
+				    "intr fatal TX/RX (%d) error 0x%08x\n",
+				    i, txrx_intr_status[i]);
+				txrx_error = 1;
+			}
 		}
-	}
-
-	/*
-	 * Acknowledge interrupt
-	 */
-	CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, intr_status);
 
-	for (i = 0; i < BWI_TXRX_NRING; ++i)
-		CSR_WRITE_4(sc, BWI_TXRX_INTR_STATUS(i), txrx_intr_status[i]);
+		/*
+		 * Acknowledge interrupt
+		 */
+		CSR_WRITE_4(sc, BWI_MAC_INTR_STATUS, intr_status);
 
-	/* Disable all interrupts */
-	bwi_disable_intrs(sc, BWI_ALL_INTRS);
+		for (i = 0; i < BWI_TXRX_NRING; ++i)
+			CSR_WRITE_4(sc, BWI_TXRX_INTR_STATUS(i),
+			    txrx_intr_status[i]);
 
-	if (intr_status & BWI_INTR_PHY_TXERR) {
-		if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) {
-			aprint_error_dev(sc->sc_dev, "intr PHY TX error\n");
-			/* XXX to netisr0? */
-			bwi_init_statechg(sc, 0);
-			return (0);
+		if (intr_status & BWI_INTR_PHY_TXERR) {
+			if (mac->mac_flags & BWI_MAC_F_PHYE_RESET) {
+				aprint_error_dev(sc->sc_dev,
+				    "intr PHY TX error\n");
+				/* XXX to netisr0? */
+				s = splnet();
+				bwi_init_statechg(sc, 0);
+				splx(s);
+				goto out;
+			}
 		}
-	}
 
-	if (txrx_error) {
-		/* TODO: reset device */
-	}
+		if (txrx_error) {
+			/* TODO: reset device */
+		}
 
-	if (intr_status & BWI_INTR_TBTT)
-		bwi_mac_config_ps(mac);
+		if (intr_status & BWI_INTR_TBTT)
+			bwi_mac_config_ps(mac);
 
-	if (intr_status & BWI_INTR_EO_ATIM)
-		aprint_normal_dev(sc->sc_dev, "EO_ATIM\n");
+		if (intr_status & BWI_INTR_EO_ATIM)
+			aprint_normal_dev(sc->sc_dev, "EO_ATIM\n");
 
-	if (intr_status & BWI_INTR_PMQ) {
-		for (;;) {
-			if ((CSR_READ_4(sc, BWI_MAC_PS_STATUS) & 0x8) == 0)
-				break;
+		if (intr_status & BWI_INTR_PMQ) {
+			for (;;) {
+				if ((CSR_READ_4(sc, BWI_MAC_PS_STATUS) & 0x8)
+				    == 0)
+					break;
+			}
+			CSR_WRITE_2(sc, BWI_MAC_PS_STATUS, 0x2);
 		}
-		CSR_WRITE_2(sc, BWI_MAC_PS_STATUS, 0x2);
-	}
 
-	if (intr_status & BWI_INTR_NOISE)
-		aprint_normal_dev(sc->sc_dev, "intr noise\n");
+		if (intr_status & BWI_INTR_NOISE)
+			aprint_normal_dev(sc->sc_dev, "intr noise\n");
 
-	if (txrx_intr_status[0] & BWI_TXRX_INTR_RX)
-		rx_data = (sc->sc_rxeof)(sc);
+		if (txrx_intr_status[0] & BWI_TXRX_INTR_RX)
+			rx_data = (sc->sc_rxeof)(sc);
 
-	if (txrx_intr_status[3] & BWI_TXRX_INTR_RX) {
-		(sc->sc_txeof_status)(sc);
-		tx = 1;
-	}
-
-	if (intr_status & BWI_INTR_TX_DONE) {
-		bwi_txeof(sc);
-		tx = 1;
-	}
+		if (txrx_intr_status[3] & BWI_TXRX_INTR_RX) {
+			(sc->sc_txeof_status)(sc);
+			tx = 1;
+		}
 
-	/* Re-enable interrupts */
-	bwi_enable_intrs(sc, BWI_INIT_INTRS);
+		if (intr_status & BWI_INTR_TX_DONE) {
+			bwi_txeof(sc);
+			tx = 1;
+		}
 
-	if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
-		int evt = BWI_LED_EVENT_NONE;
+		if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
+			int evt = BWI_LED_EVENT_NONE;
 
-		if (tx && rx_data > 0) {
-			if (sc->sc_rx_rate > sc->sc_tx_rate)
-				evt = BWI_LED_EVENT_RX;
-			else
+			if (tx && rx_data > 0) {
+				if (sc->sc_rx_rate > sc->sc_tx_rate)
+					evt = BWI_LED_EVENT_RX;
+				else
+					evt = BWI_LED_EVENT_TX;
+			} else if (tx) {
 				evt = BWI_LED_EVENT_TX;
-		} else if (tx) {
-			evt = BWI_LED_EVENT_TX;
-		} else if (rx_data > 0) {
-			evt = BWI_LED_EVENT_RX;
-		} else if (rx_data == 0) {
-			evt = BWI_LED_EVENT_POLL;
-		}
+			} else if (rx_data > 0) {
+				evt = BWI_LED_EVENT_RX;
+			} else if (rx_data == 0) {
+				evt = BWI_LED_EVENT_POLL;
+			}
 
-		if (evt != BWI_LED_EVENT_NONE)
-			bwi_led_event(sc, evt);
+			if (evt != BWI_LED_EVENT_NONE)
+				bwi_led_event(sc, evt);
+		}
 	}
 
-	return (1);
+out:
+	/* Re-enable interrupts */
+	bwi_enable_intrs(sc, BWI_INIT_INTRS);
 }
 
 int
@@ -832,6 +853,12 @@ bwi_attach(struct bwi_softc *sc)
 	/* [TRC: XXX Is this necessary?] */
 	s = splnet();
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, bwi_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		error = ENXIO;
+		goto fail;
+	}
+
 	/*
 	 * Initialize sysctl variables
 	 */
@@ -994,8 +1021,10 @@ bwi_attach(struct bwi_softc *sc)
 
 	ic->ic_updateslot = bwi_updateslot;
 
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	/* [TRC: XXX Not supported on NetBSD?] */
 	/* ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; */
@@ -1027,6 +1056,7 @@ bwi_attach(struct bwi_softc *sc)
 	return (0);
 fail:
 	/* [TRC: XXX DragonFlyBSD detaches the device here.  Should we?] */
+	splx(s);
 	return (error);
 }
 
@@ -1050,6 +1080,9 @@ bwi_detach(struct bwi_softc *sc)
 
 	sysctl_teardown(&sc->sc_sysctllog);
 
+	if (sc->sc_soft_ih != NULL)
+		softint_disestablish(sc->sc_soft_ih);
+
 	splx(s);
 
 	bwi_dma_free(sc);
@@ -7664,7 +7697,9 @@ bwi_amrr_timeout(void *arg)
 {
 	struct bwi_softc *sc = arg;
 	struct ieee80211com *ic = &sc->sc_ic;
+	int s;
 
+	s = splnet();
 	if (ic->ic_opmode == IEEE80211_M_STA)
 		bwi_iter_func(sc, ic->ic_bss);
 	else
@@ -7673,6 +7708,7 @@ bwi_amrr_timeout(void *arg)
 		ieee80211_iterate_nodes(&ic->ic_sta, bwi_iter_func, sc);
 
 	callout_schedule(&sc->sc_amrr_ch, hz / 2);
+	splx(s);
 }
 
 static void
@@ -8416,7 +8452,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_
 	struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = &sc->sc_if;
-	int idx, rx_data = 0;
+	int s, idx, rx_data = 0;
 
 	idx = rbd->rbd_idx;
 	while (idx != end_idx) {
@@ -8467,6 +8503,8 @@ bwi_rxeof(struct bwi_softc *sc, int end_
 		else
 			rate = bwi_ds_plcp2rate(plcp);
 
+		s = splnet();
+
 		/* RX radio tap */
 		if (sc->sc_drvbpf != NULL) {
 			struct mbuf mb;
@@ -8506,6 +8544,8 @@ bwi_rxeof(struct bwi_softc *sc, int end_
 			rx_data = 1;
 			sc->sc_rx_rate = rate;
 		}
+
+		splx(s);
 next:
 		idx = (idx + 1) % BWI_RX_NDESC;
 	}
@@ -9238,7 +9278,9 @@ bwi_txeof_status32(struct bwi_softc *sc)
 {
 	struct ifnet *ifp = &sc->sc_if;
 	uint32_t val, ctrl_base;
-	int end_idx;
+	int end_idx, s;
+
+	s = splnet();
 
 	ctrl_base = sc->sc_txstats->stats_ctrl_base;
 
@@ -9253,6 +9295,8 @@ bwi_txeof_status32(struct bwi_softc *sc)
 
 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
 		ifp->if_start(ifp); /* [TRC: XXX Why not bwi_start?] */
+
+	splx(s);
 }
 
 static void
@@ -9324,6 +9368,9 @@ static void
 bwi_txeof(struct bwi_softc *sc)
 {
 	struct ifnet *ifp = &sc->sc_if;
+	int s;
+
+	s = splnet();
 
 	for (;;) {
 		uint32_t tx_status0;
@@ -9347,6 +9394,8 @@ bwi_txeof(struct bwi_softc *sc)
 
 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
 		ifp->if_start(ifp);
+
+	splx(s);
 }
 
 static int

Index: src/sys/dev/ic/malo.c
diff -u src/sys/dev/ic/malo.c:1.8 src/sys/dev/ic/malo.c:1.9
--- src/sys/dev/ic/malo.c:1.8	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/malo.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: malo.c,v 1.8 2016/06/10 13:27:13 ozaki-r Exp $ */
+/*	$NetBSD: malo.c,v 1.9 2017/02/02 10:05:35 nonaka Exp $ */
 /*	$OpenBSD: malo.c,v 1.92 2010/08/27 17:08:00 jsg Exp $ */
 
 /*
@@ -19,7 +19,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: malo.c,v 1.8 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: malo.c,v 1.9 2017/02/02 10:05:35 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -314,13 +314,34 @@ malo_intr(void *arg)
 		/* not for us */
 		return (0);
 
+	/* disable interrupts */
+	malo_ctl_read4(sc, MALO_REG_A2H_INTERRUPT_CAUSE);
+	malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_CAUSE, 0);
+	malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_MASK, 0);
+	malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_STATUS_MASK, 0);
+
+	softint_schedule(sc->sc_soft_ih);
+	return (1);
+}
+
+void
+malo_softintr(void *arg)
+{
+	struct malo_softc *sc = arg;
+	uint32_t status;
+
+	status = malo_ctl_read4(sc, MALO_REG_A2H_INTERRUPT_CAUSE);
+	if (status == 0xffffffff || status == 0)
+		goto out;	/* not for us */
+
 	if (status & MALO_A2HRIC_BIT_TX_DONE)
 		malo_tx_intr(sc);
 	if (status & MALO_A2HRIC_BIT_RX_RDY)
 		malo_rx_intr(sc);
 	if (status & MALO_A2HRIC_BIT_OPC_DONE) {
 		/* XXX cmd done interrupt handling doesn't work yet */
-		DPRINTF(1, "%s: got cmd done interrupt\n", device_xname(sc->sc_dev));
+		DPRINTF(1, "%s: got cmd done interrupt\n",
+		    device_xname(sc->sc_dev));
 		//malo_cmd_response(sc);
 	}
 
@@ -332,7 +353,12 @@ malo_intr(void *arg)
 	/* just ack the interrupt */
 	malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_CAUSE, 0);
 
-	return (1);
+out:
+	/* enable interrupts */
+	malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_MASK, 0x1f);
+	malo_ctl_barrier(sc, BUS_SPACE_BARRIER_WRITE);
+	malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_STATUS_MASK, 0x1f);
+	malo_ctl_barrier(sc, BUS_SPACE_BARRIER_WRITE);
 }
 
 int
@@ -396,8 +422,11 @@ malo_attach(struct malo_softc *sc)
 	aprint_normal(", address %s\n", ether_sprintf(ic->ic_myaddr));
 
 	/* attach interface */
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	/* post attach vector functions */
 	sc->sc_newstate = ic->ic_newstate;
@@ -1300,10 +1329,12 @@ malo_tx_intr(struct malo_softc *sc)
 	struct malo_tx_desc *desc;
 	struct malo_tx_data *data;
 	struct malo_node *rn;
-	int stat;
+	int stat, s;
 
 	DPRINTF(2, "%s: %s\n", device_xname(sc->sc_dev), __func__);
 
+	s = splnet();
+
 	stat = sc->sc_txring.stat;
 	for (;;) {
 		desc = &sc->sc_txring.desc[sc->sc_txring.stat];
@@ -1362,6 +1393,8 @@ next:
 	sc->sc_tx_timer = 0;
 	ifp->if_flags &= ~IFF_OACTIVE;
 	malo_start(ifp);
+
+	splx(s);
 }
 
 static int
@@ -1498,7 +1531,7 @@ malo_rx_intr(struct malo_softc *sc)
 	struct ieee80211_node *ni;
 	struct mbuf *mnew, *m;
 	uint32_t rxRdPtr, rxWrPtr;
-	int error, i;
+	int error, i, s;
 
 	rxRdPtr = malo_mem_read4(sc, sc->sc_RxPdRdPtr);
 	rxWrPtr = malo_mem_read4(sc, sc->sc_RxPdWrPtr);
@@ -1578,6 +1611,8 @@ malo_rx_intr(struct malo_softc *sc)
 		memmove(m->m_data +6, m->m_data, 26);
 		m_adj(m, 8);
 
+		s = splnet();
+
 		if (sc->sc_drvbpf != NULL) {
 			struct malo_rx_radiotap_hdr *tap = &sc->sc_rxtap;
 
@@ -1599,6 +1634,8 @@ malo_rx_intr(struct malo_softc *sc)
 		/* node is no longer needed */
 		ieee80211_free_node(ni);
 
+		splx(s);
+
 skip:
 		desc->rxctrl = 0;
 		rxRdPtr = le32toh(desc->physnext);

Index: src/sys/dev/ic/malovar.h
diff -u src/sys/dev/ic/malovar.h:1.2 src/sys/dev/ic/malovar.h:1.3
--- src/sys/dev/ic/malovar.h:1.2	Sun Aug  5 09:16:54 2012
+++ src/sys/dev/ic/malovar.h	Thu Feb  2 10:05:35 2017
@@ -76,9 +76,10 @@ struct malo_tx_radiotap_hdr {
 
 struct malo_softc {
 	device_t		sc_dev;
-	struct ethercom		 sc_ec;
+	struct ethercom		sc_ec;
 	struct ieee80211com	sc_ic;
 #define sc_if sc_ec.ec_if
+	void			*sc_soft_ih;
 	struct malo_rx_ring	sc_rxring;
 	struct malo_tx_ring	sc_txring;
 
@@ -90,7 +91,7 @@ struct malo_softc {
 
 	bus_dmamap_t		sc_cmd_dmam;
 	bus_dma_segment_t	sc_cmd_dmas;
-	void				*sc_cmd_mem;
+	void			*sc_cmd_mem;
 	bus_addr_t		sc_cmd_dmaaddr;
 	uint32_t		*sc_cookie;
 	bus_addr_t		sc_cookie_dmaaddr;
@@ -105,7 +106,7 @@ struct malo_softc {
 	int			(*sc_enable)(struct malo_softc *);
 	void			(*sc_disable)(struct malo_softc *);
 
-	struct callout	sc_scan_to;
+	struct callout		sc_scan_to;
 	int			sc_tx_timer;
 	int			sc_last_txrate;
 
@@ -127,6 +128,7 @@ struct malo_softc {
 };
 
 int malo_intr(void *arg);
+void malo_softintr(void *arg);
 int malo_attach(struct malo_softc *sc);
 int malo_detach(void *arg);
 int malo_init(struct ifnet *);

Index: src/sys/dev/ic/rt2560.c
diff -u src/sys/dev/ic/rt2560.c:1.28 src/sys/dev/ic/rt2560.c:1.29
--- src/sys/dev/ic/rt2560.c:1.28	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/rt2560.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rt2560.c,v 1.28 2016/06/10 13:27:13 ozaki-r Exp $	*/
+/*	$NetBSD: rt2560.c,v 1.29 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: rt2560.c,v 1.15 2006/04/20 20:31:12 miod Exp $  */
 /*	$FreeBSD: rt2560.c,v 1.3 2006/03/21 21:15:43 damien Exp $*/
 
@@ -24,7 +24,7 @@
  * http://www.ralinktech.com/
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rt2560.c,v 1.28 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rt2560.c,v 1.29 2017/02/02 10:05:35 nonaka Exp $");
 
 
 #include <sys/param.h>
@@ -140,6 +140,7 @@ static void	rt2560_read_eeprom(struct rt
 static int	rt2560_bbp_init(struct rt2560_softc *);
 static int	rt2560_init(struct ifnet *);
 static void	rt2560_stop(struct ifnet *, int);
+static void	rt2560_softintr(void *);
 
 /*
  * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
@@ -353,6 +354,12 @@ rt2560_attach(void *xsc, int id)
 	aprint_normal_dev(sc->sc_dev, "MAC/BBP RT2560 (rev 0x%02x), RF %s\n",
 	    sc->asic_rev, rt2560_get_rf(sc->rf_rev));
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, rt2560_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(sc->sc_dev, "could not establish softint\n)");
+		goto fail0;
+	}
+
 	/*
 	 * Allocate Tx and Rx rings.
 	 */
@@ -446,8 +453,12 @@ rt2560_attach(void *xsc, int id)
 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 	}
 
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
+
 	ic->ic_node_alloc = rt2560_node_alloc;
 	ic->ic_updateslot = rt2560_update_slot;
 	ic->ic_reset = rt2560_reset;
@@ -485,8 +496,9 @@ fail5:	rt2560_free_tx_ring(sc, &sc->bcnq
 fail4:	rt2560_free_tx_ring(sc, &sc->prioq);
 fail3:	rt2560_free_tx_ring(sc, &sc->atimq);
 fail2:	rt2560_free_tx_ring(sc, &sc->txq);
-fail1:
-	return ENXIO;
+fail1:	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
+fail0:	return ENXIO;
 }
 
 
@@ -512,6 +524,11 @@ rt2560_detach(void *xsc)
 	rt2560_free_tx_ring(sc, &sc->bcnq);
 	rt2560_free_rx_ring(sc, &sc->rxq);
 
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
+
 	return 0;
 }
 
@@ -843,9 +860,12 @@ rt2560_next_scan(void *arg)
 {
 	struct rt2560_softc *sc = arg;
 	struct ieee80211com *ic = &sc->sc_ic;
+	int s;
 
+	s = splnet();
 	if (ic->ic_state == IEEE80211_S_SCAN)
 		ieee80211_next_scan(ic);
+	splx(s);
 }
 
 /*
@@ -868,10 +888,13 @@ rt2560_update_rssadapt(void *arg)
 {
 	struct rt2560_softc *sc = arg;
 	struct ieee80211com *ic = &sc->sc_ic;
+	int s;
 
+	s = splnet();
 	ieee80211_iterate_nodes(&ic->ic_sta, rt2560_iter_func, arg);
 
 	callout_reset(&sc->rssadapt_ch, hz / 10, rt2560_update_rssadapt, sc);
+	splx(s);
 }
 
 int
@@ -1067,6 +1090,9 @@ rt2560_tx_intr(struct rt2560_softc *sc)
 	struct rt2560_tx_desc *desc;
 	struct rt2560_tx_data *data;
 	struct rt2560_node *rn;
+	int s;
+
+	s = splnet();
 
 	for (;;) {
 		desc = &sc->txq.desc[sc->txq.next];
@@ -1112,7 +1138,8 @@ rt2560_tx_intr(struct rt2560_softc *sc)
 		case RT2560_TX_FAIL_INVALID:
 		case RT2560_TX_FAIL_OTHER:
 		default:
-			aprint_error_dev(sc->sc_dev, "sending data frame failed 0x%08x\n",
+			aprint_error_dev(sc->sc_dev,
+			    "sending data frame failed 0x%08x\n",
 			    le32toh(desc->flags));
 			ifp->if_oerrors++;
 		}
@@ -1141,6 +1168,8 @@ rt2560_tx_intr(struct rt2560_softc *sc)
 	sc->sc_tx_timer = 0;
 	ifp->if_flags &= ~IFF_OACTIVE;
 	rt2560_start(ifp);
+
+	splx(s);
 }
 
 void
@@ -1150,6 +1179,9 @@ rt2560_prio_intr(struct rt2560_softc *sc
 	struct ifnet *ifp = ic->ic_ifp;
 	struct rt2560_tx_desc *desc;
 	struct rt2560_tx_data *data;
+	int s;
+
+	s = splnet();
 
 	for (;;) {
 		desc = &sc->prioq.desc[sc->prioq.next];
@@ -1209,6 +1241,8 @@ rt2560_prio_intr(struct rt2560_softc *sc
 	sc->sc_tx_timer = 0;
 	ifp->if_flags &= ~IFF_OACTIVE;
 	rt2560_start(ifp);
+
+	splx(s);
 }
 
 /*
@@ -1226,7 +1260,7 @@ rt2560_decryption_intr(struct rt2560_sof
 	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
 	struct mbuf *mnew, *m;
-	int hw, error;
+	int hw, error, s;
 
 	/* retrieve last decriptor index processed by cipher engine */
 	hw = (RAL_READ(sc, RT2560_SECCSR0) - sc->rxq.physaddr) /
@@ -1312,6 +1346,8 @@ rt2560_decryption_intr(struct rt2560_sof
 		m->m_pkthdr.len = m->m_len =
 		    (le32toh(desc->flags) >> 16) & 0xfff;
 
+		s = splnet();
+
 		if (sc->sc_drvbpf != NULL) {
 			struct rt2560_rx_radiotap_header *tap = &sc->sc_rxtap;
 			uint32_t tsf_lo, tsf_hi;
@@ -1347,6 +1383,8 @@ rt2560_decryption_intr(struct rt2560_sof
 		/* node is no longer needed */
 		ieee80211_free_node(ni);
 
+		splx(s);
+
 skip:		desc->flags = htole32(RT2560_RX_BUSY);
 
 		bus_dmamap_sync(sc->sc_dmat, sc->rxq.map,
@@ -1363,8 +1401,10 @@ skip:		desc->flags = htole32(RT2560_RX_B
 	 * In HostAP mode, ieee80211_input() will enqueue packets in if_snd
 	 * without calling if_start().
 	 */
+	s = splnet();
 	if (!IFQ_IS_EMPTY(&ifp->if_snd) && !(ifp->if_flags & IFF_OACTIVE))
 		rt2560_start(ifp);
+	splx(s);
 }
 
 /*
@@ -1471,17 +1511,34 @@ rt2560_intr(void *arg)
 
 	if ((r = RAL_READ(sc, RT2560_CSR7)) == 0)
 		return 0;       /* not for us */
-	
+
 	/* disable interrupts */
 	RAL_WRITE(sc, RT2560_CSR8, 0xffffffff);
 
-	/* acknowledge interrupts */
-	RAL_WRITE(sc, RT2560_CSR7, r);
-
 	/* don't re-enable interrupts if we're shutting down */
 	if (!(ifp->if_flags & IFF_RUNNING))
 		return 0;
 
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+rt2560_softintr(void *arg)
+{
+	struct rt2560_softc *sc = arg;
+	struct ifnet *ifp = &sc->sc_if;
+	uint32_t r;
+
+	if (!device_is_active(sc->sc_dev) || !(ifp->if_flags & IFF_RUNNING))
+		return;
+
+	if ((r = RAL_READ(sc, RT2560_CSR7)) == 0)
+		goto out;
+
+	/* acknowledge interrupts */
+	RAL_WRITE(sc, RT2560_CSR7, r);
+
 	if (r & RT2560_BEACON_EXPIRE)
 		rt2560_beacon_expire(sc);
 
@@ -1503,10 +1560,9 @@ rt2560_intr(void *arg)
 	if (r & RT2560_RX_DONE)
 		rt2560_rx_intr(sc);
 
+out:
 	/* re-enable interrupts */
 	RAL_WRITE(sc, RT2560_CSR8, RT2560_INTR_MASK);
-
-	return 1;
 }
 
 /* quickly determine if a given rate is CCK or OFDM */
@@ -2858,5 +2914,4 @@ rt2560_stop(struct ifnet *ifp, int disab
 	rt2560_reset_tx_ring(sc, &sc->prioq);
 	rt2560_reset_tx_ring(sc, &sc->bcnq);
 	rt2560_reset_rx_ring(sc, &sc->rxq);
-
 }

Index: src/sys/dev/ic/rt2661.c
diff -u src/sys/dev/ic/rt2661.c:1.33 src/sys/dev/ic/rt2661.c:1.34
--- src/sys/dev/ic/rt2661.c:1.33	Fri Jun 10 13:27:13 2016
+++ src/sys/dev/ic/rt2661.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rt2661.c,v 1.33 2016/06/10 13:27:13 ozaki-r Exp $	*/
+/*	$NetBSD: rt2661.c,v 1.34 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: rt2661.c,v 1.17 2006/05/01 08:41:11 damien Exp $	*/
 /*	$FreeBSD: rt2560.c,v 1.5 2006/06/02 19:59:31 csjp Exp $	*/
 
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rt2661.c,v 1.33 2016/06/10 13:27:13 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rt2661.c,v 1.34 2017/02/02 10:05:35 nonaka Exp $");
 
 
 #include <sys/param.h>
@@ -165,6 +165,7 @@ static int	rt2661_radar_stop(struct rt26
 static int	rt2661_prepare_beacon(struct rt2661_softc *);
 static void	rt2661_enable_tsf_sync(struct rt2661_softc *);
 static int	rt2661_get_rssi(struct rt2661_softc *, uint8_t);
+static void	rt2661_softintr(void *);
 
 /*
  * Supported rates for 802.11a/b/g modes (in 500Kbps unit).
@@ -236,6 +237,12 @@ rt2661_attach(void *xsc, int id)
 	aprint_normal_dev(sc->sc_dev, "MAC/BBP RT%X, RF %s\n", val,
 	    rt2661_get_rf(sc->rf_rev));
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, rt2661_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(sc->sc_dev, "could not establish softint\n");
+		goto fail0;
+	}
+
 	/*
 	 * Allocate Tx and Rx rings.
 	 */
@@ -335,8 +342,12 @@ rt2661_attach(void *xsc, int id)
 		    IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
 	}
 
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
+
 	ic->ic_node_alloc = rt2661_node_alloc;
 	ic->ic_newassoc = rt2661_newassoc;
 	ic->ic_updateslot = rt2661_updateslot;
@@ -374,7 +385,9 @@ fail5:	rt2661_free_tx_ring(sc, &sc->txq[
 fail4:	rt2661_free_tx_ring(sc, &sc->txq[2]);
 fail3:	rt2661_free_tx_ring(sc, &sc->txq[1]);
 fail2:	rt2661_free_tx_ring(sc, &sc->txq[0]);
-fail1:	return ENXIO;
+fail1:	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
+fail0:	return ENXIO;
 }
 
 int
@@ -398,6 +411,11 @@ rt2661_detach(void *xsc)
 	rt2661_free_tx_ring(sc, &sc->mgtq);
 	rt2661_free_rx_ring(sc, &sc->rxq);
 
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
+
 	return 0;
 }
 
@@ -916,7 +934,9 @@ rt2661_tx_intr(struct rt2661_softc *sc)
 	struct rt2661_tx_data *data;
 	struct rt2661_node *rn;
 	uint32_t val;
-	int qid, retrycnt;
+	int qid, retrycnt, s;
+
+	s = splnet();
 
 	for (;;) {
 		val = RAL_READ(sc, RT2661_STA_CSR4);
@@ -974,6 +994,8 @@ rt2661_tx_intr(struct rt2661_softc *sc)
 	sc->sc_tx_timer = 0;
 	ifp->if_flags &= ~IFF_OACTIVE;
 	rt2661_start(ifp);
+
+	splx(s);
 }
 
 static void
@@ -1025,7 +1047,7 @@ rt2661_rx_intr(struct rt2661_softc *sc)
 	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
 	struct mbuf *mnew, *m;
-	int error, rssi;
+	int error, rssi, s;
 
 	for (;;) {
 		desc = &sc->rxq.desc[sc->rxq.cur];
@@ -1112,6 +1134,8 @@ rt2661_rx_intr(struct rt2661_softc *sc)
 		m->m_pkthdr.len = m->m_len =
 		    (le32toh(desc->flags) >> 16) & 0xfff;
 
+		s = splnet();
+
 		if (sc->sc_drvbpf != NULL) {
 			struct rt2661_rx_radiotap_header *tap = &sc->sc_rxtap;
 			uint32_t tsf_lo, tsf_hi;
@@ -1149,6 +1173,8 @@ rt2661_rx_intr(struct rt2661_softc *sc)
 		/* node is no longer needed */
 		ieee80211_free_node(ni);
 
+		splx(s);
+
 skip:		desc->flags |= htole32(RT2661_RX_BUSY);
 
 		bus_dmamap_sync(sc->sc_dmat, sc->rxq.map,
@@ -1164,8 +1190,10 @@ skip:		desc->flags |= htole32(RT2661_RX_
 	 * In HostAP mode, ieee80211_input() will enqueue packets in if_snd
 	 * without calling if_start().
 	 */
+	s = splnet();
 	if (!IFQ_IS_EMPTY(&ifp->if_snd) && !(ifp->if_flags & IFF_OACTIVE))
 		rt2661_start(ifp);
+	splx(s);
 }
 
 /*
@@ -1220,7 +1248,6 @@ rt2661_intr(void *arg)
 	struct rt2661_softc *sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
 	uint32_t r1, r2;
-	int rv = 0;
 
 	/* don't re-enable interrupts if we're shutting down */
 	if (!(ifp->if_flags & IFF_RUNNING)) {
@@ -1230,6 +1257,26 @@ rt2661_intr(void *arg)
 		return 0;
 	}
 
+	r1 = RAL_READ(sc, RT2661_INT_SOURCE_CSR);
+	r2 = RAL_READ(sc, RT2661_MCU_INT_SOURCE_CSR);
+
+	if ((r1 & RT2661_INT_CSR_ALL) == 0 && (r2 & RT2661_MCU_INT_ALL) == 0)
+		return 0;
+
+	/* disable interrupts */
+	RAL_WRITE(sc, RT2661_INT_MASK_CSR, 0xffffff7f);
+	RAL_WRITE(sc, RT2661_MCU_INT_MASK_CSR, 0xffffffff);
+
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+rt2661_softintr(void *arg)
+{
+	struct rt2661_softc *sc = arg;
+	uint32_t r1, r2;
+
 	for (;;) {
 		r1 = RAL_READ(sc, RT2661_INT_SOURCE_CSR);
 		r2 = RAL_READ(sc, RT2661_MCU_INT_SOURCE_CSR);
@@ -1241,8 +1288,6 @@ rt2661_intr(void *arg)
 		RAL_WRITE(sc, RT2661_INT_SOURCE_CSR, r1);
 		RAL_WRITE(sc, RT2661_MCU_INT_SOURCE_CSR, r2);
 
-		rv = 1;
-
 		if (r1 & RT2661_MGT_DONE)
 			rt2661_tx_dma_intr(sc, &sc->mgtq);
 
@@ -1274,7 +1319,9 @@ rt2661_intr(void *arg)
 			rt2661_mcu_wakeup(sc);
 	}
 
-	return rv;
+	/* enable interrupts */
+	RAL_WRITE(sc, RT2661_INT_MASK_CSR, 0x0000ff10);
+	RAL_WRITE(sc, RT2661_MCU_INT_MASK_CSR, 0);
 }
 
 /* quickly determine if a given rate is CCK or OFDM */

Index: src/sys/dev/ic/rt2860.c
diff -u src/sys/dev/ic/rt2860.c:1.24 src/sys/dev/ic/rt2860.c:1.25
--- src/sys/dev/ic/rt2860.c:1.24	Sat Oct  8 15:57:11 2016
+++ src/sys/dev/ic/rt2860.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rt2860.c,v 1.24 2016/10/08 15:57:11 christos Exp $	*/
+/*	$NetBSD: rt2860.c,v 1.25 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: rt2860.c,v 1.90 2016/04/13 10:49:26 mpi Exp $	*/
 /*	$FreeBSD: head/sys/dev/ral/rt2860.c 306591 2016-10-02 20:35:55Z avos $ */
 
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rt2860.c,v 1.24 2016/10/08 15:57:11 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rt2860.c,v 1.25 2017/02/02 10:05:35 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/sockio.h>
@@ -169,6 +169,7 @@ static void	rt2860_switch_chan(struct rt
 static int	rt2860_setup_beacon(struct rt2860_softc *);
 #endif
 static void	rt2860_enable_tsf_sync(struct rt2860_softc *);
+static void	rt2860_softintr(void *);
 
 static const struct {
 	uint32_t	reg;
@@ -253,6 +254,13 @@ rt2860_attach(void *xsc, int id)
 	    sc->mac_ver, sc->mac_rev, rt2860_get_rf(sc->rf_rev),
 	    sc->ntxchains, sc->nrxchains);
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, rt2860_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(sc->sc_dev, "could not establish softint\n");
+		error = EINVAL;
+		goto fail0;
+	}
+
 	/*
 	 * Allocate Tx (4 EDCAs + HCCA + Mgt) and Rx rings.
 	 */
@@ -285,6 +293,8 @@ rt2860_attach(void *xsc, int id)
 fail2:	rt2860_free_rx_ring(sc, &sc->rxq);
 fail1:	while (--qid >= 0)
 		rt2860_free_tx_ring(sc, &sc->txq[qid]);
+fail0:	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
 	return error;
 }
 
@@ -388,8 +398,12 @@ rt2860_attachhook(device_t self)
 	IFQ_SET_READY(&ifp->if_snd);
 	memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
 
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
+
 	ic->ic_node_alloc = rt2860_node_alloc;
 	ic->ic_newassoc = rt2860_newassoc;
 #ifdef notyet
@@ -446,6 +460,11 @@ rt2860_detach(void *xsc)
 	rt2860_free_rx_ring(sc, &sc->rxq);
 	rt2860_free_tx_pool(sc);
 
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
+
 	if (sc->ucode != NULL)
 		free(sc->ucode, M_DEVBUF);
 
@@ -874,6 +893,7 @@ static void
 rt2860_updatestats(struct rt2860_softc *sc)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
+	int s;
 
 #ifndef IEEE80211_STA_ONLY
 	/*
@@ -896,12 +916,14 @@ rt2860_updatestats(struct rt2860_softc *
 		}
 	}
 #endif
+	s = splnet();
 	if (ic->ic_opmode == IEEE80211_M_STA)
 		rt2860_iter_func(sc, ic->ic_bss);
 #ifndef IEEE80211_STA_ONLY
 	else
 		ieee80211_iterate_nodes(&ic->ic_sta, rt2860_iter_func, sc);
 #endif
+	splx(s);
 }
 
 static void
@@ -1227,6 +1249,9 @@ rt2860_tx_intr(struct rt2860_softc *sc, 
 	struct ifnet *ifp = &sc->sc_if;
 	struct rt2860_tx_ring *ring = &sc->txq[qid];
 	uint32_t hw;
+	int s;
+
+	s = splnet();
 
 	rt2860_drain_stats_fifo(sc);
 
@@ -1258,6 +1283,8 @@ rt2860_tx_intr(struct rt2860_softc *sc, 
 		sc->qfullmsk &= ~(1 << qid);
 	ifp->if_flags &= ~IFF_OACTIVE;
 	rt2860_start(ifp);
+
+	splx(s);
 }
 
 /*
@@ -1288,7 +1315,7 @@ rt2860_rx_intr(struct rt2860_softc *sc)
 	struct mbuf *m, *m1;
 	uint32_t hw;
 	uint8_t ant, rssi;
-	int error;
+	int error, s;
 	struct rt2860_rx_radiotap_header *tap;
 	uint16_t phy;
 
@@ -1398,6 +1425,8 @@ rt2860_rx_intr(struct rt2860_softc *sc)
 		ant = rt2860_maxrssi_chain(sc, rxwi);
 		rssi = rxwi->rssi[ant];
 
+		s = splnet();
+
 		if (__predict_true(sc->sc_drvbpf == NULL))
 			goto skipbpf;
 
@@ -1446,6 +1475,8 @@ skipbpf:
 		/* node is no longer needed */
 		ieee80211_free_node(ni);
 
+		splx(s);
+
 skip:		rxd->sdl0 &= ~htole16(RT2860_RX_DDONE);
 
 		bus_dmamap_sync(sc->sc_dmat, sc->rxq.map,
@@ -1494,13 +1525,16 @@ static void
 rt2860_gp_intr(struct rt2860_softc *sc)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
+	int s;
 
 	DPRINTFN(2, ("GP timeout state=%d\n", ic->ic_state));
 
+	s = splnet();
 	if (ic->ic_state == IEEE80211_S_SCAN)
 		ieee80211_next_scan(ic);
 	else if (ic->ic_state == IEEE80211_S_RUN)
 		rt2860_updatestats(sc);
+	splx(s);
 }
 
 int
@@ -1515,6 +1549,22 @@ rt2860_intr(void *arg)
 	if (r == 0)
 		return 0;	/* not for us */
 
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+rt2860_softintr(void *arg)
+{
+	struct rt2860_softc *sc = arg;
+	uint32_t r;
+
+	r = RAL_READ(sc, RT2860_INT_STATUS);
+	if (__predict_false(r == 0xffffffff))
+		goto out;	/* device likely went away */
+	if (r == 0)
+		goto out;
+
 	/* acknowledge interrupts */
 	RAL_WRITE(sc, RT2860_INT_STATUS, r);
 
@@ -1555,7 +1605,9 @@ rt2860_intr(void *arg)
 	if (r & RT2860_MAC_INT_4)	/* GP timer */
 		rt2860_gp_intr(sc);
 
-	return 1;
+out:
+	/* enable interrupts */
+	RAL_WRITE(sc, RT2860_INT_MASK, 0x3fffc);
 }
 
 static int

Index: src/sys/dev/ic/rt2860var.h
diff -u src/sys/dev/ic/rt2860var.h:1.3 src/sys/dev/ic/rt2860var.h:1.4
--- src/sys/dev/ic/rt2860var.h:1.3	Fri Jul  8 01:24:53 2016
+++ src/sys/dev/ic/rt2860var.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: rt2860var.h,v 1.3 2016/07/08 01:24:53 christos Exp $	*/
+/*	$NetBSD: rt2860var.h,v 1.4 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: rt2860var.h,v 1.23 2016/03/21 21:16:30 stsp Exp $	*/
 
 /*-
@@ -120,6 +120,7 @@ struct rt2860_softc {
 	bus_dma_tag_t			sc_dmat;
 	bus_space_tag_t			sc_st;
 	bus_space_handle_t		sc_sh;
+	void				*sc_soft_ih;
 
 	struct ethercom			sc_ec;
 #define sc_if  sc_ec.ec_if

Index: src/sys/dev/ic/rtw.c
diff -u src/sys/dev/ic/rtw.c:1.124 src/sys/dev/ic/rtw.c:1.125
--- src/sys/dev/ic/rtw.c:1.124	Thu Sep 15 21:45:37 2016
+++ src/sys/dev/ic/rtw.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: rtw.c,v 1.124 2016/09/15 21:45:37 jdolecek Exp $ */
+/* $NetBSD: rtw.c,v 1.125 2017/02/02 10:05:35 nonaka Exp $ */
 /*-
  * Copyright (c) 2004, 2005, 2006, 2007 David Young.  All rights
  * reserved.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.124 2016/09/15 21:45:37 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.125 2017/02/02 10:05:35 nonaka Exp $");
 
 
 #include <sys/param.h>
@@ -89,6 +89,7 @@ static void rtw_disable_interrupts(struc
 static void rtw_enable_interrupts(struct rtw_softc *);
 
 static int rtw_init(struct ifnet *);
+static void rtw_softintr(void *);
 
 static void rtw_start(struct ifnet *);
 static void rtw_reset_oactive(struct rtw_softc *);
@@ -1456,7 +1457,7 @@ rtw_intr_rx(struct rtw_softc *sc, uint16
 							 * hardware -> net80211
 							 */
 	u_int next, nproc = 0;
-	int hwrate, len, rate, rssi, sq;
+	int hwrate, len, rate, rssi, sq, s;
 	uint32_t hrssi, hstat, htsfth, htsftl;
 	struct rtw_rxdesc *rd;
 	struct rtw_rxsoft *rs;
@@ -1611,6 +1612,8 @@ rtw_intr_rx(struct rtw_softc *sc, uint16
 
 		wh = mtod(m, struct ieee80211_frame_min *);
 
+		s = splnet();
+
 		if (!IS_BEACON(wh->i_fc[0]))
 			sc->sc_led_state.ls_event |= RTW_LED_S_RX;
 
@@ -1653,6 +1656,7 @@ rtw_intr_rx(struct rtw_softc *sc, uint16
 
 		if ((hstat & RTW_RXSTAT_RES) != 0) {
 			m_freem(m);
+			splx(s);
 			goto next;
 		}
 
@@ -1663,6 +1667,7 @@ rtw_intr_rx(struct rtw_softc *sc, uint16
 		ni = ieee80211_find_rxnode(&sc->sc_ic, wh);
 		ieee80211_input(&sc->sc_ic, m, ni, rssi, htsftl);
 		ieee80211_free_node(ni);
+		splx(s);
 next:
 		rtw_rxdesc_init(rdb, rs, next, 0);
 	}
@@ -1839,11 +1844,13 @@ rtw_collect_txring(struct rtw_softc *sc,
 static void
 rtw_intr_tx(struct rtw_softc *sc, uint16_t isr)
 {
-	int pri;
+	int pri, s;
 	struct rtw_txsoft_blk	*tsb;
 	struct rtw_txdesc_blk	*tdb;
 	struct ifnet *ifp = &sc->sc_if;
 
+	s = splnet();
+
 	for (pri = 0; pri < RTW_NTXPRI; pri++) {
 		tsb = &sc->sc_txsoft_blk[pri];
 		tdb = &sc->sc_txdesc_blk[pri];
@@ -1853,7 +1860,7 @@ rtw_intr_tx(struct rtw_softc *sc, uint16
 	if ((isr & RTW_INTR_TX) != 0)
 		rtw_start(ifp);
 
-	return;
+	splx(s);
 }
 
 static void
@@ -1865,6 +1872,9 @@ rtw_intr_beacon(struct rtw_softc *sc, ui
 	struct rtw_txdesc_blk *tdb = &sc->sc_txdesc_blk[RTW_TXPRIBCN];
 	struct rtw_txsoft_blk *tsb = &sc->sc_txsoft_blk[RTW_TXPRIBCN];
 	struct mbuf *m;
+	int s;
+
+	s = splnet();
 
 	tsfth = RTW_READ(&sc->sc_regs, RTW_TSFTRH);
 	tsftl = RTW_READ(&sc->sc_regs, RTW_TSFTRL);
@@ -1900,12 +1910,15 @@ rtw_intr_beacon(struct rtw_softc *sc, ui
 		if (m == NULL) {
 			aprint_error_dev(sc->sc_dev,
 			    "could not allocate beacon\n");
+			splx(s);
 			return;
 		}
 		M_SETCTX(m, ieee80211_ref_node(ic->ic_bss));
 		IF_ENQUEUE(&sc->sc_beaconq, m);
 		rtw_start(&sc->sc_if);
 	}
+
+	splx(s);
 }
 
 static void
@@ -2077,11 +2090,15 @@ rtw_txdescs_reset(struct rtw_softc *sc)
 static void
 rtw_intr_ioerror(struct rtw_softc *sc, uint16_t isr)
 {
+	int s;
+
 	aprint_error_dev(sc->sc_dev, "tx fifo underflow\n");
 
 	RTW_DPRINTF(RTW_DEBUG_BUGS, ("%s: cleaning up xmit, isr %" PRIx16
 	    "\n", device_xname(sc->sc_dev), isr));
 
+	s = splnet();
+
 #ifdef RTW_DEBUG
 	rtw_dump_rings(sc);
 #endif /* RTW_DEBUG */
@@ -2094,6 +2111,8 @@ rtw_intr_ioerror(struct rtw_softc *sc, u
 #ifdef RTW_DEBUG
 	rtw_dump_rings(sc);
 #endif /* RTW_DEBUG */
+
+	splx(s);
 }
 
 static inline void
@@ -2129,16 +2148,18 @@ rtw_resume_ticks(struct rtw_softc *sc)
 static void
 rtw_intr_timeout(struct rtw_softc *sc)
 {
+	int s;
+
+	s = splnet();
 	RTW_DPRINTF(RTW_DEBUG_TIMEOUT, ("%s: timeout\n", device_xname(sc->sc_dev)));
 	if (sc->sc_do_tick)
 		rtw_resume_ticks(sc);
-	return;
+	splx(s);
 }
 
 int
 rtw_intr(void *arg)
 {
-	int i;
 	struct rtw_softc *sc = arg;
 	struct rtw_regs *regs = &sc->sc_regs;
 	uint16_t isr;
@@ -2155,6 +2176,34 @@ rtw_intr(void *arg)
 		return (0);
 	}
 
+	isr = RTW_READ16(regs, RTW_ISR);
+	if (isr == 0)
+		return (0);
+
+	/* Disable interrupts. */
+	RTW_WRITE16(regs, RTW_IMR, 0);
+	RTW_WBW(regs, RTW_IMR, RTW_IMR);
+
+	softint_schedule(sc->sc_soft_ih);
+	return (1);
+}
+
+static void
+rtw_softintr(void *arg)
+{
+	int i;
+	struct rtw_softc *sc = arg;
+	struct rtw_regs *regs = &sc->sc_regs;
+	uint16_t isr;
+	struct ifnet *ifp = &sc->sc_if;
+
+	if ((ifp->if_flags & IFF_RUNNING) == 0 ||
+	    !device_activation(sc->sc_dev, DEVACT_LEVEL_DRIVER)) {
+		RTW_DPRINTF(RTW_DEBUG_INTR, ("%s: stray interrupt\n",
+		    device_xname(sc->sc_dev)));
+		return;
+	}
+
 	for (i = 0; i < 10; i++) {
 		isr = RTW_READ16(regs, RTW_ISR);
 
@@ -2216,8 +2265,12 @@ rtw_intr(void *arg)
 		if ((isr & RTW_INTR_TIMEOUT) != 0)
 			rtw_intr_timeout(sc);
 	}
+	if (i == 10)
+		softint_schedule(sc->sc_soft_ih);
 
-	return 1;
+	/* Re-enable interrupts */
+	RTW_WRITE16(regs, RTW_IMR, sc->sc_inten);
+	RTW_WBW(regs, RTW_IMR, RTW_IMR);
 }
 
 /* Must be called at splnet. */
@@ -4001,6 +4054,12 @@ rtw_attach(struct rtw_softc *sc)
 
 	NEXT_ATTACH_STATE(sc, DETACHED);
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, rtw_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(sc->sc_dev, "could not establish softint\n");
+		goto err;
+	}
+
 	switch (RTW_READ(&sc->sc_regs, RTW_TCR) & RTW_TCR_HWVERID_MASK) {
 	case RTW_TCR_HWVERID_F:
 		sc->sc_hwverid = 'F';
@@ -4170,8 +4229,11 @@ rtw_attach(struct rtw_softc *sc)
 	/*
 	 * Call MI attach routines.
 	 */
-	if_attach(ifp);
-	ieee80211_ifattach(&sc->sc_ic);
+	if_initialize(ifp);
+	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	rtw_set80211methods(&sc->sc_mtbl, &sc->sc_ic);
 
@@ -4256,6 +4318,10 @@ rtw_detach(struct rtw_softc *sc)
 		    sc->sc_desc_nsegs);
 		/*FALLTHROUGH*/
 	case DETACHED:
+		if (sc->sc_soft_ih != NULL) {
+			softint_disestablish(sc->sc_soft_ih);
+			sc->sc_soft_ih = NULL;
+		}
 		NEXT_ATTACH_STATE(sc, DETACHED);
 		break;
 	}

Index: src/sys/dev/ic/rtwvar.h
diff -u src/sys/dev/ic/rtwvar.h:1.44 src/sys/dev/ic/rtwvar.h:1.45
--- src/sys/dev/ic/rtwvar.h:1.44	Thu Sep 15 21:45:37 2016
+++ src/sys/dev/ic/rtwvar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: rtwvar.h,v 1.44 2016/09/15 21:45:37 jdolecek Exp $ */
+/* $NetBSD: rtwvar.h,v 1.45 2017/02/02 10:05:35 nonaka Exp $ */
 /*-
  * Copyright (c) 2004, 2005 David Young.  All rights reserved.
  *
@@ -464,6 +464,7 @@ struct rtw_softc {
 	struct rtw_regs		sc_regs;
 	bus_dma_tag_t		sc_dmat;
 	uint32_t		sc_flags;
+	void			*sc_soft_ih;
 
 	enum rtw_attach_state	sc_attach_state;
 	enum rtw_rfchipid	sc_rfchipid;

Index: src/sys/dev/ic/wi.c
diff -u src/sys/dev/ic/wi.c:1.241 src/sys/dev/ic/wi.c:1.242
--- src/sys/dev/ic/wi.c:1.241	Wed Feb  1 02:37:43 2017
+++ src/sys/dev/ic/wi.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wi.c,v 1.241 2017/02/01 02:37:43 nonaka Exp $	*/
+/*	$NetBSD: wi.c,v 1.242 2017/02/02 10:05:35 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -99,7 +99,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.241 2017/02/01 02:37:43 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.242 2017/02/02 10:05:35 nonaka Exp $");
 
 #define WI_HERMES_AUTOINC_WAR	/* Work around data write autoinc bug. */
 #define WI_HERMES_STATS_WAR	/* Work around stats counter bug. */
@@ -137,6 +137,7 @@ __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.241
 #include <net/bpfdesc.h>
 
 #include <sys/bus.h>
+#include <sys/intr.h>
 
 #include <dev/ic/wi_ieee.h>
 #include <dev/ic/wireg.h>
@@ -150,6 +151,7 @@ STATIC void wi_watchdog(struct ifnet *);
 STATIC int  wi_ioctl(struct ifnet *, u_long, void *);
 STATIC int  wi_media_change(struct ifnet *);
 STATIC void wi_media_status(struct ifnet *, struct ifmediareq *);
+STATIC void wi_softintr(void *);
 
 static void wi_ioctl_init(struct wi_softc *);
 static int wi_ioctl_enter(struct wi_softc *);
@@ -373,6 +375,12 @@ wi_attach(struct wi_softc *sc, const u_i
 	};
 	int s;
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, wi_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		printf(" could not establish softint\n");
+		goto err;
+	}
+
 	wi_ioctl_init(sc);
 
 	s = splnet();
@@ -386,8 +394,7 @@ wi_attach(struct wi_softc *sc, const u_i
 	/* Reset the NIC. */
 	if (wi_reset(sc) != 0) {
 		sc->sc_invalid = 1;
-		splx(s);
-		return 1;
+		goto fail;
 	}
 
 	if (wi_read_xrid(sc, WI_RID_MAC_NODE, ic->ic_myaddr,
@@ -397,8 +404,7 @@ wi_attach(struct wi_softc *sc, const u_i
 			memcpy(ic->ic_myaddr, macaddr, IEEE80211_ADDR_LEN);
 		else {
 			printf(" could not get mac address, attach failed\n");
-			splx(s);
-			return 1;
+			goto fail;
 		}
 	}
 
@@ -448,7 +454,7 @@ wi_attach(struct wi_softc *sc, const u_i
 	}
 	if (ic->ic_ibss_chan == NULL) {
 		aprint_error_dev(sc->sc_dev, "no available channel\n");
-		return 1;
+		goto fail;
 	}
 
 	if (sc->sc_firmware_type == WI_LUCENT) {
@@ -529,7 +535,7 @@ wi_attach(struct wi_softc *sc, const u_i
 		ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = nrate;
 	} else {
 		aprint_error_dev(sc->sc_dev, "no supported rate list\n");
-		return 1;
+		goto fail;
 	}
 
 	sc->sc_max_datalen = 2304;
@@ -544,8 +550,11 @@ wi_attach(struct wi_softc *sc, const u_i
 	/*
 	 * Call MI attach routines.
 	 */
-	if_attach(ifp);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	sc->sc_newstate = ic->ic_newstate;
 	sc->sc_set_tim = ic->ic_set_tim;
@@ -578,6 +587,11 @@ wi_attach(struct wi_softc *sc, const u_i
 	splx(s);
 	ieee80211_announce(ic);
 	return 0;
+
+fail:	splx(s);
+	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
+err:	return 1;
 }
 
 int
@@ -598,6 +612,8 @@ wi_detach(struct wi_softc *sc)
 	if_detach(ifp);
 	splx(s);
 	wi_ioctl_drain(sc);
+	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
 	return 0;
 }
 
@@ -618,7 +634,6 @@ wi_activate(device_t self, enum devact a
 int
 wi_intr(void *arg)
 {
-	int i;
 	struct wi_softc	*sc = arg;
 	struct ifnet *ifp = &sc->sc_if;
 	u_int16_t status;
@@ -639,6 +654,40 @@ wi_intr(void *arg)
 	 */
 	CSR_WRITE_2(sc, WI_INT_EN, 0);
 
+	status = CSR_READ_2(sc, WI_EVENT_STAT);
+#ifdef WI_DEBUG
+	if (wi_debug > 1) {
+		printf("%s: status %#04x\n", __func__, status);
+	}
+#endif /* WI_DEBUG */
+	if ((status & WI_INTRS) == 0) {
+		/* re-enable interrupts */
+		CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
+		return 0;
+	}
+
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+STATIC void
+wi_softintr(void *arg)
+{
+	int i, s;
+	struct wi_softc	*sc = arg;
+	struct ifnet *ifp = &sc->sc_if;
+	u_int16_t status;
+
+	if (sc->sc_enabled == 0 ||
+	    !device_is_active(sc->sc_dev) ||
+	    (ifp->if_flags & IFF_RUNNING) == 0)
+		goto out;
+
+	if ((ifp->if_flags & IFF_UP) == 0) {
+		CSR_WRITE_2(sc, WI_EVENT_ACK, ~0);
+		return;
+	}
+
 	/* maximum 10 loops per interrupt */
 	for (i = 0; i < 10; i++) {
 		status = CSR_READ_2(sc, WI_EVENT_STAT);
@@ -675,18 +724,22 @@ wi_intr(void *arg)
 
 		if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
 		    (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0 &&
-		    !IFQ_IS_EMPTY(&ifp->if_snd))
+		    !IFQ_IS_EMPTY(&ifp->if_snd)) {
+			s = splnet();
 			wi_start(ifp);
+			splx(s);
+		}
 
 		sc->sc_status = 0;
 	}
+	if (i == 10)
+		softint_schedule(sc->sc_soft_ih);
 
-	/* re-enable interrupts */
-	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
-
+out:
 	sc->sc_status = 0;
 
-	return 1;
+	/* re-enable interrupts */
+	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
 }
 
 #define arraylen(a) (sizeof(a) / sizeof((a)[0]))
@@ -1043,11 +1096,16 @@ STATIC void
 wi_raise_rate(struct ieee80211com *ic, struct ieee80211_rssdesc *id)
 {
 	struct wi_node *wn;
+	int s;
+
+	s = splnet();
 	if (id->id_node == NULL)
-		return;
+		goto out;
 
 	wn = (void*)id->id_node;
 	ieee80211_rssadapt_raise_rate(ic, &wn->wn_rssadapt, id);
+out:
+	splx(s);
 }
 
 STATIC void
@@ -1069,7 +1127,6 @@ wi_lower_rate(struct ieee80211com *ic, s
 	ieee80211_rssadapt_lower_rate(ic, ni, &wn->wn_rssadapt, id);
 out:
 	splx(s);
-	return;
 }
 
 STATIC void
@@ -1547,6 +1604,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ieee80211_node *ni = ic->ic_bss;
 	struct ifnet *ifp = &sc->sc_if;
+	int s;
 
 	if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid))
 		return;
@@ -1571,7 +1629,9 @@ wi_sync_bssid(struct wi_softc *sc, u_int
 	 * reusing the existing node as we know wi_newstate will be
 	 * called and it will overwrite the node state.
 	 */
+	s = splnet();
         ieee80211_sta_join(ic, ieee80211_ref_node(ni));
+	splx(s);
 }
 
 static inline void
@@ -1602,6 +1662,7 @@ wi_rx_intr(struct wi_softc *sc)
 	u_int8_t dir;
 	u_int16_t status;
 	u_int32_t rstamp;
+	int s;
 
 	fid = CSR_READ_2(sc, WI_RX_FID);
 
@@ -1676,6 +1737,9 @@ wi_rx_intr(struct wi_softc *sc)
 		 */
 		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
 	}
+
+	s = splnet();
+
 	if (sc->sc_drvbpf) {
 		struct wi_rx_radiotap_header *tap = &sc->sc_rxtap;
 
@@ -1708,6 +1772,8 @@ wi_rx_intr(struct wi_softc *sc)
 	 * so use release_node here instead of unref_node.
 	 */
 	ieee80211_free_node(ni);
+
+	splx(s);
 }
 
 STATIC void
@@ -1719,9 +1785,11 @@ wi_tx_ex_intr(struct wi_softc *sc)
 	struct ieee80211_rssdesc *id;
 	struct wi_rssdesc *rssd;
 	struct wi_frame frmhdr;
-	int fid;
+	int fid, s;
 	u_int16_t status;
 
+	s = splnet();
+
 	fid = CSR_READ_2(sc, WI_TX_CMP_FID);
 	/* Read in the frame header */
 	if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
@@ -1788,12 +1856,15 @@ wi_tx_ex_intr(struct wi_softc *sc)
 	SLIST_INSERT_HEAD(&sc->sc_rssdfree, rssd, rd_next);
 out:
 	ifp->if_flags &= ~IFF_OACTIVE;
+	splx(s);
 }
 
 STATIC void
 wi_txalloc_intr(struct wi_softc *sc)
 {
-	int fid, cur;
+	int fid, cur, s;
+
+	s = splnet();
 
 	fid = CSR_READ_2(sc, WI_ALLOC_FID);
 
@@ -1803,6 +1874,7 @@ wi_txalloc_intr(struct wi_softc *sc)
 		printf("%s: spurious alloc %x != %x, alloc %d queue %d start %d alloced %d queued %d started %d\n",
 		    device_xname(sc->sc_dev), fid, sc->sc_txd[cur].d_fid, cur,
 		    sc->sc_txqueue, sc->sc_txstart, sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted);
+		splx(s);
 		return;
 	}
 #endif
@@ -1816,15 +1888,19 @@ wi_txalloc_intr(struct wi_softc *sc)
 	    sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart,
 	    sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted);
 #endif
+	splx(s);
 }
 
 STATIC void
 wi_cmd_intr(struct wi_softc *sc)
 {
 	struct ifnet *ifp = &sc->sc_if;
+	int s;
 
 	if (sc->sc_invalid)
 		return;
+
+	s = splnet();
 #ifdef WI_DEBUG
 	if (wi_debug > 1)
 		printf("%s: %d txcmds outstanding\n", __func__, sc->sc_txcmds);
@@ -1844,6 +1920,7 @@ wi_cmd_intr(struct wi_softc *sc)
 #endif
 	} else
 		wi_push_packet(sc);
+	splx(s);
 }
 
 STATIC void
@@ -1890,7 +1967,9 @@ wi_tx_intr(struct wi_softc *sc)
 	struct ieee80211_rssdesc *id;
 	struct wi_rssdesc *rssd;
 	struct wi_frame frmhdr;
-	int fid;
+	int fid, s;
+
+	s = splnet();
 
 	fid = CSR_READ_2(sc, WI_TX_CMP_FID);
 	/* Read in the frame header */
@@ -1934,6 +2013,7 @@ wi_tx_intr(struct wi_softc *sc)
 	SLIST_INSERT_HEAD(&sc->sc_rssdfree, rssd, rd_next);
 out:
 	ifp->if_flags &= ~IFF_OACTIVE;
+	splx(s);
 }
 
 STATIC void
@@ -1941,7 +2021,7 @@ wi_info_intr(struct wi_softc *sc)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = &sc->sc_if;
-	int i, fid, len, off;
+	int i, s, fid, len, off;
 	u_int16_t ltbuf[2];
 	u_int16_t stat;
 	u_int32_t *ptr;
@@ -1962,7 +2042,9 @@ wi_info_intr(struct wi_softc *sc)
 				break;
 			/* FALLTHROUGH */
 		case AP_CHANGE:
+			s = splnet();
 			ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+			splx(s);
 			break;
 		case AP_IN_RANGE:
 			sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
@@ -1980,8 +2062,10 @@ wi_info_intr(struct wi_softc *sc)
 			break;
 		case DISCONNECTED:
 		case ASSOC_FAILED:
+			s = splnet();
 			if (ic->ic_opmode == IEEE80211_M_STA)
 				ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+			splx(s);
 			break;
 		}
 		break;
@@ -3061,11 +3145,15 @@ wi_rssadapt_updatestats(void *arg)
 {
 	struct wi_softc *sc = arg;
 	struct ieee80211com *ic = &sc->sc_ic;
+	int s;
+
+	s = splnet();
 	ieee80211_iterate_nodes(&ic->ic_sta, wi_rssadapt_updatestats_cb, arg);
 	if (ic->ic_opmode != IEEE80211_M_MONITOR &&
 	    ic->ic_state == IEEE80211_S_RUN)
 		callout_reset(&sc->sc_rssadapt_ch, hz / 10,
 		    wi_rssadapt_updatestats, arg);
+	splx(s);
 }
 
 /*

Index: src/sys/dev/ic/wivar.h
diff -u src/sys/dev/ic/wivar.h:1.65 src/sys/dev/ic/wivar.h:1.66
--- src/sys/dev/ic/wivar.h:1.65	Mon Aug 15 18:24:34 2011
+++ src/sys/dev/ic/wivar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wivar.h,v 1.65 2011/08/15 18:24:34 dyoung Exp $	*/
+/*	$NetBSD: wivar.h,v 1.66 2017/02/02 10:05:35 nonaka Exp $	*/
 
 /*
  * Copyright (c) 1997, 1998, 1999
@@ -83,6 +83,7 @@ struct wi_softc	{
 	struct ieee80211com	sc_ic;
 	u_int32_t		sc_ic_flags;	/* backup of ic->ic_flags */
 	void			*sc_ih;		/* interrupt handler */
+	void			*sc_soft_ih;
 	int			(*sc_enable)(device_t, int);
 	void			(*sc_reset)(struct wi_softc *);
 

Index: src/sys/dev/pci/if_ipw.c
diff -u src/sys/dev/pci/if_ipw.c:1.62 src/sys/dev/pci/if_ipw.c:1.63
--- src/sys/dev/pci/if_ipw.c:1.62	Wed Feb  1 03:00:41 2017
+++ src/sys/dev/pci/if_ipw.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ipw.c,v 1.62 2017/02/01 03:00:41 nonaka Exp $	*/
+/*	$NetBSD: if_ipw.c,v 1.63 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	FreeBSD: src/sys/dev/ipw/if_ipw.c,v 1.15 2005/11/13 17:17:40 damien Exp 	*/
 
 /*-
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_ipw.c,v 1.62 2017/02/01 03:00:41 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_ipw.c,v 1.63 2017/02/02 10:05:35 nonaka Exp $");
 
 /*-
  * Intel(R) PRO/Wireless 2100 MiniPCI driver
@@ -102,14 +102,15 @@ static uint16_t	ipw_read_prom_word(struc
 static void	ipw_command_intr(struct ipw_softc *, struct ipw_soft_buf *);
 static void	ipw_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
 static void	ipw_data_intr(struct ipw_softc *, struct ipw_status *,
-    struct ipw_soft_bd *, struct ipw_soft_buf *);
+		    struct ipw_soft_bd *, struct ipw_soft_buf *);
 static void	ipw_rx_intr(struct ipw_softc *);
 static void	ipw_release_sbd(struct ipw_softc *, struct ipw_soft_bd *);
 static void	ipw_tx_intr(struct ipw_softc *);
 static int	ipw_intr(void *);
+static void	ipw_softintr(void *);
 static int	ipw_cmd(struct ipw_softc *, uint32_t, void *, uint32_t);
 static int	ipw_tx_start(struct ifnet *, struct mbuf *,
-    struct ieee80211_node *);
+		    struct ieee80211_node *);
 static void	ipw_start(struct ifnet *);
 static void	ipw_watchdog(struct ifnet *);
 static int	ipw_ioctl(struct ifnet *, u_long, void *);
@@ -216,7 +217,13 @@ ipw_attach(device_t parent, device_t sel
 
 	if (pci_intr_map(pa, &ih) != 0) {
 		aprint_error_dev(sc->sc_dev, "could not map interrupt\n");
-		return;
+		goto fail;
+	}
+
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, ipw_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(sc->sc_dev, "could not establish softint\n");
+		goto fail;
 	}
 
 	intrstr = pci_intr_string(sc->sc_pct, ih, intrbuf, sizeof(intrbuf));
@@ -226,7 +233,7 @@ ipw_attach(device_t parent, device_t sel
 		if (intrstr != NULL)
 			aprint_error(" at %s", intrstr);
 		aprint_error("\n");
-		return;
+		goto fail;
 	}
 	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
 
@@ -296,9 +303,11 @@ ipw_attach(device_t parent, device_t sel
 	aprint_normal_dev(sc->sc_dev, "802.11 address %s\n",
 	    ether_sprintf(ic->ic_myaddr));
 
-	if_attach(ifp);
-	if_deferred_start_init(ifp, NULL);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	/* override state transition machine */
 	sc->sc_newstate = ic->ic_newstate;
@@ -357,6 +366,11 @@ ipw_detach(device_t self, int flags)
 		sc->sc_ih = NULL;
 	}
 
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
+
 	bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz);
 
 	return 0;
@@ -909,6 +923,7 @@ ipw_newstate_intr(struct ipw_softc *sc, 
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = sc->sc_ic.ic_ifp;
 	uint32_t state;
+	int s;
 
 	bus_dmamap_sync(sc->sc_dmat, sbuf->map, 0, sizeof state,
 	    BUS_DMASYNC_POSTREAD);
@@ -917,6 +932,8 @@ ipw_newstate_intr(struct ipw_softc *sc, 
 
 	DPRINTFN(2, ("entering state %u\n", state));
 
+	s = splnet();
+
 	switch (state) {
 	case IPW_STATE_ASSOCIATED:
 		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
@@ -944,6 +961,8 @@ ipw_newstate_intr(struct ipw_softc *sc, 
 		ipw_stop(ifp, 1);
 		break;
 	}
+
+	splx(s);
 }
 
 /*
@@ -992,7 +1011,7 @@ ipw_data_intr(struct ipw_softc *sc, stru
 	struct mbuf *mnew, *m;
 	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
-	int error;
+	int error, s;
 
 	DPRINTFN(5, ("received frame len=%u, rssi=%u\n", le32toh(status->len),
 	    status->rssi));
@@ -1058,6 +1077,8 @@ ipw_data_intr(struct ipw_softc *sc, stru
 	m_set_rcvif(m, ifp);
 	m->m_pkthdr.len = m->m_len = le32toh(status->len);
 
+	s = splnet();
+
 	if (sc->sc_drvbpf != NULL) {
 		struct ipw_rx_radiotap_header *tap = &sc->sc_rxtap;
 
@@ -1078,6 +1099,8 @@ ipw_data_intr(struct ipw_softc *sc, stru
 	/* node is no longer needed */
 	ieee80211_free_node(ni);
 
+	splx(s);
+
 	bus_dmamap_sync(sc->sc_dmat, sbuf->map, 0,
 	    sbuf->map->dm_mapsize, BUS_DMASYNC_PREREAD);
 }
@@ -1195,10 +1218,13 @@ ipw_tx_intr(struct ipw_softc *sc)
 	struct ifnet *ifp = &sc->sc_if;
 	struct ipw_soft_bd *sbd;
 	uint32_t r, i;
+	int s;
 
 	if (!(sc->flags & IPW_FLAG_FW_INITED))
 		return;
 
+	s = splnet();
+
 	r = CSR_READ_4(sc, IPW_CSR_TX_READ);
 
 	for (i = (sc->txold + 1) % IPW_NTBD; i != r; i = (i + 1) % IPW_NTBD) {
@@ -1216,7 +1242,9 @@ ipw_tx_intr(struct ipw_softc *sc)
 
 	/* Call start() since some buffer descriptors have been released */
 	ifp->if_flags &= ~IFF_OACTIVE;
-	if_schedule_deferred_start(ifp);
+	ipw_start(ifp);
+
+	splx(s);
 }
 
 static int
@@ -1232,10 +1260,27 @@ ipw_intr(void *arg)
 	/* Disable interrupts */
 	CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, 0);
 
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+ipw_softintr(void *arg)
+{
+	struct ipw_softc *sc = arg;
+	uint32_t r;
+	int s;
+
+	r = CSR_READ_4(sc, IPW_CSR_INTR);
+	if (r == 0 || r == 0xffffffff)
+		goto out;
+
 	if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) {
 		aprint_error_dev(sc->sc_dev, "fatal error\n");
+		s = splnet();
 		sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
 		ipw_stop(&sc->sc_if, 1);
+		splx(s);
 	}
 
 	if (r & IPW_INTR_FW_INIT_DONE) {
@@ -1252,10 +1297,9 @@ ipw_intr(void *arg)
 	/* Acknowledge all interrupts */
 	CSR_WRITE_4(sc, IPW_CSR_INTR, r);
 
+ out:
 	/* Re-enable interrupts */
 	CSR_WRITE_4(sc, IPW_CSR_INTR_MASK, IPW_INTR_MASK);
-
-	return 0;
 }
 
 /*
@@ -1352,7 +1396,8 @@ ipw_tx_start(struct ifnet *ifp, struct m
 	/* trim IEEE802.11 header */
 	m_adj(m0, sizeof (struct ieee80211_frame));
 
-	error = bus_dmamap_load_mbuf(sc->sc_dmat, sbuf->map, m0, BUS_DMA_NOWAIT);
+	error = bus_dmamap_load_mbuf(sc->sc_dmat, sbuf->map, m0,
+	    BUS_DMA_NOWAIT);
 	if (error != 0 && error != EFBIG) {
 		aprint_error_dev(sc->sc_dev, "could not map mbuf (error %d)\n",
 		    error);
@@ -1388,7 +1433,8 @@ ipw_tx_start(struct ifnet *ifp, struct m
 		error = bus_dmamap_load_mbuf(sc->sc_dmat, sbuf->map, m0,
 		    BUS_DMA_WRITE | BUS_DMA_NOWAIT);
 		if (error != 0) {
-			aprint_error_dev(sc->sc_dev, "could not map mbuf (error %d)\n", error);
+			aprint_error_dev(sc->sc_dev,
+			    "could not map mbuf (error %d)\n", error);
 			m_freem(m0);
 			return error;
 		}
@@ -1470,7 +1516,6 @@ ipw_start(struct ifnet *ifp)
 	struct ether_header *eh;
 	struct ieee80211_node *ni;
 
-
 	if (ic->ic_state != IEEE80211_S_RUN)
 		return;
 
@@ -1832,7 +1877,8 @@ ipw_load_firmware(struct ipw_softc *sc, 
 
 	/* wait at most one second for firmware initialization to complete */
 	if ((error = tsleep(sc, 0, "ipwinit", hz)) != 0) {
-		aprint_error_dev(sc->sc_dev, "timeout waiting for firmware initialization "
+		aprint_error_dev(sc->sc_dev,
+		    "timeout waiting for firmware initialization "
 		    "to complete\n");
 		return error;
 	}
@@ -2141,7 +2187,8 @@ ipw_init(struct ifnet *ifp)
 
 	if (!(sc->flags & IPW_FLAG_FW_CACHED)) {
 		if (ipw_cache_firmware(sc) != 0) {
-			aprint_error_dev(sc->sc_dev, "could not cache the firmware (%s)\n",
+			aprint_error_dev(sc->sc_dev,
+			    "could not cache the firmware (%s)\n",
 			    sc->sc_fwname);
 			goto fail;
 		}

Index: src/sys/dev/pci/if_ipwvar.h
diff -u src/sys/dev/pci/if_ipwvar.h:1.17 src/sys/dev/pci/if_ipwvar.h:1.18
--- src/sys/dev/pci/if_ipwvar.h:1.17	Sun Sep  6 06:01:00 2015
+++ src/sys/dev/pci/if_ipwvar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_ipwvar.h,v 1.17 2015/09/06 06:01:00 dholland Exp $	*/
+/*	$NetBSD: if_ipwvar.h,v 1.18 2017/02/02 10:05:35 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2004
@@ -103,6 +103,7 @@ struct ipw_softc {
 	bus_space_tag_t			sc_st;
 	bus_space_handle_t		sc_sh;
 	void				*sc_ih;
+	void				*sc_soft_ih;
 	pci_chipset_tag_t		sc_pct;
 	pcitag_t			sc_pcitag;
 	bus_size_t			sc_sz;

Index: src/sys/dev/pci/if_iwi.c
diff -u src/sys/dev/pci/if_iwi.c:1.101 src/sys/dev/pci/if_iwi.c:1.102
--- src/sys/dev/pci/if_iwi.c:1.101	Thu Dec  8 01:12:01 2016
+++ src/sys/dev/pci/if_iwi.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwi.c,v 1.101 2016/12/08 01:12:01 ozaki-r Exp $  */
+/*	$NetBSD: if_iwi.c,v 1.102 2017/02/02 10:05:35 nonaka Exp $  */
 /*	$OpenBSD: if_iwi.c,v 1.111 2010/11/15 19:11:57 damien Exp $	*/
 
 /*-
@@ -19,7 +19,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_iwi.c,v 1.101 2016/12/08 01:12:01 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_iwi.c,v 1.102 2017/02/02 10:05:35 nonaka Exp $");
 
 /*-
  * Intel(R) PRO/Wireless 2200BG/2225BG/2915ABG driver
@@ -117,6 +117,7 @@ static void	iwi_cmd_intr(struct iwi_soft
 static void	iwi_rx_intr(struct iwi_softc *);
 static void	iwi_tx_intr(struct iwi_softc *, struct iwi_tx_ring *);
 static int	iwi_intr(void *);
+static void	iwi_softintr(void *);
 static int	iwi_cmd(struct iwi_softc *, uint8_t, void *, uint8_t, int);
 static void	iwi_write_ibssnode(struct iwi_softc *, const struct iwi_node *);
 static int	iwi_tx_start(struct ifnet *, struct mbuf *, struct ieee80211_node *,
@@ -253,7 +254,15 @@ iwi_attach(device_t parent, device_t sel
 	/* disable interrupts */
 	CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0);
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, iwi_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(self, "could not establish softint\n");
+		return;
+	}
+
 	if (pci_intr_map(pa, &ih) != 0) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
 		aprint_error_dev(self, "could not map interrupt\n");
 		return;
 	}
@@ -261,6 +270,8 @@ iwi_attach(device_t parent, device_t sel
 	intrstr = pci_intr_string(sc->sc_pct, ih, intrbuf, sizeof(intrbuf));
 	sc->sc_ih = pci_intr_establish(sc->sc_pct, ih, IPL_NET, iwi_intr, sc);
 	if (sc->sc_ih == NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
 		aprint_error_dev(self, "could not establish interrupt");
 		if (intrstr != NULL)
 			aprint_error(" at %s", intrstr);
@@ -271,6 +282,8 @@ iwi_attach(device_t parent, device_t sel
 
 	if (iwi_reset(sc) != 0) {
 		pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
 		aprint_error_dev(self, "could not reset adapter\n");
 		return;
 	}
@@ -354,9 +367,12 @@ iwi_attach(device_t parent, device_t sel
 	IFQ_SET_READY(&ifp->if_snd);
 	memcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
 
-	if_attach(ifp);
-	if_deferred_start_init(ifp, NULL);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
+
 	/* override default methods */
 	ic->ic_node_alloc = iwi_node_alloc;
 	sc->sc_node_free = ic->ic_node_free;
@@ -461,6 +477,11 @@ iwi_detach(device_t self, int flags)
 		sc->sc_ih = NULL;
 	}
 
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
+
 	bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz);
 
 	return 0;
@@ -1145,7 +1166,7 @@ iwi_frame_intr(struct iwi_softc *sc, str
 	struct mbuf *m, *m_new;
 	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
-	int error;
+	int error, s;
 
 	DPRINTFN(5, ("received frame len=%u chan=%u rssi=%u\n",
 	    le16toh(frame->len), frame->chan, frame->rssi_dbm));
@@ -1204,6 +1225,8 @@ iwi_frame_intr(struct iwi_softc *sc, str
 
 	m_adj(m, sizeof (struct iwi_hdr) + sizeof (struct iwi_frame));
 
+	s = splnet();
+
 	if (ic->ic_state == IEEE80211_S_SCAN)
 		iwi_fix_channel(ic, m);
 
@@ -1229,6 +1252,8 @@ iwi_frame_intr(struct iwi_softc *sc, str
 
 	/* node is no longer needed */
 	ieee80211_free_node(ni);
+
+	splx(s);
 }
 
 static void
@@ -1238,6 +1263,7 @@ iwi_notification_intr(struct iwi_softc *
 	struct iwi_notif_authentication *auth;
 	struct iwi_notif_association *assoc;
 	struct iwi_notif_beacon_state *beacon;
+	int s;
 
 	switch (notif->type) {
 	case IWI_NOTIF_TYPE_SCAN_CHANNEL:
@@ -1264,11 +1290,13 @@ iwi_notification_intr(struct iwi_softc *
 #endif
 
 		/* monitor mode uses scan to set the channel ... */
+		s = splnet();
 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
 			sc->flags &= ~IWI_FLAG_SCANNING;
 			ieee80211_end_scan(ic);
 		} else
 			iwi_set_chan(sc, ic->ic_ibss_chan);
+		splx(s);
 		break;
 
 	case IWI_NOTIF_TYPE_AUTHENTICATION:
@@ -1278,8 +1306,10 @@ iwi_notification_intr(struct iwi_softc *
 
 		switch (auth->state) {
 		case IWI_AUTH_SUCCESS:
+			s = splnet();
 			ieee80211_node_authorize(ic->ic_bss);
 			ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1);
+			splx(s);
 			break;
 
 		case IWI_AUTH_FAIL:
@@ -1311,11 +1341,15 @@ iwi_notification_intr(struct iwi_softc *
 			break;
 
 		case IWI_ASSOC_SUCCESS:
+			s = splnet();
 			ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+			splx(s);
 			break;
 
 		case IWI_ASSOC_FAIL:
+			s = splnet();
 			ieee80211_begin_scan(ic, 1);
+			splx(s);
 			break;
 
 		default:
@@ -1363,7 +1397,8 @@ iwi_cmd_intr(struct iwi_softc *sc)
 	sc->cmdq.next = (sc->cmdq.next + 1) % sc->cmdq.count;
 
 	if (--sc->cmdq.queued > 0) {
-		CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX, (sc->cmdq.next + 1) % sc->cmdq.count);
+		CSR_WRITE_4(sc, IWI_CSR_CMD_WIDX,
+		    (sc->cmdq.next + 1) % sc->cmdq.count);
 	}
 }
 
@@ -1419,6 +1454,9 @@ iwi_tx_intr(struct iwi_softc *sc, struct
 	struct ifnet *ifp = &sc->sc_if;
 	struct iwi_tx_data *data;
 	uint32_t hw;
+	int s;
+
+	s = splnet();
 
 	hw = CSR_READ_4(sc, txq->csr_ridx);
 
@@ -1442,10 +1480,15 @@ iwi_tx_intr(struct iwi_softc *sc, struct
 	}
 
 	sc->sc_tx_timer = 0;
-	ifp->if_flags &= ~IFF_OACTIVE;
 
-	/* Call start() since some buffer descriptors have been released */
-	if_schedule_deferred_start(ifp);
+	if (txq->queued < txq->count - 8 - 8 && (ifp->if_flags & IFF_OACTIVE)) {
+		ifp->if_flags &= ~IFF_OACTIVE;
+
+		/* Call start() since some buffer descriptors have been released */
+		iwi_start(ifp);
+	}
+
+	splx(s);
 }
 
 static int
@@ -1457,14 +1500,33 @@ iwi_intr(void *arg)
 	if ((r = CSR_READ_4(sc, IWI_CSR_INTR)) == 0 || r == 0xffffffff)
 		return 0;
 
+	/* Disable interrupts */
+	CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0);
+
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+iwi_softintr(void *arg)
+{
+	struct iwi_softc *sc = arg;
+	uint32_t r;
+	int s;
+
+	if ((r = CSR_READ_4(sc, IWI_CSR_INTR)) == 0 || r == 0xffffffff)
+		goto out;
+
 	/* Acknowledge interrupts */
 	CSR_WRITE_4(sc, IWI_CSR_INTR, r);
 
 	if (r & IWI_INTR_FATAL_ERROR) {
 		aprint_error_dev(sc->sc_dev, "fatal error\n");
+		s = splnet();
 		sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
 		iwi_stop(&sc->sc_if, 1);
-		return (1);
+		splx(s);
+		return;
 	}
 
 	if (r & IWI_INTR_FW_INITED) {
@@ -1474,9 +1536,11 @@ iwi_intr(void *arg)
 
 	if (r & IWI_INTR_RADIO_OFF) {
 		DPRINTF(("radio transmitter off\n"));
+		s = splnet();
 		sc->sc_ic.ic_ifp->if_flags &= ~IFF_UP;
 		iwi_stop(&sc->sc_if, 1);
-		return (1);
+		splx(s);
+		return;
 	}
 
 	if (r & IWI_INTR_CMD_DONE)
@@ -1500,7 +1564,9 @@ iwi_intr(void *arg)
 	if (r & IWI_INTR_PARITY_ERROR)
 		aprint_error_dev(sc->sc_dev, "parity error\n");
 
-	return 1;
+ out:
+	/* Re-enable interrupts */
+	CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, IWI_INTR_MASK);
 }
 
 static int
@@ -1728,7 +1794,7 @@ iwi_start(struct ifnet *ifp)
 		return;
 
 	for (;;) {
-		IF_DEQUEUE(&ifp->if_snd, m0);
+		IFQ_DEQUEUE(&ifp->if_snd, m0);
 		if (m0 == NULL)
 			break;
 
@@ -1760,7 +1826,9 @@ iwi_start(struct ifnet *ifp)
 
 		if (sc->txq[ac].queued > sc->txq[ac].count - 8) {
 			/* there is no place left in this ring */
+			IFQ_LOCK(&ifp->if_snd);
 			IF_PREPEND(&ifp->if_snd, m0);
+			IFQ_UNLOCK(&ifp->if_snd);
 			ifp->if_flags |= IFF_OACTIVE;
 			break;
 		}

Index: src/sys/dev/pci/if_iwivar.h
diff -u src/sys/dev/pci/if_iwivar.h:1.18 src/sys/dev/pci/if_iwivar.h:1.19
--- src/sys/dev/pci/if_iwivar.h:1.18	Sun Sep  6 06:01:00 2015
+++ src/sys/dev/pci/if_iwivar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwivar.h,v 1.18 2015/09/06 06:01:00 dholland Exp $ */
+/*	$NetBSD: if_iwivar.h,v 1.19 2017/02/02 10:05:35 nonaka Exp $ */
 
 /*-
  * Copyright (c) 2004, 2005
@@ -146,6 +146,7 @@ struct iwi_softc {
 	pci_chipset_tag_t	sc_pct;
 	pcitag_t		sc_pcitag;
 	bus_size_t		sc_sz;
+	void			*sc_soft_ih;
 
 	struct sysctllog	*sc_sysctllog;
 
Index: src/sys/dev/pci/if_iwnvar.h
diff -u src/sys/dev/pci/if_iwnvar.h:1.18 src/sys/dev/pci/if_iwnvar.h:1.19
--- src/sys/dev/pci/if_iwnvar.h:1.18	Thu Feb  2 03:20:20 2017
+++ src/sys/dev/pci/if_iwnvar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwnvar.h,v 1.18 2017/02/02 03:20:20 nonaka Exp $	*/
+/*	$NetBSD: if_iwnvar.h,v 1.19 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: if_iwnvar.h,v 1.28 2014/09/09 18:55:08 sthen Exp $	*/
 
 /*-
@@ -225,6 +225,7 @@ struct iwn_softc {
 #define IWN_FLAG_SCANNING_2GHZ	(1 << 9)
 #define IWN_FLAG_SCANNING_5GHZ	(1 << 10)
 #define IWN_FLAG_SCANNING	(IWN_FLAG_SCANNING_2GHZ|IWN_FLAG_SCANNING_5GHZ)
+#define IWN_FLAG_ATTACHED	(1 << 11)
 
 	uint8_t 		hw_type;
 
@@ -266,6 +267,7 @@ struct iwn_softc {
 	bus_space_handle_t	sc_sh;
 	pci_intr_handle_t	*sc_pihp;
 	void 			*sc_ih;
+	void			*sc_soft_ih;
 	pci_chipset_tag_t	sc_pct;
 	pcitag_t		sc_pcitag;
 	bus_size_t		sc_sz;

Index: src/sys/dev/pci/if_iwm.c
diff -u src/sys/dev/pci/if_iwm.c:1.69 src/sys/dev/pci/if_iwm.c:1.70
--- src/sys/dev/pci/if_iwm.c:1.69	Sat Jan 21 05:54:06 2017
+++ src/sys/dev/pci/if_iwm.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwm.c,v 1.69 2017/01/21 05:54:06 nonaka Exp $	*/
+/*	$NetBSD: if_iwm.c,v 1.70 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	OpenBSD: if_iwm.c,v 1.148 2016/11/19 21:07:08 stsp Exp	*/
 #define IEEE80211_NO_HT
 /*
@@ -107,7 +107,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.69 2017/01/21 05:54:06 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.70 2017/02/02 10:05:35 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -7223,10 +7223,22 @@ static int
 iwm_intr(void *arg)
 {
 	struct iwm_softc *sc = arg;
-	int r1, r2;
 
+	/* Disable interrupts */
 	IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
 
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+iwm_softintr(void *arg)
+{
+	struct iwm_softc *sc = arg;
+	struct ifnet *ifp = IC2IFP(&sc->sc_ic);
+	uint32_t r1, r2;
+	int isperiodic = 0, s;
+
 	if (__predict_true(sc->sc_flags & IWM_FLAG_USE_ICT)) {
 		uint32_t *ict = sc->ict_dma.vaddr;
 		int tmp;
@@ -7234,8 +7246,8 @@ iwm_intr(void *arg)
 		bus_dmamap_sync(sc->sc_dmat, sc->ict_dma.map,
 		    0, sc->ict_dma.size, BUS_DMASYNC_POSTREAD);
 		tmp = htole32(ict[sc->ict_cur]);
-		if (!tmp)
-			goto out_ena;
+		if (tmp == 0)
+			goto out_ena;	/* Interrupt not for us. */
 
 		/*
 		 * ok, there was something.  keep plowing until we have all.
@@ -7262,11 +7274,11 @@ iwm_intr(void *arg)
 	} else {
 		r1 = IWM_READ(sc, IWM_CSR_INT);
 		if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0)
-			goto out;
+			return;	/* Hardware gone! */
 		r2 = IWM_READ(sc, IWM_CSR_FH_INT_STATUS);
 	}
 	if (r1 == 0 && r2 == 0) {
-		goto out_ena;
+		goto out_ena;	/* Interrupt not for us. */
 	}
 
 	/* Acknowledge interrupts. */
@@ -7274,26 +7286,6 @@ iwm_intr(void *arg)
 	if (__predict_false(!(sc->sc_flags & IWM_FLAG_USE_ICT)))
 		IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, r2);
 
-	atomic_or_32(&sc->sc_soft_flags, r1);
-	softint_schedule(sc->sc_soft_ih);
-	return 1;
-
- out_ena:
-	iwm_restore_interrupts(sc);
- out:
-	return 0;
-}
-
-static void
-iwm_softintr(void *arg)
-{
-	struct iwm_softc *sc = arg;
-	struct ifnet *ifp = IC2IFP(&sc->sc_ic);
-	uint32_t r1;
-	int isperiodic = 0, s;
-
-	r1 = atomic_swap_32(&sc->sc_soft_flags, 0);
-
 	if (r1 & IWM_CSR_INT_BIT_SW_ERR) {
 #ifdef IWM_DEBUG
 		int i;
@@ -7363,6 +7355,7 @@ iwm_softintr(void *arg)
 			    IWM_CSR_INT_PERIODIC_ENA);
 	}
 
+out_ena:
 	iwm_restore_interrupts(sc);
 }
 

Index: src/sys/dev/pci/if_iwmvar.h
diff -u src/sys/dev/pci/if_iwmvar.h:1.16 src/sys/dev/pci/if_iwmvar.h:1.17
--- src/sys/dev/pci/if_iwmvar.h:1.16	Sat Jan 21 05:58:49 2017
+++ src/sys/dev/pci/if_iwmvar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwmvar.h,v 1.16 2017/01/21 05:58:49 nonaka Exp $	*/
+/*	$NetBSD: if_iwmvar.h,v 1.17 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	OpenBSD: if_iwmvar.h,v 1.24 2016/09/21 13:53:18 stsp Exp 	*/
 
 /*
@@ -372,7 +372,6 @@ struct iwm_softc {
 	pcireg_t sc_pciid;
 	const void *sc_ih;
 	void *sc_soft_ih;
-	uint32_t sc_soft_flags;
 
 	/* TX scheduler rings. */
 	struct iwm_dma_info		sched_dma;

Index: src/sys/dev/pci/if_iwn.c
diff -u src/sys/dev/pci/if_iwn.c:1.83 src/sys/dev/pci/if_iwn.c:1.84
--- src/sys/dev/pci/if_iwn.c:1.83	Thu Feb  2 03:20:19 2017
+++ src/sys/dev/pci/if_iwn.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_iwn.c,v 1.83 2017/02/02 03:20:19 nonaka Exp $	*/
+/*	$NetBSD: if_iwn.c,v 1.84 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: if_iwn.c,v 1.135 2014/09/10 07:22:09 dcoppa Exp $	*/
 
 /*-
@@ -22,7 +22,7 @@
  * adapters.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_iwn.c,v 1.83 2017/02/02 03:20:19 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_iwn.c,v 1.84 2017/02/02 10:05:35 nonaka Exp $");
 
 #define IWN_USE_RBUF	/* Use local storage for RX */
 #undef IWN_HWCRYPTO	/* XXX does not even compile yet */
@@ -47,7 +47,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_iwn.c,v 1
 
 #include <sys/bus.h>
 #include <machine/endian.h>
-#include <machine/intr.h>
+#include <sys/intr.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -201,6 +201,7 @@ static void	iwn_notif_intr(struct iwn_so
 static void	iwn_wakeup_intr(struct iwn_softc *);
 static void	iwn_fatal_intr(struct iwn_softc *);
 static int	iwn_intr(void *);
+static void	iwn_softintr(void *);
 static void	iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t,
 		    uint16_t);
 static void	iwn5000_update_sched(struct iwn_softc *, int, int, uint8_t,
@@ -408,11 +409,17 @@ iwn_attach(device_t parent __unused, dev
 		return;
 	}
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, iwn_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(self, "can't establish soft interrupt\n");
+		goto unmap;
+	}
+
 	/* Install interrupt handler. */
 	error = pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0);
 	if (error) {
 		aprint_error_dev(self, "can't allocate interrupt\n");
-		goto unmap;
+		goto failsi;
 	}
 	reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG);
 	if (pci_intr_type(sc->sc_pct, sc->sc_pihp[0]) == PCI_INTR_TYPE_INTX)
@@ -589,9 +596,12 @@ iwn_attach(device_t parent __unused, dev
 	IFQ_SET_READY(&ifp->if_snd);
 	memcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
 
-	if_attach(ifp);
-	if_deferred_start_init(ifp, NULL);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
+
 	ic->ic_node_alloc = iwn_node_alloc;
 	ic->ic_newassoc = iwn_newassoc;
 #ifdef IWN_HWCRYPTO
@@ -629,6 +639,7 @@ iwn_attach(device_t parent __unused, dev
 	/* XXX NetBSD add call to ieee80211_announce for dmesg. */
 	ieee80211_announce(ic);
 
+	sc->sc_flags |= IWN_FLAG_ATTACHED;
 	return;
 
 	/* Free allocated memory if something failed during attachment. */
@@ -646,6 +657,8 @@ failih:	pci_intr_disestablish(sc->sc_pct
 	sc->sc_ih = NULL;
 failia:	pci_intr_release(sc->sc_pct, sc->sc_pihp, 1);
 	sc->sc_pihp = NULL;
+failsi:	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
 unmap:	bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz);
 }
 
@@ -829,6 +842,9 @@ iwn_detach(device_t self, int flags __un
 	struct ifnet *ifp = sc->sc_ic.ic_ifp;
 	int qid;
 
+	if (!(sc->sc_flags & IWN_FLAG_ATTACHED))
+		return 0;
+
 	callout_stop(&sc->calib_to);
 
 	/* Uninstall interrupt handler. */
@@ -836,6 +852,8 @@ iwn_detach(device_t self, int flags __un
 		pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
 	if (sc->sc_pihp != NULL)
 		pci_intr_release(sc->sc_pct, sc->sc_pihp, 1);
+	if (sc->sc_soft_ih != NULL)
+		softint_disestablish(sc->sc_soft_ih);
 
 	/* Free DMA resources. */
 	iwn_free_rx_ring(sc, &sc->rxq);
@@ -1474,6 +1492,8 @@ iwn5000_ict_reset(struct iwn_softc *sc)
 
 	/* Reset ICT table. */
 	memset(sc->ict, 0, IWN_ICT_SIZE);
+	bus_dmamap_sync(sc->sc_dmat, sc->ict_dma.map, 0, IWN_ICT_SIZE,
+	    BUS_DMASYNC_PREWRITE);
 	sc->ict_cur = 0;
 
 	/* Set physical address of ICT table (4KB aligned). */
@@ -1954,7 +1974,7 @@ iwn_calib_timeout(void *arg)
 	splx(s);
 
 	/* Automatic rate control triggered every 500ms. */
-	callout_schedule(&sc->calib_to, hz/2);
+	callout_schedule(&sc->calib_to, mstohz(500));
 }
 
 /*
@@ -1994,7 +2014,7 @@ iwn_rx_done(struct iwn_softc *sc, struct
 	struct iwn_rx_stat *stat;
 	char	*head;
 	uint32_t flags;
-	int error, len, rssi;
+	int error, len, rssi, s;
 
 	if (desc->type == IWN_MPDU_RX_DONE) {
 		/* Check for prior RX_PHY notification. */
@@ -2084,6 +2104,8 @@ iwn_rx_done(struct iwn_softc *sc, struct
 	m->m_data = head;
 	m->m_pkthdr.len = m->m_len = len;
 
+	s = splnet();
+
 	/* Grab a reference to the source node. */
 	wh = mtod(m, struct ieee80211_frame *);
 	ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
@@ -2137,6 +2159,8 @@ iwn_rx_done(struct iwn_softc *sc, struct
 
 	/* Node is no longer needed. */
 	ieee80211_free_node(ni);
+
+	splx(s);
 }
 
 #ifndef IEEE80211_NO_HT
@@ -2321,6 +2345,9 @@ iwn_tx_done(struct iwn_softc *sc, struct
 	struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
 	struct iwn_tx_data *data = &ring->data[desc->idx];
 	struct iwn_node *wn = (struct iwn_node *)data->ni;
+	int s;
+
+	s = splnet();
 
 	/* Update rate control statistics. */
 	wn->amn.amn_txcnt++;
@@ -2346,9 +2373,11 @@ iwn_tx_done(struct iwn_softc *sc, struct
 		sc->qfullmsk &= ~(1 << ring->qid);
 		if (sc->qfullmsk == 0 && (ifp->if_flags & IFF_OACTIVE)) {
 			ifp->if_flags &= ~IFF_OACTIVE;
-			if_schedule_deferred_start(ifp);
+			iwn_start(ifp);
 		}
 	}
+
+	splx(s);
 }
 
 /*
@@ -2387,6 +2416,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = ic->ic_ifp;
 	uint16_t hw;
+	int s;
 
 	bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map,
 	    0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD);
@@ -2490,8 +2520,10 @@ iwn_notif_intr(struct iwn_softc *sc)
 				aprint_error_dev(sc->sc_dev,
 				    "Radio transmitter is off\n");
 				/* Turn the interface down. */
+				s = splnet();
 				ifp->if_flags &= ~IFF_UP;
 				iwn_stop(ifp, 1);
+				splx(s);
 				return;	/* No further processing. */
 			}
 			break;
@@ -2639,12 +2671,22 @@ static int
 iwn_intr(void *arg)
 {
 	struct iwn_softc *sc = arg;
-	struct ifnet *ifp = sc->sc_ic.ic_ifp;
-	uint32_t r1, r2, tmp;
 
 	/* Disable interrupts. */
 	IWN_WRITE(sc, IWN_INT_MASK, 0);
 
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+iwn_softintr(void *arg)
+{
+	struct iwn_softc *sc = arg;
+	struct ifnet *ifp = sc->sc_ic.ic_ifp;
+	uint32_t r1, r2, tmp;
+	int s;
+
 	/* Read interrupts from ICT (fast) or from registers (slow). */
 	if (sc->sc_flags & IWN_FLAG_USE_ICT) {
 		bus_dmamap_sync(sc->sc_dmat, sc->ict_dma.map, 0,
@@ -2667,13 +2709,11 @@ iwn_intr(void *arg)
 	} else {
 		r1 = IWN_READ(sc, IWN_INT);
 		if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0)
-			return 0;	/* Hardware gone! */
+			return;	/* Hardware gone! */
 		r2 = IWN_READ(sc, IWN_FH_INT);
 	}
 	if (r1 == 0 && r2 == 0) {
-		if (ifp->if_flags & IFF_UP)
-			IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
-		return 0;	/* Interrupt not for us. */
+		goto out;	/* Interrupt not for us. */
 	}
 
 	/* Acknowledge interrupts. */
@@ -2696,17 +2736,18 @@ iwn_intr(void *arg)
 		    "fatal firmware error\n");
 		/* Dump firmware error log and stop. */
 		iwn_fatal_intr(sc);
+		s = splnet();
 		ifp->if_flags &= ~IFF_UP;
 		iwn_stop(ifp, 1);
-		return 1;
+		splx(s);
+		return;
 	}
 	if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) ||
 	    (r2 & IWN_FH_INT_RX)) {
 		if (sc->sc_flags & IWN_FLAG_USE_ICT) {
 			if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX))
 				IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_RX);
-			IWN_WRITE_1(sc, IWN_INT_PERIODIC,
-			    IWN_INT_PERIODIC_DIS);
+			IWN_WRITE_1(sc, IWN_INT_PERIODIC, IWN_INT_PERIODIC_DIS);
 			iwn_notif_intr(sc);
 			if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) {
 				IWN_WRITE_1(sc, IWN_INT_PERIODIC,
@@ -2728,11 +2769,10 @@ iwn_intr(void *arg)
 	if (r1 & IWN_INT_WAKEUP)
 		iwn_wakeup_intr(sc);
 
+out:
 	/* Re-enable interrupts. */
 	if (ifp->if_flags & IFF_UP)
 		IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
-
-	return 1;
 }
 
 /*
@@ -5957,8 +5997,7 @@ iwn_apm_stop_master(struct iwn_softc *sc
 			return;
 		DELAY(10);
 	}
-	aprint_error_dev(sc->sc_dev,
-	    "timeout waiting for master\n");
+	aprint_error_dev(sc->sc_dev, "timeout waiting for master\n");
 }
 
 static void
@@ -6029,7 +6068,7 @@ iwn5000_nic_config(struct iwn_softc *sc)
 		IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA);
 	}
 	if ((sc->hw_type == IWN_HW_REV_TYPE_6050 ||
-		sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) {
+	     sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) {
 		/* Indicate that ROM calibration version is >=6. */
 		IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6);
 	}

Index: src/sys/dev/pci/if_malo_pci.c
diff -u src/sys/dev/pci/if_malo_pci.c:1.5 src/sys/dev/pci/if_malo_pci.c:1.6
--- src/sys/dev/pci/if_malo_pci.c:1.5	Sat Mar 29 19:28:25 2014
+++ src/sys/dev/pci/if_malo_pci.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_malo_pci.c,v 1.5 2014/03/29 19:28:25 christos Exp $	*/
+/*	$NetBSD: if_malo_pci.c,v 1.6 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: if_malo_pci.c,v 1.6 2010/08/28 23:19:29 deraadt Exp $ */
 
 /*
@@ -22,7 +22,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_malo_pci.c,v 1.5 2014/03/29 19:28:25 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_malo_pci.c,v 1.6 2017/02/02 10:05:35 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/sockio.h>
@@ -139,7 +139,7 @@ malo_pci_attach(device_t parent, device_
 		break;
 	default:
 		aprint_error_dev(self, "invalid base address register\n");
-		return;
+		goto unmap1;
 	}
 
 	error = pci_mapreg_map(pa, MALO_PCI_BAR2,
@@ -147,13 +147,19 @@ malo_pci_attach(device_t parent, device_
 		NULL, &psc->sc_mapsize2);
 	if (error != 0) {
 		aprint_error_dev(self, "can't map 2nd mem space\n");
-		return;
+		goto unmap1;
+	}
+
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, malo_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(self, "could not establish softint\n");
+		goto unmap2;
 	}
 
 	/* map interrupt */
 	if (pci_intr_map(pa, &ih) != 0) {
 		aprint_error_dev(self, "can't map interrupt\n");
-		return;
+		goto failsi;
 	}
 
 	/* establish interrupt */
@@ -164,16 +170,25 @@ malo_pci_attach(device_t parent, device_
 		if (intrstr != NULL)
 			aprint_error(" at %s", intrstr);
 		aprint_error("\n");
-		return;
+		goto failsi;
 	}
 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
 
-	malo_attach(sc);
+	if (malo_attach(sc))
+		goto failih;
 
 	if (pmf_device_register(self, malo_pci_suspend, malo_pci_resume))
 		pmf_class_network_register(self, &sc->sc_if);
 	else
 		aprint_error_dev(self, "couldn't establish power handler\n");
+	return;
+
+failih:	pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
+	psc->sc_ih = NULL;
+failsi:	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
+unmap2:	bus_space_unmap(sc->sc_mem2_bt, sc->sc_mem2_bh, psc->sc_mapsize2);
+unmap1:	bus_space_unmap(sc->sc_mem1_bt, sc->sc_mem1_bh, psc->sc_mapsize1);
 }
 
 int
@@ -183,7 +198,16 @@ malo_pci_detach(device_t self, int flags
 	struct malo_softc *sc = &psc->sc_malo;
 
 	malo_detach(sc);
-	pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
+	if (psc->sc_ih != NULL) {
+		pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
+		psc->sc_ih = NULL;
+	}
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
+	bus_space_unmap(sc->sc_mem2_bt, sc->sc_mem2_bh, psc->sc_mapsize2);
+	bus_space_unmap(sc->sc_mem1_bt, sc->sc_mem1_bh, psc->sc_mapsize1);
 
 	return (0);
 }

Index: src/sys/dev/pci/if_rtwn.c
diff -u src/sys/dev/pci/if_rtwn.c:1.10 src/sys/dev/pci/if_rtwn.c:1.11
--- src/sys/dev/pci/if_rtwn.c:1.10	Tue Jan 24 10:18:33 2017
+++ src/sys/dev/pci/if_rtwn.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_rtwn.c,v 1.10 2017/01/24 10:18:33 nonaka Exp $	*/
+/*	$NetBSD: if_rtwn.c,v 1.11 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: if_rtwn.c,v 1.5 2015/06/14 08:02:47 stsp Exp $	*/
 #define	IEEE80211_NO_HT
 /*-
@@ -23,7 +23,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_rtwn.c,v 1.10 2017/01/24 10:18:33 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_rtwn.c,v 1.11 2017/02/02 10:05:35 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/sockio.h>
@@ -174,6 +174,7 @@ static int	rtwn_init(struct ifnet *);
 static void	rtwn_init_task(void *);
 static void	rtwn_stop(struct ifnet *, int);
 static int	rtwn_intr(void *);
+static void	rtwn_softintr(void *);
 
 /* Aliases. */
 #define	rtwn_bb_write	rtwn_write_4
@@ -228,6 +229,7 @@ rtwn_attach(device_t parent, device_t se
 	callout_init(&sc->calib_to, 0);
 	callout_setfunc(&sc->calib_to, rtwn_calib_to, sc);
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, rtwn_softintr, sc);
 	sc->init_task = softint_establish(SOFTINT_NET, rtwn_init_task, sc);
 
 	/* Power up the device */
@@ -359,7 +361,6 @@ rtwn_attach(device_t parent, device_t se
 	ieee80211_ifattach(ic);
 	/* Use common softint-based if_input */
 	ifp->if_percpuq = if_percpuq_create(ifp);
-	if_deferred_start_init(ifp, NULL);
 	if_register(ifp);
 
 	/* override default methods */
@@ -424,6 +425,8 @@ rtwn_detach(device_t self, int flags)
 
 	if (sc->init_task != NULL)
 		softint_disestablish(sc->init_task);
+	if (sc->sc_soft_ih != NULL)
+		softint_disestablish(sc->sc_soft_ih);
 
 	if (sc->sc_ih != NULL) {
 		pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
@@ -1214,9 +1217,12 @@ rtwn_calib_to(void *arg)
 {
 	struct rtwn_softc *sc = arg;
 	struct r92c_fw_cmd_rssi cmd;
+	int s;
 
 	DPRINTFN(3, ("%s: %s\n", device_xname(sc->sc_dev), __func__));
 
+	s = splnet();
+
 	if (sc->sc_ic.ic_state != IEEE80211_S_RUN)
 		goto restart_timer;
 
@@ -1234,6 +1240,8 @@ rtwn_calib_to(void *arg)
 
  restart_timer:
 	callout_schedule(&sc->calib_to, mstohz(2000));
+
+	splx(s);
 }
 
 static void
@@ -1657,7 +1665,7 @@ rtwn_rx_frame(struct rtwn_softc *sc, str
 	struct mbuf *m, *m1;
 	uint8_t rate;
 	int8_t rssi = 0;
-	int infosz, pktlen, shift, totlen, error;
+	int infosz, pktlen, shift, totlen, error, s;
 
 	DPRINTFN(3, ("%s: %s\n", device_xname(sc->sc_dev), __func__));
 
@@ -1765,6 +1773,8 @@ rtwn_rx_frame(struct rtwn_softc *sc, str
 		m_adj(m, shift);
 	wh = mtod(m, struct ieee80211_frame *);
 
+	s = splnet();
+
 	if (__predict_false(sc->sc_drvbpf != NULL)) {
 		struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
 
@@ -1806,6 +1816,8 @@ rtwn_rx_frame(struct rtwn_softc *sc, str
 
 	/* Node is no longer needed. */
 	ieee80211_free_node(ni);
+
+	splx(s);
 }
 
 static int
@@ -2006,11 +2018,13 @@ rtwn_tx_done(struct rtwn_softc *sc, int 
 	struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
 	struct rtwn_tx_data *tx_data;
 	struct r92c_tx_desc *tx_desc;
-	int i;
+	int i, s;
 
 	DPRINTFN(3, ("%s: %s: qid=%d\n", device_xname(sc->sc_dev), __func__,
 	    qid));
 
+	s = splnet();
+
 	bus_dmamap_sync(sc->sc_dmat, tx_ring->map,
 	    0, sizeof(*tx_desc) * RTWN_TX_LIST_COUNT,
 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
@@ -2037,6 +2051,8 @@ rtwn_tx_done(struct rtwn_softc *sc, int 
 
 	if (tx_ring->queued < RTWN_TX_LIST_LOMARK)
 		sc->qfullmsk &= ~(1 << qid);
+
+	splx(s);
 }
 
 static void
@@ -3475,7 +3491,6 @@ rtwn_intr(void *xsc)
 {
 	struct rtwn_softc *sc = xsc;
 	uint32_t status;
-	int i;
 
 	if (!ISSET(sc->sc_flags, RTWN_FLAG_FW_LOADED))
 		return 0;
@@ -3487,6 +3502,24 @@ rtwn_intr(void *xsc)
 	/* Disable interrupts. */
 	rtwn_write_4(sc, R92C_HIMR, 0x00000000);
 
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+rtwn_softintr(void *xsc)
+{
+	struct rtwn_softc *sc = xsc;
+	uint32_t status;
+	int i, s;
+
+	if (!ISSET(sc->sc_flags, RTWN_FLAG_FW_LOADED))
+		return;
+
+	status = rtwn_read_4(sc, R92C_HISR);
+	if (status == 0 || status == 0xffffffff)
+		goto out;
+
 	/* Ack interrupts. */
 	rtwn_write_4(sc, R92C_HISR, status);
 
@@ -3519,12 +3552,13 @@ rtwn_intr(void *xsc)
 		rtwn_tx_done(sc, RTWN_VO_QUEUE);
 	if ((status & RTWN_INT_ENABLE_TX) && sc->qfullmsk == 0) {
 		struct ifnet *ifp = GET_IFP(sc);
+		s = splnet();
 		ifp->if_flags &= ~IFF_OACTIVE;
-		if_schedule_deferred_start(ifp);
+		rtwn_start(ifp);
+		splx(s);
 	}
 
+ out:
 	/* Enable interrupts. */
 	rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE);
-
-	return 1;
 }

Index: src/sys/dev/pci/if_rtwnreg.h
diff -u src/sys/dev/pci/if_rtwnreg.h:1.3 src/sys/dev/pci/if_rtwnreg.h:1.4
--- src/sys/dev/pci/if_rtwnreg.h:1.3	Tue Jan 24 10:18:33 2017
+++ src/sys/dev/pci/if_rtwnreg.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_rtwnreg.h,v 1.3 2017/01/24 10:18:33 nonaka Exp $	*/
+/*	$NetBSD: if_rtwnreg.h,v 1.4 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $	*/
 
 /*-
@@ -1287,7 +1287,7 @@ struct rtwn_softc {
 	bus_space_handle_t		sc_sh;
 	bus_size_t			sc_mapsize;
 	int				sc_cap_off;
-
+	void				*sc_soft_ih;
 
 	struct callout			scan_to;
 	struct callout			calib_to;

Index: src/sys/dev/pci/if_wpi.c
diff -u src/sys/dev/pci/if_wpi.c:1.76 src/sys/dev/pci/if_wpi.c:1.77
--- src/sys/dev/pci/if_wpi.c:1.76	Thu Feb  2 03:41:22 2017
+++ src/sys/dev/pci/if_wpi.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wpi.c,v 1.76 2017/02/02 03:41:22 jakllsch Exp $	*/
+/*	$NetBSD: if_wpi.c,v 1.77 2017/02/02 10:05:35 nonaka Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007
@@ -18,7 +18,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1.76 2017/02/02 03:41:22 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wpi.c,v 1.77 2017/02/02 10:05:35 nonaka Exp $");
 
 /*
  * Driver for Intel PRO/Wireless 3945ABG 802.11 network adapters.
@@ -125,6 +125,7 @@ static void	wpi_tx_intr(struct wpi_softc
 static void	wpi_cmd_intr(struct wpi_softc *, struct wpi_rx_desc *);
 static void	wpi_notif_intr(struct wpi_softc *);
 static int	wpi_intr(void *);
+static void	wpi_softintr(void *);
 static void	wpi_read_eeprom(struct wpi_softc *);
 static void	wpi_read_eeprom_channels(struct wpi_softc *, int);
 static void	wpi_read_eeprom_group(struct wpi_softc *, int);
@@ -255,9 +256,15 @@ wpi_attach(device_t parent __unused, dev
 	sc->sc_sh = memh;
 	sc->sc_dmat = pa->pa_dmat;
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, wpi_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(self, "could not establish softint\n");
+		goto unmap;
+	}
+
 	if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0)) {
 		aprint_error_dev(self, "could not map interrupt\n");
-		return;
+		goto failsi;
 	}
 
 	intrstr = pci_intr_string(sc->sc_pct, sc->sc_pihp[0], intrbuf,
@@ -269,7 +276,7 @@ wpi_attach(device_t parent __unused, dev
 		if (intrstr != NULL)
 			aprint_error(" at %s", intrstr);
 		aprint_error("\n");
-		return;
+		goto failia;
 	}
 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
 
@@ -278,7 +285,7 @@ wpi_attach(device_t parent __unused, dev
 	 */
 	if ((error = wpi_reset(sc)) != 0) {
 		aprint_error_dev(self, "could not reset adapter\n");
-		return;
+		goto failih;
 	}
 
 	/*
@@ -286,7 +293,7 @@ wpi_attach(device_t parent __unused, dev
 	 */
 	if ((error = wpi_alloc_fwmem(sc)) != 0) {
 		aprint_error_dev(self, "could not allocate firmware memory\n");
-		return;
+		goto failih;
 	}
 
 	/*
@@ -359,9 +366,12 @@ wpi_attach(device_t parent __unused, dev
 	IFQ_SET_READY(&ifp->if_snd);
 	memcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
 
-	if_attach(ifp);
-	if_deferred_start_init(ifp, NULL);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
+
 	/* override default methods */
 	ic->ic_node_alloc = wpi_node_alloc;
 	ic->ic_newassoc = wpi_newassoc;
@@ -405,6 +415,13 @@ fail3:	while (--ac >= 0)
 	wpi_free_rpool(sc);
 fail2:	wpi_free_shared(sc);
 fail1:	wpi_free_fwmem(sc);
+failih:	pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
+	sc->sc_ih = NULL;
+failia:	pci_intr_release(sc->sc_pct, sc->sc_pihp, 1);
+	sc->sc_pihp = NULL;
+failsi:	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
+unmap:	bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz);
 }
 
 static int
@@ -437,6 +454,11 @@ wpi_detach(device_t self, int flags __un
 		pci_intr_release(sc->sc_pct, sc->sc_pihp, 1);
 		sc->sc_pihp = NULL;
 	}
+	if (sc->sc_soft_ih != NULL) {
+		softint_disestablish(sc->sc_soft_ih);
+		sc->sc_soft_ih = NULL;
+	}
+
 	mutex_enter(&sc->sc_rsw_mtx);
 	sc->sc_dying = 1;
 	cv_signal(&sc->sc_rsw_cv);
@@ -1461,7 +1483,7 @@ wpi_rx_intr(struct wpi_softc *sc, struct
 	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
 	struct mbuf *m, *mnew;
-	int data_off, error;
+	int data_off, error, s;
 
 	bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize,
 	    BUS_DMASYNC_POSTREAD);
@@ -1549,6 +1571,8 @@ wpi_rx_intr(struct wpi_softc *sc, struct
 	/* finalize mbuf */
 	m_set_rcvif(m, ifp);
 
+	s = splnet();
+
 	if (sc->sc_drvbpf != NULL) {
 		struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap;
 
@@ -1594,6 +1618,8 @@ wpi_rx_intr(struct wpi_softc *sc, struct
 
 	/* release node reference */
 	ieee80211_free_node(ni);
+
+	splx(s);
 }
 
 static void
@@ -1604,12 +1630,15 @@ wpi_tx_intr(struct wpi_softc *sc, struct
 	struct wpi_tx_data *data = &ring->data[desc->idx];
 	struct wpi_tx_stat *stat = (struct wpi_tx_stat *)(desc + 1);
 	struct wpi_node *wn = (struct wpi_node *)data->ni;
+	int s;
 
 	DPRINTFN(4, ("tx done: qid=%d idx=%d retries=%d nkill=%d rate=%x "
 	    "duration=%d status=%x\n", desc->qid, desc->idx, stat->ntries,
 	    stat->nkill, stat->rate, le32toh(stat->duration),
 	    le32toh(stat->status)));
 
+	s = splnet();
+
 	/*
 	 * Update rate control statistics for the node.
 	 * XXX we should not count mgmt frames since they're always sent at
@@ -1636,7 +1665,9 @@ wpi_tx_intr(struct wpi_softc *sc, struct
 
 	sc->sc_tx_timer = 0;
 	ifp->if_flags &= ~IFF_OACTIVE;
-	if_schedule_deferred_start(ifp);
+	wpi_start(ifp);
+
+	splx(s);
 }
 
 static void
@@ -1666,6 +1697,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp =  ic->ic_ifp;
 	uint32_t hw;
+	int s;
 
 	bus_dmamap_sync(sc->sc_dmat, sc->shared_dma.map, 0,
 	    sizeof(struct wpi_shared), BUS_DMASYNC_POSTREAD);
@@ -1721,6 +1753,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 			DPRINTF(("state changed to %x\n", le32toh(*status)));
 
 			if (le32toh(*status) & 1) {
+				s = splnet();
 				/* the radio button has to be pushed */
 				/* wake up thread to signal powerd */
 				cv_signal(&sc->sc_rsw_cv);
@@ -1729,6 +1762,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 				/* turn the interface down */
 				ifp->if_flags &= ~IFF_UP;
 				wpi_stop(ifp, 1);
+				splx(s);
 				return;	/* no further processing */
 			}
 			break;
@@ -1757,10 +1791,11 @@ wpi_notif_intr(struct wpi_softc *sc)
 			DPRINTF(("scan finished nchan=%d status=%d chan=%d\n",
 			    scan->nchan, scan->status, scan->chan));
 
+			s = splnet();
 			sc->is_scanning = false;
 			if (ic->ic_state == IEEE80211_S_SCAN)
 				ieee80211_next_scan(ic);
-
+			splx(s);
 			break;
 		}
 		}
@@ -1777,7 +1812,6 @@ static int
 wpi_intr(void *arg)
 {
 	struct wpi_softc *sc = arg;
-	struct ifnet *ifp = sc->sc_ic.ic_ifp;
 	uint32_t r;
 
 	r = WPI_READ(sc, WPI_INTR);
@@ -1788,6 +1822,22 @@ wpi_intr(void *arg)
 
 	/* disable interrupts */
 	WPI_WRITE(sc, WPI_MASK, 0);
+
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+wpi_softintr(void *arg)
+{
+	struct wpi_softc *sc = arg;
+	struct ifnet *ifp = sc->sc_ic.ic_ifp;
+	uint32_t r;
+
+	r = WPI_READ(sc, WPI_INTR);
+	if (r == 0 || r == 0xffffffff)
+		goto out;
+
 	/* ack interrupts */
 	WPI_WRITE(sc, WPI_INTR, r);
 
@@ -1796,7 +1846,7 @@ wpi_intr(void *arg)
 		aprint_error_dev(sc->sc_dev, "fatal firmware error\n");
 		ifp->if_flags &= ~IFF_UP;
 		wpi_stop(ifp, 1);
-		return 1;
+		return;
 	}
 
 	if (r & WPI_RX_INTR)
@@ -1805,11 +1855,10 @@ wpi_intr(void *arg)
 	if (r & WPI_ALIVE_INTR)	/* firmware initialized */
 		wakeup(sc);
 
+ out:
 	/* re-enable interrupts */
 	if (ifp->if_flags & IFF_UP)
 		WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK);
-
-	return 1;
 }
 
 static uint8_t

Index: src/sys/dev/pci/if_wpivar.h
diff -u src/sys/dev/pci/if_wpivar.h:1.20 src/sys/dev/pci/if_wpivar.h:1.21
--- src/sys/dev/pci/if_wpivar.h:1.20	Thu Feb  2 03:41:22 2017
+++ src/sys/dev/pci/if_wpivar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*  $NetBSD: if_wpivar.h,v 1.20 2017/02/02 03:41:22 jakllsch Exp $    */
+/*  $NetBSD: if_wpivar.h,v 1.21 2017/02/02 10:05:35 nonaka Exp $    */
 
 /*-
  * Copyright (c) 2006
@@ -150,6 +150,7 @@ struct wpi_softc {
 	bus_space_tag_t		sc_st;
 	bus_space_handle_t	sc_sh;
 	void 			*sc_ih;
+	void			*sc_soft_ih;
 	pci_intr_handle_t	*sc_pihp;
 	pci_chipset_tag_t	sc_pct;
 	pcitag_t		sc_pcitag;

Index: src/sys/dev/pcmcia/if_malo_pcmcia.c
diff -u src/sys/dev/pcmcia/if_malo_pcmcia.c:1.12 src/sys/dev/pcmcia/if_malo_pcmcia.c:1.13
--- src/sys/dev/pcmcia/if_malo_pcmcia.c:1.12	Thu Dec 15 09:28:06 2016
+++ src/sys/dev/pcmcia/if_malo_pcmcia.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_malo_pcmcia.c,v 1.12 2016/12/15 09:28:06 ozaki-r Exp $	*/
+/*	$NetBSD: if_malo_pcmcia.c,v 1.13 2017/02/02 10:05:35 nonaka Exp $	*/
 /*      $OpenBSD: if_malo.c,v 1.65 2009/03/29 21:53:53 sthen Exp $ */
 
 /*
@@ -18,7 +18,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_malo_pcmcia.c,v 1.12 2016/12/15 09:28:06 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_malo_pcmcia.c,v 1.13 2017/02/02 10:05:35 nonaka Exp $");
 
 #ifdef _MODULE
 #include <sys/module.h>
@@ -82,6 +82,7 @@ static void	malo_pcmcia_disable(struct m
 static void	cmalo_attach(void *);
 static void	cmalo_detach(void *);
 static int	cmalo_intr(void *);
+static void	cmalo_softintr(void *);
 
 static void	cmalo_start(struct ifnet *);
 static int	cmalo_ioctl(struct ifnet *, u_long, void *);
@@ -178,6 +179,12 @@ malo_pcmcia_attach(device_t parent, devi
 		return;
 	}
 
+	sc->sc_soft_ih = softint_establish(SOFTINT_NET, cmalo_softintr, sc);
+	if (sc->sc_soft_ih == NULL) {
+		aprint_error_dev(self, "couldn't establish softint\n");
+		return;
+	}
+
 	malo_pcmcia_enable(sc);
 
 	cfe = pa->pf->cfe;
@@ -199,6 +206,9 @@ fail:
 	if (sc->sc_flags & MALO_DEVICE_ATTACHED)
 		return;
 
+	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
+
 	pcmcia_function_unconfigure(pa->pf);
 	return;
 }
@@ -211,6 +221,8 @@ malo_pcmcia_detach(device_t dev, int fla
 
 	cmalo_detach(sc);
 	malo_pcmcia_disable(sc);
+	softint_disestablish(sc->sc_soft_ih);
+	sc->sc_soft_ih = NULL;
 	pcmcia_function_unconfigure(psc->sc_pf);
 
 	return 0;
@@ -355,9 +367,11 @@ cmalo_attach(void *arg)
 	}
 
 	/* attach interface */
-	if_attach(ifp);
-	if_deferred_start_init(ifp, NULL);
+	if_initialize(ifp);
 	ieee80211_ifattach(ic);
+	/* Use common softint-based if_input */
+	ifp->if_percpuq = if_percpuq_create(ifp);
+	if_register(ifp);
 
 	sc->sc_newstate = ic->ic_newstate;
 	ic->ic_newstate = cmalo_newstate;
@@ -414,7 +428,7 @@ static int
 cmalo_intr(void *arg)
 {
 	struct malo_softc *sc = arg;
-	uint16_t intr = 0;
+	uint16_t intr;
 
 	/* read interrupt reason */
 	intr = MALO_READ_2(sc, MALO_REG_HOST_INTR_CAUSE);
@@ -428,16 +442,28 @@ cmalo_intr(void *arg)
 	/* disable interrupts */
 	cmalo_intr_mask(sc, 0);
 
+	DPRINTF(2, "%s: interrupt handler called (intr = 0x%04x)\n",
+	    device_xname(sc->sc_dev), intr);
+
+	softint_schedule(sc->sc_soft_ih);
+	return 1;
+}
+
+static void
+cmalo_softintr(void *arg)
+{
+	struct malo_softc *sc = arg;
+	uint16_t intr;
+
+	/* read interrupt reason */
+	intr = MALO_READ_2(sc, MALO_REG_HOST_INTR_CAUSE);
+	if (intr == 0 || intr == 0xffff)
+		goto out;
+
 	/* acknowledge interrupt */
 	MALO_WRITE_2(sc, MALO_REG_HOST_INTR_CAUSE,
 	    intr & MALO_VAL_HOST_INTR_MASK_ON);
 
-	/* enable interrupts */
-	cmalo_intr_mask(sc, 1);
-
-	DPRINTF(2, "%s: interrupt handler called (intr = 0x%04x)\n",
-	    device_xname(sc->sc_dev), intr);
-
 	if (intr & MALO_VAL_HOST_INTR_TX)
 		/* TX frame sent */
 		cmalo_tx_done(sc);
@@ -456,7 +482,9 @@ cmalo_intr(void *arg)
 		/* event */
 		cmalo_event(sc);
 
-	return 1;
+ out:
+	/* enable interrupts */
+	cmalo_intr_mask(sc, 1);
 }
 
 
@@ -914,7 +942,7 @@ static void
 cmalo_stop(struct malo_softc *sc)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
-        struct ifnet *ifp = &sc->sc_if;
+	struct ifnet *ifp = &sc->sc_if;
 
 	/* device down */
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
@@ -1060,13 +1088,16 @@ static void
 cmalo_tx_done(struct malo_softc *sc)
 {
 	struct ifnet *ifp = &sc->sc_if;
+	int s;
 
 	DPRINTF(2, "%s: TX done\n", device_xname(sc->sc_dev));
 
+	s = splnet();
 	ifp->if_opackets++;
 	ifp->if_flags &= ~IFF_OACTIVE;
 	ifp->if_timer = 0;
-	if_schedule_deferred_start(ifp);
+	cmalo_start(ifp);
+	splx(s);
 }
 
 static void

Index: src/sys/dev/pcmcia/if_malo_pcmciavar.h
diff -u src/sys/dev/pcmcia/if_malo_pcmciavar.h:1.2 src/sys/dev/pcmcia/if_malo_pcmciavar.h:1.3
--- src/sys/dev/pcmcia/if_malo_pcmciavar.h:1.2	Mon May 12 02:26:19 2014
+++ src/sys/dev/pcmcia/if_malo_pcmciavar.h	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_malo_pcmciavar.h,v 1.2 2014/05/12 02:26:19 christos Exp $	*/
+/*	$NetBSD: if_malo_pcmciavar.h,v 1.3 2017/02/02 10:05:35 nonaka Exp $	*/
 /*	$OpenBSD: if_malovar.h,v 1.27 2007/10/09 20:37:32 mglocker Exp $ */
 
 /*
@@ -367,6 +367,7 @@ struct malo_softc {
 	struct ethercom		 sc_ec;
 #define sc_if	sc_ec.ec_if
 	struct ieee80211com	 sc_ic;
+	void			*sc_soft_ih;
 	bus_space_tag_t		 sc_iot;
 	bus_space_handle_t	 sc_ioh;
 	int			 (*sc_newstate)

Index: src/sys/net80211/ieee80211_input.c
diff -u src/sys/net80211/ieee80211_input.c:1.86 src/sys/net80211/ieee80211_input.c:1.87
--- src/sys/net80211/ieee80211_input.c:1.86	Thu Dec 15 09:28:06 2016
+++ src/sys/net80211/ieee80211_input.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ieee80211_input.c,v 1.86 2016/12/15 09:28:06 ozaki-r Exp $	*/
+/*	$NetBSD: ieee80211_input.c,v 1.87 2017/02/02 10:05:35 nonaka Exp $	*/
 /*-
  * Copyright (c) 2001 Atsushi Onoe
  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@@ -36,7 +36,7 @@
 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_input.c,v 1.81 2005/08/10 16:22:29 sam Exp $");
 #endif
 #ifdef __NetBSD__
-__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.86 2016/12/15 09:28:06 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.87 2017/02/02 10:05:35 nonaka Exp $");
 #endif
 
 #ifdef _KERNEL_OPT
@@ -59,6 +59,7 @@ __KERNEL_RCSID(0, "$NetBSD: ieee80211_in
 #include <sys/errno.h>
 #include <sys/proc.h>
 #include <sys/sysctl.h>
+#include <sys/cpu.h>
 
 #include <net/if.h>
 #include <net/if_media.h>
@@ -175,6 +176,8 @@ ieee80211_input(struct ieee80211com *ic,
 	u_int16_t rxseq;
 	IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]);
 
+	KASSERT(!cpu_intr_p());
+
 	IASSERT(ni != NULL, ("null node"));
 	ni->ni_inact = ni->ni_inact_reload;
 

Index: src/sys/net80211/ieee80211_proto.c
diff -u src/sys/net80211/ieee80211_proto.c:1.33 src/sys/net80211/ieee80211_proto.c:1.34
--- src/sys/net80211/ieee80211_proto.c:1.33	Thu Jul  7 06:55:43 2016
+++ src/sys/net80211/ieee80211_proto.c	Thu Feb  2 10:05:35 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ieee80211_proto.c,v 1.33 2016/07/07 06:55:43 msaitoh Exp $	*/
+/*	$NetBSD: ieee80211_proto.c,v 1.34 2017/02/02 10:05:35 nonaka Exp $	*/
 /*-
  * Copyright (c) 2001 Atsushi Onoe
  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
@@ -36,7 +36,7 @@
 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.23 2005/08/10 16:22:29 sam Exp $");
 #endif
 #ifdef __NetBSD__
-__KERNEL_RCSID(0, "$NetBSD: ieee80211_proto.c,v 1.33 2016/07/07 06:55:43 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ieee80211_proto.c,v 1.34 2017/02/02 10:05:35 nonaka Exp $");
 #endif
 
 /*
@@ -57,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: ieee80211_pr
 #include <sys/errno.h>
 #include <sys/proc.h>
 #include <sys/sysctl.h>
+#include <sys/cpu.h>
 
 #include <net/if.h>
 #include <net/if_media.h>
@@ -918,6 +919,8 @@ ieee80211_newstate(struct ieee80211com *
 	struct ieee80211_node *ni;
 	enum ieee80211_state ostate;
 
+	KASSERT(!cpu_intr_p());
+
 	ostate = ic->ic_state;
 	IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__,
 		ieee80211_state_name[ostate], ieee80211_state_name[nstate]);

Reply via email to