Bringing up a wifi device

This is TBD in more detail.

802.11n bring-up

        ic->ic_htcaps =
            IEEE80211_HTC_HT
            | IEEE80211_HTC_AMPDU
            | IEEE80211_HTC_AMSDU
            | IEEE80211_HTCAP_MAXAMSDU_3839
            | IEEE80211_HTCAP_SMPS_OFF;

        if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI)
                ic->ic_htcaps |= IEEE80211_HTCAP_SHORTGI20;

        /*
         * XXX TODO: enable HT40 once the channel setup code
         * knows how to correctly do it.
         */
        /* XXX TODO: STBC */

        /* XXX TODO: LDPC */

        /* XXX TODO: max ampdu size / density; but is per-vap */

        /* Streams */
        ic->ic_txstream = ar->num_rf_chains;
        ic->ic_rxstream = ar->num_rf_chains;
        device_printf(ar->sc_dev, "%s: %d tx streams, %d rx streams\n",
            __func__,

        if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) {
                setbit(bands, IEEE80211_MODE_11B);
                setbit(bands, IEEE80211_MODE_11G);
                if (ar->ht_cap_info & WMI_HT_CAP_ENABLED)
                        setbit(bands, IEEE80211_MODE_11NG);
                ieee80211_add_channel_list_2ghz(chans, IEEE80211_CHAN_MAX,
                    nchans, chan_list_2ghz, nitems(chan_list_2ghz),
                    bands, ht40);
        }
        if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) {
                setbit(bands, IEEE80211_MODE_11A);
                if (ar->ht_cap_info & WMI_HT_CAP_ENABLED)
                        setbit(bands, IEEE80211_MODE_11NA);
                ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
                    nchans, chan_list_5ghz, nitems(chan_list_5ghz),
                    bands, ht40);
        }

static void
athp_update_chw(struct ieee80211com *ic)
{

}

/*
 * This always /disables/ negotiating AMPDU-TX via net80211.
 * The firmware may negotiate it if it does AMPDU TX offload (eg QCA ath10k firmware.)
 */
static int
athp_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
{

        return (0);
}
...
        /* 11n methods */
        ic->ic_update_chw = athp_update_chw;
        ic->ic_ampdu_enable = athp_ampdu_enable;

Then you should be able to create a vap, associate, have A-MPDU RX negotiated, etc. However, you need to do a couple things in the RX path so 11n frames are tagged right:

        /* RX path to net80211 */
        ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *));
        if (ni != NULL) {
                if (ni->ni_flags & IEEE80211_NODE_HT)
                        m->m_flags |= M_AMPDU;
                ieee80211_input_mimo(ni, m);
                ieee80211_free_node(ni);
        } else {
                ieee80211_input_mimo_all(ic, m);
        }

You need to tag frames going to a HT node with M_AMPDU. Yes, this should be done in the net80211 stack, sigh.

Ok, so at this point I'd suggest:

That way ampdu TX/RX is disabled entirely (so you don't have to debug A-MPDU stuff.) Verify that you can TX/RX 11n MCS frames.

At this point you should be able to receive 11n MCS frames, but your TX path still likely transmits legacy frames. You'll need to look at the TX setup path to see how you setup and send MCS frames. If 11n is enabled then the fixed rates for ucast, mcast, etc may be MCS rates (ucast), may be legacy (mcast, mgmt.) So you can't assume /all/ frames are MCS. Look at the TX path for both raw and normal and log/debug exactly what's being sent.

Then, for A-MPDU RX, you need to setup the A-MPDU density and size. This is typically done in the vap create handler:

        /* A-MPDU density/maximum size */
        vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_8;
        vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K;

        if (ieee80211_vap_setup(ic, vap, name, unit, opmode,
            flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) {
                free(uvp, M_80211_VAP);
                return (NULL);
        }

Density is 'how much spacing between each A-MPDU subframe.' size is "how big an A-MPDU can i receive." You can overshoot this and say, do an 8K MAXRXAMPDU and density of 32 - I think all NICs should support this anyway.

(note: if you read this - bug adrian to make sure that he updates ath(4) to obey the /peer/ iv_ampdu_density / iv_ampdu_max when sending frames in both STA and AP mode. I have a feeling that STA mode is fine, but AP isn't. Sigh.)

At this point you can attempt to enable A-MPDU RX and see if it works:

Now, some NICs will just give A-MPDU sub-frames back the same way normal frames are (eg ath(4)); some have a different RX path (eg iwn(4), iwm(4).) This is where you get to discover this.

Once this is done and iperf shows A-MPDU RX is working out okay, you can look at enable sending non-aggregate 11n MCS frames. Hopefully you've done some homework above and figured out how you send non-aggregate MCS frames in the transmit path.

Once non-aggregate 11n frames are being sent, you can attempt one of a few things:

    ic->ic_caps |= IEEE80211_C_SWAMSDUTX;

Make sure your TX path can handle writing an 8k frame out to the NIC, rather than say a 2k frame.

Chances are that A-MPDU TX in software will be too painful and it isn't important right now, so flip on A-MSDU TX. Flipping on A-MSDU TX in software requires implementing some queue flushing when things slow down. The net80211 A-MSDU TX uses the same path as SUPERG, so go look at a driver that does SUPERG / fast-frames (if_otus, if_rtwn) and insert a suitable call to ieee80211_ff_flush_all(ic, 100); in the RX callback and TX callback.

At this point you can look at HT40 channel setup and programming.

Then, once this is done, I'd look at short-gi, STBC, LDPC, etc negotiation.

notes

WiFi/BringUp (last edited 2018-04-05T23:30:41+0000 by MateuszPiotrowski)