From: Stefan Sperling Subject: Re: sys/qwz: add AMPDU callbacks To: tech@openbsd.org Date: Tue, 26 May 2026 15:46:50 +0200 On Tue, May 26, 2026 at 03:24:05PM +0200, Kirill A. Korinsky wrote: > tech@, > > here I added the same BlockAck task and AMPDU callback plumbing used by qwx. > > This wires net80211 ADDBA/DELBA handling into the existing qwz RX > TID/reorder setup code, while leaving TX aggregation to firmware as qwx. > Ok? Looks good to me! ok. > Index: sys/dev/ic/qwz.c > =================================================================== > RCS file: /home/cvs/src/sys/dev/ic/qwz.c,v > diff -u -p -r1.36 qwz.c > --- sys/dev/ic/qwz.c 25 May 2026 20:33:58 -0000 1.36 > +++ sys/dev/ic/qwz.c 26 May 2026 13:11:21 -0000 > @@ -345,6 +345,7 @@ qwz_stop(struct ifnet *ifp) > task_del(systq, &sc->init_task); > qwz_del_task(sc, sc->sc_nswq, &sc->newstate_task); > qwz_del_task(sc, systq, &sc->setkey_task); > + qwz_del_task(sc, systq, &sc->ba_task); > refcnt_finalize(&sc->task_refs, "qwzstop"); > > qwz_setkey_clear(sc); > @@ -868,9 +869,7 @@ qwz_newstate(struct ieee80211com *ic, en > nstate != IEEE80211_S_AUTH) > return 0; > if (ic->ic_state == IEEE80211_S_RUN) { > -#if 0 > qwz_del_task(sc, systq, &sc->ba_task); > -#endif > qwz_del_task(sc, systq, &sc->setkey_task); > qwz_setkey_clear(sc); > #if 0 > @@ -24432,6 +24431,116 @@ qwz_peer_assoc_prepare(struct qwz_softc > /* TODO: amsdu_disable req? */ > } > > +void > +qwz_rx_agg_start(struct qwz_softc *sc, struct ieee80211_node *ni, uint8_t tid, > + uint16_t ssn, uint16_t winsize) > +{ > + struct ieee80211com *ic = &sc->sc_ic; > + struct qwz_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + uint8_t pdev_id = 0; /* XXX derive pdev ID somehow */ > + enum hal_pn_type pn_type; > + > + if (!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, sc->sc_flags) && > + (ic->ic_flags & IEEE80211_F_RSNON)) > + pn_type = HAL_PN_TYPE_WPA; > + else > + pn_type = HAL_PN_TYPE_NONE; > + > + if (qwz_peer_rx_tid_setup(sc, ni, arvif->vdev_id, pdev_id, tid, > + winsize, ssn, pn_type)) > + ieee80211_addba_req_refuse(ic, ni, tid); > + else > + ieee80211_addba_req_accept(ic, ni, tid); > +} > + > +void > +qwz_rx_agg_stop(struct qwz_softc *sc, struct ieee80211_node *ni, uint8_t tid) > +{ > + struct qwz_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ > + uint8_t pdev_id = 0; /* XXX derive pdev ID somehow */ > + struct qwz_node *nq = (struct qwz_node *)ni; > + struct ath12k_peer *peer = &nq->peer; > + uint64_t paddr; > + int ret; > + > + if (peer->peer_id == HAL_INVALID_PEERID) > + return; > + > + if (!peer->rx_tid[tid].active) > + return; > + > + ret = qwz_peer_rx_tid_reo_update(sc, peer, &peer->rx_tid[tid], > + 1, 0, 0); > + if (ret) { > + printf("%s: failed to update reo for rx tid %d: %d\n", > + sc->sc_dev.dv_xname, tid, ret); > + } > + > + paddr = peer->rx_tid[tid].paddr; > + ret = qwz_wmi_peer_rx_reorder_queue_setup(sc, arvif->vdev_id, pdev_id, > + ni->ni_macaddr, paddr, tid, 1, 1); > + if (ret) { > + printf("%s: failed to send wmi to delete rx tid %d\n", > + sc->sc_dev.dv_xname, ret); > + } > +} > + > +void > +qwz_ba_task(void *arg) > +{ > + struct qwz_softc *sc = arg; > + struct ieee80211com *ic = &sc->sc_ic; > + struct ieee80211_node *ni = ic->ic_bss; > + int s = splnet(); > + int tid; > + > + for (tid = 0; tid < IEEE80211_NUM_TID; tid++) { > + if (test_bit(ATH12K_FLAG_CRASH_FLUSH, sc->sc_flags)) > + break; > + if (sc->ba_rx.start_tidmask & (1 << tid)) { > + struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid]; > + qwz_rx_agg_start(sc, ni, tid, ba->ba_winstart, > + ba->ba_winsize); > + sc->ba_rx.start_tidmask &= ~(1 << tid); > + } else if (sc->ba_rx.stop_tidmask & (1 << tid)) { > + qwz_rx_agg_stop(sc, ni, tid); > + sc->ba_rx.stop_tidmask &= ~(1 << tid); > + } > + } > + > + refcnt_rele_wake(&sc->task_refs); > + splx(s); > +} > + > +int > +qwz_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni, > + uint8_t tid) > +{ > + struct qwz_softc *sc = ic->ic_softc; > + > + sc->ba_rx.start_tidmask |= (1 << tid); > + qwz_add_task(sc, systq, &sc->ba_task); > + return EBUSY; > +} > + > +void > +qwz_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni, > + uint8_t tid) > +{ > + struct qwz_softc *sc = ic->ic_softc; > + > + sc->ba_rx.stop_tidmask |= (1 << tid); > + qwz_add_task(sc, systq, &sc->ba_task); > +} > + > +int > +qwz_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni, > + uint8_t tid) > +{ > + /* Firmware handles Tx aggregation internally. */ > + return 0; > +} > + > int > qwz_run(struct qwz_softc *sc) > { > @@ -24608,6 +24717,7 @@ qwz_attach(struct qwz_softc *sc) > task_set(&sc->init_task, qwz_init_task, sc); > task_set(&sc->newstate_task, qwz_newstate_task, sc); > task_set(&sc->setkey_task, qwz_setkey_task, sc); > + task_set(&sc->ba_task, qwz_ba_task, sc); > timeout_set_proc(&sc->scan.timeout, qwz_scan_timeout, sc); > #if NBPFILTER > 0 > qwz_radiotap_attach(sc); > Index: sys/dev/ic/qwzvar.h > =================================================================== > RCS file: /home/cvs/src/sys/dev/ic/qwzvar.h,v > diff -u -p -r1.17 qwzvar.h > --- sys/dev/ic/qwzvar.h 19 May 2026 04:17:51 -0000 1.17 > +++ sys/dev/ic/qwzvar.h 26 May 2026 13:10:36 -0000 > @@ -1910,6 +1910,11 @@ struct qwz_setkey_task_arg { > #define QWZ_DEL_KEY 2 > }; > > +struct qwz_ba_task_data { > + uint32_t start_tidmask; > + uint32_t stop_tidmask; > +}; > + > struct qwz_softc { > struct device sc_dev; > struct ieee80211com sc_ic; > @@ -1944,6 +1949,10 @@ struct qwz_softc { > int install_key_done; > int install_key_status; > > + /* Task for firmware BlockAck setup/teardown and its arguments. */ > + struct task ba_task; > + struct qwz_ba_task_data ba_rx; > + > enum ath12k_11d_state state_11d; > int completed_11d_scan; > uint32_t vdev_id_11d_scan; > @@ -2161,6 +2170,12 @@ int qwz_set_key(struct ieee80211com *, s > struct ieee80211_key *); > void qwz_delete_key(struct ieee80211com *, struct ieee80211_node *, > struct ieee80211_key *); > +int qwz_ampdu_rx_start(struct ieee80211com *, struct ieee80211_node *, > + uint8_t); > +void qwz_ampdu_rx_stop(struct ieee80211com *, struct ieee80211_node *, > + uint8_t); > +int qwz_ampdu_tx_start(struct ieee80211com *, struct ieee80211_node *, > + uint8_t); > > void qwz_qrtr_recv_msg(struct qwz_softc *, struct mbuf *); > > Index: sys/dev/pci/if_qwz_pci.c > =================================================================== > RCS file: /home/cvs/src/sys/dev/pci/if_qwz_pci.c,v > diff -u -p -r1.11 if_qwz_pci.c > --- sys/dev/pci/if_qwz_pci.c 18 May 2026 13:47:32 -0000 1.11 > +++ sys/dev/pci/if_qwz_pci.c 26 May 2026 13:10:36 -0000 > @@ -1007,6 +1007,10 @@ qwz_pci_attach(struct device *parent, st > ic->ic_updateedca = qwz_updateedca; > ic->ic_updatedtim = qwz_updatedtim; > #endif > + ic->ic_ampdu_rx_start = qwz_ampdu_rx_start; > + ic->ic_ampdu_rx_stop = qwz_ampdu_rx_stop; > + ic->ic_ampdu_tx_start = qwz_ampdu_tx_start; > + ic->ic_ampdu_tx_stop = NULL; > /* > * We cannot read the MAC address without loading the > * firmware from disk. Postpone until mountroot is done. > > > -- > wbr, Kirill > >