1
0
mirror of https://github.com/openbsd/src.git synced 2026-06-18 07:13:36 +02:00

sys/qwz: add 802.11n support

Advertise HT capabilities and pass HT/QoS peer association.

OK: stsp@
This commit is contained in:
kirill
2026-05-18 13:47:32 +00:00
parent 08041194ec
commit eda1c51e17
3 changed files with 192 additions and 27 deletions
+172 -23
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: qwz.c,v 1.28 2026/05/15 19:02:12 mglocker Exp $ */
/* $OpenBSD: qwz.c,v 1.29 2026/05/18 13:47:32 kirill Exp $ */
/*
* Copyright 2023 Stefan Sperling <stsp@openbsd.org>
@@ -10676,7 +10676,8 @@ qwz_init_channels_world(struct qwz_softc *sc)
chan->ic_flags = IEEE80211_CHAN_CCK |
IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN |
IEEE80211_CHAN_2GHZ;
IEEE80211_CHAN_2GHZ |
IEEE80211_CHAN_HT;
}
}
@@ -10686,6 +10687,7 @@ qwz_init_channels_world(struct qwz_softc *sc)
chan->ic_freq = ieee80211_ieee2mhz(channels_5ghz[i],
IEEE80211_CHAN_5GHZ);
chan->ic_flags = IEEE80211_CHAN_A |
IEEE80211_CHAN_HT |
IEEE80211_CHAN_PASSIVE;
}
}
@@ -10730,7 +10732,8 @@ qwz_init_channels(struct qwz_softc *sc, struct cur_regulatory_info *reg_info)
chan->ic_flags = IEEE80211_CHAN_CCK |
IEEE80211_CHAN_OFDM |
IEEE80211_CHAN_DYN |
IEEE80211_CHAN_2GHZ;
IEEE80211_CHAN_2GHZ |
IEEE80211_CHAN_HT;
}
chnum++;
freq = ieee80211_ieee2mhz(chnum, IEEE80211_CHAN_2GHZ);
@@ -10764,7 +10767,8 @@ qwz_init_channels(struct qwz_softc *sc, struct cur_regulatory_info *reg_info)
chan->ic_flags = 0;
} else {
chan->ic_freq = freq;
chan->ic_flags = IEEE80211_CHAN_A;
chan->ic_flags = IEEE80211_CHAN_A |
IEEE80211_CHAN_HT;
if (rule->flags & (REGULATORY_CHAN_RADAR |
REGULATORY_CHAN_NO_IR |
REGULATORY_CHAN_INDOOR_ONLY)) {
@@ -20857,14 +20861,30 @@ qwz_reg_update_chan_list(struct qwz_softc *sc, uint8_t pdev_id)
int num_channels = 0;
size_t params_size;
int ret;
int scan_2ghz = 1, scan_5ghz = 1;
#if 0
if (ar->state == ATH12K_STATE_RESTARTING)
return 0;
#endif
/*
* Scan an appropriate subset of channels if we are running
* in a fixed, user-specified phy mode.
*/
if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) {
if (ic->ic_curmode == IEEE80211_MODE_11A)
scan_2ghz = 0;
if (ic->ic_curmode == IEEE80211_MODE_11B ||
ic->ic_curmode == IEEE80211_MODE_11G)
scan_5ghz = 0;
}
lastc = &ic->ic_channels[IEEE80211_CHAN_MAX];
for (channel = &ic->ic_channels[1]; channel <= lastc; channel++) {
if (channel->ic_flags == 0)
continue;
if ((!scan_2ghz && IEEE80211_IS_CHAN_2GHZ(channel)) ||
(!scan_5ghz && IEEE80211_IS_CHAN_5GHZ(channel)))
continue;
num_channels++;
}
@@ -20890,6 +20910,9 @@ qwz_reg_update_chan_list(struct qwz_softc *sc, uint8_t pdev_id)
for (channel = &ic->ic_channels[1]; channel <= lastc; channel++) {
if (channel->ic_flags == 0)
continue;
if ((!scan_2ghz && IEEE80211_IS_CHAN_2GHZ(channel)) ||
(!scan_5ghz && IEEE80211_IS_CHAN_5GHZ(channel)))
continue;
/*
* XXX We do not populate 6 GHz channels here yet.
* Linux sets these scan capability bits unconditionally too.
@@ -20910,13 +20933,24 @@ qwz_reg_update_chan_list(struct qwz_softc *sc, uint8_t pdev_id)
ch->maxregpower = ch->maxpower;
ch->antennamax = 0;
/* TODO: Use appropriate phymodes */
if (IEEE80211_IS_CHAN_A(channel))
switch (IFM_MODE(ic->ic_media.ifm_cur->ifm_media)) {
case IFM_IEEE80211_11A:
ch->phy_mode = MODE_11A;
else if (IEEE80211_IS_CHAN_G(channel))
break;
case IFM_IEEE80211_11G:
ch->phy_mode = MODE_11G;
else
break;
case IFM_IEEE80211_11B:
ch->phy_mode = MODE_11B;
break;
case IFM_IEEE80211_11N:
default:
if (IEEE80211_IS_CHAN_A(channel))
ch->phy_mode = MODE_11NA_HT20;
else
ch->phy_mode = MODE_11NG_HT20;
break;
}
#ifdef notyet
if (channel->band == NL80211_BAND_6GHZ &&
cfg80211_channel_is_psc(channel))
@@ -21052,6 +21086,7 @@ int
qwz_mac_op_start(struct qwz_pdev *pdev)
{
struct qwz_softc *sc = pdev->sc;
struct ieee80211com *ic = &sc->sc_ic;
int ret;
ret = qwz_wmi_pdev_set_param(sc, WMI_PDEV_PARAM_PMF_QOS, 1,
@@ -21103,6 +21138,15 @@ qwz_mac_op_start(struct qwz_pdev *pdev)
qwz_set_antenna(pdev, pdev->cap.tx_chain_mask, pdev->cap.rx_chain_mask);
memset(ic->ic_sup_mcs, 0, sizeof(ic->ic_sup_mcs));
ic->ic_sup_mcs[0] = 0xff; /* MCS 0-7 */
if (sc->num_rx_chains > 1)
ic->ic_sup_mcs[1] = 0xff; /* MCS 8-15 */
if (sc->num_rx_chains > 2)
ic->ic_sup_mcs[2] = 0xff; /* MCS 16-23 */
if (sc->num_rx_chains > 3)
ic->ic_sup_mcs[3] = 0xff; /* MCS 24-31 */
/* TODO: Do we need to enable ANI? */
ret = qwz_reg_update_chan_list(sc, pdev->pdev_id);
@@ -21340,21 +21384,12 @@ qwz_mac_vdev_start_restart(struct qwz_softc *sc, struct qwz_vif *arvif,
arg.channel.band_center_freq1 = chan->ic_freq;
arg.channel.band_center_freq2 = chan->ic_freq;
switch (ic->ic_curmode) {
case IEEE80211_MODE_11A:
if (IEEE80211_IS_CHAN_5GHZ(chan))
arg.channel.mode = MODE_11A;
break;
case IEEE80211_MODE_11B:
arg.channel.mode = MODE_11B;
break;
case IEEE80211_MODE_11G:
else if (ic->ic_bss->ni_flags & IEEE80211_NODE_ERP)
arg.channel.mode = MODE_11G;
break;
default:
printf("%s: unsupported phy mode %d\n",
sc->sc_dev.dv_xname, ic->ic_curmode);
return ENOTSUP;
}
else
arg.channel.mode = MODE_11B;
arg.channel.min_power = 0;
arg.channel.max_power = 20; /* XXX */
@@ -23993,6 +24028,12 @@ qwz_peer_assoc_h_phymode(struct qwz_softc *sc, struct ieee80211_node *ni,
case IEEE80211_MODE_11G:
phymode = MODE_11G;
break;
case IEEE80211_MODE_11N:
if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
phymode = MODE_11NA_HT20;
else
phymode = MODE_11NG_HT20;
break;
default:
phymode = MODE_UNKNOWN;
break;
@@ -24004,6 +24045,114 @@ qwz_peer_assoc_h_phymode(struct qwz_softc *sc, struct ieee80211_node *ni,
arg->peer_phymode = phymode;
}
uint8_t
qwz_parse_mpdudensity(uint8_t mpdudensity)
{
switch (mpdudensity) {
case 0:
return 0;
case 1:
case 2:
case 3:
return 1;
case 4:
return 2;
case 5:
return 4;
case 6:
return 8;
case 7:
return 16;
default:
return 0;
}
}
void
qwz_peer_assoc_h_ht(struct qwz_softc *sc, struct ieee80211_node *ni,
struct peer_assoc_params *arg)
{
struct ieee80211com *ic = &sc->sc_ic;
int i, n;
uint8_t max_nss;
uint32_t stbc, aggsize, mpdu_density;
#ifdef notyet
lockdep_assert_held(&ar->conf_mutex);
#endif
if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
return;
arg->ht_flag = true;
aggsize = (ni->ni_ampdu_param & IEEE80211_AMPDU_PARAM_LE);
arg->peer_max_mpdu = (1 << (13 + aggsize)) - 1;
mpdu_density = (ni->ni_ampdu_param & IEEE80211_AMPDU_PARAM_SS) >> 2;
arg->peer_mpdu_density = qwz_parse_mpdudensity(mpdu_density);
arg->peer_ht_caps = ni->ni_htcaps;
arg->peer_rate_caps |= WMI_HOST_RC_HT_FLAG;
if (ni->ni_htcaps & IEEE80211_HTCAP_LDPC)
arg->ldpc_flag = true;
#if 0
if (sta->deflink.bandwidth >= IEEE80211_STA_RX_BW_40) {
arg->bw_40 = true;
arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG;
}
#endif
if (ieee80211_node_supports_ht_sgi20(ni) ||
ieee80211_node_supports_ht_sgi40(ni))
arg->peer_rate_caps |= WMI_HOST_RC_SGI_FLAG;
if (ni->ni_htcaps & IEEE80211_HTCAP_TXSTBC) {
arg->peer_rate_caps |= WMI_HOST_RC_TX_STBC_FLAG;
arg->stbc_flag = true;
}
if (ni->ni_htcaps & IEEE80211_HTCAP_TXSTBC) {
stbc = ni->ni_htcaps & IEEE80211_HTCAP_RXSTBC_MASK;
stbc = stbc >> IEEE80211_HTCAP_RXSTBC_SHIFT;
stbc = stbc << WMI_HOST_RC_RX_STBC_FLAG_S;
arg->peer_rate_caps |= stbc;
arg->stbc_flag = true;
}
if (ni->ni_rxmcs[1] && ni->ni_rxmcs[2])
arg->peer_rate_caps |= WMI_HOST_RC_TS_FLAG;
else if (ni->ni_rxmcs[1])
arg->peer_rate_caps |= WMI_HOST_RC_DS_FLAG;
for (i = 0, n = 0, max_nss = 0; i < nitems(ni->ni_rxmcs) * 8; i++)
if ((ic->ic_sup_mcs[i / 8] & BIT(i % 8)) &&
(ni->ni_rxmcs[i / 8] & BIT(i % 8))) {
max_nss = (i / 8) + 1;
arg->peer_ht_rates.rates[n++] = i;
}
if (n == 0) {
arg->peer_ht_rates.num_rates = 8;
for (i = 0; i < arg->peer_ht_rates.num_rates; i++)
arg->peer_ht_rates.rates[i] = i;
} else {
arg->peer_ht_rates.num_rates = n;
arg->peer_nss = max_nss;
}
DNPRINTF(QWZ_D_MAC, "%s: ht peer %s mcs cnt %d nss %d\n", __func__,
ether_sprintf(arg->peer_mac), arg->peer_ht_rates.num_rates,
arg->peer_nss);
}
void
qwz_peer_assoc_h_qos(struct ieee80211_node *ni, struct peer_assoc_params *arg)
{
if (ni->ni_flags & IEEE80211_NODE_QOS) {
arg->is_wme_set = 1;
arg->qos_flag = 1;
}
}
void
qwz_peer_assoc_prepare(struct qwz_softc *sc, struct qwz_vif *arvif,
struct ieee80211_node *ni, struct peer_assoc_params *arg, int reassoc)
@@ -24015,12 +24164,12 @@ qwz_peer_assoc_prepare(struct qwz_softc *sc, struct qwz_vif *arvif,
qwz_peer_assoc_h_crypto(sc, arvif, ni, arg);
qwz_peer_assoc_h_rates(ni, arg);
qwz_peer_assoc_h_phymode(sc, ni, arg);
qwz_peer_assoc_h_ht(sc, ni, arg);
qwz_peer_assoc_h_qos(ni, arg);
#if 0
qwz_peer_assoc_h_ht(sc, arvif, ni, arg);
qwz_peer_assoc_h_vht(sc, arvif, ni, arg);
qwz_peer_assoc_h_he(sc, arvif, ni, arg);
qwz_peer_assoc_h_he_6ghz(sc, arvif, ni, arg);
qwz_peer_assoc_h_qos(sc, arvif, ni, arg);
qwz_peer_assoc_h_smps(ni, arg);
#endif
#if 0
+8 -1
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: qwzreg.h,v 1.14 2026/05/14 16:17:21 mglocker Exp $ */
/* $OpenBSD: qwzreg.h,v 1.15 2026/05/18 13:47:32 kirill Exp $ */
/*
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
@@ -13251,6 +13251,13 @@ struct htt_rx_full_monitor_mode_cfg_cmd {
uint32_t cfg;
} __packed;
#define WMI_HOST_RC_DS_FLAG 0x01
#define WMI_HOST_RC_SGI_FLAG 0x04
#define WMI_HOST_RC_HT_FLAG 0x08
#define WMI_HOST_RC_TX_STBC_FLAG 0x20
#define WMI_HOST_RC_RX_STBC_FLAG_S 6
#define WMI_HOST_RC_TS_FLAG 0x200
/* HTT message target->host */
enum htt_t2h_msg_type {
+12 -3
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: if_qwz_pci.c,v 1.10 2026/05/15 19:02:12 mglocker Exp $ */
/* $OpenBSD: if_qwz_pci.c,v 1.11 2026/05/18 13:47:32 kirill Exp $ */
/*
* Copyright 2023 Stefan Sperling <stsp@openbsd.org>
@@ -953,9 +953,7 @@ qwz_pci_attach(struct device *parent, struct device *self, void *aux)
/* Set device capabilities. */
ic->ic_caps =
#if 0
IEEE80211_C_QOS | IEEE80211_C_TX_AMPDU | /* A-MPDU */
#endif
IEEE80211_C_ADDBA_OFFLOAD | /* device sends ADDBA/DELBA frames */
IEEE80211_C_WEP | /* WEP */
IEEE80211_C_RSN | /* WPA/RSN */
@@ -971,6 +969,17 @@ qwz_pci_attach(struct device *parent, struct device *self, void *aux)
ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_AMSDU7935;
ic->ic_htcaps |=
(IEEE80211_HTCAP_SMPS_DIS << IEEE80211_HTCAP_SMPS_SHIFT);
ic->ic_htxcaps = 0;
ic->ic_txbfcaps = 0;
ic->ic_aselcaps = 0;
ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_NONE | 0x3 /* 64k */);
memset(ic->ic_sup_mcs, 0, sizeof(ic->ic_sup_mcs));
ic->ic_sup_mcs[0] = 0xff; /* MCS 0-7 */
/* IBSS channel undefined for now. */
ic->ic_ibss_chan = &ic->ic_channels[1];