Module Name: src
Committed By: nonaka
Date: Sun Jan 8 07:42:00 UTC 2017
Modified Files:
src/sys/dev/pci: if_iwm.c if_iwmvar.h
Log Message:
iwm(4): make interrupt routine running on softint context.
see http://mail-index.netbsd.org/tech-kern/2016/12/06/msg021281.html
To generate a diff of this commit:
cvs rdiff -u -r1.49 -r1.50 src/sys/dev/pci/if_iwm.c
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/pci/if_iwmvar.h
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/pci/if_iwm.c
diff -u src/sys/dev/pci/if_iwm.c:1.49 src/sys/dev/pci/if_iwm.c:1.50
--- src/sys/dev/pci/if_iwm.c:1.49 Sun Jan 8 06:49:10 2017
+++ src/sys/dev/pci/if_iwm.c Sun Jan 8 07:42:00 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: if_iwm.c,v 1.49 2017/01/08 06:49:10 nonaka Exp $ */
+/* $NetBSD: if_iwm.c,v 1.50 2017/01/08 07:42:00 nonaka Exp $ */
/* OpenBSD: if_iwm.c,v 1.147 2016/11/17 14:12:33 stsp Exp */
#define IEEE80211_NO_HT
/*
@@ -107,7 +107,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.49 2017/01/08 06:49:10 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.50 2017/01/08 07:42:00 nonaka Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@@ -455,7 +455,7 @@ static int iwm_setrates(struct iwm_node
static int iwm_media_change(struct ifnet *);
static void iwm_newstate_cb(struct work *, void *);
static int iwm_newstate(struct ieee80211com *, enum ieee80211_state, int);
-static void iwm_endscan_cb(struct work *, void *);
+static void iwm_endscan(struct iwm_softc *);
static void iwm_fill_sf_command(struct iwm_softc *, struct iwm_sf_cfg_cmd *,
struct ieee80211_node *);
static int iwm_sf_config(struct iwm_softc *, int);
@@ -474,6 +474,7 @@ static void iwm_nic_error(struct iwm_sof
static void iwm_nic_umac_error(struct iwm_softc *);
#endif
static void iwm_notif_intr(struct iwm_softc *);
+static void iwm_softintr(void *);
static int iwm_intr(void *);
static int iwm_preinit(struct iwm_softc *);
static void iwm_attach_hook(device_t);
@@ -3472,6 +3473,7 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, str
uint32_t len;
uint32_t rx_pkt_status;
int rssi;
+ int s;
bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
BUS_DMASYNC_POSTREAD);
@@ -3519,6 +3521,8 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, str
if (le32toh(phy_info->channel) < __arraycount(ic->ic_channels))
c = &ic->ic_channels[le32toh(phy_info->channel)];
+ s = splnet();
+
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
if (c)
ni->ni_chan = c;
@@ -3568,6 +3572,8 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, str
}
ieee80211_input(ic, m, ni, rssi, device_timestamp);
ieee80211_free_node(ni);
+
+ splx(s);
}
static void
@@ -3639,12 +3645,7 @@ iwm_rx_tx_cmd(struct iwm_softc *sc, stru
sc->qfullmsk &= ~(1 << ring->qid);
if (sc->qfullmsk == 0 && (ifp->if_flags & IFF_OACTIVE)) {
ifp->if_flags &= ~IFF_OACTIVE;
- /*
- * Well, we're in interrupt context, but then again
- * I guess net80211 does all sorts of stunts in
- * interrupt context, so maybe this is no biggie.
- */
- if_schedule_deferred_start(ifp);
+ if_start_lock(ifp);
}
}
}
@@ -5892,9 +5893,8 @@ iwm_newstate(struct ieee80211com *ic, en
}
static void
-iwm_endscan_cb(struct work *work __unused, void *arg)
+iwm_endscan(struct iwm_softc *sc)
{
- struct iwm_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
DPRINTF(("scan ended\n"));
@@ -6311,6 +6311,7 @@ iwm_start(struct ifnet *ifp)
IF_DEQUEUE(&ic->ic_mgtq, m);
if (m) {
ni = M_GETCTX(m, struct ieee80211_node *);
+ M_CLEARCTX(m);
ac = WME_AC_BE;
goto sendit;
}
@@ -6319,8 +6320,9 @@ iwm_start(struct ifnet *ifp)
}
IFQ_DEQUEUE(&ifp->if_snd, m);
- if (!m)
+ if (m == NULL)
break;
+
if (m->m_len < sizeof (*eh) &&
(m = m_pullup(m, sizeof (*eh))) == NULL) {
ifp->if_oerrors++;
@@ -6334,6 +6336,7 @@ iwm_start(struct ifnet *ifp)
ifp->if_oerrors++;
continue;
}
+
/* classify mbuf so we can find which tx ring to use */
if (ieee80211_classify(ic, m, ni) != 0) {
m_freem(m);
@@ -6943,21 +6946,21 @@ iwm_notif_intr(struct iwm_softc *sc)
case IWM_SCAN_ITERATION_COMPLETE: {
struct iwm_lmac_scan_complete_notif *notif;
SYNC_RESP_STRUCT(notif, pkt);
- workqueue_enqueue(sc->sc_eswq, &sc->sc_eswk, NULL);
+ iwm_endscan(sc);
break;
}
case IWM_SCAN_COMPLETE_UMAC: {
struct iwm_umac_scan_complete *notif;
SYNC_RESP_STRUCT(notif, pkt);
- workqueue_enqueue(sc->sc_eswq, &sc->sc_eswk, NULL);
+ iwm_endscan(sc);
break;
}
case IWM_SCAN_ITERATION_COMPLETE_UMAC: {
struct iwm_umac_scan_iter_complete_notif *notif;
SYNC_RESP_STRUCT(notif, pkt);
- workqueue_enqueue(sc->sc_eswq, &sc->sc_eswk, NULL);
+ iwm_endscan(sc);
break;
}
@@ -7017,64 +7020,17 @@ iwm_notif_intr(struct iwm_softc *sc)
IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, hw & ~7);
}
-static int
-iwm_intr(void *arg)
+static void
+iwm_softintr(void *arg)
{
struct iwm_softc *sc = arg;
struct ifnet *ifp = IC2IFP(&sc->sc_ic);
- int handled = 0;
- int r1, r2, rv = 0;
+ uint32_t r1;
int isperiodic = 0;
- IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
-
- if (sc->sc_flags & IWM_FLAG_USE_ICT) {
- uint32_t *ict = sc->ict_dma.vaddr;
- int tmp;
-
- 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;
-
- /*
- * ok, there was something. keep plowing until we have all.
- */
- r1 = r2 = 0;
- while (tmp) {
- r1 |= tmp;
- ict[sc->ict_cur] = 0; /* Acknowledge. */
- bus_dmamap_sync(sc->sc_dmat, sc->ict_dma.map,
- &ict[sc->ict_cur] - ict, sizeof(*ict),
- BUS_DMASYNC_PREWRITE);
- sc->ict_cur = (sc->ict_cur + 1) % IWM_ICT_COUNT;
- tmp = htole32(ict[sc->ict_cur]);
- }
-
- /* this is where the fun begins. don't ask */
- if (r1 == 0xffffffff)
- r1 = 0;
-
- /* i am not expected to understand this */
- if (r1 & 0xc0000)
- r1 |= 0x8000;
- r1 = (0xff & r1) | ((0xff00 & r1) << 16);
- } else {
- r1 = IWM_READ(sc, IWM_CSR_INT);
- if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0)
- goto out;
- r2 = IWM_READ(sc, IWM_CSR_FH_INT_STATUS);
- }
- if (r1 == 0 && r2 == 0) {
- goto out_ena;
- }
-
- IWM_WRITE(sc, IWM_CSR_INT, r1 | ~sc->sc_intmask);
-
- /* ignored */
- handled |= (r1 & (IWM_CSR_INT_BIT_ALIVE /*| IWM_CSR_INT_BIT_SCD*/));
+ r1 = atomic_swap_32(&sc->sc_soft_flags, 0);
+ restart:
if (r1 & IWM_CSR_INT_BIT_SW_ERR) {
#ifdef IWM_DEBUG
int i;
@@ -7095,33 +7051,28 @@ iwm_intr(void *arg)
#endif
aprint_error_dev(sc->sc_dev, "fatal firmware error\n");
+ fatal:
ifp->if_flags &= ~IFF_UP;
iwm_stop(ifp, 1);
- rv = 1;
- goto out;
+ /* Don't restore interrupt mask */
+ return;
}
if (r1 & IWM_CSR_INT_BIT_HW_ERR) {
- handled |= IWM_CSR_INT_BIT_HW_ERR;
aprint_error_dev(sc->sc_dev,
"hardware error, stopping device\n");
- ifp->if_flags &= ~IFF_UP;
- iwm_stop(ifp, 1);
- rv = 1;
- goto out;
+ goto fatal;
}
/* firmware chunk loaded */
if (r1 & IWM_CSR_INT_BIT_FH_TX) {
IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_TX_MASK);
- handled |= IWM_CSR_INT_BIT_FH_TX;
sc->sc_fw_chunk_done = 1;
wakeup(&sc->sc_fw);
}
if (r1 & IWM_CSR_INT_BIT_RF_KILL) {
- handled |= IWM_CSR_INT_BIT_RF_KILL;
if (iwm_check_rfkill(sc) && (ifp->if_flags & IFF_UP)) {
ifp->if_flags &= ~IFF_UP;
iwm_stop(ifp, 1);
@@ -7129,7 +7080,6 @@ iwm_intr(void *arg)
}
if (r1 & IWM_CSR_INT_BIT_RX_PERIODIC) {
- handled |= IWM_CSR_INT_BIT_RX_PERIODIC;
IWM_WRITE(sc, IWM_CSR_INT, IWM_CSR_INT_BIT_RX_PERIODIC);
if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) == 0)
IWM_WRITE_1(sc,
@@ -7139,7 +7089,6 @@ iwm_intr(void *arg)
if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) ||
isperiodic) {
- handled |= (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX);
IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_RX_MASK);
iwm_notif_intr(sc);
@@ -7151,12 +7100,73 @@ iwm_intr(void *arg)
IWM_CSR_INT_PERIODIC_ENA);
}
- rv = 1;
+ r1 = atomic_swap_32(&sc->sc_soft_flags, 0);
+ if (r1 != 0)
+ goto restart;
+
+ iwm_restore_interrupts(sc);
+}
+
+static int
+iwm_intr(void *arg)
+{
+ struct iwm_softc *sc = arg;
+ int r1, r2;
+
+ IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
+
+ if (sc->sc_flags & IWM_FLAG_USE_ICT) {
+ uint32_t *ict = sc->ict_dma.vaddr;
+ int tmp;
+
+ 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;
+
+ /*
+ * ok, there was something. keep plowing until we have all.
+ */
+ r1 = r2 = 0;
+ while (tmp) {
+ r1 |= tmp;
+ ict[sc->ict_cur] = 0; /* Acknowledge. */
+ bus_dmamap_sync(sc->sc_dmat, sc->ict_dma.map,
+ &ict[sc->ict_cur] - ict, sizeof(*ict),
+ BUS_DMASYNC_PREWRITE);
+ sc->ict_cur = (sc->ict_cur + 1) % IWM_ICT_COUNT;
+ tmp = htole32(ict[sc->ict_cur]);
+ }
+
+ /* this is where the fun begins. don't ask */
+ if (r1 == 0xffffffff)
+ r1 = 0;
+
+ /* i am not expected to understand this */
+ if (r1 & 0xc0000)
+ r1 |= 0x8000;
+ r1 = (0xff & r1) | ((0xff00 & r1) << 16);
+ } else {
+ r1 = IWM_READ(sc, IWM_CSR_INT);
+ if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0)
+ goto out;
+ r2 = IWM_READ(sc, IWM_CSR_FH_INT_STATUS);
+ }
+ if (r1 == 0 && r2 == 0) {
+ goto out_ena;
+ }
+
+ IWM_WRITE(sc, IWM_CSR_INT, r1 | ~sc->sc_intmask);
+
+ atomic_or_32(&sc->sc_soft_flags, r1);
+ softint_schedule(sc->sc_soft_ih);
+ return 1;
out_ena:
iwm_restore_interrupts(sc);
out:
- return rv;
+ return 0;
}
/*
@@ -7273,14 +7283,13 @@ iwm_attach(device_t parent, device_t sel
pci_aprint_devinfo(pa, NULL);
- if (workqueue_create(&sc->sc_eswq, "iwmes",
- iwm_endscan_cb, sc, PRI_NONE, IPL_NET, 0))
- panic("%s: could not create workqueue: scan",
- device_xname(self));
if (workqueue_create(&sc->sc_nswq, "iwmns",
iwm_newstate_cb, sc, PRI_NONE, IPL_NET, 0))
panic("%s: could not create workqueue: newstate",
device_xname(self));
+ sc->sc_soft_ih = softint_establish(SOFTINT_NET, iwm_softintr, sc);
+ if (sc->sc_soft_ih == NULL)
+ panic("%s: could not establish softint", device_xname(self));
/*
* Get the offset of the PCI Express Capability Structure in PCI
Index: src/sys/dev/pci/if_iwmvar.h
diff -u src/sys/dev/pci/if_iwmvar.h:1.10 src/sys/dev/pci/if_iwmvar.h:1.11
--- src/sys/dev/pci/if_iwmvar.h:1.10 Sun Dec 18 02:18:29 2016
+++ src/sys/dev/pci/if_iwmvar.h Sun Jan 8 07:42:00 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: if_iwmvar.h,v 1.10 2016/12/18 02:18:29 nonaka Exp $ */
+/* $NetBSD: if_iwmvar.h,v 1.11 2017/01/08 07:42:00 nonaka Exp $ */
/* OpenBSD: if_iwmvar.h,v 1.24 2016/09/21 13:53:18 stsp Exp */
/*
@@ -372,6 +372,8 @@ struct iwm_softc {
pcitag_t sc_pcitag;
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;
@@ -455,8 +457,7 @@ struct iwm_softc {
uint8_t sc_cmd_resp[IWM_CMD_RESP_MAX];
int sc_wantresp;
- struct workqueue *sc_nswq, *sc_eswq;
- struct work sc_eswk;
+ struct workqueue *sc_nswq;
struct iwm_rx_phy_info sc_last_phy_info;
int sc_ampdu_ref;
@@ -471,7 +472,7 @@ struct iwm_softc {
struct sysctllog *sc_clog;
- struct bpf_if * sc_drvbpf;
+ struct bpf_if *sc_drvbpf;
union {
struct iwm_rx_radiotap_header th;