DF-3593 / fix.diff
--- a/sys/dev/netif/bwn/bwn/if_bwn.c +++ b/sys/dev/netif/bwn/bwn/if_bwn.c @@ -5982,6 +5982,25 @@ bwn_dma_handle_txeof(struct bwn_mac *mac, dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot); if (dr == NULL) { device_printf(sc->sc_dev, "failed to parse cookie\n"); return; } + + /* + * A duplicate TX-done for an already completed frame delivers a + * valid cookie whose BODY descriptor was already cleared + * (mt_m == NULL). The firmware is known to emit duplicate TX DONE + * events (see the XXX FIXME in bwn_dma_parse_cookie); completing a + * frame twice NULL-derefs mt_ni and underflows dr_usedslot. + * Peek at the BODY slot (HEADER slots never carry mt_m) and drop + * the status instead. + */ + dr->getdesc(dr, slot, &desc, &meta); + if (!meta->mt_islast) + dr->getdesc(dr, bwn_dma_nextslot(dr, slot), &desc, &meta); + if (meta->mt_m == NULL) { + device_printf(sc->sc_dev, + "%s: duplicate TX status (cookie %#x) ignored\n", + __func__, status->cookie); + return; + } + KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__)); while (1) { @@ -6048,6 +6067,16 @@ bwn_pio_handle_txeof(struct bwn_mac *mac, tq = bwn_pio_parse_cookie(mac, status->cookie, &tp); if (tq == NULL) return; + + /* Duplicate TX-done: packet already completed and free-listed. */ + if (tp->tp_m == NULL) { + device_printf(sc->sc_dev, + "%s: duplicate TX status (cookie %#x) ignored\n", + __func__, status->cookie); + return; + } tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4); tq->tq_free++; |