Add two sanity checks to iwm's firmware notification interrupt handler:

1) Clamp the firmware-provided index into the rx ring to the size of the ring.
Linux started doing this, too, to work around HW bugs in the 9000 series.

2) Don't call iwm_cmd_done() if the firmware response in the Rx buffer
is not recognized. We should just skip such buffers, not act on them.

Not tested on hardware yet; these changes evidenty shouldn't break anything.

ok?

diff 74c6ffce73f932dd8464cc1def1ee4fcaa3e671f /usr/src
blob - 335033d21091a23511403804f09d1548b109b104
file + sys/dev/pci/if_iwm.c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -7000,10 +7000,11 @@ iwm_notif_intr(struct iwm_softc *sc)
            0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD);
 
        hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff;
+       hw &= (IWM_RX_RING_COUNT - 1);
        while (sc->rxq.cur != hw) {
                struct iwm_rx_data *data = &sc->rxq.data[sc->rxq.cur];
                struct iwm_rx_packet *pkt;
-               int qid, idx, code;
+               int qid, idx, code, handled = 1;
 
                bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof(*pkt),
                    BUS_DMASYNC_POSTREAD);
@@ -7256,6 +7257,7 @@ iwm_notif_intr(struct iwm_softc *sc)
                }
 
                default:
+                       handled = 0;
                        printf("%s: unhandled firmware response 0x%x/0x%x "
                            "rx ring %d[%d]\n",
                            DEVNAME(sc), pkt->hdr.code, pkt->len_n_flags, qid,
@@ -7270,7 +7272,7 @@ iwm_notif_intr(struct iwm_softc *sc)
                 * For example, uCode issues IWM_REPLY_RX when it sends a
                 * received frame to the driver.
                 */
-               if (!(pkt->hdr.qid & (1 << 7))) {
+               if (handled && !(pkt->hdr.qid & (1 << 7))) {
                        iwm_cmd_done(sc, pkt);
                }
 

Reply via email to