This diff adds mira support to the iwn(4) driver.

I have tested this with:
iwn0 at pci2 dev 0 function 0 "Intel WiFi Link 5100" rev 0x00: msi, MIMO 1T2R
When reporting test results please mention which device was tested.

There's a little hack for 4965 hardware because it does not report the
number of bytes transmitted. I tested this hack in the 5000 code path
and it works there. I did find an actual 4965 device in my pile but it
seems to be broken (never shows up in dmesg).
Tests on 4965 hardware would be very much appreciated.

Index: if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.176
diff -u -p -r1.176 if_iwn.c
--- if_iwn.c    30 Nov 2016 10:52:10 -0000      1.176
+++ if_iwn.c    1 Dec 2016 18:40:38 -0000
@@ -55,6 +55,7 @@
 
 #include <net80211/ieee80211_var.h>
 #include <net80211/ieee80211_amrr.h>
+#include <net80211/ieee80211_mira.h>
 #include <net80211/ieee80211_radiotap.h>
 
 #include <dev/pci/if_iwnreg.h>
@@ -164,8 +165,8 @@ void                iwn4965_tx_done(struct iwn_softc *
                    struct iwn_rx_data *);
 void           iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
                    struct iwn_rx_data *);
-void           iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int,
-                   uint8_t);
+void           iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
+                   uint8_t, uint8_t, uint8_t, uint16_t);
 void           iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
 void           iwn_notif_intr(struct iwn_softc *);
 void           iwn_wakeup_intr(struct iwn_softc *);
@@ -1694,8 +1695,10 @@ iwn_newassoc(struct ieee80211com *ic, st
        uint8_t rate;
        int ridx, i;
 
-       ieee80211_amrr_node_init(&sc->amrr, &wn->amn);
-       /* Start at lowest available bit-rate, AMRR will raise. */
+       if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
+               ieee80211_amrr_node_init(&sc->amrr, &wn->amn);
+
+       /* Start at lowest available bit-rate, AMRR/MiRA will raise. */
        ni->ni_txrate = 0;
        ni->ni_txmcs = 0;
 
@@ -1749,10 +1752,16 @@ iwn_newstate(struct ieee80211com *ic, en
 {
        struct ifnet *ifp = &ic->ic_if;
        struct iwn_softc *sc = ifp->if_softc;
+       struct ieee80211_node *ni = ic->ic_bss;
+       struct iwn_node *wn = (struct iwn_node *)ni;
        int error;
 
        timeout_del(&sc->calib_to);
 
+       if (ic->ic_state == IEEE80211_S_RUN &&
+           (ni->ni_flags & IEEE80211_NODE_HT))
+               ieee80211_mira_node_destroy(&wn->mn);
+
        switch (nstate) {
        case IEEE80211_S_SCAN:
                /* Make the link LED blink while we're scanning. */
@@ -1805,7 +1814,8 @@ iwn_iter_func(void *arg, struct ieee8021
        struct iwn_softc *sc = arg;
        struct iwn_node *wn = (struct iwn_node *)ni;
 
-       ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn);
+       if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
+               ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn);
 }
 
 void
@@ -2319,10 +2329,16 @@ iwn4965_tx_done(struct iwn_softc *sc, st
     struct iwn_rx_data *data)
 {
        struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1);
+       struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
+       struct iwn_tx_data *txdata = &ring->data[desc->idx];
+       /* XXX 4965 does not report byte count */
+       uint16_t len = txdata->totlen + IEEE80211_CRC_LEN;
 
        bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
            sizeof (*stat), BUS_DMASYNC_POSTREAD);
-       iwn_tx_done(sc, desc, stat->ackfailcnt, letoh32(stat->status) & 0xff);
+
+       iwn_tx_done(sc, desc, stat->nframes, stat->ackfailcnt,
+           letoh32(stat->status) & 0xff, len);
 }
 
 void
@@ -2338,28 +2354,42 @@ iwn5000_tx_done(struct iwn_softc *sc, st
 
        bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
            sizeof (*stat), BUS_DMASYNC_POSTREAD);
-       iwn_tx_done(sc, desc, stat->ackfailcnt, letoh16(stat->status) & 0xff);
+       iwn_tx_done(sc, desc, stat->nframes, stat->ackfailcnt,
+           letoh16(stat->status) & 0xff, letoh16(stat->len));
 }
 
 /*
  * Adapter-independent backend for TX_DONE firmware notifications.
  */
 void
-iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt,
-    uint8_t status)
+iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, uint8_t nframes,
+    uint8_t ackfailcnt, uint8_t status, uint16_t len)
 {
        struct ieee80211com *ic = &sc->sc_ic;
        struct ifnet *ifp = &ic->ic_if;
        struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
        struct iwn_tx_data *data = &ring->data[desc->idx];
        struct iwn_node *wn = (struct iwn_node *)data->ni;
+       int txfail = (status != 1 && status != 2);
 
-       /* Update rate control statistics. */
-       wn->amn.amn_txcnt++;
-       if (ackfailcnt > 0)
-               wn->amn.amn_retrycnt++;
+       KASSERT(nframes == 1); /* We don't support aggregation yet. */
 
-       if (status != 1 && status != 2) {
+       /* Update rate control statistics. */
+       if (data->ni->ni_flags & IEEE80211_NODE_HT) {
+               wn->mn.frames += nframes;
+               wn->mn.ampdu_size = len;
+               wn->mn.agglen = nframes; 
+               if (txfail) {
+                       wn->mn.retries += ackfailcnt;
+                       wn->mn.txfail += nframes;
+               }
+               ieee80211_mira_choose(&wn->mn, ic, data->ni);
+       } else {
+               wn->amn.amn_txcnt++;
+               if (ackfailcnt > 0)
+                       wn->amn.amn_retrycnt++;
+       }
+       if (txfail) {
                DPRINTF(("%s: status=0x%x\n", __func__, status));
                ifp->if_oerrors++;
        } else
@@ -2921,6 +2951,8 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
                        totlen += IEEE80211_CCMP_HDRLEN;
        }
 
+       data->totlen = totlen;
+
        /* Prepare TX firmware command. */
        cmd = &ring->cmd[ring->cur];
        cmd->code = IWN_CMD_TX_DATA;
@@ -4980,6 +5012,11 @@ iwn_run(struct iwn_softc *sc)
        sc->calib.state = IWN_CALIB_STATE_ASSOC;
        sc->calib_cnt = 0;
        timeout_add_msec(&sc->calib_to, 500);
+
+       if (ni->ni_flags & IEEE80211_NODE_HT) {
+               struct iwn_node *wn = (void *)ni;
+               ieee80211_mira_node_init(&wn->mn);
+       }
 
        /* Link LED always on while associated. */
        iwn_set_led(sc, IWN_LED_LINK, 0, 1);
Index: if_iwnvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwnvar.h,v
retrieving revision 1.31
diff -u -p -r1.31 if_iwnvar.h
--- if_iwnvar.h 5 Sep 2016 08:18:18 -0000       1.31
+++ if_iwnvar.h 1 Dec 2016 18:25:59 -0000
@@ -66,6 +66,7 @@ struct iwn_tx_data {
        bus_addr_t              scratch_paddr;
        struct mbuf             *m;
        struct ieee80211_node   *ni;
+       int totlen;
 };
 
 struct iwn_tx_ring {
@@ -98,6 +99,7 @@ struct iwn_rx_ring {
 struct iwn_node {
        struct  ieee80211_node          ni;     /* must be the first */
        struct  ieee80211_amrr_node     amn;
+       struct  ieee80211_mira_node     mn;
        uint16_t                        disable_tid;
        uint8_t                         id;
        uint8_t                         ridx[IEEE80211_RATE_MAXSIZE];

Reply via email to