From 43c7d6ad349d2a994c07fe5d3aa1be6e95deee51 Mon Sep 17 00:00:00 2001 From: zxystd <1051244836@qq.com> Date: Sat, 9 Mar 2024 22:57:08 +0800 Subject: [PATCH] iwm: use per-Tx-queue interface timers to ensure that the interface watchdog will trigger a device timeout if a particular Tx queue gets stuck while other Tx queues keep working. https://github.com/openbsd/src/commit/f2e5212624567973232a5a618335b62f7fd013da --- itlwm/hal_iwm/if_iwmvar.h | 2 +- itlwm/hal_iwm/mac80211.cpp | 54 +++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/itlwm/hal_iwm/if_iwmvar.h b/itlwm/hal_iwm/if_iwmvar.h index 8624e10e..bc849305 100644 --- a/itlwm/hal_iwm/if_iwmvar.h +++ b/itlwm/hal_iwm/if_iwmvar.h @@ -628,7 +628,7 @@ struct iwm_softc { struct iwm_bf_data sc_bf; - int sc_tx_timer; + int sc_tx_timer[IWM_MAX_QUEUES]; int sc_rx_ba_sessions; int sc_scan_last_antenna; diff --git a/itlwm/hal_iwm/mac80211.cpp b/itlwm/hal_iwm/mac80211.cpp index a86bf36e..994e7e6a 100644 --- a/itlwm/hal_iwm/mac80211.cpp +++ b/itlwm/hal_iwm/mac80211.cpp @@ -1179,7 +1179,7 @@ iwm_rx_tx_ba_notif(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_r if (qid != IWM_FIRST_AGG_TX_QUEUE + ba_notif->tid) return; - sc->sc_tx_timer = 0; + sc->sc_tx_timer[qid] = 0; ba = &ni->ni_tx_ba[ba_notif->tid]; if (ba->ba_state != IEEE80211_BA_AGREED) @@ -1237,8 +1237,6 @@ iwm_ampdu_tx_done(struct iwm_softc *sc, struct iwm_cmd_header *cmd_hdr, status != IWM_TX_STATUS_DIRECT_DONE); struct ieee80211_tx_ba *ba; - sc->sc_tx_timer = 0; - if (ic->ic_state != IEEE80211_S_RUN) return; @@ -1444,8 +1442,8 @@ iwm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct iwm_cmd_header *cmd_hdr = &pkt->hdr; int idx = cmd_hdr->idx; int qid = cmd_hdr->qid; - struct iwm_tx_ring *ring = &sc->txq[qid]; - struct iwm_tx_data *txd = &ring->data[idx]; + struct iwm_tx_ring *ring; + struct iwm_tx_data *txd; struct iwm_tx_resp *tx_resp = (struct iwm_tx_resp *)pkt->data; uint32_t ssn; uint32_t len = iwm_rx_packet_len(pkt); @@ -1454,8 +1452,6 @@ iwm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt, bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE, BUS_DMASYNC_POSTREAD); - sc->sc_tx_timer = 0; - /* Sanity checks. */ if (sizeof(*tx_resp) > len) return; @@ -1467,6 +1463,11 @@ iwm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt, tx_resp->frame_count * sizeof(struct iwm_agg_tx_status) > len) return; + sc->sc_tx_timer[qid] = 0; + + ring = &sc->txq[qid]; + txd = &ring->data[idx]; + if (tx_resp->frame_count > 1) { for (int i = 0; i < tx_resp->frame_count; i++) { struct iwm_agg_tx_status *frame_status = iwl_mvm_get_agg_status(sc, tx_resp); @@ -1899,6 +1900,9 @@ iwm_tx(struct iwm_softc *sc, mbuf_t m, struct ieee80211_node *ni, int ac) sc->qfullmsk |= 1 << ring->qid; } + if (ic->ic_if.if_flags & IFF_UP) + sc->sc_tx_timer[ring->qid] = 15; + return 0; } @@ -3581,10 +3585,8 @@ _iwm_start_task(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3 } ifp->netStat->outputPackets++; - if (ifp->if_flags & IFF_UP) { - sc->sc_tx_timer = 15; + if (ifp->if_flags & IFF_UP) ifp->if_timer = 1; - } } return kIOReturnSuccess; @@ -3667,7 +3669,8 @@ iwm_stop(struct _ifnet *ifp) iwm_clear_reorder_buffer(sc, rxba); } iwm_led_blink_stop(sc); - ifp->if_timer = sc->sc_tx_timer = 0; + memset(sc->sc_tx_timer, 0, sizeof(sc->sc_tx_timer)); + ifp->if_timer = 0; splx(s); } @@ -3677,22 +3680,31 @@ iwm_watchdog(struct _ifnet *ifp) { struct iwm_softc *sc = (struct iwm_softc *)ifp->if_softc; ItlIwm *that = container_of(sc, ItlIwm, com); + int i; ifp->if_timer = 0; - if (sc->sc_tx_timer > 0) { - if (--sc->sc_tx_timer == 0) { - XYLog("%s: device timeout\n", DEVNAME(sc)); + + /* + * We maintain a separate timer for each Tx queue because + * Tx aggregation queues can get "stuck" while other queues + * keep working. The Linux driver uses a similar workaround. + */ + for (i = 0; i < nitems(sc->sc_tx_timer); i++) { + if (sc->sc_tx_timer[i] > 0) { + if (--sc->sc_tx_timer[i] == 0) { + XYLog("%s: device timeout\n", DEVNAME(sc)); #ifdef IWM_DEBUG - that->iwm_nic_error(sc); + that->iwm_nic_error(sc); #endif - if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0) { - task_add(systq, &sc->init_task); + if ((sc->sc_flags & IWM_FLAG_SHUTDOWN) == 0) { + task_add(systq, &sc->init_task); + } + XYLog("%s %d OUTPUT_ERROR\n", __FUNCTION__, __LINE__); + ifp->netStat->outputErrors++; + return; } - XYLog("%s %d OUTPUT_ERROR\n", __FUNCTION__, __LINE__); - ifp->netStat->outputErrors++; - return; + ifp->if_timer = 1; } - ifp->if_timer = 1; } ieee80211_watchdog(ifp);