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); }