call if_input only once per Rx interrupt from net80211

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

call if_input only once per Rx interrupt from net80211

Stefan Sperling-5
robert@ noticed that iwm(4) Rx throughput increased after running:
        sysctl net.link.ifrxq.pressure_drop=32
The default value for this sysctl is 8.

dlg@ explained the problem to me:
[[[
the pressure stuff counts the number of times ifiq_input (which is
called from if_input) gets called before a corresponding ifiq_process
call gets run. if ifiq_input gets called a lot before ifiq_process runs,
pressure builds up and after ifiq_pressure_drop calls it will shed load
by dropping packets.

ifiq_input is built to handle a list of packets built by processing
the rx ring of a nic in a single interrupt. every hw interrupt should
cause a single ifiq_input call. the list is hopefully processed in nettq
in between the hw interrupts, but the pressure thresholds give you a bit
of leeway.
]]]

The wifi stack currently calls if_input once per packet instead of once
per interrupt. To make the wifi layer play nicely with the network stack
we can split ieee80211_input() into two parts:
 
1) enqueue frames pulled from hardware to an mbuf list: ieee80211_input()
1) deliver frames to network stack via if_input: ieee80211_input_flush()

Existing ieee80211_input() calls don't need to be adjusted because
enqueuing happens under the hood onto a new mbuf list in ieee80211com.
Drivers call ieee80211_input_flush() once per Rx interrupt.

This diff touches all drivers and should be tested on as many drivers
as possible. While these changes are mostly mechanical, a lot of this
touches legacy drivers which I cannot easily test.
Please thoroughly review for errors.

bwfm(4) does not use ieee80211_input() for data frames but has the
same bug and will need to be fixed separately (patrick@ is aware).

I expect that 11n mode in particular will benefit from this.
ifq pressure drops can be fairly easily triggered by Rx aggregation.

diff refs/heads/master refs/heads/ifqdrop
blob - a1ca62ea1a4b5af7d1d1765eb1da131e15e21e4e
blob + bb0660f8da5ea340de57519e471b3a1a88c7da33
--- sys/dev/ic/acx.c
+++ sys/dev/ic/acx.c
@@ -1398,6 +1398,7 @@ acx_rxeof(struct acx_softc *sc)
  rxi.rxi_rssi = head->rbh_level;
  rxi.rxi_tstamp = letoh32(head->rbh_time);
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  ieee80211_release_node(ic, ni);
  } else {
blob - d3b9ada242c555f179dad1529c20a1748d4b7917
blob + d62e42897867623911ae53637503a42178637603
--- sys/dev/ic/an.c
+++ sys/dev/ic/an.c
@@ -477,6 +477,7 @@ an_rxeof(struct an_softc *sc)
  rxi.rxi_rssi = frmhdr.an_rx_signal_strength;
  rxi.rxi_tstamp = an_switch32(frmhdr.an_rx_time);
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
  ieee80211_release_node(ic, ni);
 }
 
blob - d72e8edceada8a680744a6b8478bb91ac9e15e6e
blob + 14dc84e692380a6a59b9fd9e3846f83e9a28e461
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -960,7 +960,12 @@ ar5008_rx_process(struct athn_softc *sc)
 void
 ar5008_rx_intr(struct athn_softc *sc)
 {
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
  while (ar5008_rx_process(sc) == 0);
+
+ ieee80211_input_flush(ifp);
 }
 
 int
blob - 69ade5ade5a35e632a025db327668d695a0edd2d
blob + c34c8dae63f268c4baa4b8be396e0a6f6af8d05b
--- sys/dev/ic/ar9003.c
+++ sys/dev/ic/ar9003.c
@@ -1066,7 +1066,12 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
 void
 ar9003_rx_intr(struct athn_softc *sc, int qid)
 {
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
  while (ar9003_rx_process(sc, qid) == 0);
+
+ ieee80211_input_flush(ifp);
 }
 
 int
blob - c0c5f4241b010c5c38a557d97963fbdbc884336d
blob + 4d481bf2aada58fd7f9c484e3564db5b3d96d2b0
--- sys/dev/ic/ath.c
+++ sys/dev/ic/ath.c
@@ -2005,6 +2005,8 @@ ath_rx_proc(void *arg, int npending)
  TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
  } while (ath_rxbuf_init(sc, bf) == 0);
 
+ ieee80211_input_flush(ifp);
+
  ath_hal_set_rx_signal(ah); /* rx signal state monitoring */
  ath_hal_start_rx(ah); /* in case of RXEOL */
 #undef PA2DESC
blob - cbf21da74007080c510fa9c56a58aedff62fa586
blob + 301b784e1b6878e0b024e17f7e515097fa6363d1
--- sys/dev/ic/atw.c
+++ sys/dev/ic/atw.c
@@ -3191,6 +3191,7 @@ atw_rxintr(struct atw_softc *sc)
  */
  ieee80211_release_node(ic, ni);
  }
+ ieee80211_input_flush(ifp);
 
  /* Update the receive pointer. */
  sc->sc_rxptr = i;
blob - 7d6f2c5a5693881e2dffdd1814a757c9563196fc
blob + 9ce7309aeb96e7282fc8ac28e3cfc633e1d9f592
--- sys/dev/ic/bwfm.c
+++ sys/dev/ic/bwfm.c
@@ -2118,6 +2118,7 @@ bwfm_rx_auth_ind(struct bwfm_softc *sc, struct bwfm_ev
  rxi.rxi_rssi = 0;
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ic->ic_bss, &rxi);
+ ieee80211_input_flush(ifp);
 }
 
 void
@@ -2174,6 +2175,7 @@ bwfm_rx_assoc_ind(struct bwfm_softc *sc, struct bwfm_e
  rxi.rxi_rssi = 0;
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 }
 
 void
@@ -2229,6 +2231,7 @@ bwfm_rx_leave_ind(struct bwfm_softc *sc, struct bwfm_e
  rxi.rxi_rssi = 0;
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 }
 #endif
 
@@ -2418,6 +2421,7 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
  rxi.rxi_rssi = (int16_t)letoh16(bss->rssi);
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
  /* Restore channel */
  if (bss_chan)
  ni->ni_chan = bss_chan;
blob - 58417ce6f7de644fe86347459c04553956b2edc0
blob + 25a40399a82089a496698f4a1fb8d88cb59375ac
--- sys/dev/ic/bwi.c
+++ sys/dev/ic/bwi.c
@@ -8466,6 +8466,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 next:
  idx = (idx + 1) % BWI_RX_NDESC;
  }
+ ieee80211_input_flush(ifp);
 
  rbd->rbd_idx = idx;
  bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
blob - 6a8c5646f0b6f649a60793e127cbd746d8ee89d7
blob + bcd515d11a392f49f75914f1af6581b35b8cf054
--- sys/dev/ic/malo.c
+++ sys/dev/ic/malo.c
@@ -1727,6 +1727,7 @@ skip:
  sc->sc_rxring.cur = (sc->sc_rxring.cur + 1) %
     MALO_RX_RING_COUNT;
  }
+ ieee80211_input_flush(ifp);
 
  malo_mem_write4(sc, sc->sc_RxPdRdPtr, rxRdPtr);
 }
blob - f44264645097e6f991f5642f7973ed5ebe3e5d7e
blob + 2f316718eb1c5310c46c64394c8b3603b056499e
--- sys/dev/ic/pgt.c
+++ sys/dev/ic/pgt.c
@@ -1036,6 +1036,7 @@ input:
  ifp->if_ierrors++;
  }
  }
+ ieee80211_input_flush(ifp);
 }
 
 void
blob - c8d85564272d263215e829d007c11a47741316e6
blob + 32b3ddbc260c86e39043baef04ceb64edf4c02b4
--- sys/dev/ic/rt2560.c
+++ sys/dev/ic/rt2560.c
@@ -1220,6 +1220,7 @@ skip: desc->flags = htole32(RT2560_RX_BUSY);
  sc->rxq.cur_decrypt =
     (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT;
  }
+ ieee80211_input_flush(ifp);
 }
 
 /*
blob - 591115f692d4f77a522d114e5a91d6026e3452fe
blob + 8e090624a986aee3b0748884baa8a84332d92ff5
--- sys/dev/ic/rt2661.c
+++ sys/dev/ic/rt2661.c
@@ -1302,6 +1302,7 @@ skip: desc->flags |= htole32(RT2661_RX_BUSY);
 
  sc->rxq.cur = (sc->rxq.cur + 1) % RT2661_RX_RING_COUNT;
  }
+ ieee80211_input_flush(ifp);
 }
 
 #ifndef IEEE80211_STA_ONLY
blob - c6c811c835ef4558079c00d50041075b9a8321bb
blob + 2fc9aedb090a50080c099d5b24ca96535ccf33dc
--- sys/dev/ic/rt2860.c
+++ sys/dev/ic/rt2860.c
@@ -1432,6 +1432,7 @@ skip: rxd->sdl0 &= ~htole16(RT2860_RX_DDONE);
 
  sc->rxq.cur = (sc->rxq.cur + 1) % RT2860_RX_RING_COUNT;
  }
+ ieee80211_input_flush(ifp);
 
  /* tell HW what we have processed */
  RAL_WRITE(sc, RT2860_RX_CALC_IDX,
blob - ce7686c40fa4b1166d0af3fe54d8cad60704f556
blob + 420bcd5f0db656fb85833f6ad290b2432c1fe82f
--- sys/dev/ic/rtw.c
+++ sys/dev/ic/rtw.c
@@ -1294,6 +1294,7 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
 next:
  rtw_rxdesc_init(rdb, rs, next, 0);
  }
+ ieee80211_input_flush(&sc->sc_if);
  rdb->rdb_next = next;
 
  KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
blob - cd0d354d12f45e34327a1d9d2d6ae5b480f9e305
blob + cf8f4f3f38d70f01c28136f6a2e3f9f8fa9dc7c4
--- sys/dev/pci/if_ipw.c
+++ sys/dev/pci/if_ipw.c
@@ -966,6 +966,7 @@ ipw_rx_intr(struct ipw_softc *sc)
     i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
     BUS_DMASYNC_PREWRITE);
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  /* tell the firmware what we have processed */
  sc->rxcur = (r == 0) ? IPW_NRBD - 1 : r - 1;
blob - bdb4827425118b9159ae05ad1263bdf5c084254f
blob + 77621142318b26269d864de7443d3f6cd27ffe27
--- sys/dev/pci/if_iwi.c
+++ sys/dev/pci/if_iwi.c
@@ -1105,6 +1105,7 @@ iwi_rx_intr(struct iwi_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  /* tell the firmware what we have processed */
  hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
blob - 0b2116dbc13428f1726773000e8e6a8c251d86b4
blob + d347c3d8f4853099592dd1617dcfd5946bdd5c6c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -7289,6 +7289,7 @@ iwm_notif_intr(struct iwm_softc *sc)
 
  ADVANCE_RXQ(sc);
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  /*
  * Tell the firmware what we have processed.
blob - 6be794c2cd435c74b1b5c3f028b9613dc74ecf20
blob + 06d0e55d42910fc8c60bd29078829399cf337fe4
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2913,6 +2913,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  /* Tell the firmware what we have processed. */
  hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1;
blob - 2c53aa925247b5056360daf479fca12e45624107
blob + 9dc76928c677c89fc9f7d2aa09082bf73e62190c
--- sys/dev/pci/if_rtwn.c
+++ sys/dev/pci/if_rtwn.c
@@ -1511,6 +1511,8 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
  rtwn_tx_done(sc, RTWN_VO_QUEUE);
  if ((status & (R88E_HIMR_ROK | R88E_HIMR_RDU)) ||
     (estatus & R88E_HIMRE_RXFOVW)) {
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
  bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
     sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
     BUS_DMASYNC_POSTREAD);
@@ -1524,6 +1526,7 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
 
  rtwn_rx_frame(sc, rx_desc, rx_data, i);
  }
+ ieee80211_input_flush(&ic->ic_if);
  }
 
  if (status & R88E_HIMR_HSISR_IND_ON_INT) {
@@ -1561,6 +1564,8 @@ rtwn_intr(void *xsc)
 
  /* Vendor driver treats RX errors like ROK... */
  if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) {
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
  bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
     sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
     BUS_DMASYNC_POSTREAD);
@@ -1574,6 +1579,7 @@ rtwn_intr(void *xsc)
 
  rtwn_rx_frame(sc, rx_desc, rx_data, i);
  }
+ ieee80211_input_flush(&ic->ic_if);
  }
 
  if (status & R92C_IMR_BDOK)
blob - 2a91ccec016f8047bfe26ede71e8881404fef619
blob + 02f8191621b3c3967aab4abec9447c7cd4e5ffac
--- sys/dev/pci/if_wpi.c
+++ sys/dev/pci/if_wpi.c
@@ -1527,6 +1527,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;
  }
+ ieee80211_input_flush(&ic->ic_if);
 
  /* Tell the firmware what we have processed. */
  hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1;
blob - 39edb129685cac47d29224f18c6f2e7c92922720
blob + 2fe4fc1af606a4ab32e6dcce83cc7c710e3c814b
--- sys/dev/usb/if_athn_usb.c
+++ sys/dev/usb/if_athn_usb.c
@@ -2175,6 +2175,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
  buf += off;
  len -= off;
  }
+ ieee80211_input_flush(ifp);
 
  resubmit:
  /* Setup a new transfer. */
blob - 7c49042002e73f07bda3c9a5dc7e13e9d7e97503
blob + 46fa39efc05c66d59e7e73c94dfe2b5ec635d9ad
--- sys/dev/usb/if_atu.c
+++ sys/dev/usb/if_atu.c
@@ -1743,6 +1743,7 @@ atu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
  rxi.rxi_rssi = h->rssi;
  rxi.rxi_tstamp = UGETDW(h->rx_time);
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  ieee80211_release_node(ic, ni);
 done1:
blob - cb7e65865adb17b86e10bf5c2bc59983a5c8c2c9
blob + 3c8da94867b14ab18d315b7c69c1188cc770569d
--- sys/dev/usb/if_otus.c
+++ sys/dev/usb/if_otus.c
@@ -1241,6 +1241,7 @@ otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
  buf += hlen;
  len -= hlen;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  resubmit:
  usbd_setup_xfer(xfer, sc->data_rx_pipe, data, data->buf, OTUS_RXBUFSZ,
blob - 9d81664f824def87770512b3e61a015782c99be0
blob + 623fd79146a1879baf23aee4380611444c21f440
--- sys/dev/usb/if_ral.c
+++ sys/dev/usb/if_ral.c
@@ -782,6 +782,7 @@ ural_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - 417666c3503da89fce1d3dc4301b48376dcf7e41
blob + e8d263d2c4322d44836e0197cdd909adc795648e
--- sys/dev/usb/if_rsu.c
+++ sys/dev/usb/if_rsu.c
@@ -1120,6 +1120,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, i
  rxi.rxi_rssi = letoh32(bss->rssi);
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
 }
@@ -1415,6 +1416,7 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf,
  buf += totlen;
  len -= totlen;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 }
 
 void
blob - 7126aaa9540a3f838e7bc1d4e80a06e759e98517
blob + 3fe904607ebf7584cee0348ebb9d4135510d499e
--- sys/dev/usb/if_rum.c
+++ sys/dev/usb/if_rum.c
@@ -851,6 +851,7 @@ rum_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - fc6ba52f271725fe7afbb4abf1a4a1700920a1b4
blob + 5342470a39c8094143e9372855c0511c2ed0161e
--- sys/dev/usb/if_run.c
+++ sys/dev/usb/if_run.c
@@ -2352,6 +2352,7 @@ run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
  buf += dmalen + 8;
  xferlen -= dmalen + 8;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
 skip: /* setup a new transfer */
  usbd_setup_xfer(xfer, sc->rxq.pipeh, data, data->buf, RUN_MAX_RXSZ,
blob - 30aa31b56bfd1226a4199c9024907adbbb3e429d
blob + d657466dccf52fb1271a3650718feecb6e19c297
--- sys/dev/usb/if_uath.c
+++ sys/dev/usb/if_uath.c
@@ -1265,6 +1265,7 @@ uath_data_rxeof(struct usbd_xfer *xfer, void *priv,
  rxi.rxi_rssi = (int)betoh32(desc->rssi);
  rxi.rxi_tstamp = 0; /* unused */
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - 6c8b66842fb650329fb36d812e76fa41be9ab9c7
blob + 72928af7c891bcc295dd79d71a2b6155a64eb0a5
--- sys/dev/usb/if_upgt.c
+++ sys/dev/usb/if_upgt.c
@@ -1748,6 +1748,7 @@ upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkgl
  rxi.rxi_rssi = rxdesc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - 17d56c174230515195c13c070aed9065a68bc959
blob + 87bdc93a6df4786458f6eec62ceb025cc7e75a5a
--- sys/dev/usb/if_urtw.c
+++ sys/dev/usb/if_urtw.c
@@ -3161,6 +3161,7 @@ urtw_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - 96a1ad1a91c3e98ebc6dece98df6ac277046612c
blob + 3f353ff8296162cde2163af94099b9a666bb106c
--- sys/dev/usb/if_urtwn.c
+++ sys/dev/usb/if_urtwn.c
@@ -1206,6 +1206,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
 {
  struct urtwn_rx_data *data = priv;
  struct urtwn_softc *sc = data->sc;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
  struct r92c_rx_desc_usb *rxd;
  uint32_t rxdw0;
  uint8_t *buf;
@@ -1305,6 +1306,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
  buf += totlen;
  len -= totlen;
  }
+ ieee80211_input_flush(&ic->ic_if);
 
  resubmit:
  /* Setup a new transfer. */
blob - 689ac7e7178ca36a091d25cc6f2cf8d15cc45b0b
blob + 498bb68138994cd361f996c866e95c959a5ddf15
--- sys/dev/usb/if_zyd.c
+++ sys/dev/usb/if_zyd.c
@@ -2039,6 +2039,7 @@ zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
 
  zyd_rx_data(sc, data->buf, len);
  }
+ ieee80211_input_flush(ifp);
 
 skip: /* setup a new transfer */
  usbd_setup_xfer(xfer, sc->zyd_ep[ZYD_ENDPT_BIN], data, NULL,
blob - ace97a38cc4ff76b454c1f6a12655565ad131275
blob + c20962c799b141638a2fff11d5ceef6d6db47667
--- sys/net80211/ieee80211.c
+++ sys/net80211/ieee80211.c
@@ -184,6 +184,8 @@ ieee80211_ifattach(struct ifnet *ifp)
  ic->ic_bmissthres = 7; /* default 7 beacons */
  ic->ic_dtim_period = 1; /* all TIMs are DTIMs */
 
+ ml_init(&ic->ic_ml);
+
  ieee80211_node_attach(ifp);
  ieee80211_proto_attach(ifp);
 
@@ -200,6 +202,7 @@ ieee80211_ifdetach(struct ifnet *ifp)
 {
  struct ieee80211com *ic = (void *)ifp;
 
+ ml_purge(&ic->ic_ml);
  timeout_del(&ic->ic_bgscan_timeout);
  ieee80211_proto_detach(ifp);
  ieee80211_crypto_detach(ifp);
blob - 73a9d5229502797c5279734663b1ac1591bec309
blob + de36481038ec3372d0d5533002cbc62a1ebe2b6a
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -71,11 +71,11 @@ void ieee80211_input_ba_seq(struct ieee80211com *,
     struct ieee80211_node *, uint8_t, uint16_t);
 struct mbuf *ieee80211_align_mbuf(struct mbuf *);
 void ieee80211_decap(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
+    struct ieee80211_node *, int, struct mbuf_list *);
 void ieee80211_amsdu_decap(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
-void ieee80211_deliver_data(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
+    struct ieee80211_node *, int, struct mbuf_list *);
+void ieee80211_enqueue_data(struct ieee80211com *, struct mbuf *,
+    struct ieee80211_node *, int, struct mbuf_list *);
 int ieee80211_parse_edca_params_body(struct ieee80211com *,
     const u_int8_t *);
 int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
@@ -155,6 +155,9 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh)
  * any units so long as values have consistent units and higher values
  * mean ``better signal''.  The receive timestamp is currently not used
  * by the 802.11 layer.
+ *
+ * This function only queues frames for delivery.
+ * Actual delivery to upper layers is triggered by ieee80211_input_flush().
  */
 void
 ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
@@ -463,9 +466,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
 
  if ((ni->ni_flags & IEEE80211_NODE_HT) &&
     hasqos && (qos & IEEE80211_QOS_AMSDU))
- ieee80211_amsdu_decap(ic, m, ni, hdrlen);
+ ieee80211_amsdu_decap(ic, m, ni, hdrlen, &ic->ic_ml);
  else
- ieee80211_decap(ic, m, ni, hdrlen);
+ ieee80211_decap(ic, m, ni, hdrlen, &ic->ic_ml);
  return;
 
  case IEEE80211_FC0_TYPE_MGT:
@@ -561,6 +564,22 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
 }
 
 /*
+ * Deliver frames queued by ieee80211_input() to the network stack.
+ * Drivers should call this function only once per Rx interrupt to avoid
+ * triggering the input ifq pressure drop mechanism unnecessarily.
+ */
+void
+ieee80211_input_flush(struct ifnet *ifp)
+{
+ struct ieee80211com *ic = (void *)ifp;
+ int s;
+
+ s = splnet();
+ if_input(ifp, &ic->ic_ml);
+ splx(s);
+}
+
+/*
  * Handle defragmentation (see 9.5 and Annex C).  We support the concurrent
  * reception of fragments of three fragmented MSDUs or MMPDUs.
  */
@@ -856,8 +875,8 @@ ieee80211_ba_move_window(struct ieee80211com *ic, stru
 }
 
 void
-ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int mcast)
+ieee80211_enqueue_data(struct ieee80211com *ic, struct mbuf *m,
+    struct ieee80211_node *ni, int mcast, struct mbuf_list *ml)
 {
  struct ifnet *ifp = &ic->ic_if;
  struct ether_header *eh;
@@ -920,16 +939,14 @@ ieee80211_deliver_data(struct ieee80211com *ic, struct
 #endif
  ieee80211_eapol_key_input(ic, m, ni);
  } else {
- struct mbuf_list ml = MBUF_LIST_INITIALIZER();
- ml_enqueue(&ml, m);
- if_input(ifp, &ml);
+ ml_enqueue(ml, m);
  }
  }
 }
 
 void
 ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
  struct ether_header eh;
  struct ieee80211_frame *wh;
@@ -985,7 +1002,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  return;
  }
  }
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 }
 
 /*
@@ -993,7 +1010,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  */
 void
 ieee80211_amsdu_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
  struct mbuf *n;
  struct ether_header *eh;
@@ -1059,7 +1076,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct
  m_freem(m);
  break;
  }
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 
  if (n->m_pkthdr.len == 0) {
  m_freem(n);
blob - d00d1b631f2966efbd88992c92fea88a99e3ddf8
blob + 43f9de3d52b149afef46a71ff51a94b81b6799b9
--- sys/net80211/ieee80211_proto.c
+++ sys/net80211/ieee80211_proto.c
@@ -974,9 +974,11 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee8
  struct ieee80211_node *ni;
  enum ieee80211_state ostate;
  u_int rate;
-#ifndef IEEE80211_STA_ONLY
  int s;
-#endif
+
+ s = splnet();
+ ml_purge(&ic->ic_ml);
+ splx(s);
 
  ostate = ic->ic_state;
  if (ifp->if_flags & IFF_DEBUG)
blob - e622d35f4dcd21ea0bb40c6a5d0b3f758e197b38
blob + c1d3ad65a46f76266533a4cfd5fffa08b4fa6537
--- sys/net80211/ieee80211_proto.h
+++ sys/net80211/ieee80211_proto.h
@@ -68,6 +68,7 @@ extern u_int ieee80211_get_hdrlen(const struct ieee802
 extern int ieee80211_classify(struct ieee80211com *, struct mbuf *);
 extern void ieee80211_input(struct ifnet *, struct mbuf *,
  struct ieee80211_node *, struct ieee80211_rxinfo *);
+extern void ieee80211_input_flush(struct ifnet *);
 extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,
  struct rtentry *);
 extern void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
blob - 2a567a01422aaaf6024b05c5589f6f45b3744100
blob + fcbe48513883c4c81cfb4c4d96e4d5d08a07ab7f
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -340,6 +340,8 @@ struct ieee80211com {
  u_int8_t ic_dialog_token;
  int ic_fixed_mcs;
  TAILQ_HEAD(, ieee80211_ess) ic_ess;
+
+ struct mbuf_list ic_ml; /* frames queued for if_input() */
 };
 #define ic_if ic_ac.ac_if
 #define ic_softc ic_if.if_softc


Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Stefan Sperling-5
On Mon, Sep 09, 2019 at 03:10:04PM +0200, Stefan Sperling wrote:
> The wifi stack currently calls if_input once per packet instead of once
> per interrupt. To make the wifi layer play nicely with the network stack
> we can split ieee80211_input() into two parts:

Updated diff which avoids purging the input queue at every state
change, e.g. even during SCAN->SCAN. With this we only purge the
queue if we're leaving RUN state or going back to INIT state.

diff refs/heads/master refs/heads/ifqdrop
blob - a1ca62ea1a4b5af7d1d1765eb1da131e15e21e4e
blob + bb0660f8da5ea340de57519e471b3a1a88c7da33
--- sys/dev/ic/acx.c
+++ sys/dev/ic/acx.c
@@ -1398,6 +1398,7 @@ acx_rxeof(struct acx_softc *sc)
  rxi.rxi_rssi = head->rbh_level;
  rxi.rxi_tstamp = letoh32(head->rbh_time);
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  ieee80211_release_node(ic, ni);
  } else {
blob - d3b9ada242c555f179dad1529c20a1748d4b7917
blob + d62e42897867623911ae53637503a42178637603
--- sys/dev/ic/an.c
+++ sys/dev/ic/an.c
@@ -477,6 +477,7 @@ an_rxeof(struct an_softc *sc)
  rxi.rxi_rssi = frmhdr.an_rx_signal_strength;
  rxi.rxi_tstamp = an_switch32(frmhdr.an_rx_time);
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
  ieee80211_release_node(ic, ni);
 }
 
blob - d72e8edceada8a680744a6b8478bb91ac9e15e6e
blob + 14dc84e692380a6a59b9fd9e3846f83e9a28e461
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -960,7 +960,12 @@ ar5008_rx_process(struct athn_softc *sc)
 void
 ar5008_rx_intr(struct athn_softc *sc)
 {
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
  while (ar5008_rx_process(sc) == 0);
+
+ ieee80211_input_flush(ifp);
 }
 
 int
blob - 69ade5ade5a35e632a025db327668d695a0edd2d
blob + c34c8dae63f268c4baa4b8be396e0a6f6af8d05b
--- sys/dev/ic/ar9003.c
+++ sys/dev/ic/ar9003.c
@@ -1066,7 +1066,12 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
 void
 ar9003_rx_intr(struct athn_softc *sc, int qid)
 {
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
  while (ar9003_rx_process(sc, qid) == 0);
+
+ ieee80211_input_flush(ifp);
 }
 
 int
blob - c0c5f4241b010c5c38a557d97963fbdbc884336d
blob + 4d481bf2aada58fd7f9c484e3564db5b3d96d2b0
--- sys/dev/ic/ath.c
+++ sys/dev/ic/ath.c
@@ -2005,6 +2005,8 @@ ath_rx_proc(void *arg, int npending)
  TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
  } while (ath_rxbuf_init(sc, bf) == 0);
 
+ ieee80211_input_flush(ifp);
+
  ath_hal_set_rx_signal(ah); /* rx signal state monitoring */
  ath_hal_start_rx(ah); /* in case of RXEOL */
 #undef PA2DESC
blob - cbf21da74007080c510fa9c56a58aedff62fa586
blob + 301b784e1b6878e0b024e17f7e515097fa6363d1
--- sys/dev/ic/atw.c
+++ sys/dev/ic/atw.c
@@ -3191,6 +3191,7 @@ atw_rxintr(struct atw_softc *sc)
  */
  ieee80211_release_node(ic, ni);
  }
+ ieee80211_input_flush(ifp);
 
  /* Update the receive pointer. */
  sc->sc_rxptr = i;
blob - 7d6f2c5a5693881e2dffdd1814a757c9563196fc
blob + 9ce7309aeb96e7282fc8ac28e3cfc633e1d9f592
--- sys/dev/ic/bwfm.c
+++ sys/dev/ic/bwfm.c
@@ -2118,6 +2118,7 @@ bwfm_rx_auth_ind(struct bwfm_softc *sc, struct bwfm_ev
  rxi.rxi_rssi = 0;
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ic->ic_bss, &rxi);
+ ieee80211_input_flush(ifp);
 }
 
 void
@@ -2174,6 +2175,7 @@ bwfm_rx_assoc_ind(struct bwfm_softc *sc, struct bwfm_e
  rxi.rxi_rssi = 0;
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 }
 
 void
@@ -2229,6 +2231,7 @@ bwfm_rx_leave_ind(struct bwfm_softc *sc, struct bwfm_e
  rxi.rxi_rssi = 0;
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 }
 #endif
 
@@ -2418,6 +2421,7 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
  rxi.rxi_rssi = (int16_t)letoh16(bss->rssi);
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
  /* Restore channel */
  if (bss_chan)
  ni->ni_chan = bss_chan;
blob - 58417ce6f7de644fe86347459c04553956b2edc0
blob + 25a40399a82089a496698f4a1fb8d88cb59375ac
--- sys/dev/ic/bwi.c
+++ sys/dev/ic/bwi.c
@@ -8466,6 +8466,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 next:
  idx = (idx + 1) % BWI_RX_NDESC;
  }
+ ieee80211_input_flush(ifp);
 
  rbd->rbd_idx = idx;
  bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
blob - 6a8c5646f0b6f649a60793e127cbd746d8ee89d7
blob + bcd515d11a392f49f75914f1af6581b35b8cf054
--- sys/dev/ic/malo.c
+++ sys/dev/ic/malo.c
@@ -1727,6 +1727,7 @@ skip:
  sc->sc_rxring.cur = (sc->sc_rxring.cur + 1) %
     MALO_RX_RING_COUNT;
  }
+ ieee80211_input_flush(ifp);
 
  malo_mem_write4(sc, sc->sc_RxPdRdPtr, rxRdPtr);
 }
blob - f44264645097e6f991f5642f7973ed5ebe3e5d7e
blob + 2f316718eb1c5310c46c64394c8b3603b056499e
--- sys/dev/ic/pgt.c
+++ sys/dev/ic/pgt.c
@@ -1036,6 +1036,7 @@ input:
  ifp->if_ierrors++;
  }
  }
+ ieee80211_input_flush(ifp);
 }
 
 void
blob - c8d85564272d263215e829d007c11a47741316e6
blob + 32b3ddbc260c86e39043baef04ceb64edf4c02b4
--- sys/dev/ic/rt2560.c
+++ sys/dev/ic/rt2560.c
@@ -1220,6 +1220,7 @@ skip: desc->flags = htole32(RT2560_RX_BUSY);
  sc->rxq.cur_decrypt =
     (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT;
  }
+ ieee80211_input_flush(ifp);
 }
 
 /*
blob - 591115f692d4f77a522d114e5a91d6026e3452fe
blob + 8e090624a986aee3b0748884baa8a84332d92ff5
--- sys/dev/ic/rt2661.c
+++ sys/dev/ic/rt2661.c
@@ -1302,6 +1302,7 @@ skip: desc->flags |= htole32(RT2661_RX_BUSY);
 
  sc->rxq.cur = (sc->rxq.cur + 1) % RT2661_RX_RING_COUNT;
  }
+ ieee80211_input_flush(ifp);
 }
 
 #ifndef IEEE80211_STA_ONLY
blob - c6c811c835ef4558079c00d50041075b9a8321bb
blob + 2fc9aedb090a50080c099d5b24ca96535ccf33dc
--- sys/dev/ic/rt2860.c
+++ sys/dev/ic/rt2860.c
@@ -1432,6 +1432,7 @@ skip: rxd->sdl0 &= ~htole16(RT2860_RX_DDONE);
 
  sc->rxq.cur = (sc->rxq.cur + 1) % RT2860_RX_RING_COUNT;
  }
+ ieee80211_input_flush(ifp);
 
  /* tell HW what we have processed */
  RAL_WRITE(sc, RT2860_RX_CALC_IDX,
blob - ce7686c40fa4b1166d0af3fe54d8cad60704f556
blob + 420bcd5f0db656fb85833f6ad290b2432c1fe82f
--- sys/dev/ic/rtw.c
+++ sys/dev/ic/rtw.c
@@ -1294,6 +1294,7 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
 next:
  rtw_rxdesc_init(rdb, rs, next, 0);
  }
+ ieee80211_input_flush(&sc->sc_if);
  rdb->rdb_next = next;
 
  KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
blob - cd0d354d12f45e34327a1d9d2d6ae5b480f9e305
blob + cf8f4f3f38d70f01c28136f6a2e3f9f8fa9dc7c4
--- sys/dev/pci/if_ipw.c
+++ sys/dev/pci/if_ipw.c
@@ -966,6 +966,7 @@ ipw_rx_intr(struct ipw_softc *sc)
     i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
     BUS_DMASYNC_PREWRITE);
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  /* tell the firmware what we have processed */
  sc->rxcur = (r == 0) ? IPW_NRBD - 1 : r - 1;
blob - bdb4827425118b9159ae05ad1263bdf5c084254f
blob + 77621142318b26269d864de7443d3f6cd27ffe27
--- sys/dev/pci/if_iwi.c
+++ sys/dev/pci/if_iwi.c
@@ -1105,6 +1105,7 @@ iwi_rx_intr(struct iwi_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  /* tell the firmware what we have processed */
  hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
blob - 0b2116dbc13428f1726773000e8e6a8c251d86b4
blob + d347c3d8f4853099592dd1617dcfd5946bdd5c6c
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -7289,6 +7289,7 @@ iwm_notif_intr(struct iwm_softc *sc)
 
  ADVANCE_RXQ(sc);
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  /*
  * Tell the firmware what we have processed.
blob - 6be794c2cd435c74b1b5c3f028b9613dc74ecf20
blob + 06d0e55d42910fc8c60bd29078829399cf337fe4
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2913,6 +2913,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  /* Tell the firmware what we have processed. */
  hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1;
blob - 2c53aa925247b5056360daf479fca12e45624107
blob + 9dc76928c677c89fc9f7d2aa09082bf73e62190c
--- sys/dev/pci/if_rtwn.c
+++ sys/dev/pci/if_rtwn.c
@@ -1511,6 +1511,8 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
  rtwn_tx_done(sc, RTWN_VO_QUEUE);
  if ((status & (R88E_HIMR_ROK | R88E_HIMR_RDU)) ||
     (estatus & R88E_HIMRE_RXFOVW)) {
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
  bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
     sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
     BUS_DMASYNC_POSTREAD);
@@ -1524,6 +1526,7 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
 
  rtwn_rx_frame(sc, rx_desc, rx_data, i);
  }
+ ieee80211_input_flush(&ic->ic_if);
  }
 
  if (status & R88E_HIMR_HSISR_IND_ON_INT) {
@@ -1561,6 +1564,8 @@ rtwn_intr(void *xsc)
 
  /* Vendor driver treats RX errors like ROK... */
  if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) {
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
  bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
     sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
     BUS_DMASYNC_POSTREAD);
@@ -1574,6 +1579,7 @@ rtwn_intr(void *xsc)
 
  rtwn_rx_frame(sc, rx_desc, rx_data, i);
  }
+ ieee80211_input_flush(&ic->ic_if);
  }
 
  if (status & R92C_IMR_BDOK)
blob - 2a91ccec016f8047bfe26ede71e8881404fef619
blob + 02f8191621b3c3967aab4abec9447c7cd4e5ffac
--- sys/dev/pci/if_wpi.c
+++ sys/dev/pci/if_wpi.c
@@ -1527,6 +1527,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;
  }
+ ieee80211_input_flush(&ic->ic_if);
 
  /* Tell the firmware what we have processed. */
  hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1;
blob - 39edb129685cac47d29224f18c6f2e7c92922720
blob + 2fe4fc1af606a4ab32e6dcce83cc7c710e3c814b
--- sys/dev/usb/if_athn_usb.c
+++ sys/dev/usb/if_athn_usb.c
@@ -2175,6 +2175,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
  buf += off;
  len -= off;
  }
+ ieee80211_input_flush(ifp);
 
  resubmit:
  /* Setup a new transfer. */
blob - 7c49042002e73f07bda3c9a5dc7e13e9d7e97503
blob + 46fa39efc05c66d59e7e73c94dfe2b5ec635d9ad
--- sys/dev/usb/if_atu.c
+++ sys/dev/usb/if_atu.c
@@ -1743,6 +1743,7 @@ atu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
  rxi.rxi_rssi = h->rssi;
  rxi.rxi_tstamp = UGETDW(h->rx_time);
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  ieee80211_release_node(ic, ni);
 done1:
blob - cb7e65865adb17b86e10bf5c2bc59983a5c8c2c9
blob + 3c8da94867b14ab18d315b7c69c1188cc770569d
--- sys/dev/usb/if_otus.c
+++ sys/dev/usb/if_otus.c
@@ -1241,6 +1241,7 @@ otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
  buf += hlen;
  len -= hlen;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
  resubmit:
  usbd_setup_xfer(xfer, sc->data_rx_pipe, data, data->buf, OTUS_RXBUFSZ,
blob - 9d81664f824def87770512b3e61a015782c99be0
blob + 623fd79146a1879baf23aee4380611444c21f440
--- sys/dev/usb/if_ral.c
+++ sys/dev/usb/if_ral.c
@@ -782,6 +782,7 @@ ural_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - 417666c3503da89fce1d3dc4301b48376dcf7e41
blob + e8d263d2c4322d44836e0197cdd909adc795648e
--- sys/dev/usb/if_rsu.c
+++ sys/dev/usb/if_rsu.c
@@ -1120,6 +1120,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, i
  rxi.rxi_rssi = letoh32(bss->rssi);
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
 }
@@ -1415,6 +1416,7 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf,
  buf += totlen;
  len -= totlen;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 }
 
 void
blob - 7126aaa9540a3f838e7bc1d4e80a06e759e98517
blob + 3fe904607ebf7584cee0348ebb9d4135510d499e
--- sys/dev/usb/if_rum.c
+++ sys/dev/usb/if_rum.c
@@ -851,6 +851,7 @@ rum_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - fc6ba52f271725fe7afbb4abf1a4a1700920a1b4
blob + 5342470a39c8094143e9372855c0511c2ed0161e
--- sys/dev/usb/if_run.c
+++ sys/dev/usb/if_run.c
@@ -2352,6 +2352,7 @@ run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
  buf += dmalen + 8;
  xferlen -= dmalen + 8;
  }
+ ieee80211_input_flush(&sc->sc_ic.ic_if);
 
 skip: /* setup a new transfer */
  usbd_setup_xfer(xfer, sc->rxq.pipeh, data, data->buf, RUN_MAX_RXSZ,
blob - 30aa31b56bfd1226a4199c9024907adbbb3e429d
blob + d657466dccf52fb1271a3650718feecb6e19c297
--- sys/dev/usb/if_uath.c
+++ sys/dev/usb/if_uath.c
@@ -1265,6 +1265,7 @@ uath_data_rxeof(struct usbd_xfer *xfer, void *priv,
  rxi.rxi_rssi = (int)betoh32(desc->rssi);
  rxi.rxi_tstamp = 0; /* unused */
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - 6c8b66842fb650329fb36d812e76fa41be9ab9c7
blob + 72928af7c891bcc295dd79d71a2b6155a64eb0a5
--- sys/dev/usb/if_upgt.c
+++ sys/dev/usb/if_upgt.c
@@ -1748,6 +1748,7 @@ upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkgl
  rxi.rxi_rssi = rxdesc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - 17d56c174230515195c13c070aed9065a68bc959
blob + 87bdc93a6df4786458f6eec62ceb025cc7e75a5a
--- sys/dev/usb/if_urtw.c
+++ sys/dev/usb/if_urtw.c
@@ -3161,6 +3161,7 @@ urtw_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0;
  ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_input_flush(ifp);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
blob - 96a1ad1a91c3e98ebc6dece98df6ac277046612c
blob + 3f353ff8296162cde2163af94099b9a666bb106c
--- sys/dev/usb/if_urtwn.c
+++ sys/dev/usb/if_urtwn.c
@@ -1206,6 +1206,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
 {
  struct urtwn_rx_data *data = priv;
  struct urtwn_softc *sc = data->sc;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
  struct r92c_rx_desc_usb *rxd;
  uint32_t rxdw0;
  uint8_t *buf;
@@ -1305,6 +1306,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
  buf += totlen;
  len -= totlen;
  }
+ ieee80211_input_flush(&ic->ic_if);
 
  resubmit:
  /* Setup a new transfer. */
blob - 689ac7e7178ca36a091d25cc6f2cf8d15cc45b0b
blob + 498bb68138994cd361f996c866e95c959a5ddf15
--- sys/dev/usb/if_zyd.c
+++ sys/dev/usb/if_zyd.c
@@ -2039,6 +2039,7 @@ zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
 
  zyd_rx_data(sc, data->buf, len);
  }
+ ieee80211_input_flush(ifp);
 
 skip: /* setup a new transfer */
  usbd_setup_xfer(xfer, sc->zyd_ep[ZYD_ENDPT_BIN], data, NULL,
blob - ace97a38cc4ff76b454c1f6a12655565ad131275
blob + c20962c799b141638a2fff11d5ceef6d6db47667
--- sys/net80211/ieee80211.c
+++ sys/net80211/ieee80211.c
@@ -184,6 +184,8 @@ ieee80211_ifattach(struct ifnet *ifp)
  ic->ic_bmissthres = 7; /* default 7 beacons */
  ic->ic_dtim_period = 1; /* all TIMs are DTIMs */
 
+ ml_init(&ic->ic_ml);
+
  ieee80211_node_attach(ifp);
  ieee80211_proto_attach(ifp);
 
@@ -200,6 +202,7 @@ ieee80211_ifdetach(struct ifnet *ifp)
 {
  struct ieee80211com *ic = (void *)ifp;
 
+ ml_purge(&ic->ic_ml);
  timeout_del(&ic->ic_bgscan_timeout);
  ieee80211_proto_detach(ifp);
  ieee80211_crypto_detach(ifp);
blob - 73a9d5229502797c5279734663b1ac1591bec309
blob + de36481038ec3372d0d5533002cbc62a1ebe2b6a
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -71,11 +71,11 @@ void ieee80211_input_ba_seq(struct ieee80211com *,
     struct ieee80211_node *, uint8_t, uint16_t);
 struct mbuf *ieee80211_align_mbuf(struct mbuf *);
 void ieee80211_decap(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
+    struct ieee80211_node *, int, struct mbuf_list *);
 void ieee80211_amsdu_decap(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
-void ieee80211_deliver_data(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
+    struct ieee80211_node *, int, struct mbuf_list *);
+void ieee80211_enqueue_data(struct ieee80211com *, struct mbuf *,
+    struct ieee80211_node *, int, struct mbuf_list *);
 int ieee80211_parse_edca_params_body(struct ieee80211com *,
     const u_int8_t *);
 int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
@@ -155,6 +155,9 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh)
  * any units so long as values have consistent units and higher values
  * mean ``better signal''.  The receive timestamp is currently not used
  * by the 802.11 layer.
+ *
+ * This function only queues frames for delivery.
+ * Actual delivery to upper layers is triggered by ieee80211_input_flush().
  */
 void
 ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
@@ -463,9 +466,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
 
  if ((ni->ni_flags & IEEE80211_NODE_HT) &&
     hasqos && (qos & IEEE80211_QOS_AMSDU))
- ieee80211_amsdu_decap(ic, m, ni, hdrlen);
+ ieee80211_amsdu_decap(ic, m, ni, hdrlen, &ic->ic_ml);
  else
- ieee80211_decap(ic, m, ni, hdrlen);
+ ieee80211_decap(ic, m, ni, hdrlen, &ic->ic_ml);
  return;
 
  case IEEE80211_FC0_TYPE_MGT:
@@ -561,6 +564,22 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
 }
 
 /*
+ * Deliver frames queued by ieee80211_input() to the network stack.
+ * Drivers should call this function only once per Rx interrupt to avoid
+ * triggering the input ifq pressure drop mechanism unnecessarily.
+ */
+void
+ieee80211_input_flush(struct ifnet *ifp)
+{
+ struct ieee80211com *ic = (void *)ifp;
+ int s;
+
+ s = splnet();
+ if_input(ifp, &ic->ic_ml);
+ splx(s);
+}
+
+/*
  * Handle defragmentation (see 9.5 and Annex C).  We support the concurrent
  * reception of fragments of three fragmented MSDUs or MMPDUs.
  */
@@ -856,8 +875,8 @@ ieee80211_ba_move_window(struct ieee80211com *ic, stru
 }
 
 void
-ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int mcast)
+ieee80211_enqueue_data(struct ieee80211com *ic, struct mbuf *m,
+    struct ieee80211_node *ni, int mcast, struct mbuf_list *ml)
 {
  struct ifnet *ifp = &ic->ic_if;
  struct ether_header *eh;
@@ -920,16 +939,14 @@ ieee80211_deliver_data(struct ieee80211com *ic, struct
 #endif
  ieee80211_eapol_key_input(ic, m, ni);
  } else {
- struct mbuf_list ml = MBUF_LIST_INITIALIZER();
- ml_enqueue(&ml, m);
- if_input(ifp, &ml);
+ ml_enqueue(ml, m);
  }
  }
 }
 
 void
 ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
  struct ether_header eh;
  struct ieee80211_frame *wh;
@@ -985,7 +1002,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  return;
  }
  }
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 }
 
 /*
@@ -993,7 +1010,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  */
 void
 ieee80211_amsdu_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
  struct mbuf *n;
  struct ether_header *eh;
@@ -1059,7 +1076,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct
  m_freem(m);
  break;
  }
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 
  if (n->m_pkthdr.len == 0) {
  m_freem(n);
blob - d00d1b631f2966efbd88992c92fea88a99e3ddf8
blob + 87c41116d48d86cf446cae6486ee1dde42a92701
--- sys/net80211/ieee80211_proto.c
+++ sys/net80211/ieee80211_proto.c
@@ -974,9 +974,7 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee8
  struct ieee80211_node *ni;
  enum ieee80211_state ostate;
  u_int rate;
-#ifndef IEEE80211_STA_ONLY
  int s;
-#endif
 
  ostate = ic->ic_state;
  if (ifp->if_flags & IFF_DEBUG)
@@ -1060,6 +1058,9 @@ justcleanup:
  ic->ic_mgt_timer = 0;
  mq_purge(&ic->ic_mgtq);
  mq_purge(&ic->ic_pwrsaveq);
+ s = splnet();
+ ml_purge(&ic->ic_ml);
+ splx(s);
  ieee80211_free_allnodes(ic, 1);
  break;
  }
@@ -1113,6 +1114,9 @@ justcleanup:
  ic->ic_bgscan_fail = 0;
  ieee80211_stop_ampdu_tx(ic, ni, mgt);
  ieee80211_free_allnodes(ic, 1);
+ s = splnet();
+ ml_purge(&ic->ic_ml);
+ splx(s);
  /* FALLTHROUGH */
  case IEEE80211_S_AUTH:
  case IEEE80211_S_ASSOC:
@@ -1161,6 +1165,9 @@ justcleanup:
  ic->ic_bgscan_fail = 0;
  ieee80211_stop_ampdu_tx(ic, ni, mgt);
  ieee80211_ba_del(ni);
+ s = splnet();
+ ml_purge(&ic->ic_ml);
+ splx(s);
  switch (mgt) {
  case IEEE80211_FC0_SUBTYPE_AUTH:
  IEEE80211_SEND_MGMT(ic, ni,
@@ -1193,6 +1200,9 @@ justcleanup:
  case IEEE80211_S_RUN:
  ieee80211_stop_ampdu_tx(ic, ni, mgt);
  ieee80211_ba_del(ni);
+ s = splnet();
+ ml_purge(&ic->ic_ml);
+ splx(s);
  IEEE80211_SEND_MGMT(ic, ni,
     IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
  break;
blob - e622d35f4dcd21ea0bb40c6a5d0b3f758e197b38
blob + c1d3ad65a46f76266533a4cfd5fffa08b4fa6537
--- sys/net80211/ieee80211_proto.h
+++ sys/net80211/ieee80211_proto.h
@@ -68,6 +68,7 @@ extern u_int ieee80211_get_hdrlen(const struct ieee802
 extern int ieee80211_classify(struct ieee80211com *, struct mbuf *);
 extern void ieee80211_input(struct ifnet *, struct mbuf *,
  struct ieee80211_node *, struct ieee80211_rxinfo *);
+extern void ieee80211_input_flush(struct ifnet *);
 extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,
  struct rtentry *);
 extern void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
blob - 2a567a01422aaaf6024b05c5589f6f45b3744100
blob + fcbe48513883c4c81cfb4c4d96e4d5d08a07ab7f
--- sys/net80211/ieee80211_var.h
+++ sys/net80211/ieee80211_var.h
@@ -340,6 +340,8 @@ struct ieee80211com {
  u_int8_t ic_dialog_token;
  int ic_fixed_mcs;
  TAILQ_HEAD(, ieee80211_ess) ic_ess;
+
+ struct mbuf_list ic_ml; /* frames queued for if_input() */
 };
 #define ic_if ic_ac.ac_if
 #define ic_softc ic_if.if_softc

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Florian Obser-2
this seems to work fine on
iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless AC 7260" rev 0x83, msi

download is considerably less wobbly, upload also benefits a bit(?):

before:

[florian@x1:~]$ tcpbench -t 10 192.168.178.73
  elapsed_ms          bytes         mbps   bwidth
        1001        2683144       21.444  100.00%
Conn:   1 Mbps:       21.444 Peak Mbps:       21.444 Avg Mbps:       21.444
        2013        2894552       22.904  100.00%
Conn:   1 Mbps:       22.904 Peak Mbps:       22.904 Avg Mbps:       22.904
        3014         771784        6.174  100.00%
Conn:   1 Mbps:        6.174 Peak Mbps:       22.904 Avg Mbps:        6.174
        4014        2380512       19.044  100.00%
Conn:   1 Mbps:       19.044 Peak Mbps:       22.904 Avg Mbps:       19.044
        5039        3042248       23.768  100.00%
Conn:   1 Mbps:       23.768 Peak Mbps:       23.768 Avg Mbps:       23.768
        6035        2858352       22.959  100.00%
Conn:   1 Mbps:       22.959 Peak Mbps:       23.768 Avg Mbps:       22.959
        7034        2875728       23.029  100.00%
Conn:   1 Mbps:       23.029 Peak Mbps:       23.768 Avg Mbps:       23.029
        8034        3701088       29.609  100.00%
Conn:   1 Mbps:       29.609 Peak Mbps:       29.609 Avg Mbps:       29.609
        9035        2927856       23.423  100.00%
Conn:   1 Mbps:       23.423 Peak Mbps:       29.609 Avg Mbps:       23.423
       10039        4019648       32.061  100.00%
Conn:   1 Mbps:       32.061 Peak Mbps:       32.061 Avg Mbps:       32.061

[florian@x1:~]$ tcpbench -s                                                    
  elapsed_ms          bytes         mbps   bwidth
        1013        2939440       23.214  100.00%
Conn:   1 Mbps:       23.214 Peak Mbps:       23.214 Avg Mbps:       23.214
        2018         127424        1.015  100.00%
Conn:   1 Mbps:        1.015 Peak Mbps:       23.214 Avg Mbps:        1.015
        3019        3453480       27.628  100.00%
Conn:   1 Mbps:       27.628 Peak Mbps:       27.628 Avg Mbps:       27.628
        4033        1781040       14.052  100.00%
Conn:   1 Mbps:       14.052 Peak Mbps:       27.628 Avg Mbps:       14.052
        5034         928168        7.425  100.00%
Conn:   1 Mbps:        7.425 Peak Mbps:       27.628 Avg Mbps:        7.425
        6036        3386872       27.068  100.00%
Conn:   1 Mbps:       27.068 Peak Mbps:       27.628 Avg Mbps:       27.068
        7053        3233384       25.435  100.00%
Conn:   1 Mbps:       25.435 Peak Mbps:       27.628 Avg Mbps:       25.435
        8063        1796968       14.233  100.00%
Conn:   1 Mbps:       14.233 Peak Mbps:       27.628 Avg Mbps:       14.233
        9068          97016        0.773  100.00%
Conn:   1 Mbps:        0.773 Peak Mbps:       27.628 Avg Mbps:        0.773
       10069        2641152       21.129  100.00%
Conn:   1 Mbps:       21.129 Peak Mbps:       27.628 Avg Mbps:       21.129
       11073        1106272        8.815  100.00%
Conn:   1 Mbps:        8.815 Peak Mbps:       27.628 Avg Mbps:        8.815

------------------------------------------------------------------------

after:

[florian@x1:~]$ tcpbench -t 10 192.168.178.73    
  elapsed_ms          bytes         mbps   bwidth
        1004        3311576       26.387  100.00%
Conn:   1 Mbps:       26.387 Peak Mbps:       26.387 Avg Mbps:       26.387
        2006        3247864       25.957  100.00%
Conn:   1 Mbps:       25.957 Peak Mbps:       26.387 Avg Mbps:       25.957
        3048        3614208       27.748  100.00%
Conn:   1 Mbps:       27.748 Peak Mbps:       27.748 Avg Mbps:       27.748
        4050        3876296       30.979  100.00%
Conn:   1 Mbps:       30.979 Peak Mbps:       30.979 Avg Mbps:       30.979
        5054        3518640       28.065  100.00%
Conn:   1 Mbps:       28.065 Peak Mbps:       30.979 Avg Mbps:       28.065
        6053        3604072       28.861  100.00%
Conn:   1 Mbps:       28.861 Peak Mbps:       30.979 Avg Mbps:       28.861
        7054        3494024       27.924  100.00%
Conn:   1 Mbps:       27.924 Peak Mbps:       30.979 Avg Mbps:       27.924
        8055        3200080       25.601  100.00%
Conn:   1 Mbps:       25.601 Peak Mbps:       30.979 Avg Mbps:       25.601
        9056        3525880       28.179  100.00%
Conn:   1 Mbps:       28.179 Peak Mbps:       30.979 Avg Mbps:       28.179
       10057        3084240       24.649  100.00%
Conn:   1 Mbps:       24.649 Peak Mbps:       30.979 Avg Mbps:       24.649

[florian@x1:~]$ tcpbench -s                                                    
  elapsed_ms          bytes         mbps   bwidth
        1002        4358480       34.798  100.00%
Conn:   1 Mbps:       34.798 Peak Mbps:       34.798 Avg Mbps:       34.798
        2013        5059312       40.034  100.00%
Conn:   1 Mbps:       40.034 Peak Mbps:       40.034 Avg Mbps:       40.034
        3011        4960848       39.766  100.00%
Conn:   1 Mbps:       39.766 Peak Mbps:       40.034 Avg Mbps:       39.766
        4014        5622584       44.891  100.00%
Conn:   1 Mbps:       44.891 Peak Mbps:       44.891 Avg Mbps:       44.891
        5013        5432896       43.507  100.00%
Conn:   1 Mbps:       43.507 Peak Mbps:       44.891 Avg Mbps:       43.507
        6014        5311264       42.490  100.00%
Conn:   1 Mbps:       42.490 Peak Mbps:       44.891 Avg Mbps:       42.490
        7028        6329208       49.935  100.00%
Conn:   1 Mbps:       49.935 Peak Mbps:       49.935 Avg Mbps:       49.935
        8036        6056984       48.119  100.00%
Conn:   1 Mbps:       48.119 Peak Mbps:       49.935 Avg Mbps:       48.119
        9055        5977344       46.973  100.00%
Conn:   1 Mbps:       46.973 Peak Mbps:       49.935 Avg Mbps:       46.973
       10090        6000568       46.426  100.00%
Conn:   1 Mbps:       46.426 Peak Mbps:       49.935 Avg Mbps:       46.426
       11060        5396640       44.554  100.00%
Conn:   1 Mbps:       44.554 Peak Mbps:       49.935 Avg Mbps:       44.554
Conn:   0 Mbps:        0.000 Peak Mbps:       49.935 Avg Mbps:        0.000



--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Björn Ketelaars
In reply to this post by Stefan Sperling-5
On Mon 09/09/2019 16:37, Stefan Sperling wrote:
> On Mon, Sep 09, 2019 at 03:10:04PM +0200, Stefan Sperling wrote:
> > The wifi stack currently calls if_input once per packet instead of once
> > per interrupt. To make the wifi layer play nicely with the network stack
> > we can split ieee80211_input() into two parts:
>
> Updated diff which avoids purging the input queue at every state
> change, e.g. even during SCAN->SCAN. With this we only purge the
> queue if we're leaving RUN state or going back to INIT state.

I tested the updated diff by downloading a 400M file and looking at the
throughput and Idrop before, and after each run. I also tried different
values for net.link.ifrxq.pressure_drop.

$ dmesg | grep iwn
iwn0 at pci2 dev 0 function 0 "Intel Centrino Advanced-N 6205" rev 0x34:
msi, MIMO 2T2R, MoW, address

Before applying your diff:
pressure_drop MB/s Idrop before Idrop after
8 3.0 2194 4117
32 4.3 4117 4345
128 4.1 4345 4345

After applying your diff:
pressure_drop MB/s Idrop before Idrop after
8 5.4 3354 3606
32 6.2 3606 3606
128 6.2 3606 3606

It seems that your diff improves throughput, and reduces number of
Idrops. At higher values of net.link.ifrxq.pressure_drop throughput is
even higher and delta Idrop is 0.

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Matthias Schmidt
In reply to this post by Stefan Sperling-5
Hi Stefan,

* Stefan Sperling wrote:
> On Mon, Sep 09, 2019 at 03:10:04PM +0200, Stefan Sperling wrote:
> > The wifi stack currently calls if_input once per packet instead of once
> > per interrupt. To make the wifi layer play nicely with the network stack
> > we can split ieee80211_input() into two parts:
>
> Updated diff which avoids purging the input queue at every state
> change, e.g. even during SCAN->SCAN. With this we only purge the
> queue if we're leaving RUN state or going back to INIT state.

Tested your diff with

iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless-AC 8265"

So far, the diff provides amazing results.  Without your diff the
maximum speed of file downloads from my favorite mirror is around
1.2M/s in average.  With your diff it is around 4.5M/s in average.

Cheers
        Matthias

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Martin Pieuchot
In reply to this post by Stefan Sperling-5
On 09/09/19(Mon) 16:37, Stefan Sperling wrote:
> On Mon, Sep 09, 2019 at 03:10:04PM +0200, Stefan Sperling wrote:
> > The wifi stack currently calls if_input once per packet instead of once
> > per interrupt. To make the wifi layer play nicely with the network stack
> > we can split ieee80211_input() into two parts:
>
> Updated diff which avoids purging the input queue at every state
> change, e.g. even during SCAN->SCAN. With this we only purge the
> queue if we're leaving RUN state or going back to INIT state.

Thanks a lot!  I must say I looked at this in the past but got lost in
ieee80211_input().

Why not keep ieee80211_input() as a wrapper around your new mechanism?
This way you don't need to touch all drivers at once.

I'd also suggest using a queue on-stack like we do for Ethernet drivers,
this would get rid of the cleanup of `ic_ml' when the state change.  It
would also help developers familiar with Ethernet drivers to understand
what's happening ;o)

What about:

          ieee80211_enqueue(ifp, m, ni, &rxi, &ml);
          ieee80211_inputm(ifp, &ml);

Are you sure if_input() needs to be called at splnet()?  I don't think
so because many pseudo-drivers call it at a different IPL.

> diff refs/heads/master refs/heads/ifqdrop
> blob - a1ca62ea1a4b5af7d1d1765eb1da131e15e21e4e
> blob + bb0660f8da5ea340de57519e471b3a1a88c7da33
> --- sys/dev/ic/acx.c
> +++ sys/dev/ic/acx.c
> @@ -1398,6 +1398,7 @@ acx_rxeof(struct acx_softc *sc)
>   rxi.rxi_rssi = head->rbh_level;
>   rxi.rxi_tstamp = letoh32(head->rbh_time);
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  
>   ieee80211_release_node(ic, ni);
>   } else {
> blob - d3b9ada242c555f179dad1529c20a1748d4b7917
> blob + d62e42897867623911ae53637503a42178637603
> --- sys/dev/ic/an.c
> +++ sys/dev/ic/an.c
> @@ -477,6 +477,7 @@ an_rxeof(struct an_softc *sc)
>   rxi.rxi_rssi = frmhdr.an_rx_signal_strength;
>   rxi.rxi_tstamp = an_switch32(frmhdr.an_rx_time);
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>   ieee80211_release_node(ic, ni);
>  }
>  
> blob - d72e8edceada8a680744a6b8478bb91ac9e15e6e
> blob + 14dc84e692380a6a59b9fd9e3846f83e9a28e461
> --- sys/dev/ic/ar5008.c
> +++ sys/dev/ic/ar5008.c
> @@ -960,7 +960,12 @@ ar5008_rx_process(struct athn_softc *sc)
>  void
>  ar5008_rx_intr(struct athn_softc *sc)
>  {
> + struct ieee80211com *ic = &sc->sc_ic;
> + struct ifnet *ifp = &ic->ic_if;
> +
>   while (ar5008_rx_process(sc) == 0);
> +
> + ieee80211_input_flush(ifp);
>  }
>  
>  int
> blob - 69ade5ade5a35e632a025db327668d695a0edd2d
> blob + c34c8dae63f268c4baa4b8be396e0a6f6af8d05b
> --- sys/dev/ic/ar9003.c
> +++ sys/dev/ic/ar9003.c
> @@ -1066,7 +1066,12 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
>  void
>  ar9003_rx_intr(struct athn_softc *sc, int qid)
>  {
> + struct ieee80211com *ic = &sc->sc_ic;
> + struct ifnet *ifp = &ic->ic_if;
> +
>   while (ar9003_rx_process(sc, qid) == 0);
> +
> + ieee80211_input_flush(ifp);
>  }
>  
>  int
> blob - c0c5f4241b010c5c38a557d97963fbdbc884336d
> blob + 4d481bf2aada58fd7f9c484e3564db5b3d96d2b0
> --- sys/dev/ic/ath.c
> +++ sys/dev/ic/ath.c
> @@ -2005,6 +2005,8 @@ ath_rx_proc(void *arg, int npending)
>   TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
>   } while (ath_rxbuf_init(sc, bf) == 0);
>  
> + ieee80211_input_flush(ifp);
> +
>   ath_hal_set_rx_signal(ah); /* rx signal state monitoring */
>   ath_hal_start_rx(ah); /* in case of RXEOL */
>  #undef PA2DESC
> blob - cbf21da74007080c510fa9c56a58aedff62fa586
> blob + 301b784e1b6878e0b024e17f7e515097fa6363d1
> --- sys/dev/ic/atw.c
> +++ sys/dev/ic/atw.c
> @@ -3191,6 +3191,7 @@ atw_rxintr(struct atw_softc *sc)
>   */
>   ieee80211_release_node(ic, ni);
>   }
> + ieee80211_input_flush(ifp);
>  
>   /* Update the receive pointer. */
>   sc->sc_rxptr = i;
> blob - 7d6f2c5a5693881e2dffdd1814a757c9563196fc
> blob + 9ce7309aeb96e7282fc8ac28e3cfc633e1d9f592
> --- sys/dev/ic/bwfm.c
> +++ sys/dev/ic/bwfm.c
> @@ -2118,6 +2118,7 @@ bwfm_rx_auth_ind(struct bwfm_softc *sc, struct bwfm_ev
>   rxi.rxi_rssi = 0;
>   rxi.rxi_tstamp = 0;
>   ieee80211_input(ifp, m, ic->ic_bss, &rxi);
> + ieee80211_input_flush(ifp);
>  }
>  
>  void
> @@ -2174,6 +2175,7 @@ bwfm_rx_assoc_ind(struct bwfm_softc *sc, struct bwfm_e
>   rxi.rxi_rssi = 0;
>   rxi.rxi_tstamp = 0;
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  }
>  
>  void
> @@ -2229,6 +2231,7 @@ bwfm_rx_leave_ind(struct bwfm_softc *sc, struct bwfm_e
>   rxi.rxi_rssi = 0;
>   rxi.rxi_tstamp = 0;
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  }
>  #endif
>  
> @@ -2418,6 +2421,7 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
>   rxi.rxi_rssi = (int16_t)letoh16(bss->rssi);
>   rxi.rxi_tstamp = 0;
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>   /* Restore channel */
>   if (bss_chan)
>   ni->ni_chan = bss_chan;
> blob - 58417ce6f7de644fe86347459c04553956b2edc0
> blob + 25a40399a82089a496698f4a1fb8d88cb59375ac
> --- sys/dev/ic/bwi.c
> +++ sys/dev/ic/bwi.c
> @@ -8466,6 +8466,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
>  next:
>   idx = (idx + 1) % BWI_RX_NDESC;
>   }
> + ieee80211_input_flush(ifp);
>  
>   rbd->rbd_idx = idx;
>   bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
> blob - 6a8c5646f0b6f649a60793e127cbd746d8ee89d7
> blob + bcd515d11a392f49f75914f1af6581b35b8cf054
> --- sys/dev/ic/malo.c
> +++ sys/dev/ic/malo.c
> @@ -1727,6 +1727,7 @@ skip:
>   sc->sc_rxring.cur = (sc->sc_rxring.cur + 1) %
>      MALO_RX_RING_COUNT;
>   }
> + ieee80211_input_flush(ifp);
>  
>   malo_mem_write4(sc, sc->sc_RxPdRdPtr, rxRdPtr);
>  }
> blob - f44264645097e6f991f5642f7973ed5ebe3e5d7e
> blob + 2f316718eb1c5310c46c64394c8b3603b056499e
> --- sys/dev/ic/pgt.c
> +++ sys/dev/ic/pgt.c
> @@ -1036,6 +1036,7 @@ input:
>   ifp->if_ierrors++;
>   }
>   }
> + ieee80211_input_flush(ifp);
>  }
>  
>  void
> blob - c8d85564272d263215e829d007c11a47741316e6
> blob + 32b3ddbc260c86e39043baef04ceb64edf4c02b4
> --- sys/dev/ic/rt2560.c
> +++ sys/dev/ic/rt2560.c
> @@ -1220,6 +1220,7 @@ skip: desc->flags = htole32(RT2560_RX_BUSY);
>   sc->rxq.cur_decrypt =
>      (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT;
>   }
> + ieee80211_input_flush(ifp);
>  }
>  
>  /*
> blob - 591115f692d4f77a522d114e5a91d6026e3452fe
> blob + 8e090624a986aee3b0748884baa8a84332d92ff5
> --- sys/dev/ic/rt2661.c
> +++ sys/dev/ic/rt2661.c
> @@ -1302,6 +1302,7 @@ skip: desc->flags |= htole32(RT2661_RX_BUSY);
>  
>   sc->rxq.cur = (sc->rxq.cur + 1) % RT2661_RX_RING_COUNT;
>   }
> + ieee80211_input_flush(ifp);
>  }
>  
>  #ifndef IEEE80211_STA_ONLY
> blob - c6c811c835ef4558079c00d50041075b9a8321bb
> blob + 2fc9aedb090a50080c099d5b24ca96535ccf33dc
> --- sys/dev/ic/rt2860.c
> +++ sys/dev/ic/rt2860.c
> @@ -1432,6 +1432,7 @@ skip: rxd->sdl0 &= ~htole16(RT2860_RX_DDONE);
>  
>   sc->rxq.cur = (sc->rxq.cur + 1) % RT2860_RX_RING_COUNT;
>   }
> + ieee80211_input_flush(ifp);
>  
>   /* tell HW what we have processed */
>   RAL_WRITE(sc, RT2860_RX_CALC_IDX,
> blob - ce7686c40fa4b1166d0af3fe54d8cad60704f556
> blob + 420bcd5f0db656fb85833f6ad290b2432c1fe82f
> --- sys/dev/ic/rtw.c
> +++ sys/dev/ic/rtw.c
> @@ -1294,6 +1294,7 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
>  next:
>   rtw_rxdesc_init(rdb, rs, next, 0);
>   }
> + ieee80211_input_flush(&sc->sc_if);
>   rdb->rdb_next = next;
>  
>   KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
> blob - cd0d354d12f45e34327a1d9d2d6ae5b480f9e305
> blob + cf8f4f3f38d70f01c28136f6a2e3f9f8fa9dc7c4
> --- sys/dev/pci/if_ipw.c
> +++ sys/dev/pci/if_ipw.c
> @@ -966,6 +966,7 @@ ipw_rx_intr(struct ipw_softc *sc)
>      i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
>      BUS_DMASYNC_PREWRITE);
>   }
> + ieee80211_input_flush(&sc->sc_ic.ic_if);
>  
>   /* tell the firmware what we have processed */
>   sc->rxcur = (r == 0) ? IPW_NRBD - 1 : r - 1;
> blob - bdb4827425118b9159ae05ad1263bdf5c084254f
> blob + 77621142318b26269d864de7443d3f6cd27ffe27
> --- sys/dev/pci/if_iwi.c
> +++ sys/dev/pci/if_iwi.c
> @@ -1105,6 +1105,7 @@ iwi_rx_intr(struct iwi_softc *sc)
>  
>   sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
>   }
> + ieee80211_input_flush(&sc->sc_ic.ic_if);
>  
>   /* tell the firmware what we have processed */
>   hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
> blob - 0b2116dbc13428f1726773000e8e6a8c251d86b4
> blob + d347c3d8f4853099592dd1617dcfd5946bdd5c6c
> --- sys/dev/pci/if_iwm.c
> +++ sys/dev/pci/if_iwm.c
> @@ -7289,6 +7289,7 @@ iwm_notif_intr(struct iwm_softc *sc)
>  
>   ADVANCE_RXQ(sc);
>   }
> + ieee80211_input_flush(&sc->sc_ic.ic_if);
>  
>   /*
>   * Tell the firmware what we have processed.
> blob - 6be794c2cd435c74b1b5c3f028b9613dc74ecf20
> blob + 06d0e55d42910fc8c60bd29078829399cf337fe4
> --- sys/dev/pci/if_iwn.c
> +++ sys/dev/pci/if_iwn.c
> @@ -2913,6 +2913,7 @@ iwn_notif_intr(struct iwn_softc *sc)
>  
>   sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT;
>   }
> + ieee80211_input_flush(&sc->sc_ic.ic_if);
>  
>   /* Tell the firmware what we have processed. */
>   hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1;
> blob - 2c53aa925247b5056360daf479fca12e45624107
> blob + 9dc76928c677c89fc9f7d2aa09082bf73e62190c
> --- sys/dev/pci/if_rtwn.c
> +++ sys/dev/pci/if_rtwn.c
> @@ -1511,6 +1511,8 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
>   rtwn_tx_done(sc, RTWN_VO_QUEUE);
>   if ((status & (R88E_HIMR_ROK | R88E_HIMR_RDU)) ||
>      (estatus & R88E_HIMRE_RXFOVW)) {
> + struct ieee80211com *ic = &sc->sc_sc.sc_ic;
> +
>   bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
>      sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
>      BUS_DMASYNC_POSTREAD);
> @@ -1524,6 +1526,7 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
>  
>   rtwn_rx_frame(sc, rx_desc, rx_data, i);
>   }
> + ieee80211_input_flush(&ic->ic_if);
>   }
>  
>   if (status & R88E_HIMR_HSISR_IND_ON_INT) {
> @@ -1561,6 +1564,8 @@ rtwn_intr(void *xsc)
>  
>   /* Vendor driver treats RX errors like ROK... */
>   if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) {
> + struct ieee80211com *ic = &sc->sc_sc.sc_ic;
> +
>   bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
>      sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
>      BUS_DMASYNC_POSTREAD);
> @@ -1574,6 +1579,7 @@ rtwn_intr(void *xsc)
>  
>   rtwn_rx_frame(sc, rx_desc, rx_data, i);
>   }
> + ieee80211_input_flush(&ic->ic_if);
>   }
>  
>   if (status & R92C_IMR_BDOK)
> blob - 2a91ccec016f8047bfe26ede71e8881404fef619
> blob + 02f8191621b3c3967aab4abec9447c7cd4e5ffac
> --- sys/dev/pci/if_wpi.c
> +++ sys/dev/pci/if_wpi.c
> @@ -1527,6 +1527,7 @@ wpi_notif_intr(struct wpi_softc *sc)
>  
>   sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;
>   }
> + ieee80211_input_flush(&ic->ic_if);
>  
>   /* Tell the firmware what we have processed. */
>   hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1;
> blob - 39edb129685cac47d29224f18c6f2e7c92922720
> blob + 2fe4fc1af606a4ab32e6dcce83cc7c710e3c814b
> --- sys/dev/usb/if_athn_usb.c
> +++ sys/dev/usb/if_athn_usb.c
> @@ -2175,6 +2175,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
>   buf += off;
>   len -= off;
>   }
> + ieee80211_input_flush(ifp);
>  
>   resubmit:
>   /* Setup a new transfer. */
> blob - 7c49042002e73f07bda3c9a5dc7e13e9d7e97503
> blob + 46fa39efc05c66d59e7e73c94dfe2b5ec635d9ad
> --- sys/dev/usb/if_atu.c
> +++ sys/dev/usb/if_atu.c
> @@ -1743,6 +1743,7 @@ atu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
>   rxi.rxi_rssi = h->rssi;
>   rxi.rxi_tstamp = UGETDW(h->rx_time);
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  
>   ieee80211_release_node(ic, ni);
>  done1:
> blob - cb7e65865adb17b86e10bf5c2bc59983a5c8c2c9
> blob + 3c8da94867b14ab18d315b7c69c1188cc770569d
> --- sys/dev/usb/if_otus.c
> +++ sys/dev/usb/if_otus.c
> @@ -1241,6 +1241,7 @@ otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
>   buf += hlen;
>   len -= hlen;
>   }
> + ieee80211_input_flush(&sc->sc_ic.ic_if);
>  
>   resubmit:
>   usbd_setup_xfer(xfer, sc->data_rx_pipe, data, data->buf, OTUS_RXBUFSZ,
> blob - 9d81664f824def87770512b3e61a015782c99be0
> blob + 623fd79146a1879baf23aee4380611444c21f440
> --- sys/dev/usb/if_ral.c
> +++ sys/dev/usb/if_ral.c
> @@ -782,6 +782,7 @@ ural_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
>   rxi.rxi_rssi = desc->rssi;
>   rxi.rxi_tstamp = 0; /* unused */
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  
>   /* node is no longer needed */
>   ieee80211_release_node(ic, ni);
> blob - 417666c3503da89fce1d3dc4301b48376dcf7e41
> blob + e8d263d2c4322d44836e0197cdd909adc795648e
> --- sys/dev/usb/if_rsu.c
> +++ sys/dev/usb/if_rsu.c
> @@ -1120,6 +1120,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, i
>   rxi.rxi_rssi = letoh32(bss->rssi);
>   rxi.rxi_tstamp = 0;
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>   /* Node is no longer needed. */
>   ieee80211_release_node(ic, ni);
>  }
> @@ -1415,6 +1416,7 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf,
>   buf += totlen;
>   len -= totlen;
>   }
> + ieee80211_input_flush(&sc->sc_ic.ic_if);
>  }
>  
>  void
> blob - 7126aaa9540a3f838e7bc1d4e80a06e759e98517
> blob + 3fe904607ebf7584cee0348ebb9d4135510d499e
> --- sys/dev/usb/if_rum.c
> +++ sys/dev/usb/if_rum.c
> @@ -851,6 +851,7 @@ rum_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
>   rxi.rxi_rssi = desc->rssi;
>   rxi.rxi_tstamp = 0; /* unused */
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  
>   /* node is no longer needed */
>   ieee80211_release_node(ic, ni);
> blob - fc6ba52f271725fe7afbb4abf1a4a1700920a1b4
> blob + 5342470a39c8094143e9372855c0511c2ed0161e
> --- sys/dev/usb/if_run.c
> +++ sys/dev/usb/if_run.c
> @@ -2352,6 +2352,7 @@ run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
>   buf += dmalen + 8;
>   xferlen -= dmalen + 8;
>   }
> + ieee80211_input_flush(&sc->sc_ic.ic_if);
>  
>  skip: /* setup a new transfer */
>   usbd_setup_xfer(xfer, sc->rxq.pipeh, data, data->buf, RUN_MAX_RXSZ,
> blob - 30aa31b56bfd1226a4199c9024907adbbb3e429d
> blob + d657466dccf52fb1271a3650718feecb6e19c297
> --- sys/dev/usb/if_uath.c
> +++ sys/dev/usb/if_uath.c
> @@ -1265,6 +1265,7 @@ uath_data_rxeof(struct usbd_xfer *xfer, void *priv,
>   rxi.rxi_rssi = (int)betoh32(desc->rssi);
>   rxi.rxi_tstamp = 0; /* unused */
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  
>   /* node is no longer needed */
>   ieee80211_release_node(ic, ni);
> blob - 6c8b66842fb650329fb36d812e76fa41be9ab9c7
> blob + 72928af7c891bcc295dd79d71a2b6155a64eb0a5
> --- sys/dev/usb/if_upgt.c
> +++ sys/dev/usb/if_upgt.c
> @@ -1748,6 +1748,7 @@ upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkgl
>   rxi.rxi_rssi = rxdesc->rssi;
>   rxi.rxi_tstamp = 0; /* unused */
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  
>   /* node is no longer needed */
>   ieee80211_release_node(ic, ni);
> blob - 17d56c174230515195c13c070aed9065a68bc959
> blob + 87bdc93a6df4786458f6eec62ceb025cc7e75a5a
> --- sys/dev/usb/if_urtw.c
> +++ sys/dev/usb/if_urtw.c
> @@ -3161,6 +3161,7 @@ urtw_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
>   rxi.rxi_rssi = rssi;
>   rxi.rxi_tstamp = 0;
>   ieee80211_input(ifp, m, ni, &rxi);
> + ieee80211_input_flush(ifp);
>  
>   /* node is no longer needed */
>   ieee80211_release_node(ic, ni);
> blob - 96a1ad1a91c3e98ebc6dece98df6ac277046612c
> blob + 3f353ff8296162cde2163af94099b9a666bb106c
> --- sys/dev/usb/if_urtwn.c
> +++ sys/dev/usb/if_urtwn.c
> @@ -1206,6 +1206,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
>  {
>   struct urtwn_rx_data *data = priv;
>   struct urtwn_softc *sc = data->sc;
> + struct ieee80211com *ic = &sc->sc_sc.sc_ic;
>   struct r92c_rx_desc_usb *rxd;
>   uint32_t rxdw0;
>   uint8_t *buf;
> @@ -1305,6 +1306,7 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
>   buf += totlen;
>   len -= totlen;
>   }
> + ieee80211_input_flush(&ic->ic_if);
>  
>   resubmit:
>   /* Setup a new transfer. */
> blob - 689ac7e7178ca36a091d25cc6f2cf8d15cc45b0b
> blob + 498bb68138994cd361f996c866e95c959a5ddf15
> --- sys/dev/usb/if_zyd.c
> +++ sys/dev/usb/if_zyd.c
> @@ -2039,6 +2039,7 @@ zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
>  
>   zyd_rx_data(sc, data->buf, len);
>   }
> + ieee80211_input_flush(ifp);
>  
>  skip: /* setup a new transfer */
>   usbd_setup_xfer(xfer, sc->zyd_ep[ZYD_ENDPT_BIN], data, NULL,
> blob - ace97a38cc4ff76b454c1f6a12655565ad131275
> blob + c20962c799b141638a2fff11d5ceef6d6db47667
> --- sys/net80211/ieee80211.c
> +++ sys/net80211/ieee80211.c
> @@ -184,6 +184,8 @@ ieee80211_ifattach(struct ifnet *ifp)
>   ic->ic_bmissthres = 7; /* default 7 beacons */
>   ic->ic_dtim_period = 1; /* all TIMs are DTIMs */
>  
> + ml_init(&ic->ic_ml);
> +
>   ieee80211_node_attach(ifp);
>   ieee80211_proto_attach(ifp);
>  
> @@ -200,6 +202,7 @@ ieee80211_ifdetach(struct ifnet *ifp)
>  {
>   struct ieee80211com *ic = (void *)ifp;
>  
> + ml_purge(&ic->ic_ml);
>   timeout_del(&ic->ic_bgscan_timeout);
>   ieee80211_proto_detach(ifp);
>   ieee80211_crypto_detach(ifp);
> blob - 73a9d5229502797c5279734663b1ac1591bec309
> blob + de36481038ec3372d0d5533002cbc62a1ebe2b6a
> --- sys/net80211/ieee80211_input.c
> +++ sys/net80211/ieee80211_input.c
> @@ -71,11 +71,11 @@ void ieee80211_input_ba_seq(struct ieee80211com *,
>      struct ieee80211_node *, uint8_t, uint16_t);
>  struct mbuf *ieee80211_align_mbuf(struct mbuf *);
>  void ieee80211_decap(struct ieee80211com *, struct mbuf *,
> -    struct ieee80211_node *, int);
> +    struct ieee80211_node *, int, struct mbuf_list *);
>  void ieee80211_amsdu_decap(struct ieee80211com *, struct mbuf *,
> -    struct ieee80211_node *, int);
> -void ieee80211_deliver_data(struct ieee80211com *, struct mbuf *,
> -    struct ieee80211_node *, int);
> +    struct ieee80211_node *, int, struct mbuf_list *);
> +void ieee80211_enqueue_data(struct ieee80211com *, struct mbuf *,
> +    struct ieee80211_node *, int, struct mbuf_list *);
>  int ieee80211_parse_edca_params_body(struct ieee80211com *,
>      const u_int8_t *);
>  int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
> @@ -155,6 +155,9 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh)
>   * any units so long as values have consistent units and higher values
>   * mean ``better signal''.  The receive timestamp is currently not used
>   * by the 802.11 layer.
> + *
> + * This function only queues frames for delivery.
> + * Actual delivery to upper layers is triggered by ieee80211_input_flush().
>   */
>  void
>  ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
> @@ -463,9 +466,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
>  
>   if ((ni->ni_flags & IEEE80211_NODE_HT) &&
>      hasqos && (qos & IEEE80211_QOS_AMSDU))
> - ieee80211_amsdu_decap(ic, m, ni, hdrlen);
> + ieee80211_amsdu_decap(ic, m, ni, hdrlen, &ic->ic_ml);
>   else
> - ieee80211_decap(ic, m, ni, hdrlen);
> + ieee80211_decap(ic, m, ni, hdrlen, &ic->ic_ml);
>   return;
>  
>   case IEEE80211_FC0_TYPE_MGT:
> @@ -561,6 +564,22 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
>  }
>  
>  /*
> + * Deliver frames queued by ieee80211_input() to the network stack.
> + * Drivers should call this function only once per Rx interrupt to avoid
> + * triggering the input ifq pressure drop mechanism unnecessarily.
> + */
> +void
> +ieee80211_input_flush(struct ifnet *ifp)
> +{
> + struct ieee80211com *ic = (void *)ifp;
> + int s;
> +
> + s = splnet();
> + if_input(ifp, &ic->ic_ml);
> + splx(s);
> +}
> +
> +/*
>   * Handle defragmentation (see 9.5 and Annex C).  We support the concurrent
>   * reception of fragments of three fragmented MSDUs or MMPDUs.
>   */
> @@ -856,8 +875,8 @@ ieee80211_ba_move_window(struct ieee80211com *ic, stru
>  }
>  
>  void
> -ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m,
> -    struct ieee80211_node *ni, int mcast)
> +ieee80211_enqueue_data(struct ieee80211com *ic, struct mbuf *m,
> +    struct ieee80211_node *ni, int mcast, struct mbuf_list *ml)
>  {
>   struct ifnet *ifp = &ic->ic_if;
>   struct ether_header *eh;
> @@ -920,16 +939,14 @@ ieee80211_deliver_data(struct ieee80211com *ic, struct
>  #endif
>   ieee80211_eapol_key_input(ic, m, ni);
>   } else {
> - struct mbuf_list ml = MBUF_LIST_INITIALIZER();
> - ml_enqueue(&ml, m);
> - if_input(ifp, &ml);
> + ml_enqueue(ml, m);
>   }
>   }
>  }
>  
>  void
>  ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
> -    struct ieee80211_node *ni, int hdrlen)
> +    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
>  {
>   struct ether_header eh;
>   struct ieee80211_frame *wh;
> @@ -985,7 +1002,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
>   return;
>   }
>   }
> - ieee80211_deliver_data(ic, m, ni, mcast);
> + ieee80211_enqueue_data(ic, m, ni, mcast, ml);
>  }
>  
>  /*
> @@ -993,7 +1010,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
>   */
>  void
>  ieee80211_amsdu_decap(struct ieee80211com *ic, struct mbuf *m,
> -    struct ieee80211_node *ni, int hdrlen)
> +    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
>  {
>   struct mbuf *n;
>   struct ether_header *eh;
> @@ -1059,7 +1076,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct
>   m_freem(m);
>   break;
>   }
> - ieee80211_deliver_data(ic, m, ni, mcast);
> + ieee80211_enqueue_data(ic, m, ni, mcast, ml);
>  
>   if (n->m_pkthdr.len == 0) {
>   m_freem(n);
> blob - d00d1b631f2966efbd88992c92fea88a99e3ddf8
> blob + 87c41116d48d86cf446cae6486ee1dde42a92701
> --- sys/net80211/ieee80211_proto.c
> +++ sys/net80211/ieee80211_proto.c
> @@ -974,9 +974,7 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee8
>   struct ieee80211_node *ni;
>   enum ieee80211_state ostate;
>   u_int rate;
> -#ifndef IEEE80211_STA_ONLY
>   int s;
> -#endif
>  
>   ostate = ic->ic_state;
>   if (ifp->if_flags & IFF_DEBUG)
> @@ -1060,6 +1058,9 @@ justcleanup:
>   ic->ic_mgt_timer = 0;
>   mq_purge(&ic->ic_mgtq);
>   mq_purge(&ic->ic_pwrsaveq);
> + s = splnet();
> + ml_purge(&ic->ic_ml);
> + splx(s);
>   ieee80211_free_allnodes(ic, 1);
>   break;
>   }
> @@ -1113,6 +1114,9 @@ justcleanup:
>   ic->ic_bgscan_fail = 0;
>   ieee80211_stop_ampdu_tx(ic, ni, mgt);
>   ieee80211_free_allnodes(ic, 1);
> + s = splnet();
> + ml_purge(&ic->ic_ml);
> + splx(s);
>   /* FALLTHROUGH */
>   case IEEE80211_S_AUTH:
>   case IEEE80211_S_ASSOC:
> @@ -1161,6 +1165,9 @@ justcleanup:
>   ic->ic_bgscan_fail = 0;
>   ieee80211_stop_ampdu_tx(ic, ni, mgt);
>   ieee80211_ba_del(ni);
> + s = splnet();
> + ml_purge(&ic->ic_ml);
> + splx(s);
>   switch (mgt) {
>   case IEEE80211_FC0_SUBTYPE_AUTH:
>   IEEE80211_SEND_MGMT(ic, ni,
> @@ -1193,6 +1200,9 @@ justcleanup:
>   case IEEE80211_S_RUN:
>   ieee80211_stop_ampdu_tx(ic, ni, mgt);
>   ieee80211_ba_del(ni);
> + s = splnet();
> + ml_purge(&ic->ic_ml);
> + splx(s);
>   IEEE80211_SEND_MGMT(ic, ni,
>      IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
>   break;
> blob - e622d35f4dcd21ea0bb40c6a5d0b3f758e197b38
> blob + c1d3ad65a46f76266533a4cfd5fffa08b4fa6537
> --- sys/net80211/ieee80211_proto.h
> +++ sys/net80211/ieee80211_proto.h
> @@ -68,6 +68,7 @@ extern u_int ieee80211_get_hdrlen(const struct ieee802
>  extern int ieee80211_classify(struct ieee80211com *, struct mbuf *);
>  extern void ieee80211_input(struct ifnet *, struct mbuf *,
>   struct ieee80211_node *, struct ieee80211_rxinfo *);
> +extern void ieee80211_input_flush(struct ifnet *);
>  extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,
>   struct rtentry *);
>  extern void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
> blob - 2a567a01422aaaf6024b05c5589f6f45b3744100
> blob + fcbe48513883c4c81cfb4c4d96e4d5d08a07ab7f
> --- sys/net80211/ieee80211_var.h
> +++ sys/net80211/ieee80211_var.h
> @@ -340,6 +340,8 @@ struct ieee80211com {
>   u_int8_t ic_dialog_token;
>   int ic_fixed_mcs;
>   TAILQ_HEAD(, ieee80211_ess) ic_ess;
> +
> + struct mbuf_list ic_ml; /* frames queued for if_input() */
>  };
>  #define ic_if ic_ac.ac_if
>  #define ic_softc ic_if.if_softc
>

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Stefan Sperling-5
On Mon, Sep 09, 2019 at 06:17:34PM -0300, Martin Pieuchot wrote:

> On 09/09/19(Mon) 16:37, Stefan Sperling wrote:
> > On Mon, Sep 09, 2019 at 03:10:04PM +0200, Stefan Sperling wrote:
> > > The wifi stack currently calls if_input once per packet instead of once
> > > per interrupt. To make the wifi layer play nicely with the network stack
> > > we can split ieee80211_input() into two parts:
> >
> > Updated diff which avoids purging the input queue at every state
> > change, e.g. even during SCAN->SCAN. With this we only purge the
> > queue if we're leaving RUN state or going back to INIT state.
>
> Thanks a lot!  I must say I looked at this in the past but got lost in
> ieee80211_input().
>
> Why not keep ieee80211_input() as a wrapper around your new mechanism?
> This way you don't need to touch all drivers at once.

We can keep ieee80211_input() for use by drivers that really only deliver
one frame per interrupt. Now we don't need to touch some drivers at all.

> I'd also suggest using a queue on-stack like we do for Ethernet drivers,
> this would get rid of the cleanup of `ic_ml' when the state change.  It
> would also help developers familiar with Ethernet drivers to understand
> what's happening ;o)

Yes, thanks for this suggestion! Things make a lot more sense this way.

> What about:
>
>  ieee80211_enqueue(ifp, m, ni, &rxi, &ml);
>  ieee80211_inputm(ifp, &ml);

I don't like the name ieee80211_enqueue() because while data frames are
being enqueued, management frames are not enqueued. Instead, they cause
immediate state changes in the net80211 stack such as allocation of a
new node when a beacon is received state changes, e.g. RUN -> AUTH when
a deauth frame is received.

When drivers have the mbuf list on the stack we do not need a wrapper
for if_input() since drivers can just call it directly.

So I have chosen to use the following instead:

   ieee80211_inputm(ifp, m, ni, &rxi, &ml);
   if_input(ifp, &ml);

With ieee80211_input() being a wrapper around these two calls.

> Are you sure if_input() needs to be called at splnet()?  I don't think
> so because many pseudo-drivers call it at a different IPL.

I did this only because I was afraid the global ic_ml might be accessed
by hardware interrupts while we're running newstate() in a task as some
drivers will do. This becomes a non-issue with mbuf lists on the stack.

New diff with above changes:

diff refs/heads/master refs/heads/ifqdrop
blob - d72e8edceada8a680744a6b8478bb91ac9e15e6e
blob + a3203d7eb1a67d478bf280a551a43f2dc66c0965
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -789,7 +789,7 @@ ar5008_rx_radiotap(struct athn_softc *sc, struct mbuf
 #endif
 
 static __inline int
-ar5008_rx_process(struct athn_softc *sc)
+ar5008_rx_process(struct athn_softc *sc, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -931,7 +931,7 @@ ar5008_rx_process(struct athn_softc *sc)
  rxi.rxi_rssi = MS(ds->ds_status4, AR_RXS4_RSSI_COMBINED);
  rxi.rxi_rssi += AR_DEFAULT_NOISE_FLOOR;
  rxi.rxi_tstamp = ds->ds_status2;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -960,7 +960,13 @@ ar5008_rx_process(struct athn_softc *sc)
 void
 ar5008_rx_intr(struct athn_softc *sc)
 {
- while (ar5008_rx_process(sc) == 0);
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
+ while (ar5008_rx_process(sc, &ml) == 0);
+
+ if_input(ifp, &ml);
 }
 
 int
blob - 69ade5ade5a35e632a025db327668d695a0edd2d
blob + dafa3bd1f0b4ca2124c6d963c82e289594e88b27
--- sys/dev/ic/ar9003.c
+++ sys/dev/ic/ar9003.c
@@ -83,7 +83,7 @@ void ar9003_reset_txsring(struct athn_softc *);
 void ar9003_rx_enable(struct athn_softc *);
 void ar9003_rx_radiotap(struct athn_softc *, struct mbuf *,
     struct ar_rx_status *);
-int ar9003_rx_process(struct athn_softc *, int);
+int ar9003_rx_process(struct athn_softc *, int, struct mbuf_list *);
 void ar9003_rx_intr(struct athn_softc *, int);
 int ar9003_tx_process(struct athn_softc *);
 void ar9003_tx_intr(struct athn_softc *);
@@ -916,7 +916,7 @@ ar9003_rx_radiotap(struct athn_softc *sc, struct mbuf
 #endif
 
 int
-ar9003_rx_process(struct athn_softc *sc, int qid)
+ar9003_rx_process(struct athn_softc *sc, int qid, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1036,7 +1036,7 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
  rxi.rxi_flags = 0; /* XXX */
  rxi.rxi_rssi = MS(ds->ds_status5, AR_RXS5_RSSI_COMBINED);
  rxi.rxi_tstamp = ds->ds_status3;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -1066,7 +1066,13 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
 void
 ar9003_rx_intr(struct athn_softc *sc, int qid)
 {
- while (ar9003_rx_process(sc, qid) == 0);
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
+ while (ar9003_rx_process(sc, qid, &ml) == 0);
+
+ if_input(ifp, &ml);
 }
 
 int
blob - c0c5f4241b010c5c38a557d97963fbdbc884336d
blob + c4414e5113134012edaf4ce4557bb7e25987e9ef
--- sys/dev/ic/ath.c
+++ sys/dev/ic/ath.c
@@ -1795,6 +1795,7 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *b
 void
 ath_rx_proc(void *arg, int npending)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
 #define PA2DESC(_sc, _pa) \
  ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
  ((_pa) - (_sc)->sc_desc_paddr)))
@@ -1946,7 +1947,7 @@ ath_rx_proc(void *arg, int npending)
  if (!ath_softcrypto && (wh->i_fc[1] & IEEE80211_FC1_WEP)) {
  /*
  * WEP is decrypted by hardware. Clear WEP bit
- * and trim WEP header for ieee80211_input().
+ * and trim WEP header for ieee80211_inputm().
  */
  wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
  bcopy(wh, &whbuf, sizeof(whbuf));
@@ -1988,7 +1989,7 @@ ath_rx_proc(void *arg, int npending)
  */
  rxi.rxi_rssi = ds->ds_rxstat.rs_rssi;
  rxi.rxi_tstamp = ds->ds_rxstat.rs_tstamp;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /* Handle the rate adaption */
  ieee80211_rssadapt_input(ic, ni, &an->an_rssadapt,
@@ -2004,6 +2005,8 @@ ath_rx_proc(void *arg, int npending)
  rx_next:
  TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
  } while (ath_rxbuf_init(sc, bf) == 0);
+
+ if_input(ifp, &ml);
 
  ath_hal_set_rx_signal(ah); /* rx signal state monitoring */
  ath_hal_start_rx(ah); /* in case of RXEOL */
blob - cbf21da74007080c510fa9c56a58aedff62fa586
blob + 6f609b3d8e77c27ba27e6be88cff55fbf87bbb2c
--- sys/dev/ic/atw.c
+++ sys/dev/ic/atw.c
@@ -3029,6 +3029,7 @@ atw_hw_decrypted(struct atw_softc *sc, struct ieee8021
 void
 atw_rxintr(struct atw_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  static int rate_tbl[] = {2, 4, 11, 22, 44};
  struct ieee80211com *ic = &sc->sc_ic;
  struct ieee80211_rxinfo rxi;
@@ -3183,7 +3184,7 @@ atw_rxintr(struct atw_softc *sc)
 #endif
  rxi.rxi_rssi = (int)rssi;
  rxi.rxi_tstamp = 0;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
  /*
  * The frame may have caused the node to be marked for
  * reclamation (e.g. in response to a DEAUTH message)
@@ -3191,6 +3192,7 @@ atw_rxintr(struct atw_softc *sc)
  */
  ieee80211_release_node(ic, ni);
  }
+ if_input(ifp, &ml);
 
  /* Update the receive pointer. */
  sc->sc_rxptr = i;
blob - 58417ce6f7de644fe86347459c04553956b2edc0
blob + b383588620701ca5c656d29c0384393696914cdc
--- sys/dev/ic/bwi.c
+++ sys/dev/ic/bwi.c
@@ -8355,6 +8355,7 @@ bwi_next_scan(void *xsc)
 int
 bwi_rxeof(struct bwi_softc *sc, int end_idx)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct bwi_ring_data *rd = &sc->sc_rx_rdata;
  struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
  struct ieee80211com *ic = &sc->sc_ic;
@@ -8455,7 +8456,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 
  rxi.rxi_rssi = hdr->rxh_rssi;
  rxi.rxi_tstamp = letoh16(hdr->rxh_tsf);
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  ieee80211_release_node(ic, ni);
 
@@ -8466,6 +8467,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 next:
  idx = (idx + 1) % BWI_RX_NDESC;
  }
+ if_input(ifp, &ml);
 
  rbd->rbd_idx = idx;
  bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
blob - 6a8c5646f0b6f649a60793e127cbd746d8ee89d7
blob + af91b6b414ecc45cd3caceec3f0a7ea6e2aae400
--- sys/dev/ic/malo.c
+++ sys/dev/ic/malo.c
@@ -1593,6 +1593,7 @@ malo_tx_setup_desc(struct malo_softc *sc, struct malo_
 void
 malo_rx_intr(struct malo_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  struct malo_rx_desc *desc;
@@ -1711,7 +1712,7 @@ malo_rx_intr(struct malo_softc *sc)
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1727,6 +1728,7 @@ skip:
  sc->sc_rxring.cur = (sc->sc_rxring.cur + 1) %
     MALO_RX_RING_COUNT;
  }
+ if_input(ifp, &ml);
 
  malo_mem_write4(sc, sc->sc_RxPdRdPtr, rxRdPtr);
 }
blob - f44264645097e6f991f5642f7973ed5ebe3e5d7e
blob + 695723c6f054b8ab264aefb609696dffbaae6c6b
--- sys/dev/ic/pgt.c
+++ sys/dev/ic/pgt.c
@@ -899,6 +899,7 @@ void
 pgt_input_frames(struct pgt_softc *sc, struct mbuf *m)
 {
  struct ether_header eh;
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ifnet *ifp;
  struct ieee80211_channel *chan;
  struct ieee80211_rxinfo rxi;
@@ -1022,7 +1023,7 @@ input:
  rxi.rxi_flags = 0;
  ni->ni_rssi = rxi.rxi_rssi = rssi;
  ni->ni_rstamp = rxi.rxi_tstamp = rstamp;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
  /*
  * The frame may have caused the node to be marked for
  * reclamation (e.g. in response to a DEAUTH message)
@@ -1036,6 +1037,7 @@ input:
  ifp->if_ierrors++;
  }
  }
+ if_input(ifp, &ml);
 }
 
 void
blob - c8d85564272d263215e829d007c11a47741316e6
blob + 4b6e4c0592a9ac543cc83d2ff6ccc692427c0adf
--- sys/dev/ic/rt2560.c
+++ sys/dev/ic/rt2560.c
@@ -1076,6 +1076,7 @@ rt2560_prio_intr(struct rt2560_softc *sc)
 void
 rt2560_decryption_intr(struct rt2560_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_frame *wh;
@@ -1204,7 +1205,7 @@ rt2560_decryption_intr(struct rt2560_softc *sc)
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1220,6 +1221,7 @@ skip: desc->flags = htole32(RT2560_RX_BUSY);
  sc->rxq.cur_decrypt =
     (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT;
  }
+ if_input(ifp, &ml);
 }
 
 /*
blob - 591115f692d4f77a522d114e5a91d6026e3452fe
blob + 44f767f9bba3aec85758600684dc786d5eab3ed3
--- sys/dev/ic/rt2661.c
+++ sys/dev/ic/rt2661.c
@@ -1153,6 +1153,7 @@ rt2661_tx_dma_intr(struct rt2661_softc *sc, struct rt2
 void
 rt2661_rx_intr(struct rt2661_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_frame *wh;
@@ -1279,7 +1280,7 @@ rt2661_rx_intr(struct rt2661_softc *sc)
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /*-
  * Keep track of the average RSSI using an Exponential Moving
@@ -1302,6 +1303,7 @@ skip: desc->flags |= htole32(RT2661_RX_BUSY);
 
  sc->rxq.cur = (sc->rxq.cur + 1) % RT2661_RX_RING_COUNT;
  }
+ if_input(ifp, &ml);
 }
 
 #ifndef IEEE80211_STA_ONLY
blob - c6c811c835ef4558079c00d50041075b9a8321bb
blob + 286f4c859d84a8dc13a54e74c355bc443cf2f7e8
--- sys/dev/ic/rt2860.c
+++ sys/dev/ic/rt2860.c
@@ -1260,6 +1260,7 @@ rt2860_maxrssi_chain(struct rt2860_softc *sc, const st
 void
 rt2860_rx_intr(struct rt2860_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_frame *wh;
@@ -1419,7 +1420,7 @@ skipbpf:
  /* send the frame to the 802.11 layer */
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1432,6 +1433,7 @@ skip: rxd->sdl0 &= ~htole16(RT2860_RX_DDONE);
 
  sc->rxq.cur = (sc->rxq.cur + 1) % RT2860_RX_RING_COUNT;
  }
+ if_input(ifp, &ml);
 
  /* tell HW what we have processed */
  RAL_WRITE(sc, RT2860_RX_CALC_IDX,
blob - ce7686c40fa4b1166d0af3fe54d8cad60704f556
blob + 344ffd4381400698d23f8aaee3c623fe649f885f
--- sys/dev/ic/rtw.c
+++ sys/dev/ic/rtw.c
@@ -1081,6 +1081,7 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
  static const int ratetbl[4] = {2, 4, 11, 22}; /* convert rates:
  * hardware -> net80211
  */
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  u_int next, nproc = 0;
  int hwrate, len, rate, rssi, sq;
  u_int32_t hrssi, hstat, htsfth, htsftl;
@@ -1289,11 +1290,12 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = htsftl;
- ieee80211_input(&sc->sc_if, m, ni, &rxi);
+ ieee80211_inputm(&sc->sc_if, m, ni, &rxi, &ml);
  ieee80211_release_node(&sc->sc_ic, ni);
 next:
  rtw_rxdesc_init(rdb, rs, next, 0);
  }
+ if_input(&sc->sc_if, &ml);
  rdb->rdb_next = next;
 
  KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
blob - cd0d354d12f45e34327a1d9d2d6ae5b480f9e305
blob + abcd1e0c7f2509e16102d1ea96e245dca587de90
--- sys/dev/pci/if_ipw.c
+++ sys/dev/pci/if_ipw.c
@@ -71,7 +71,8 @@ uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_
 void ipw_command_intr(struct ipw_softc *, struct ipw_soft_buf *);
 void ipw_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
 void ipw_data_intr(struct ipw_softc *, struct ipw_status *,
-    struct ipw_soft_bd *, struct ipw_soft_buf *);
+    struct ipw_soft_bd *, struct ipw_soft_buf *,
+    struct mbuf_list *);
 void ipw_notification_intr(struct ipw_softc *,
     struct ipw_soft_buf *);
 void ipw_rx_intr(struct ipw_softc *);
@@ -816,7 +817,7 @@ ipw_newstate_intr(struct ipw_softc *sc, struct ipw_sof
 
 void
 ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
-    struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf)
+    struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -903,7 +904,7 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = status->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  ieee80211_release_node(ic, ni);
 }
@@ -917,6 +918,7 @@ ipw_notification_intr(struct ipw_softc *sc, struct ipw
 void
 ipw_rx_intr(struct ipw_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ipw_status *status;
  struct ipw_soft_bd *sbd;
  struct ipw_soft_buf *sbuf;
@@ -949,7 +951,7 @@ ipw_rx_intr(struct ipw_softc *sc)
 
  case IPW_STATUS_CODE_DATA_802_3:
  case IPW_STATUS_CODE_DATA_802_11:
- ipw_data_intr(sc, status, sbd, sbuf);
+ ipw_data_intr(sc, status, sbd, sbuf, &ml);
  break;
 
  case IPW_STATUS_CODE_NOTIFICATION:
@@ -966,6 +968,7 @@ ipw_rx_intr(struct ipw_softc *sc)
     i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
     BUS_DMASYNC_PREWRITE);
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  /* tell the firmware what we have processed */
  sc->rxcur = (r == 0) ? IPW_NRBD - 1 : r - 1;
blob - bdb4827425118b9159ae05ad1263bdf5c084254f
blob + 84366f6545bde46339adf1da2956b9af8f544469
--- sys/dev/pci/if_iwi.c
+++ sys/dev/pci/if_iwi.c
@@ -87,7 +87,7 @@ int iwi_find_txnode(struct iwi_softc *, const uint8_t
 int iwi_newstate(struct ieee80211com *, enum ieee80211_state, int);
 uint8_t iwi_rate(int);
 void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *,
-    struct iwi_frame *);
+    struct iwi_frame *, struct mbuf_list *);
 void iwi_notification_intr(struct iwi_softc *, struct iwi_rx_data *,
     struct iwi_notif *);
 void iwi_rx_intr(struct iwi_softc *);
@@ -854,7 +854,7 @@ iwi_rate(int plcp)
 
 void
 iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data,
-    struct iwi_frame *frame)
+    struct iwi_frame *frame, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -954,7 +954,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_dat
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = frame->rssi_dbm;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1073,6 +1073,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi
 void
 iwi_rx_intr(struct iwi_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct iwi_rx_data *data;
  struct iwi_hdr *hdr;
  uint32_t hw;
@@ -1090,7 +1091,7 @@ iwi_rx_intr(struct iwi_softc *sc)
  switch (hdr->type) {
  case IWI_HDR_TYPE_FRAME:
  iwi_frame_intr(sc, data,
-    (struct iwi_frame *)(hdr + 1));
+    (struct iwi_frame *)(hdr + 1), &ml);
  break;
 
  case IWI_HDR_TYPE_NOTIF:
@@ -1105,6 +1106,7 @@ iwi_rx_intr(struct iwi_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  /* tell the firmware what we have processed */
  hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
blob - 0b2116dbc13428f1726773000e8e6a8c251d86b4
blob + 26bd730272774dc8cef58c87638c21c0536a016a
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -368,7 +368,7 @@ void iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_
     struct iwm_rx_data *);
 int iwm_get_noise(const struct iwm_statistics_rx_non_phy *);
 void iwm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *,
-    struct iwm_rx_data *);
+    struct iwm_rx_data *, struct mbuf_list *);
 void iwm_enable_ht_cck_fallback(struct iwm_softc *, struct iwm_node *);
 void iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
     struct iwm_node *);
@@ -3431,7 +3431,7 @@ iwm_get_noise(const struct iwm_statistics_rx_non_phy *
 
 void
 iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
-    struct iwm_rx_data *data)
+    struct iwm_rx_data *data, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ieee80211_frame *wh;
@@ -3564,9 +3564,9 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
  bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
  }
 #endif
- ieee80211_input(IC2IFP(ic), m, ni, &rxi);
+ ieee80211_inputm(IC2IFP(ic), m, ni, &rxi, ml);
  /*
- * ieee80211_input() might have changed our BSS.
+ * ieee80211_inputm() might have changed our BSS.
  * Restore ic_bss's channel if we are still in the same BSS.
  */
  if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
@@ -7005,6 +7005,7 @@ do { \
 void
 iwm_notif_intr(struct iwm_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  uint16_t hw;
 
  bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map,
@@ -7042,7 +7043,7 @@ iwm_notif_intr(struct iwm_softc *sc)
  break;
 
  case IWM_REPLY_RX_MPDU_CMD:
- iwm_rx_rx_mpdu(sc, pkt, data);
+ iwm_rx_rx_mpdu(sc, pkt, data, &ml);
  break;
 
  case IWM_TX_CMD:
@@ -7289,6 +7290,7 @@ iwm_notif_intr(struct iwm_softc *sc)
 
  ADVANCE_RXQ(sc);
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  /*
  * Tell the firmware what we have processed.
blob - 6be794c2cd435c74b1b5c3f028b9613dc74ecf20
blob + c76b53c4c97d6c49f2837667b8758958163246f4
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -156,7 +156,7 @@ int iwn_ccmp_decap(struct iwn_softc *, struct mbuf *,
 void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
     struct iwn_rx_data *);
 void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
-    struct iwn_rx_data *);
+    struct iwn_rx_data *, struct mbuf_list *);
 void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
     struct iwn_rx_data *);
 void iwn5000_rx_calib_results(struct iwn_softc *,
@@ -1937,7 +1937,7 @@ iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, s
  * Such frames may be received out of order due to
  * legitimate retransmissions of failed subframes
  * in previous A-MPDUs. Duplicates will be handled
- * in ieee80211_input() as part of A-MPDU reordering.
+ * in ieee80211_inputm() as part of A-MPDU reordering.
  */
  } else if (ieee80211_has_seq(wh)) {
  /*
@@ -2007,7 +2007,7 @@ iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *d
  */
 void
 iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
-    struct iwn_rx_data *data)
+    struct iwn_rx_data *data, struct mbuf_list *ml)
 {
  struct iwn_ops *ops = &sc->ops;
  struct ieee80211com *ic = &sc->sc_ic;
@@ -2240,7 +2240,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *
  /* Send the frame to the 802.11 layer. */
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Restore BSS channel. */
  if (ni == ic->ic_bss)
@@ -2737,6 +2737,7 @@ iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc
 void
 iwn_notif_intr(struct iwn_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct iwn_ops *ops = &sc->ops;
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -2768,7 +2769,7 @@ iwn_notif_intr(struct iwn_softc *sc)
  case IWN_RX_DONE: /* 4965AGN only. */
  case IWN_MPDU_RX_DONE:
  /* An 802.11 frame has been received. */
- iwn_rx_done(sc, desc, data);
+ iwn_rx_done(sc, desc, data, &ml);
  break;
  case IWN_RX_COMPRESSED_BA:
  /* A Compressed BlockAck has been received. */
@@ -2913,6 +2914,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  /* Tell the firmware what we have processed. */
  hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1;
blob - 2c53aa925247b5056360daf479fca12e45624107
blob + 15629e1a07ec75f8eea39d7a629d2d84da6e550e
--- sys/dev/pci/if_rtwn.c
+++ sys/dev/pci/if_rtwn.c
@@ -248,7 +248,8 @@ uint8_t rtwn_pci_read_1(void *, uint16_t);
 uint16_t rtwn_pci_read_2(void *, uint16_t);
 uint32_t rtwn_pci_read_4(void *, uint16_t);
 void rtwn_rx_frame(struct rtwn_pci_softc *,
-    struct r92c_rx_desc_pci *, struct rtwn_rx_data *, int);
+    struct r92c_rx_desc_pci *, struct rtwn_rx_data *, int,
+    struct mbuf_list *);
 int rtwn_tx(void *, struct mbuf *, struct ieee80211_node *);
 void rtwn_tx_done(struct rtwn_pci_softc *, int);
 int rtwn_alloc_buffers(void *);
@@ -813,7 +814,7 @@ rtwn_pci_read_4(void *cookie, uint16_t addr)
 
 void
 rtwn_rx_frame(struct rtwn_pci_softc *sc, struct r92c_rx_desc_pci *rx_desc,
-    struct rtwn_rx_data *rx_data, int desc_idx)
+    struct rtwn_rx_data *rx_data, int desc_idx, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_sc.sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -974,7 +975,7 @@ rtwn_rx_frame(struct rtwn_pci_softc *sc, struct r92c_r
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* Unused. */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
 }
@@ -1480,6 +1481,7 @@ rtwn_pci_stop(void *cookie)
 int
 rtwn_88e_intr(struct rtwn_pci_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  u_int32_t status, estatus;
  int i;
 
@@ -1511,6 +1513,8 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
  rtwn_tx_done(sc, RTWN_VO_QUEUE);
  if ((status & (R88E_HIMR_ROK | R88E_HIMR_RDU)) ||
     (estatus & R88E_HIMRE_RXFOVW)) {
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
  bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
     sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
     BUS_DMASYNC_POSTREAD);
@@ -1522,8 +1526,9 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
  if (letoh32(rx_desc->rxdw0) & R92C_RXDW0_OWN)
  continue;
 
- rtwn_rx_frame(sc, rx_desc, rx_data, i);
+ rtwn_rx_frame(sc, rx_desc, rx_data, i, &ml);
  }
+ if_input(&ic->ic_if, &ml);
  }
 
  if (status & R88E_HIMR_HSISR_IND_ON_INT) {
@@ -1543,6 +1548,7 @@ int
 rtwn_intr(void *xsc)
 {
  struct rtwn_pci_softc *sc = xsc;
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  u_int32_t status;
  int i;
 
@@ -1561,6 +1567,8 @@ rtwn_intr(void *xsc)
 
  /* Vendor driver treats RX errors like ROK... */
  if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) {
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
  bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
     sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
     BUS_DMASYNC_POSTREAD);
@@ -1572,8 +1580,9 @@ rtwn_intr(void *xsc)
  if (letoh32(rx_desc->rxdw0) & R92C_RXDW0_OWN)
  continue;
 
- rtwn_rx_frame(sc, rx_desc, rx_data, i);
+ rtwn_rx_frame(sc, rx_desc, rx_data, i, &ml);
  }
+ if_input(&ic->ic_if, &ml);
  }
 
  if (status & R92C_IMR_BDOK)
blob - 2a91ccec016f8047bfe26ede71e8881404fef619
blob + 87f91434312f42404dbb02241eb2d4804ebbdd12
--- sys/dev/pci/if_wpi.c
+++ sys/dev/pci/if_wpi.c
@@ -103,7 +103,7 @@ void wpi_calib_timeout(void *);
 int wpi_ccmp_decap(struct wpi_softc *, struct mbuf *,
     struct ieee80211_key *);
 void wpi_rx_done(struct wpi_softc *, struct wpi_rx_desc *,
-    struct wpi_rx_data *);
+    struct wpi_rx_data *, struct mbuf_list *);
 void wpi_tx_done(struct wpi_softc *, struct wpi_rx_desc *);
 void wpi_cmd_done(struct wpi_softc *, struct wpi_rx_desc *);
 void wpi_notif_intr(struct wpi_softc *);
@@ -1180,7 +1180,7 @@ wpi_ccmp_decap(struct wpi_softc *sc, struct mbuf *m, s
 
 void
 wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc,
-    struct wpi_rx_data *data)
+    struct wpi_rx_data *data, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1344,7 +1344,7 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *
  /* Send the frame to the 802.11 layer. */
  rxi.rxi_rssi = stat->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -1412,6 +1412,7 @@ wpi_cmd_done(struct wpi_softc *sc, struct wpi_rx_desc
 void
 wpi_notif_intr(struct wpi_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  uint32_t hw;
@@ -1438,7 +1439,7 @@ wpi_notif_intr(struct wpi_softc *sc)
  switch (desc->type) {
  case WPI_RX_DONE:
  /* An 802.11 frame has been received. */
- wpi_rx_done(sc, desc, data);
+ wpi_rx_done(sc, desc, data, &ml);
  break;
 
  case WPI_TX_DONE:
@@ -1527,6 +1528,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;
  }
+ if_input(&ic->ic_if, &ml);
 
  /* Tell the firmware what we have processed. */
  hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1;
blob - 39edb129685cac47d29224f18c6f2e7c92922720
blob + 281a19ea8aa92c91869ae177649be9196c947ac3
--- sys/dev/usb/if_athn_usb.c
+++ sys/dev/usb/if_athn_usb.c
@@ -176,7 +176,8 @@ void athn_usb_intr(struct usbd_xfer *, void *,
     usbd_status);
 void athn_usb_rx_radiotap(struct athn_softc *, struct mbuf *,
     struct ar_rx_status *);
-void athn_usb_rx_frame(struct athn_usb_softc *, struct mbuf *);
+void athn_usb_rx_frame(struct athn_usb_softc *, struct mbuf *,
+    struct mbuf_list *);
 void athn_usb_rxeof(struct usbd_xfer *, void *,
     usbd_status);
 void athn_usb_txeof(struct usbd_xfer *, void *,
@@ -1994,7 +1995,8 @@ athn_usb_rx_radiotap(struct athn_softc *sc, struct mbu
 #endif
 
 void
-athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m)
+athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m,
+    struct mbuf_list *ml)
 {
  struct athn_softc *sc = &usc->sc_sc;
  struct ieee80211com *ic = &sc->sc_ic;
@@ -2060,7 +2062,7 @@ athn_usb_rx_frame(struct athn_usb_softc *usc, struct m
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rs->rs_rssi + AR_USB_DEFAULT_NF;
  rxi.rxi_tstamp = betoh64(rs->rs_tstamp);
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -2074,6 +2076,7 @@ void
 athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
     usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct athn_usb_rx_data *data = priv;
  struct athn_usb_softc *usc = data->sc;
  struct athn_softc *sc = &usc->sc_sc;
@@ -2101,7 +2104,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
  if (__predict_true(stream->m != NULL)) {
  memcpy(mtod(stream->m, uint8_t *) +
     stream->moff, buf, stream->left);
- athn_usb_rx_frame(usc, stream->m);
+ athn_usb_rx_frame(usc, stream->m, &ml);
  stream->m = NULL;
  }
  /* Next header is 32-bit aligned. */
@@ -2167,7 +2170,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
  if (__predict_true(m != NULL)) {
  /* We have all the pktlen bytes in this xfer. */
  memcpy(mtod(m, uint8_t *), buf, pktlen);
- athn_usb_rx_frame(usc, m);
+ athn_usb_rx_frame(usc, m, &ml);
  }
 
  /* Next header is 32-bit aligned. */
@@ -2175,6 +2178,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
  buf += off;
  len -= off;
  }
+ if_input(ifp, &ml);
 
  resubmit:
  /* Setup a new transfer. */
blob - cb7e65865adb17b86e10bf5c2bc59983a5c8c2c9
blob + 7461c3e57fb2d76faa3c0da0380827a85d19d5f7
--- sys/dev/usb/if_otus.c
+++ sys/dev/usb/if_otus.c
@@ -124,7 +124,8 @@ void otus_newassoc(struct ieee80211com *, struct ieee
     int);
 void otus_intr(struct usbd_xfer *, void *, usbd_status);
 void otus_cmd_rxeof(struct otus_softc *, uint8_t *, int);
-void otus_sub_rxeof(struct otus_softc *, uint8_t *, int);
+void otus_sub_rxeof(struct otus_softc *, uint8_t *, int,
+    struct mbuf_list *);
 void otus_rxeof(struct usbd_xfer *, void *, usbd_status);
 void otus_txeof(struct usbd_xfer *, void *, usbd_status);
 int otus_tx(struct otus_softc *, struct mbuf *,
@@ -1064,7 +1065,8 @@ otus_cmd_rxeof(struct otus_softc *sc, uint8_t *buf, in
 }
 
 void
-otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, int len)
+otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, int len,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1195,7 +1197,7 @@ otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, in
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = tail->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -1205,6 +1207,7 @@ otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, in
 void
 otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct otus_rx_data *data = priv;
  struct otus_softc *sc = data->sc;
  caddr_t buf = data->buf;
@@ -1234,13 +1237,14 @@ otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
  break;
  }
  /* Process sub-xfer. */
- otus_sub_rxeof(sc, (uint8_t *)&head[1], hlen);
+ otus_sub_rxeof(sc, (uint8_t *)&head[1], hlen, &ml);
 
  /* Next sub-xfer is aligned on a 32-bit boundary. */
  hlen = (sizeof (*head) + hlen + 3) & ~3;
  buf += hlen;
  len -= hlen;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  resubmit:
  usbd_setup_xfer(xfer, sc->data_rx_pipe, data, data->buf, OTUS_RXBUFSZ,
blob - 417666c3503da89fce1d3dc4301b48376dcf7e41
blob + 71c2c98b878349169107680c071978482dce1678
--- sys/dev/usb/if_rsu.c
+++ sys/dev/usb/if_rsu.c
@@ -161,7 +161,8 @@ void rsu_event_join_bss(struct rsu_softc *, uint8_t *
 void rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int);
 void rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int);
 int8_t rsu_get_rssi(struct rsu_softc *, int, void *);
-void rsu_rx_frame(struct rsu_softc *, uint8_t *, int);
+void rsu_rx_frame(struct rsu_softc *, uint8_t *, int,
+    struct mbuf_list *);
 void rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int);
 void rsu_rxeof(struct usbd_xfer *, void *, usbd_status);
 void rsu_txeof(struct usbd_xfer *, void *, usbd_status);
@@ -1261,7 +1262,8 @@ rsu_get_rssi(struct rsu_softc *sc, int rate, void *phy
 }
 
 void
-rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen)
+rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1371,7 +1373,7 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int p
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* Unused. */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
  splx(s);
@@ -1380,6 +1382,7 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int p
 void
 rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct r92s_rx_stat *stat;
  uint32_t rxdw0;
  int totlen, pktlen, infosz, npkts;
@@ -1408,13 +1411,14 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf,
  break;
 
  /* Process 802.11 frame. */
- rsu_rx_frame(sc, buf, pktlen);
+ rsu_rx_frame(sc, buf, pktlen, &ml);
 
  /* Next chunk is 128-byte aligned. */
  totlen = (totlen + 127) & ~127;
  buf += totlen;
  len -= totlen;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 }
 
 void
blob - fc6ba52f271725fe7afbb4abf1a4a1700920a1b4
blob + f22d6d4decb01bab31aa8c0f6fae587651dd3589
--- sys/dev/usb/if_run.c
+++ sys/dev/usb/if_run.c
@@ -376,7 +376,8 @@ void run_calibrate_to(void *);
 void run_calibrate_cb(struct run_softc *, void *);
 void run_newassoc(struct ieee80211com *, struct ieee80211_node *,
     int);
-void run_rx_frame(struct run_softc *, uint8_t *, int);
+void run_rx_frame(struct run_softc *, uint8_t *, int,
+    struct mbuf_list *);
 void run_rxeof(struct usbd_xfer *, void *, usbd_status);
 void run_txeof(struct usbd_xfer *, void *, usbd_status);
 int run_tx(struct run_softc *, struct mbuf *,
@@ -2158,7 +2159,8 @@ run_maxrssi_chain(struct run_softc *sc, const struct r
 }
 
 void
-run_rx_frame(struct run_softc *sc, uint8_t *buf, int dmalen)
+run_rx_frame(struct run_softc *sc, uint8_t *buf, int dmalen,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -2295,7 +2297,7 @@ run_rx_frame(struct run_softc *sc, uint8_t *buf, int d
  ni = ieee80211_find_rxnode(ic, wh);
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -2305,6 +2307,7 @@ run_rx_frame(struct run_softc *sc, uint8_t *buf, int d
 void
 run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct run_rx_data *data = priv;
  struct run_softc *sc = data->sc;
  uint8_t *buf;
@@ -2348,10 +2351,11 @@ run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
     dmalen + 8, xferlen));
  break;
  }
- run_rx_frame(sc, buf + sizeof (uint32_t), dmalen);
+ run_rx_frame(sc, buf + sizeof (uint32_t), dmalen, &ml);
  buf += dmalen + 8;
  xferlen -= dmalen + 8;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
 skip: /* setup a new transfer */
  usbd_setup_xfer(xfer, sc->rxq.pipeh, data, data->buf, RUN_MAX_RXSZ,
blob - 96a1ad1a91c3e98ebc6dece98df6ac277046612c
blob + 12fc517090e80d703749a326949aeaaf83617639
--- sys/dev/usb/if_urtwn.c
+++ sys/dev/usb/if_urtwn.c
@@ -380,7 +380,8 @@ void urtwn_set_key_cb(struct urtwn_softc *, void *);
 void urtwn_delete_key(struct ieee80211com *,
     struct ieee80211_node *, struct ieee80211_key *);
 void urtwn_delete_key_cb(struct urtwn_softc *, void *);
-void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int);
+void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int,
+    struct mbuf_list *);
 void urtwn_rxeof(struct usbd_xfer *, void *,
     usbd_status);
 void urtwn_txeof(struct usbd_xfer *, void *,
@@ -1083,7 +1084,8 @@ urtwn_delete_key_cb(struct urtwn_softc *sc, void *arg)
 }
 
 void
-urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen)
+urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_sc.sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1194,7 +1196,7 @@ urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, i
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* Unused. */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
  splx(s);
@@ -1204,8 +1206,10 @@ void
 urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
     usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct urtwn_rx_data *data = priv;
  struct urtwn_softc *sc = data->sc;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
  struct r92c_rx_desc_usb *rxd;
  uint32_t rxdw0;
  uint8_t *buf;
@@ -1298,13 +1302,14 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
  break;
 
  /* Process 802.11 frame. */
- urtwn_rx_frame(sc, buf, pktlen);
+ urtwn_rx_frame(sc, buf, pktlen, &ml);
 
  /* Handle chunk alignment. */
  totlen = (totlen + align) & ~align;
  buf += totlen;
  len -= totlen;
  }
+ if_input(&ic->ic_if, &ml);
 
  resubmit:
  /* Setup a new transfer. */
blob - 689ac7e7178ca36a091d25cc6f2cf8d15cc45b0b
blob + ea8545a4ba48d49eb2830b4e6886613e2e181a7c
--- sys/dev/usb/if_zyd.c
+++ sys/dev/usb/if_zyd.c
@@ -217,7 +217,8 @@ void zyd_set_chan(struct zyd_softc *, struct ieee8021
 int zyd_set_beacon_interval(struct zyd_softc *, int);
 uint8_t zyd_plcp_signal(int);
 void zyd_intr(struct usbd_xfer *, void *, usbd_status);
-void zyd_rx_data(struct zyd_softc *, const uint8_t *, uint16_t);
+void zyd_rx_data(struct zyd_softc *, const uint8_t *, uint16_t,
+    struct mbuf_list *);
 void zyd_rxeof(struct usbd_xfer *, void *, usbd_status);
 void zyd_txeof(struct usbd_xfer *, void *, usbd_status);
 int zyd_tx(struct zyd_softc *, struct mbuf *,
@@ -1894,7 +1895,8 @@ zyd_intr(struct usbd_xfer *xfer, void *priv, usbd_stat
 }
 
 void
-zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf, uint16_t len)
+zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf, uint16_t len,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1980,7 +1982,7 @@ zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf,
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = stat->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1991,6 +1993,7 @@ zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf,
 void
 zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct zyd_rx_data *data = priv;
  struct zyd_softc *sc = data->sc;
  struct ieee80211com *ic = &sc->sc_ic;
@@ -2030,15 +2033,16 @@ zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
  if (len == 0 || p + len >= end)
  break;
 
- zyd_rx_data(sc, p, len);
+ zyd_rx_data(sc, p, len, &ml);
  /* next frame is aligned on a 32-bit boundary */
  p += (len + 3) & ~3;
  }
  } else {
  DPRINTFN(3, ("received single-frame transfer\n"));
 
- zyd_rx_data(sc, data->buf, len);
+ zyd_rx_data(sc, data->buf, len, &ml);
  }
+ if_input(ifp, &ml);
 
 skip: /* setup a new transfer */
  usbd_setup_xfer(xfer, sc->zyd_ep[ZYD_ENDPT_BIN], data, NULL,
blob - 73a9d5229502797c5279734663b1ac1591bec309
blob + 414b0a3419ed9a14e3331fa65a8bbb66a166391e
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -71,11 +71,11 @@ void ieee80211_input_ba_seq(struct ieee80211com *,
     struct ieee80211_node *, uint8_t, uint16_t);
 struct mbuf *ieee80211_align_mbuf(struct mbuf *);
 void ieee80211_decap(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
+    struct ieee80211_node *, int, struct mbuf_list *);
 void ieee80211_amsdu_decap(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
-void ieee80211_deliver_data(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
+    struct ieee80211_node *, int, struct mbuf_list *);
+void ieee80211_enqueue_data(struct ieee80211com *, struct mbuf *,
+    struct ieee80211_node *, int, struct mbuf_list *);
 int ieee80211_parse_edca_params_body(struct ieee80211com *,
     const u_int8_t *);
 int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
@@ -155,10 +155,16 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh)
  * any units so long as values have consistent units and higher values
  * mean ``better signal''.  The receive timestamp is currently not used
  * by the 802.11 layer.
+ *
+ * This function acts on management frames immediately and queues data frames
+ * on the specified mbuf list. Delivery of queued data frames to upper layers
+ * must be triggered with if_input(). Drivers should call if_input() only once
+ * per Rx interrupt to avoid triggering the input ifq pressure drop mechanism
+ * unnecessarily.
  */
 void
-ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
-    struct ieee80211_rxinfo *rxi)
+ieee80211_inputm(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+    struct ieee80211_rxinfo *rxi, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = (void *)ifp;
  struct ieee80211_frame *wh;
@@ -463,9 +469,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
 
  if ((ni->ni_flags & IEEE80211_NODE_HT) &&
     hasqos && (qos & IEEE80211_QOS_AMSDU))
- ieee80211_amsdu_decap(ic, m, ni, hdrlen);
+ ieee80211_amsdu_decap(ic, m, ni, hdrlen, ml);
  else
- ieee80211_decap(ic, m, ni, hdrlen);
+ ieee80211_decap(ic, m, ni, hdrlen, ml);
  return;
 
  case IEEE80211_FC0_TYPE_MGT:
@@ -560,6 +566,17 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
  }
 }
 
+/* Input handler for drivers which only receive one frame per interrupt. */
+void
+ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+    struct ieee80211_rxinfo *rxi)
+{
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+
+ ieee80211_inputm(ifp, m, ni, rxi, &ml);
+ if_input(ifp, &ml);
+}
+
 /*
  * Handle defragmentation (see 9.5 and Annex C).  We support the concurrent
  * reception of fragments of three fragmented MSDUs or MMPDUs.
@@ -856,8 +873,8 @@ ieee80211_ba_move_window(struct ieee80211com *ic, stru
 }
 
 void
-ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int mcast)
+ieee80211_enqueue_data(struct ieee80211com *ic, struct mbuf *m,
+    struct ieee80211_node *ni, int mcast, struct mbuf_list *ml)
 {
  struct ifnet *ifp = &ic->ic_if;
  struct ether_header *eh;
@@ -920,16 +937,14 @@ ieee80211_deliver_data(struct ieee80211com *ic, struct
 #endif
  ieee80211_eapol_key_input(ic, m, ni);
  } else {
- struct mbuf_list ml = MBUF_LIST_INITIALIZER();
- ml_enqueue(&ml, m);
- if_input(ifp, &ml);
+ ml_enqueue(ml, m);
  }
  }
 }
 
 void
 ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
  struct ether_header eh;
  struct ieee80211_frame *wh;
@@ -985,7 +1000,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  return;
  }
  }
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 }
 
 /*
@@ -993,7 +1008,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  */
 void
 ieee80211_amsdu_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
  struct mbuf *n;
  struct ether_header *eh;
@@ -1059,7 +1074,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct
  m_freem(m);
  break;
  }
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 
  if (n->m_pkthdr.len == 0) {
  m_freem(n);
blob - e622d35f4dcd21ea0bb40c6a5d0b3f758e197b38
blob + 52cf8fddfc1658a5c38a4895fff4e858d15bb876
--- sys/net80211/ieee80211_proto.h
+++ sys/net80211/ieee80211_proto.h
@@ -66,6 +66,9 @@ struct ieee80211_rsnparams;
 extern void ieee80211_set_link_state(struct ieee80211com *, int);
 extern u_int ieee80211_get_hdrlen(const struct ieee80211_frame *);
 extern int ieee80211_classify(struct ieee80211com *, struct mbuf *);
+extern void ieee80211_inputm(struct ifnet *, struct mbuf *,
+ struct ieee80211_node *, struct ieee80211_rxinfo *,
+ struct mbuf_list *);
 extern void ieee80211_input(struct ifnet *, struct mbuf *,
  struct ieee80211_node *, struct ieee80211_rxinfo *);
 extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Matthias Schmidt
Hi Stefan,

* Stefan Sperling wrote:
>
> New diff with above changes:

I tested your new diff with two different systems:

* Thinkpad T450s with iwm (8265, same as yesterday)
* Thinkpad X220 with iwn (6205)

and on both systems I see a drastic regression compared to yesterday's
patch.  The download speeds is around 400-700K/s on both systems.  As
soon as I switch back to the kernel with yesterday's patch, I end up
having 4M/s in average, again.

Cheers

        Matthias

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Stefan Sperling-5
On Tue, Sep 10, 2019 at 07:08:14PM +0200, Matthias Schmidt wrote:

> Hi Stefan,
>
> * Stefan Sperling wrote:
> >
> > New diff with above changes:
>
> I tested your new diff with two different systems:
>
> * Thinkpad T450s with iwm (8265, same as yesterday)
> * Thinkpad X220 with iwn (6205)
>
> and on both systems I see a drastic regression compared to yesterday's
> patch.  The download speeds is around 400-700K/s on both systems.  As
> soon as I switch back to the kernel with yesterday's patch, I end up
> having 4M/s in average, again.

I think I see why. I forgot to convert some existing ieee80211_input()
calls to ieee80211_inputm(), in ieee80211_input.c.
These calls are related to buffered aggregated frames, so aggregated
frames triggered multiple if_input() calls per interrupt again.

In the first diff ieee80211_input() was putting aggregated frames
onto the global mbuf list. With this new diff they get added to the
mbuf list which the driver's rx interrupt handler passed in.

Does this fix the issue?

diff refs/heads/master refs/heads/ifqdrop
blob - d72e8edceada8a680744a6b8478bb91ac9e15e6e
blob + a3203d7eb1a67d478bf280a551a43f2dc66c0965
--- sys/dev/ic/ar5008.c
+++ sys/dev/ic/ar5008.c
@@ -789,7 +789,7 @@ ar5008_rx_radiotap(struct athn_softc *sc, struct mbuf
 #endif
 
 static __inline int
-ar5008_rx_process(struct athn_softc *sc)
+ar5008_rx_process(struct athn_softc *sc, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -931,7 +931,7 @@ ar5008_rx_process(struct athn_softc *sc)
  rxi.rxi_rssi = MS(ds->ds_status4, AR_RXS4_RSSI_COMBINED);
  rxi.rxi_rssi += AR_DEFAULT_NOISE_FLOOR;
  rxi.rxi_tstamp = ds->ds_status2;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -960,7 +960,13 @@ ar5008_rx_process(struct athn_softc *sc)
 void
 ar5008_rx_intr(struct athn_softc *sc)
 {
- while (ar5008_rx_process(sc) == 0);
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
+ while (ar5008_rx_process(sc, &ml) == 0);
+
+ if_input(ifp, &ml);
 }
 
 int
blob - 69ade5ade5a35e632a025db327668d695a0edd2d
blob + dafa3bd1f0b4ca2124c6d963c82e289594e88b27
--- sys/dev/ic/ar9003.c
+++ sys/dev/ic/ar9003.c
@@ -83,7 +83,7 @@ void ar9003_reset_txsring(struct athn_softc *);
 void ar9003_rx_enable(struct athn_softc *);
 void ar9003_rx_radiotap(struct athn_softc *, struct mbuf *,
     struct ar_rx_status *);
-int ar9003_rx_process(struct athn_softc *, int);
+int ar9003_rx_process(struct athn_softc *, int, struct mbuf_list *);
 void ar9003_rx_intr(struct athn_softc *, int);
 int ar9003_tx_process(struct athn_softc *);
 void ar9003_tx_intr(struct athn_softc *);
@@ -916,7 +916,7 @@ ar9003_rx_radiotap(struct athn_softc *sc, struct mbuf
 #endif
 
 int
-ar9003_rx_process(struct athn_softc *sc, int qid)
+ar9003_rx_process(struct athn_softc *sc, int qid, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1036,7 +1036,7 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
  rxi.rxi_flags = 0; /* XXX */
  rxi.rxi_rssi = MS(ds->ds_status5, AR_RXS5_RSSI_COMBINED);
  rxi.rxi_tstamp = ds->ds_status3;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -1066,7 +1066,13 @@ ar9003_rx_process(struct athn_softc *sc, int qid)
 void
 ar9003_rx_intr(struct athn_softc *sc, int qid)
 {
- while (ar9003_rx_process(sc, qid) == 0);
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
+ while (ar9003_rx_process(sc, qid, &ml) == 0);
+
+ if_input(ifp, &ml);
 }
 
 int
blob - c0c5f4241b010c5c38a557d97963fbdbc884336d
blob + c4414e5113134012edaf4ce4557bb7e25987e9ef
--- sys/dev/ic/ath.c
+++ sys/dev/ic/ath.c
@@ -1795,6 +1795,7 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *b
 void
 ath_rx_proc(void *arg, int npending)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
 #define PA2DESC(_sc, _pa) \
  ((struct ath_desc *)((caddr_t)(_sc)->sc_desc + \
  ((_pa) - (_sc)->sc_desc_paddr)))
@@ -1946,7 +1947,7 @@ ath_rx_proc(void *arg, int npending)
  if (!ath_softcrypto && (wh->i_fc[1] & IEEE80211_FC1_WEP)) {
  /*
  * WEP is decrypted by hardware. Clear WEP bit
- * and trim WEP header for ieee80211_input().
+ * and trim WEP header for ieee80211_inputm().
  */
  wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
  bcopy(wh, &whbuf, sizeof(whbuf));
@@ -1988,7 +1989,7 @@ ath_rx_proc(void *arg, int npending)
  */
  rxi.rxi_rssi = ds->ds_rxstat.rs_rssi;
  rxi.rxi_tstamp = ds->ds_rxstat.rs_tstamp;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /* Handle the rate adaption */
  ieee80211_rssadapt_input(ic, ni, &an->an_rssadapt,
@@ -2004,6 +2005,8 @@ ath_rx_proc(void *arg, int npending)
  rx_next:
  TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
  } while (ath_rxbuf_init(sc, bf) == 0);
+
+ if_input(ifp, &ml);
 
  ath_hal_set_rx_signal(ah); /* rx signal state monitoring */
  ath_hal_start_rx(ah); /* in case of RXEOL */
blob - cbf21da74007080c510fa9c56a58aedff62fa586
blob + 6f609b3d8e77c27ba27e6be88cff55fbf87bbb2c
--- sys/dev/ic/atw.c
+++ sys/dev/ic/atw.c
@@ -3029,6 +3029,7 @@ atw_hw_decrypted(struct atw_softc *sc, struct ieee8021
 void
 atw_rxintr(struct atw_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  static int rate_tbl[] = {2, 4, 11, 22, 44};
  struct ieee80211com *ic = &sc->sc_ic;
  struct ieee80211_rxinfo rxi;
@@ -3183,7 +3184,7 @@ atw_rxintr(struct atw_softc *sc)
 #endif
  rxi.rxi_rssi = (int)rssi;
  rxi.rxi_tstamp = 0;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
  /*
  * The frame may have caused the node to be marked for
  * reclamation (e.g. in response to a DEAUTH message)
@@ -3191,6 +3192,7 @@ atw_rxintr(struct atw_softc *sc)
  */
  ieee80211_release_node(ic, ni);
  }
+ if_input(ifp, &ml);
 
  /* Update the receive pointer. */
  sc->sc_rxptr = i;
blob - 58417ce6f7de644fe86347459c04553956b2edc0
blob + b383588620701ca5c656d29c0384393696914cdc
--- sys/dev/ic/bwi.c
+++ sys/dev/ic/bwi.c
@@ -8355,6 +8355,7 @@ bwi_next_scan(void *xsc)
 int
 bwi_rxeof(struct bwi_softc *sc, int end_idx)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct bwi_ring_data *rd = &sc->sc_rx_rdata;
  struct bwi_rxbuf_data *rbd = &sc->sc_rx_bdata;
  struct ieee80211com *ic = &sc->sc_ic;
@@ -8455,7 +8456,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 
  rxi.rxi_rssi = hdr->rxh_rssi;
  rxi.rxi_tstamp = letoh16(hdr->rxh_tsf);
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  ieee80211_release_node(ic, ni);
 
@@ -8466,6 +8467,7 @@ bwi_rxeof(struct bwi_softc *sc, int end_idx)
 next:
  idx = (idx + 1) % BWI_RX_NDESC;
  }
+ if_input(ifp, &ml);
 
  rbd->rbd_idx = idx;
  bus_dmamap_sync(sc->sc_dmat, rd->rdata_dmap, 0,
blob - 6a8c5646f0b6f649a60793e127cbd746d8ee89d7
blob + af91b6b414ecc45cd3caceec3f0a7ea6e2aae400
--- sys/dev/ic/malo.c
+++ sys/dev/ic/malo.c
@@ -1593,6 +1593,7 @@ malo_tx_setup_desc(struct malo_softc *sc, struct malo_
 void
 malo_rx_intr(struct malo_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  struct malo_rx_desc *desc;
@@ -1711,7 +1712,7 @@ malo_rx_intr(struct malo_softc *sc)
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1727,6 +1728,7 @@ skip:
  sc->sc_rxring.cur = (sc->sc_rxring.cur + 1) %
     MALO_RX_RING_COUNT;
  }
+ if_input(ifp, &ml);
 
  malo_mem_write4(sc, sc->sc_RxPdRdPtr, rxRdPtr);
 }
blob - f44264645097e6f991f5642f7973ed5ebe3e5d7e
blob + 695723c6f054b8ab264aefb609696dffbaae6c6b
--- sys/dev/ic/pgt.c
+++ sys/dev/ic/pgt.c
@@ -899,6 +899,7 @@ void
 pgt_input_frames(struct pgt_softc *sc, struct mbuf *m)
 {
  struct ether_header eh;
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ifnet *ifp;
  struct ieee80211_channel *chan;
  struct ieee80211_rxinfo rxi;
@@ -1022,7 +1023,7 @@ input:
  rxi.rxi_flags = 0;
  ni->ni_rssi = rxi.rxi_rssi = rssi;
  ni->ni_rstamp = rxi.rxi_tstamp = rstamp;
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
  /*
  * The frame may have caused the node to be marked for
  * reclamation (e.g. in response to a DEAUTH message)
@@ -1036,6 +1037,7 @@ input:
  ifp->if_ierrors++;
  }
  }
+ if_input(ifp, &ml);
 }
 
 void
blob - c8d85564272d263215e829d007c11a47741316e6
blob + 4b6e4c0592a9ac543cc83d2ff6ccc692427c0adf
--- sys/dev/ic/rt2560.c
+++ sys/dev/ic/rt2560.c
@@ -1076,6 +1076,7 @@ rt2560_prio_intr(struct rt2560_softc *sc)
 void
 rt2560_decryption_intr(struct rt2560_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_frame *wh;
@@ -1204,7 +1205,7 @@ rt2560_decryption_intr(struct rt2560_softc *sc)
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1220,6 +1221,7 @@ skip: desc->flags = htole32(RT2560_RX_BUSY);
  sc->rxq.cur_decrypt =
     (sc->rxq.cur_decrypt + 1) % RT2560_RX_RING_COUNT;
  }
+ if_input(ifp, &ml);
 }
 
 /*
blob - 591115f692d4f77a522d114e5a91d6026e3452fe
blob + 44f767f9bba3aec85758600684dc786d5eab3ed3
--- sys/dev/ic/rt2661.c
+++ sys/dev/ic/rt2661.c
@@ -1153,6 +1153,7 @@ rt2661_tx_dma_intr(struct rt2661_softc *sc, struct rt2
 void
 rt2661_rx_intr(struct rt2661_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_frame *wh;
@@ -1279,7 +1280,7 @@ rt2661_rx_intr(struct rt2661_softc *sc)
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = desc->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /*-
  * Keep track of the average RSSI using an Exponential Moving
@@ -1302,6 +1303,7 @@ skip: desc->flags |= htole32(RT2661_RX_BUSY);
 
  sc->rxq.cur = (sc->rxq.cur + 1) % RT2661_RX_RING_COUNT;
  }
+ if_input(ifp, &ml);
 }
 
 #ifndef IEEE80211_STA_ONLY
blob - c6c811c835ef4558079c00d50041075b9a8321bb
blob + 286f4c859d84a8dc13a54e74c355bc443cf2f7e8
--- sys/dev/ic/rt2860.c
+++ sys/dev/ic/rt2860.c
@@ -1260,6 +1260,7 @@ rt2860_maxrssi_chain(struct rt2860_softc *sc, const st
 void
 rt2860_rx_intr(struct rt2860_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_frame *wh;
@@ -1419,7 +1420,7 @@ skipbpf:
  /* send the frame to the 802.11 layer */
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, &ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1432,6 +1433,7 @@ skip: rxd->sdl0 &= ~htole16(RT2860_RX_DDONE);
 
  sc->rxq.cur = (sc->rxq.cur + 1) % RT2860_RX_RING_COUNT;
  }
+ if_input(ifp, &ml);
 
  /* tell HW what we have processed */
  RAL_WRITE(sc, RT2860_RX_CALC_IDX,
blob - ce7686c40fa4b1166d0af3fe54d8cad60704f556
blob + 344ffd4381400698d23f8aaee3c623fe649f885f
--- sys/dev/ic/rtw.c
+++ sys/dev/ic/rtw.c
@@ -1081,6 +1081,7 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
  static const int ratetbl[4] = {2, 4, 11, 22}; /* convert rates:
  * hardware -> net80211
  */
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  u_int next, nproc = 0;
  int hwrate, len, rate, rssi, sq;
  u_int32_t hrssi, hstat, htsfth, htsftl;
@@ -1289,11 +1290,12 @@ rtw_intr_rx(struct rtw_softc *sc, u_int16_t isr)
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = htsftl;
- ieee80211_input(&sc->sc_if, m, ni, &rxi);
+ ieee80211_inputm(&sc->sc_if, m, ni, &rxi, &ml);
  ieee80211_release_node(&sc->sc_ic, ni);
 next:
  rtw_rxdesc_init(rdb, rs, next, 0);
  }
+ if_input(&sc->sc_if, &ml);
  rdb->rdb_next = next;
 
  KASSERT(rdb->rdb_next < rdb->rdb_ndesc);
blob - cd0d354d12f45e34327a1d9d2d6ae5b480f9e305
blob + abcd1e0c7f2509e16102d1ea96e245dca587de90
--- sys/dev/pci/if_ipw.c
+++ sys/dev/pci/if_ipw.c
@@ -71,7 +71,8 @@ uint16_t ipw_read_prom_word(struct ipw_softc *, uint8_
 void ipw_command_intr(struct ipw_softc *, struct ipw_soft_buf *);
 void ipw_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
 void ipw_data_intr(struct ipw_softc *, struct ipw_status *,
-    struct ipw_soft_bd *, struct ipw_soft_buf *);
+    struct ipw_soft_bd *, struct ipw_soft_buf *,
+    struct mbuf_list *);
 void ipw_notification_intr(struct ipw_softc *,
     struct ipw_soft_buf *);
 void ipw_rx_intr(struct ipw_softc *);
@@ -816,7 +817,7 @@ ipw_newstate_intr(struct ipw_softc *sc, struct ipw_sof
 
 void
 ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
-    struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf)
+    struct ipw_soft_bd *sbd, struct ipw_soft_buf *sbuf, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -903,7 +904,7 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = status->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  ieee80211_release_node(ic, ni);
 }
@@ -917,6 +918,7 @@ ipw_notification_intr(struct ipw_softc *sc, struct ipw
 void
 ipw_rx_intr(struct ipw_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ipw_status *status;
  struct ipw_soft_bd *sbd;
  struct ipw_soft_buf *sbuf;
@@ -949,7 +951,7 @@ ipw_rx_intr(struct ipw_softc *sc)
 
  case IPW_STATUS_CODE_DATA_802_3:
  case IPW_STATUS_CODE_DATA_802_11:
- ipw_data_intr(sc, status, sbd, sbuf);
+ ipw_data_intr(sc, status, sbd, sbuf, &ml);
  break;
 
  case IPW_STATUS_CODE_NOTIFICATION:
@@ -966,6 +968,7 @@ ipw_rx_intr(struct ipw_softc *sc)
     i * sizeof (struct ipw_bd), sizeof (struct ipw_bd),
     BUS_DMASYNC_PREWRITE);
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  /* tell the firmware what we have processed */
  sc->rxcur = (r == 0) ? IPW_NRBD - 1 : r - 1;
blob - bdb4827425118b9159ae05ad1263bdf5c084254f
blob + 84366f6545bde46339adf1da2956b9af8f544469
--- sys/dev/pci/if_iwi.c
+++ sys/dev/pci/if_iwi.c
@@ -87,7 +87,7 @@ int iwi_find_txnode(struct iwi_softc *, const uint8_t
 int iwi_newstate(struct ieee80211com *, enum ieee80211_state, int);
 uint8_t iwi_rate(int);
 void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *,
-    struct iwi_frame *);
+    struct iwi_frame *, struct mbuf_list *);
 void iwi_notification_intr(struct iwi_softc *, struct iwi_rx_data *,
     struct iwi_notif *);
 void iwi_rx_intr(struct iwi_softc *);
@@ -854,7 +854,7 @@ iwi_rate(int plcp)
 
 void
 iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data,
-    struct iwi_frame *frame)
+    struct iwi_frame *frame, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -954,7 +954,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_dat
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = frame->rssi_dbm;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1073,6 +1073,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi
 void
 iwi_rx_intr(struct iwi_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct iwi_rx_data *data;
  struct iwi_hdr *hdr;
  uint32_t hw;
@@ -1090,7 +1091,7 @@ iwi_rx_intr(struct iwi_softc *sc)
  switch (hdr->type) {
  case IWI_HDR_TYPE_FRAME:
  iwi_frame_intr(sc, data,
-    (struct iwi_frame *)(hdr + 1));
+    (struct iwi_frame *)(hdr + 1), &ml);
  break;
 
  case IWI_HDR_TYPE_NOTIF:
@@ -1105,6 +1106,7 @@ iwi_rx_intr(struct iwi_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % IWI_RX_RING_COUNT;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  /* tell the firmware what we have processed */
  hw = (hw == 0) ? IWI_RX_RING_COUNT - 1 : hw - 1;
blob - 0b2116dbc13428f1726773000e8e6a8c251d86b4
blob + 26bd730272774dc8cef58c87638c21c0536a016a
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -368,7 +368,7 @@ void iwm_rx_rx_phy_cmd(struct iwm_softc *, struct iwm_
     struct iwm_rx_data *);
 int iwm_get_noise(const struct iwm_statistics_rx_non_phy *);
 void iwm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *,
-    struct iwm_rx_data *);
+    struct iwm_rx_data *, struct mbuf_list *);
 void iwm_enable_ht_cck_fallback(struct iwm_softc *, struct iwm_node *);
 void iwm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *,
     struct iwm_node *);
@@ -3431,7 +3431,7 @@ iwm_get_noise(const struct iwm_statistics_rx_non_phy *
 
 void
 iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
-    struct iwm_rx_data *data)
+    struct iwm_rx_data *data, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ieee80211_frame *wh;
@@ -3564,9 +3564,9 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_pac
  bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
  }
 #endif
- ieee80211_input(IC2IFP(ic), m, ni, &rxi);
+ ieee80211_inputm(IC2IFP(ic), m, ni, &rxi, ml);
  /*
- * ieee80211_input() might have changed our BSS.
+ * ieee80211_inputm() might have changed our BSS.
  * Restore ic_bss's channel if we are still in the same BSS.
  */
  if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
@@ -7005,6 +7005,7 @@ do { \
 void
 iwm_notif_intr(struct iwm_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  uint16_t hw;
 
  bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map,
@@ -7042,7 +7043,7 @@ iwm_notif_intr(struct iwm_softc *sc)
  break;
 
  case IWM_REPLY_RX_MPDU_CMD:
- iwm_rx_rx_mpdu(sc, pkt, data);
+ iwm_rx_rx_mpdu(sc, pkt, data, &ml);
  break;
 
  case IWM_TX_CMD:
@@ -7289,6 +7290,7 @@ iwm_notif_intr(struct iwm_softc *sc)
 
  ADVANCE_RXQ(sc);
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  /*
  * Tell the firmware what we have processed.
blob - 6be794c2cd435c74b1b5c3f028b9613dc74ecf20
blob + c76b53c4c97d6c49f2837667b8758958163246f4
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -156,7 +156,7 @@ int iwn_ccmp_decap(struct iwn_softc *, struct mbuf *,
 void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
     struct iwn_rx_data *);
 void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
-    struct iwn_rx_data *);
+    struct iwn_rx_data *, struct mbuf_list *);
 void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
     struct iwn_rx_data *);
 void iwn5000_rx_calib_results(struct iwn_softc *,
@@ -1937,7 +1937,7 @@ iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, s
  * Such frames may be received out of order due to
  * legitimate retransmissions of failed subframes
  * in previous A-MPDUs. Duplicates will be handled
- * in ieee80211_input() as part of A-MPDU reordering.
+ * in ieee80211_inputm() as part of A-MPDU reordering.
  */
  } else if (ieee80211_has_seq(wh)) {
  /*
@@ -2007,7 +2007,7 @@ iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *d
  */
 void
 iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
-    struct iwn_rx_data *data)
+    struct iwn_rx_data *data, struct mbuf_list *ml)
 {
  struct iwn_ops *ops = &sc->ops;
  struct ieee80211com *ic = &sc->sc_ic;
@@ -2240,7 +2240,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *
  /* Send the frame to the 802.11 layer. */
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Restore BSS channel. */
  if (ni == ic->ic_bss)
@@ -2737,6 +2737,7 @@ iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc
 void
 iwn_notif_intr(struct iwn_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct iwn_ops *ops = &sc->ops;
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -2768,7 +2769,7 @@ iwn_notif_intr(struct iwn_softc *sc)
  case IWN_RX_DONE: /* 4965AGN only. */
  case IWN_MPDU_RX_DONE:
  /* An 802.11 frame has been received. */
- iwn_rx_done(sc, desc, data);
+ iwn_rx_done(sc, desc, data, &ml);
  break;
  case IWN_RX_COMPRESSED_BA:
  /* A Compressed BlockAck has been received. */
@@ -2913,6 +2914,7 @@ iwn_notif_intr(struct iwn_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  /* Tell the firmware what we have processed. */
  hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1;
blob - 2c53aa925247b5056360daf479fca12e45624107
blob + 15629e1a07ec75f8eea39d7a629d2d84da6e550e
--- sys/dev/pci/if_rtwn.c
+++ sys/dev/pci/if_rtwn.c
@@ -248,7 +248,8 @@ uint8_t rtwn_pci_read_1(void *, uint16_t);
 uint16_t rtwn_pci_read_2(void *, uint16_t);
 uint32_t rtwn_pci_read_4(void *, uint16_t);
 void rtwn_rx_frame(struct rtwn_pci_softc *,
-    struct r92c_rx_desc_pci *, struct rtwn_rx_data *, int);
+    struct r92c_rx_desc_pci *, struct rtwn_rx_data *, int,
+    struct mbuf_list *);
 int rtwn_tx(void *, struct mbuf *, struct ieee80211_node *);
 void rtwn_tx_done(struct rtwn_pci_softc *, int);
 int rtwn_alloc_buffers(void *);
@@ -813,7 +814,7 @@ rtwn_pci_read_4(void *cookie, uint16_t addr)
 
 void
 rtwn_rx_frame(struct rtwn_pci_softc *sc, struct r92c_rx_desc_pci *rx_desc,
-    struct rtwn_rx_data *rx_data, int desc_idx)
+    struct rtwn_rx_data *rx_data, int desc_idx, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_sc.sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -974,7 +975,7 @@ rtwn_rx_frame(struct rtwn_pci_softc *sc, struct r92c_r
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* Unused. */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
 }
@@ -1480,6 +1481,7 @@ rtwn_pci_stop(void *cookie)
 int
 rtwn_88e_intr(struct rtwn_pci_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  u_int32_t status, estatus;
  int i;
 
@@ -1511,6 +1513,8 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
  rtwn_tx_done(sc, RTWN_VO_QUEUE);
  if ((status & (R88E_HIMR_ROK | R88E_HIMR_RDU)) ||
     (estatus & R88E_HIMRE_RXFOVW)) {
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
  bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
     sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
     BUS_DMASYNC_POSTREAD);
@@ -1522,8 +1526,9 @@ rtwn_88e_intr(struct rtwn_pci_softc *sc)
  if (letoh32(rx_desc->rxdw0) & R92C_RXDW0_OWN)
  continue;
 
- rtwn_rx_frame(sc, rx_desc, rx_data, i);
+ rtwn_rx_frame(sc, rx_desc, rx_data, i, &ml);
  }
+ if_input(&ic->ic_if, &ml);
  }
 
  if (status & R88E_HIMR_HSISR_IND_ON_INT) {
@@ -1543,6 +1548,7 @@ int
 rtwn_intr(void *xsc)
 {
  struct rtwn_pci_softc *sc = xsc;
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  u_int32_t status;
  int i;
 
@@ -1561,6 +1567,8 @@ rtwn_intr(void *xsc)
 
  /* Vendor driver treats RX errors like ROK... */
  if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) {
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
+
  bus_dmamap_sync(sc->sc_dmat, sc->rx_ring.map, 0,
     sizeof(struct r92c_rx_desc_pci) * RTWN_RX_LIST_COUNT,
     BUS_DMASYNC_POSTREAD);
@@ -1572,8 +1580,9 @@ rtwn_intr(void *xsc)
  if (letoh32(rx_desc->rxdw0) & R92C_RXDW0_OWN)
  continue;
 
- rtwn_rx_frame(sc, rx_desc, rx_data, i);
+ rtwn_rx_frame(sc, rx_desc, rx_data, i, &ml);
  }
+ if_input(&ic->ic_if, &ml);
  }
 
  if (status & R92C_IMR_BDOK)
blob - 2a91ccec016f8047bfe26ede71e8881404fef619
blob + 87f91434312f42404dbb02241eb2d4804ebbdd12
--- sys/dev/pci/if_wpi.c
+++ sys/dev/pci/if_wpi.c
@@ -103,7 +103,7 @@ void wpi_calib_timeout(void *);
 int wpi_ccmp_decap(struct wpi_softc *, struct mbuf *,
     struct ieee80211_key *);
 void wpi_rx_done(struct wpi_softc *, struct wpi_rx_desc *,
-    struct wpi_rx_data *);
+    struct wpi_rx_data *, struct mbuf_list *);
 void wpi_tx_done(struct wpi_softc *, struct wpi_rx_desc *);
 void wpi_cmd_done(struct wpi_softc *, struct wpi_rx_desc *);
 void wpi_notif_intr(struct wpi_softc *);
@@ -1180,7 +1180,7 @@ wpi_ccmp_decap(struct wpi_softc *sc, struct mbuf *m, s
 
 void
 wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc,
-    struct wpi_rx_data *data)
+    struct wpi_rx_data *data, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1344,7 +1344,7 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *
  /* Send the frame to the 802.11 layer. */
  rxi.rxi_rssi = stat->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -1412,6 +1412,7 @@ wpi_cmd_done(struct wpi_softc *sc, struct wpi_rx_desc
 void
 wpi_notif_intr(struct wpi_softc *sc)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
  uint32_t hw;
@@ -1438,7 +1439,7 @@ wpi_notif_intr(struct wpi_softc *sc)
  switch (desc->type) {
  case WPI_RX_DONE:
  /* An 802.11 frame has been received. */
- wpi_rx_done(sc, desc, data);
+ wpi_rx_done(sc, desc, data, &ml);
  break;
 
  case WPI_TX_DONE:
@@ -1527,6 +1528,7 @@ wpi_notif_intr(struct wpi_softc *sc)
 
  sc->rxq.cur = (sc->rxq.cur + 1) % WPI_RX_RING_COUNT;
  }
+ if_input(&ic->ic_if, &ml);
 
  /* Tell the firmware what we have processed. */
  hw = (hw == 0) ? WPI_RX_RING_COUNT - 1 : hw - 1;
blob - 39edb129685cac47d29224f18c6f2e7c92922720
blob + 281a19ea8aa92c91869ae177649be9196c947ac3
--- sys/dev/usb/if_athn_usb.c
+++ sys/dev/usb/if_athn_usb.c
@@ -176,7 +176,8 @@ void athn_usb_intr(struct usbd_xfer *, void *,
     usbd_status);
 void athn_usb_rx_radiotap(struct athn_softc *, struct mbuf *,
     struct ar_rx_status *);
-void athn_usb_rx_frame(struct athn_usb_softc *, struct mbuf *);
+void athn_usb_rx_frame(struct athn_usb_softc *, struct mbuf *,
+    struct mbuf_list *);
 void athn_usb_rxeof(struct usbd_xfer *, void *,
     usbd_status);
 void athn_usb_txeof(struct usbd_xfer *, void *,
@@ -1994,7 +1995,8 @@ athn_usb_rx_radiotap(struct athn_softc *sc, struct mbu
 #endif
 
 void
-athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m)
+athn_usb_rx_frame(struct athn_usb_softc *usc, struct mbuf *m,
+    struct mbuf_list *ml)
 {
  struct athn_softc *sc = &usc->sc_sc;
  struct ieee80211com *ic = &sc->sc_ic;
@@ -2060,7 +2062,7 @@ athn_usb_rx_frame(struct athn_usb_softc *usc, struct m
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rs->rs_rssi + AR_USB_DEFAULT_NF;
  rxi.rxi_tstamp = betoh64(rs->rs_tstamp);
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -2074,6 +2076,7 @@ void
 athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
     usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct athn_usb_rx_data *data = priv;
  struct athn_usb_softc *usc = data->sc;
  struct athn_softc *sc = &usc->sc_sc;
@@ -2101,7 +2104,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
  if (__predict_true(stream->m != NULL)) {
  memcpy(mtod(stream->m, uint8_t *) +
     stream->moff, buf, stream->left);
- athn_usb_rx_frame(usc, stream->m);
+ athn_usb_rx_frame(usc, stream->m, &ml);
  stream->m = NULL;
  }
  /* Next header is 32-bit aligned. */
@@ -2167,7 +2170,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
  if (__predict_true(m != NULL)) {
  /* We have all the pktlen bytes in this xfer. */
  memcpy(mtod(m, uint8_t *), buf, pktlen);
- athn_usb_rx_frame(usc, m);
+ athn_usb_rx_frame(usc, m, &ml);
  }
 
  /* Next header is 32-bit aligned. */
@@ -2175,6 +2178,7 @@ athn_usb_rxeof(struct usbd_xfer *xfer, void *priv,
  buf += off;
  len -= off;
  }
+ if_input(ifp, &ml);
 
  resubmit:
  /* Setup a new transfer. */
blob - cb7e65865adb17b86e10bf5c2bc59983a5c8c2c9
blob + 7461c3e57fb2d76faa3c0da0380827a85d19d5f7
--- sys/dev/usb/if_otus.c
+++ sys/dev/usb/if_otus.c
@@ -124,7 +124,8 @@ void otus_newassoc(struct ieee80211com *, struct ieee
     int);
 void otus_intr(struct usbd_xfer *, void *, usbd_status);
 void otus_cmd_rxeof(struct otus_softc *, uint8_t *, int);
-void otus_sub_rxeof(struct otus_softc *, uint8_t *, int);
+void otus_sub_rxeof(struct otus_softc *, uint8_t *, int,
+    struct mbuf_list *);
 void otus_rxeof(struct usbd_xfer *, void *, usbd_status);
 void otus_txeof(struct usbd_xfer *, void *, usbd_status);
 int otus_tx(struct otus_softc *, struct mbuf *,
@@ -1064,7 +1065,8 @@ otus_cmd_rxeof(struct otus_softc *sc, uint8_t *buf, in
 }
 
 void
-otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, int len)
+otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, int len,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1195,7 +1197,7 @@ otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, in
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = tail->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
@@ -1205,6 +1207,7 @@ otus_sub_rxeof(struct otus_softc *sc, uint8_t *buf, in
 void
 otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct otus_rx_data *data = priv;
  struct otus_softc *sc = data->sc;
  caddr_t buf = data->buf;
@@ -1234,13 +1237,14 @@ otus_rxeof(struct usbd_xfer *xfer, void *priv, usbd_st
  break;
  }
  /* Process sub-xfer. */
- otus_sub_rxeof(sc, (uint8_t *)&head[1], hlen);
+ otus_sub_rxeof(sc, (uint8_t *)&head[1], hlen, &ml);
 
  /* Next sub-xfer is aligned on a 32-bit boundary. */
  hlen = (sizeof (*head) + hlen + 3) & ~3;
  buf += hlen;
  len -= hlen;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
  resubmit:
  usbd_setup_xfer(xfer, sc->data_rx_pipe, data, data->buf, OTUS_RXBUFSZ,
blob - 417666c3503da89fce1d3dc4301b48376dcf7e41
blob + 71c2c98b878349169107680c071978482dce1678
--- sys/dev/usb/if_rsu.c
+++ sys/dev/usb/if_rsu.c
@@ -161,7 +161,8 @@ void rsu_event_join_bss(struct rsu_softc *, uint8_t *
 void rsu_rx_event(struct rsu_softc *, uint8_t, uint8_t *, int);
 void rsu_rx_multi_event(struct rsu_softc *, uint8_t *, int);
 int8_t rsu_get_rssi(struct rsu_softc *, int, void *);
-void rsu_rx_frame(struct rsu_softc *, uint8_t *, int);
+void rsu_rx_frame(struct rsu_softc *, uint8_t *, int,
+    struct mbuf_list *);
 void rsu_rx_multi_frame(struct rsu_softc *, uint8_t *, int);
 void rsu_rxeof(struct usbd_xfer *, void *, usbd_status);
 void rsu_txeof(struct usbd_xfer *, void *, usbd_status);
@@ -1261,7 +1262,8 @@ rsu_get_rssi(struct rsu_softc *sc, int rate, void *phy
 }
 
 void
-rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen)
+rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int pktlen,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1371,7 +1373,7 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int p
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* Unused. */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
  splx(s);
@@ -1380,6 +1382,7 @@ rsu_rx_frame(struct rsu_softc *sc, uint8_t *buf, int p
 void
 rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf, int len)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct r92s_rx_stat *stat;
  uint32_t rxdw0;
  int totlen, pktlen, infosz, npkts;
@@ -1408,13 +1411,14 @@ rsu_rx_multi_frame(struct rsu_softc *sc, uint8_t *buf,
  break;
 
  /* Process 802.11 frame. */
- rsu_rx_frame(sc, buf, pktlen);
+ rsu_rx_frame(sc, buf, pktlen, &ml);
 
  /* Next chunk is 128-byte aligned. */
  totlen = (totlen + 127) & ~127;
  buf += totlen;
  len -= totlen;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 }
 
 void
blob - fc6ba52f271725fe7afbb4abf1a4a1700920a1b4
blob + f22d6d4decb01bab31aa8c0f6fae587651dd3589
--- sys/dev/usb/if_run.c
+++ sys/dev/usb/if_run.c
@@ -376,7 +376,8 @@ void run_calibrate_to(void *);
 void run_calibrate_cb(struct run_softc *, void *);
 void run_newassoc(struct ieee80211com *, struct ieee80211_node *,
     int);
-void run_rx_frame(struct run_softc *, uint8_t *, int);
+void run_rx_frame(struct run_softc *, uint8_t *, int,
+    struct mbuf_list *);
 void run_rxeof(struct usbd_xfer *, void *, usbd_status);
 void run_txeof(struct usbd_xfer *, void *, usbd_status);
 int run_tx(struct run_softc *, struct mbuf *,
@@ -2158,7 +2159,8 @@ run_maxrssi_chain(struct run_softc *sc, const struct r
 }
 
 void
-run_rx_frame(struct run_softc *sc, uint8_t *buf, int dmalen)
+run_rx_frame(struct run_softc *sc, uint8_t *buf, int dmalen,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -2295,7 +2297,7 @@ run_rx_frame(struct run_softc *sc, uint8_t *buf, int d
  ni = ieee80211_find_rxnode(ic, wh);
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -2305,6 +2307,7 @@ run_rx_frame(struct run_softc *sc, uint8_t *buf, int d
 void
 run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct run_rx_data *data = priv;
  struct run_softc *sc = data->sc;
  uint8_t *buf;
@@ -2348,10 +2351,11 @@ run_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
     dmalen + 8, xferlen));
  break;
  }
- run_rx_frame(sc, buf + sizeof (uint32_t), dmalen);
+ run_rx_frame(sc, buf + sizeof (uint32_t), dmalen, &ml);
  buf += dmalen + 8;
  xferlen -= dmalen + 8;
  }
+ if_input(&sc->sc_ic.ic_if, &ml);
 
 skip: /* setup a new transfer */
  usbd_setup_xfer(xfer, sc->rxq.pipeh, data, data->buf, RUN_MAX_RXSZ,
blob - 96a1ad1a91c3e98ebc6dece98df6ac277046612c
blob + 12fc517090e80d703749a326949aeaaf83617639
--- sys/dev/usb/if_urtwn.c
+++ sys/dev/usb/if_urtwn.c
@@ -380,7 +380,8 @@ void urtwn_set_key_cb(struct urtwn_softc *, void *);
 void urtwn_delete_key(struct ieee80211com *,
     struct ieee80211_node *, struct ieee80211_key *);
 void urtwn_delete_key_cb(struct urtwn_softc *, void *);
-void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int);
+void urtwn_rx_frame(struct urtwn_softc *, uint8_t *, int,
+    struct mbuf_list *);
 void urtwn_rxeof(struct usbd_xfer *, void *,
     usbd_status);
 void urtwn_txeof(struct usbd_xfer *, void *,
@@ -1083,7 +1084,8 @@ urtwn_delete_key_cb(struct urtwn_softc *sc, void *arg)
 }
 
 void
-urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen)
+urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, int pktlen,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_sc.sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1194,7 +1196,7 @@ urtwn_rx_frame(struct urtwn_softc *sc, uint8_t *buf, i
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = rssi;
  rxi.rxi_tstamp = 0; /* Unused. */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
  /* Node is no longer needed. */
  ieee80211_release_node(ic, ni);
  splx(s);
@@ -1204,8 +1206,10 @@ void
 urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
     usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct urtwn_rx_data *data = priv;
  struct urtwn_softc *sc = data->sc;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
  struct r92c_rx_desc_usb *rxd;
  uint32_t rxdw0;
  uint8_t *buf;
@@ -1298,13 +1302,14 @@ urtwn_rxeof(struct usbd_xfer *xfer, void *priv,
  break;
 
  /* Process 802.11 frame. */
- urtwn_rx_frame(sc, buf, pktlen);
+ urtwn_rx_frame(sc, buf, pktlen, &ml);
 
  /* Handle chunk alignment. */
  totlen = (totlen + align) & ~align;
  buf += totlen;
  len -= totlen;
  }
+ if_input(&ic->ic_if, &ml);
 
  resubmit:
  /* Setup a new transfer. */
blob - 689ac7e7178ca36a091d25cc6f2cf8d15cc45b0b
blob + ea8545a4ba48d49eb2830b4e6886613e2e181a7c
--- sys/dev/usb/if_zyd.c
+++ sys/dev/usb/if_zyd.c
@@ -217,7 +217,8 @@ void zyd_set_chan(struct zyd_softc *, struct ieee8021
 int zyd_set_beacon_interval(struct zyd_softc *, int);
 uint8_t zyd_plcp_signal(int);
 void zyd_intr(struct usbd_xfer *, void *, usbd_status);
-void zyd_rx_data(struct zyd_softc *, const uint8_t *, uint16_t);
+void zyd_rx_data(struct zyd_softc *, const uint8_t *, uint16_t,
+    struct mbuf_list *);
 void zyd_rxeof(struct usbd_xfer *, void *, usbd_status);
 void zyd_txeof(struct usbd_xfer *, void *, usbd_status);
 int zyd_tx(struct zyd_softc *, struct mbuf *,
@@ -1894,7 +1895,8 @@ zyd_intr(struct usbd_xfer *xfer, void *priv, usbd_stat
 }
 
 void
-zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf, uint16_t len)
+zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf, uint16_t len,
+    struct mbuf_list *ml)
 {
  struct ieee80211com *ic = &sc->sc_ic;
  struct ifnet *ifp = &ic->ic_if;
@@ -1980,7 +1982,7 @@ zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf,
  rxi.rxi_flags = 0;
  rxi.rxi_rssi = stat->rssi;
  rxi.rxi_tstamp = 0; /* unused */
- ieee80211_input(ifp, m, ni, &rxi);
+ ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
  /* node is no longer needed */
  ieee80211_release_node(ic, ni);
@@ -1991,6 +1993,7 @@ zyd_rx_data(struct zyd_softc *sc, const uint8_t *buf,
 void
 zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct zyd_rx_data *data = priv;
  struct zyd_softc *sc = data->sc;
  struct ieee80211com *ic = &sc->sc_ic;
@@ -2030,15 +2033,16 @@ zyd_rxeof(struct usbd_xfer *xfer, void *priv, usbd_sta
  if (len == 0 || p + len >= end)
  break;
 
- zyd_rx_data(sc, p, len);
+ zyd_rx_data(sc, p, len, &ml);
  /* next frame is aligned on a 32-bit boundary */
  p += (len + 3) & ~3;
  }
  } else {
  DPRINTFN(3, ("received single-frame transfer\n"));
 
- zyd_rx_data(sc, data->buf, len);
+ zyd_rx_data(sc, data->buf, len, &ml);
  }
+ if_input(ifp, &ml);
 
 skip: /* setup a new transfer */
  usbd_setup_xfer(xfer, sc->zyd_ep[ZYD_ENDPT_BIN], data, NULL,
blob - 73a9d5229502797c5279734663b1ac1591bec309
blob + 884018208fe4e91c192a9925e49a5cc041dd5cac
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -61,21 +61,22 @@
 struct mbuf *ieee80211_defrag(struct ieee80211com *, struct mbuf *, int);
 void ieee80211_defrag_timeout(void *);
 void ieee80211_input_ba(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int, struct ieee80211_rxinfo *);
+    struct ieee80211_node *, int, struct ieee80211_rxinfo *,
+    struct mbuf_list *);
 void ieee80211_input_ba_flush(struct ieee80211com *, struct ieee80211_node *,
-    struct ieee80211_rx_ba *);
+    struct ieee80211_rx_ba *, struct mbuf_list *);
 void ieee80211_input_ba_gap_timeout(void *arg);
 void ieee80211_ba_move_window(struct ieee80211com *,
-    struct ieee80211_node *, u_int8_t, u_int16_t);
+    struct ieee80211_node *, u_int8_t, u_int16_t, struct mbuf_list *);
 void ieee80211_input_ba_seq(struct ieee80211com *,
-    struct ieee80211_node *, uint8_t, uint16_t);
+    struct ieee80211_node *, uint8_t, uint16_t, struct mbuf_list *);
 struct mbuf *ieee80211_align_mbuf(struct mbuf *);
 void ieee80211_decap(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
+    struct ieee80211_node *, int, struct mbuf_list *);
 void ieee80211_amsdu_decap(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
-void ieee80211_deliver_data(struct ieee80211com *, struct mbuf *,
-    struct ieee80211_node *, int);
+    struct ieee80211_node *, int, struct mbuf_list *);
+void ieee80211_enqueue_data(struct ieee80211com *, struct mbuf *,
+    struct ieee80211_node *, int, struct mbuf_list *);
 int ieee80211_parse_edca_params_body(struct ieee80211com *,
     const u_int8_t *);
 int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
@@ -155,10 +156,16 @@ ieee80211_get_hdrlen(const struct ieee80211_frame *wh)
  * any units so long as values have consistent units and higher values
  * mean ``better signal''.  The receive timestamp is currently not used
  * by the 802.11 layer.
+ *
+ * This function acts on management frames immediately and queues data frames
+ * on the specified mbuf list. Delivery of queued data frames to upper layers
+ * must be triggered with if_input(). Drivers should call if_input() only once
+ * per Rx interrupt to avoid triggering the input ifq pressure drop mechanism
+ * unnecessarily.
  */
 void
-ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
-    struct ieee80211_rxinfo *rxi)
+ieee80211_inputm(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+    struct ieee80211_rxinfo *rxi, struct mbuf_list *ml)
 {
  struct ieee80211com *ic = (void *)ifp;
  struct ieee80211_frame *wh;
@@ -259,7 +266,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
     (qos & IEEE80211_QOS_ACK_POLICY_MASK) ==
     IEEE80211_QOS_ACK_POLICY_NORMAL)) {
  /* go through A-MPDU reordering */
- ieee80211_input_ba(ic, m, ni, tid, rxi);
+ ieee80211_input_ba(ic, m, ni, tid, rxi, ml);
  return; /* don't free m! */
  }
  }
@@ -463,9 +470,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
 
  if ((ni->ni_flags & IEEE80211_NODE_HT) &&
     hasqos && (qos & IEEE80211_QOS_AMSDU))
- ieee80211_amsdu_decap(ic, m, ni, hdrlen);
+ ieee80211_amsdu_decap(ic, m, ni, hdrlen, ml);
  else
- ieee80211_decap(ic, m, ni, hdrlen);
+ ieee80211_decap(ic, m, ni, hdrlen, ml);
  return;
 
  case IEEE80211_FC0_TYPE_MGT:
@@ -560,6 +567,17 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, str
  }
 }
 
+/* Input handler for drivers which only receive one frame per interrupt. */
+void
+ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+    struct ieee80211_rxinfo *rxi)
+{
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+
+ ieee80211_inputm(ifp, m, ni, rxi, &ml);
+ if_input(ifp, &ml);
+}
+
 /*
  * Handle defragmentation (see 9.5 and Annex C).  We support the concurrent
  * reception of fragments of three fragmented MSDUs or MMPDUs.
@@ -656,7 +674,8 @@ ieee80211_defrag_timeout(void *arg)
  */
 void
 ieee80211_input_ba(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int tid, struct ieee80211_rxinfo *rxi)
+    struct ieee80211_node *ni, int tid, struct ieee80211_rxinfo *rxi,
+    struct mbuf_list *ml)
 {
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
@@ -699,12 +718,12 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbu
  ic->ic_stats.is_ht_rx_ba_window_jump++;
  ba->ba_winmiss = 0;
  ba->ba_missedsn = 0;
- ieee80211_ba_move_window(ic, ni, tid, sn);
+ ieee80211_ba_move_window(ic, ni, tid, sn, ml);
  } else {
  ic->ic_stats.is_ht_rx_ba_window_slide++;
  ieee80211_input_ba_seq(ic, ni, tid,
-    (ba->ba_winstart + count) & 0xfff);
- ieee80211_input_ba_flush(ic, ni, ba);
+    (ba->ba_winstart + count) & 0xfff, ml);
+ ieee80211_input_ba_flush(ic, ni, ba, ml);
  }
  }
  /* WinStartB <= SN <= WinEndB */
@@ -730,7 +749,7 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbu
  else if (timeout_pending(&ba->ba_gap_to))
  timeout_del(&ba->ba_gap_to);
 
- ieee80211_input_ba_flush(ic, ni, ba);
+ ieee80211_input_ba_flush(ic, ni, ba, ml);
 }
 
 /*
@@ -739,7 +758,7 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbu
  */
 void
 ieee80211_input_ba_seq(struct ieee80211com *ic, struct ieee80211_node *ni,
-    uint8_t tid, uint16_t max_seq)
+    uint8_t tid, uint16_t max_seq, struct mbuf_list *ml)
 {
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
@@ -757,8 +776,8 @@ ieee80211_input_ba_seq(struct ieee80211com *ic, struct
     IEEE80211_SEQ_SEQ_SHIFT;
  if (!SEQ_LT(seq, max_seq))
  return;
- ieee80211_input(ifp, ba->ba_buf[ba->ba_head].m,
-    ni, &ba->ba_buf[ba->ba_head].rxi);
+ ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m,
+    ni, &ba->ba_buf[ba->ba_head].rxi, ml);
  ba->ba_buf[ba->ba_head].m = NULL;
  } else
  ic->ic_stats.is_ht_rx_ba_frame_lost++;
@@ -769,15 +788,15 @@ ieee80211_input_ba_seq(struct ieee80211com *ic, struct
 /* Flush a consecutive sequence of frames from the reorder buffer. */
 void
 ieee80211_input_ba_flush(struct ieee80211com *ic, struct ieee80211_node *ni,
-    struct ieee80211_rx_ba *ba)
+    struct ieee80211_rx_ba *ba, struct mbuf_list *ml)
 
 {
  struct ifnet *ifp = &ic->ic_if;
 
  /* pass reordered MPDUs up to the next MAC process */
  while (ba->ba_buf[ba->ba_head].m != NULL) {
- ieee80211_input(ifp, ba->ba_buf[ba->ba_head].m, ni,
-    &ba->ba_buf[ba->ba_head].rxi);
+ ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni,
+    &ba->ba_buf[ba->ba_head].rxi, ml);
  ba->ba_buf[ba->ba_head].m = NULL;
 
  ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
@@ -796,6 +815,7 @@ ieee80211_input_ba_flush(struct ieee80211com *ic, stru
 void
 ieee80211_input_ba_gap_timeout(void *arg)
 {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  struct ieee80211_rx_ba *ba = arg;
  struct ieee80211_node *ni = ba->ba_ni;
  struct ieee80211com *ic = ni->ni_ic;
@@ -816,7 +836,8 @@ ieee80211_input_ba_gap_timeout(void *arg)
  if (skipped > 0)
  ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
 
- ieee80211_input_ba_flush(ic, ni, ba);
+ ieee80211_input_ba_flush(ic, ni, ba, &ml);
+ if_input(&ic->ic_if, &ml);
 
  splx(s);
 }
@@ -828,7 +849,7 @@ ieee80211_input_ba_gap_timeout(void *arg)
  */
 void
 ieee80211_ba_move_window(struct ieee80211com *ic, struct ieee80211_node *ni,
-    u_int8_t tid, u_int16_t ssn)
+    u_int8_t tid, u_int16_t ssn, struct mbuf_list *ml)
 {
  struct ifnet *ifp = &ic->ic_if;
  struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
@@ -842,8 +863,8 @@ ieee80211_ba_move_window(struct ieee80211com *ic, stru
  while (count-- > 0) {
  /* gaps may exist */
  if (ba->ba_buf[ba->ba_head].m != NULL) {
- ieee80211_input(ifp, ba->ba_buf[ba->ba_head].m, ni,
-    &ba->ba_buf[ba->ba_head].rxi);
+ ieee80211_inputm(ifp, ba->ba_buf[ba->ba_head].m, ni,
+    &ba->ba_buf[ba->ba_head].rxi, ml);
  ba->ba_buf[ba->ba_head].m = NULL;
  } else
  ic->ic_stats.is_ht_rx_ba_frame_lost++;
@@ -852,12 +873,12 @@ ieee80211_ba_move_window(struct ieee80211com *ic, stru
  /* move window forward */
  ba->ba_winstart = ssn;
 
- ieee80211_input_ba_flush(ic, ni, ba);
+ ieee80211_input_ba_flush(ic, ni, ba, ml);
 }
 
 void
-ieee80211_deliver_data(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int mcast)
+ieee80211_enqueue_data(struct ieee80211com *ic, struct mbuf *m,
+    struct ieee80211_node *ni, int mcast, struct mbuf_list *ml)
 {
  struct ifnet *ifp = &ic->ic_if;
  struct ether_header *eh;
@@ -920,16 +941,14 @@ ieee80211_deliver_data(struct ieee80211com *ic, struct
 #endif
  ieee80211_eapol_key_input(ic, m, ni);
  } else {
- struct mbuf_list ml = MBUF_LIST_INITIALIZER();
- ml_enqueue(&ml, m);
- if_input(ifp, &ml);
+ ml_enqueue(ml, m);
  }
  }
 }
 
 void
 ieee80211_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
  struct ether_header eh;
  struct ieee80211_frame *wh;
@@ -985,7 +1004,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  return;
  }
  }
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 }
 
 /*
@@ -993,7 +1012,7 @@ ieee80211_decap(struct ieee80211com *ic, struct mbuf *
  */
 void
 ieee80211_amsdu_decap(struct ieee80211com *ic, struct mbuf *m,
-    struct ieee80211_node *ni, int hdrlen)
+    struct ieee80211_node *ni, int hdrlen, struct mbuf_list *ml)
 {
  struct mbuf *n;
  struct ether_header *eh;
@@ -1059,7 +1078,7 @@ ieee80211_amsdu_decap(struct ieee80211com *ic, struct
  m_freem(m);
  break;
  }
- ieee80211_deliver_data(ic, m, ni, mcast);
+ ieee80211_enqueue_data(ic, m, ni, mcast, ml);
 
  if (n->m_pkthdr.len == 0) {
  m_freem(n);
@@ -2564,8 +2583,11 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, stru
  return; /* not a PBAC, ignore */
 
  /* PBAC: treat the ADDBA Request like a BlockAckReq */
- if (SEQ_LT(ba->ba_winstart, ssn))
- ieee80211_ba_move_window(ic, ni, tid, ssn);
+ if (SEQ_LT(ba->ba_winstart, ssn)) {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ ieee80211_ba_move_window(ic, ni, tid, ssn, &ml);
+ if_input(&ic->ic_if, &ml);
+ }
  return;
  }
 
@@ -3174,6 +3196,9 @@ ieee80211_bar_tid(struct ieee80211com *ic, struct ieee
  if (ba->ba_timeout_val != 0)
  timeout_add_usec(&ba->ba_to, ba->ba_timeout_val);
 
- if (SEQ_LT(ba->ba_winstart, ssn))
- ieee80211_ba_move_window(ic, ni, tid, ssn);
+ if (SEQ_LT(ba->ba_winstart, ssn)) {
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ ieee80211_ba_move_window(ic, ni, tid, ssn, &ml);
+ if_input(&ic->ic_if, &ml);
+ }
 }
blob - e622d35f4dcd21ea0bb40c6a5d0b3f758e197b38
blob + 52cf8fddfc1658a5c38a4895fff4e858d15bb876
--- sys/net80211/ieee80211_proto.h
+++ sys/net80211/ieee80211_proto.h
@@ -66,6 +66,9 @@ struct ieee80211_rsnparams;
 extern void ieee80211_set_link_state(struct ieee80211com *, int);
 extern u_int ieee80211_get_hdrlen(const struct ieee80211_frame *);
 extern int ieee80211_classify(struct ieee80211com *, struct mbuf *);
+extern void ieee80211_inputm(struct ifnet *, struct mbuf *,
+ struct ieee80211_node *, struct ieee80211_rxinfo *,
+ struct mbuf_list *);
 extern void ieee80211_input(struct ifnet *, struct mbuf *,
  struct ieee80211_node *, struct ieee80211_rxinfo *);
 extern int ieee80211_output(struct ifnet *, struct mbuf *, struct sockaddr *,

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Matthias Schmidt
Hi Stefan,

* Stefan Sperling wrote:

>
> I think I see why. I forgot to convert some existing ieee80211_input()
> calls to ieee80211_inputm(), in ieee80211_input.c.
> These calls are related to buffered aggregated frames, so aggregated
> frames triggered multiple if_input() calls per interrupt again.
>
> In the first diff ieee80211_input() was putting aggregated frames
> onto the global mbuf list. With this new diff they get added to the
> mbuf list which the driver's rx interrupt handler passed in.
>
> Does this fix the issue?

Yes, indeed.  Download test files from a leaseweb mirror is now so fast
that my CPU fan starts spinning :)  This time, only tested on iwm.

Kudos for the quick fix!

        Matthias

Reply | Threaded
Open this post in threaded view
|

Re: call if_input only once per Rx interrupt from net80211

Stefan Sperling-5
On Tue, Sep 10, 2019 at 10:35:34PM +0200, Matthias Schmidt wrote:

> Hi Stefan,
>
> * Stefan Sperling wrote:
> >
> > I think I see why. I forgot to convert some existing ieee80211_input()
> > calls to ieee80211_inputm(), in ieee80211_input.c.
> > These calls are related to buffered aggregated frames, so aggregated
> > frames triggered multiple if_input() calls per interrupt again.
> >
> > In the first diff ieee80211_input() was putting aggregated frames
> > onto the global mbuf list. With this new diff they get added to the
> > mbuf list which the driver's rx interrupt handler passed in.
> >
> > Does this fix the issue?
>
> Yes, indeed.  Download test files from a leaseweb mirror is now so fast
> that my CPU fan starts spinning :)  This time, only tested on iwm.
>
> Kudos for the quick fix!
>
> Matthias
>

Thanks for your help! Glad it's fixed :)