Skip to content

Commit

Permalink
iwm: use per-Tx-queue interface timers to ensure that the interface w…
Browse files Browse the repository at this point in the history
…atchdog will trigger a device timeout if a particular Tx queue gets stuck while other Tx queues keep working.

openbsd/src@f2e5212
  • Loading branch information
zxystd committed Mar 9, 2024
1 parent ef2e076 commit 43c7d6a
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 22 deletions.
2 changes: 1 addition & 1 deletion itlwm/hal_iwm/if_iwmvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
54 changes: 33 additions & 21 deletions itlwm/hal_iwm/mac80211.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
Expand Down

0 comments on commit 43c7d6a

Please sign in to comment.