Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci iwm(4): make interrupt routine running on softin...



details:   https://anonhg.NetBSD.org/src/rev/967c9ffe0c9a
branches:  trunk
changeset: 820386:967c9ffe0c9a
user:      nonaka <nonaka%NetBSD.org@localhost>
date:      Sun Jan 08 07:42:00 2017 +0000

description:
iwm(4): make interrupt routine running on softint context.

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

diffstat:

 sys/dev/pci/if_iwm.c    |  219 ++++++++++++++++++++++++-----------------------
 sys/dev/pci/if_iwmvar.h |    9 +-
 2 files changed, 119 insertions(+), 109 deletions(-)

diffs (truncated from 393 to 300 lines):

diff -r 640c73566d19 -r 967c9ffe0c9a sys/dev/pci/if_iwm.c
--- a/sys/dev/pci/if_iwm.c      Sun Jan 08 06:49:10 2017 +0000
+++ b/sys/dev/pci/if_iwm.c      Sun Jan 08 07:42:00 2017 +0000
@@ -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_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_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 @@
        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 @@
        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 @@
        }
        ieee80211_input(ic, m, ni, rssi, device_timestamp);
        ieee80211_free_node(ni);
+
+       splx(s);
 }
 
 static void
@@ -3639,12 +3645,7 @@
                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 @@
 }
 
 static void
-iwm_endscan_cb(struct work *work __unused, void *arg)
-{
-       struct iwm_softc *sc = arg;
+iwm_endscan(struct iwm_softc *sc)
+{
        struct ieee80211com *ic = &sc->sc_ic;
 
        DPRINTF(("scan ended\n"));
@@ -6311,6 +6311,7 @@
                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 @@
                }
 
                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 @@
                        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 @@
                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,14 +7020,98 @@
        IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, hw & ~7);
 }
 
+static void
+iwm_softintr(void *arg)
+{
+       struct iwm_softc *sc = arg;
+       struct ifnet *ifp = IC2IFP(&sc->sc_ic);
+       uint32_t r1;
+       int isperiodic = 0;
+
+       r1 = atomic_swap_32(&sc->sc_soft_flags, 0);
+
+ restart:
+       if (r1 & IWM_CSR_INT_BIT_SW_ERR) {
+#ifdef IWM_DEBUG
+               int i;
+
+               iwm_nic_error(sc);
+
+               /* Dump driver status (TX and RX rings) while we're here. */
+               DPRINTF(("driver status:\n"));
+               for (i = 0; i < IWM_MAX_QUEUES; i++) {
+                       struct iwm_tx_ring *ring = &sc->txq[i];
+                       DPRINTF(("  tx ring %2d: qid=%-2d cur=%-3d "
+                           "queued=%-3d\n",
+                           i, ring->qid, ring->cur, ring->queued));
+               }
+               DPRINTF(("  rx ring: cur=%d\n", sc->rxq.cur));
+               DPRINTF(("  802.11 state %s\n",
+                   ieee80211_state_name[sc->sc_ic.ic_state]));
+#endif
+
+               aprint_error_dev(sc->sc_dev, "fatal firmware error\n");
+ fatal:
+               ifp->if_flags &= ~IFF_UP;
+               iwm_stop(ifp, 1);
+               /* Don't restore interrupt mask */
+               return;
+
+       }
+
+       if (r1 & IWM_CSR_INT_BIT_HW_ERR) {
+               aprint_error_dev(sc->sc_dev,
+                   "hardware error, stopping device\n");
+               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);
+               sc->sc_fw_chunk_done = 1;
+               wakeup(&sc->sc_fw);
+       }
+
+       if (r1 & 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);
+               }
+       }
+
+       if (r1 & 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,
+                           IWM_CSR_INT_PERIODIC_REG, IWM_CSR_INT_PERIODIC_DIS);
+               isperiodic = 1;
+       }
+
+       if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) ||
+           isperiodic) {
+               IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_RX_MASK);
+
+               iwm_notif_intr(sc);
+
+               /* enable periodic interrupt, see above */
+               if (r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX) &&
+                   !isperiodic)
+                       IWM_WRITE_1(sc, IWM_CSR_INT_PERIODIC_REG,
+                           IWM_CSR_INT_PERIODIC_ENA);
+       }
+
+       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;
-       struct ifnet *ifp = IC2IFP(&sc->sc_ic);
-       int handled = 0;
-       int r1, r2, rv = 0;
-       int isperiodic = 0;
+       int r1, r2;
 
        IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
 
@@ -7072,91 +7159,14 @@
 
        IWM_WRITE(sc, IWM_CSR_INT, r1 | ~sc->sc_intmask);
 
-       /* ignored */
-       handled |= (r1 & (IWM_CSR_INT_BIT_ALIVE /*| IWM_CSR_INT_BIT_SCD*/));
-
-       if (r1 & IWM_CSR_INT_BIT_SW_ERR) {
-#ifdef IWM_DEBUG
-               int i;
-
-               iwm_nic_error(sc);
-
-               /* Dump driver status (TX and RX rings) while we're here. */
-               DPRINTF(("driver status:\n"));
-               for (i = 0; i < IWM_MAX_QUEUES; i++) {
-                       struct iwm_tx_ring *ring = &sc->txq[i];
-                       DPRINTF(("  tx ring %2d: qid=%-2d cur=%-3d "
-                           "queued=%-3d\n",
-                           i, ring->qid, ring->cur, ring->queued));
-               }
-               DPRINTF(("  rx ring: cur=%d\n", sc->rxq.cur));
-               DPRINTF(("  802.11 state %s\n",
-                   ieee80211_state_name[sc->sc_ic.ic_state]));
-#endif
-
-               aprint_error_dev(sc->sc_dev, "fatal firmware error\n");
-               ifp->if_flags &= ~IFF_UP;
-               iwm_stop(ifp, 1);
-               rv = 1;
-               goto out;
-
-       }
-
-       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;
-       }
-
-       /* 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);
-               }



Home | Main Index | Thread Index | Old Index