Skip to content

Commit 514c306

Browse files
committed
iwlwifi: add support for IEEE802.11ax
Add support for the HE in the iwlwifi driver conforming with P802.11ax_D2.0. Signed-off-by: Luca Coelho <[email protected]>
1 parent 8a6171a commit 514c306

File tree

12 files changed

+525
-23
lines changed

12 files changed

+525
-23
lines changed

drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,101 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
463463
vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
464464
}
465465

466+
static struct ieee80211_sband_iftype_data iwl_he_capa = {
467+
.types_mask = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP),
468+
.he_cap = {
469+
.has_he = true,
470+
.he_cap_elem = {
471+
.mac_cap_info[0] =
472+
IEEE80211_HE_MAC_CAP0_HTC_HE,
473+
.mac_cap_info[1] =
474+
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
475+
IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_QOS_8,
476+
.mac_cap_info[2] =
477+
IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP |
478+
IEEE80211_HE_MAC_CAP2_ACK_EN,
479+
.mac_cap_info[3] =
480+
IEEE80211_HE_MAC_CAP3_GRP_ADDR_MULTI_STA_BA_DL_MU |
481+
IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_VHT_2,
482+
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU,
483+
.phy_cap_info[0] =
484+
IEEE80211_HE_PHY_CAP0_DUAL_BAND |
485+
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
486+
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
487+
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G,
488+
.phy_cap_info[1] =
489+
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
490+
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
491+
IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS,
492+
.phy_cap_info[2] =
493+
IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
494+
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
495+
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ,
496+
.phy_cap_info[3] =
497+
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK |
498+
IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 |
499+
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK |
500+
IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1,
501+
.phy_cap_info[4] =
502+
IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
503+
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 |
504+
IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8,
505+
.phy_cap_info[5] =
506+
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 |
507+
IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2,
508+
.phy_cap_info[6] =
509+
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
510+
.phy_cap_info[7] =
511+
IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR |
512+
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
513+
IEEE80211_HE_PHY_CAP7_MAX_NC_7,
514+
.phy_cap_info[8] =
515+
IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
516+
IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
517+
IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
518+
IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU,
519+
},
520+
/*
521+
* Set default Tx/Rx HE MCS NSS Support field. Indicate support
522+
* for up to 2 spatial streams and all MCS, without any special
523+
* cases
524+
*/
525+
.he_mcs_nss_supp = {
526+
.rx_mcs_80 = cpu_to_le16(0xfffa),
527+
.tx_mcs_80 = cpu_to_le16(0xfffa),
528+
.rx_mcs_160 = cpu_to_le16(0xfffa),
529+
.tx_mcs_160 = cpu_to_le16(0xfffa),
530+
.rx_mcs_80p80 = cpu_to_le16(0xffff),
531+
.tx_mcs_80p80 = cpu_to_le16(0xffff),
532+
},
533+
/*
534+
* Set default PPE thresholds, with PPET16 set to 0, PPET8 set
535+
* to 7
536+
*/
537+
.ppe_thres = {0x61, 0x1c, 0xc7, 0x71},
538+
},
539+
};
540+
541+
static void iwl_init_he_hw_capab(struct ieee80211_supported_band *sband,
542+
u8 tx_chains, u8 rx_chains)
543+
{
544+
if (sband->band == NL80211_BAND_2GHZ ||
545+
sband->band == NL80211_BAND_5GHZ)
546+
sband->iftype_data = &iwl_he_capa;
547+
else
548+
return;
549+
550+
sband->n_iftype_data = 1;
551+
552+
/* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */
553+
if ((tx_chains & rx_chains) != ANT_AB) {
554+
iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[1] &=
555+
~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_MAX_NSTS;
556+
iwl_he_capa.he_cap.he_cap_elem.phy_cap_info[2] &=
557+
~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_MAX_NSTS;
558+
}
559+
}
560+
466561
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
467562
struct iwl_nvm_data *data,
468563
const __le16 *nvm_ch_flags, u8 tx_chains,
@@ -483,6 +578,9 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
483578
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, NL80211_BAND_2GHZ,
484579
tx_chains, rx_chains);
485580

581+
if (data->sku_cap_11ax_enable)
582+
iwl_init_he_hw_capab(sband, tx_chains, rx_chains);
583+
486584
sband = &data->bands[NL80211_BAND_5GHZ];
487585
sband->band = NL80211_BAND_5GHZ;
488586
sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
@@ -495,6 +593,9 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
495593
iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
496594
tx_chains, rx_chains);
497595

596+
if (data->sku_cap_11ax_enable)
597+
iwl_init_he_hw_capab(sband, tx_chains, rx_chains);
598+
498599
if (n_channels != n_used)
499600
IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
500601
n_used, n_channels);
@@ -1293,6 +1394,8 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
12931394
!!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AC_ENABLED);
12941395
nvm->sku_cap_11n_enable =
12951396
!!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED);
1397+
nvm->sku_cap_11ax_enable =
1398+
!!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AX_ENABLED);
12961399
nvm->sku_cap_band_24ghz_enable =
12971400
!!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED);
12981401
nvm->sku_cap_band_52ghz_enable =

drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,9 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
780780
if (vif->probe_req_reg && vif->bss_conf.assoc && vif->p2p)
781781
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
782782

783+
if (vif->bss_conf.assoc && vif->bss_conf.he_support)
784+
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX);
785+
783786
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
784787
}
785788

drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c

Lines changed: 195 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
3737
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
3838
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
39+
* Copyright(c) 2018 Intel Corporation
3940
* All rights reserved.
4041
*
4142
* Redistribution and use in source and binary forms, with or without
@@ -914,7 +915,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
914915
enum ieee80211_ampdu_mlme_action action = params->action;
915916
u16 tid = params->tid;
916917
u16 *ssn = &params->ssn;
917-
u8 buf_size = params->buf_size;
918+
u16 buf_size = params->buf_size;
918919
bool amsdu = params->amsdu;
919920
u16 timeout = params->timeout;
920921

@@ -1897,6 +1898,194 @@ void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm,
18971898
iwl_mvm_mu_mimo_iface_iterator, notif);
18981899
}
18991900

1901+
static u8 iwl_mvm_he_get_ppe_val(u8 *ppe, u8 ppe_pos_bit)
1902+
{
1903+
u8 byte_num = ppe_pos_bit / 8;
1904+
u8 bit_num = ppe_pos_bit % 8;
1905+
u8 residue_bits;
1906+
u8 res;
1907+
1908+
if (bit_num <= 5)
1909+
return (ppe[byte_num] >> bit_num) &
1910+
(BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE) - 1);
1911+
1912+
/*
1913+
* If bit_num > 5, we have to combine bits with next byte.
1914+
* Calculate how many bits we need to take from current byte (called
1915+
* here "residue_bits"), and add them to bits from next byte.
1916+
*/
1917+
1918+
residue_bits = 8 - bit_num;
1919+
1920+
res = (ppe[byte_num + 1] &
1921+
(BIT(IEEE80211_PPE_THRES_INFO_PPET_SIZE - residue_bits) - 1)) <<
1922+
residue_bits;
1923+
res += (ppe[byte_num] >> bit_num) & (BIT(residue_bits) - 1);
1924+
1925+
return res;
1926+
}
1927+
1928+
static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
1929+
struct ieee80211_vif *vif, u8 sta_id)
1930+
{
1931+
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1932+
struct iwl_he_sta_context_cmd sta_ctxt_cmd = {
1933+
.sta_id = sta_id,
1934+
.tid_limit = IWL_MAX_TID_COUNT,
1935+
.bss_color = vif->bss_conf.bss_color,
1936+
.htc_trig_based_pkt_ext = vif->bss_conf.htc_trig_based_pkt_ext,
1937+
.frame_time_rts_th =
1938+
cpu_to_le16(vif->bss_conf.frame_time_rts_th),
1939+
};
1940+
struct ieee80211_sta *sta;
1941+
u32 flags;
1942+
int i;
1943+
1944+
rcu_read_lock();
1945+
1946+
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_ctxt_cmd.sta_id]);
1947+
if (IS_ERR(sta)) {
1948+
rcu_read_unlock();
1949+
WARN(1, "Can't find STA to configure HE\n");
1950+
return;
1951+
}
1952+
1953+
if (!sta->he_cap.has_he) {
1954+
rcu_read_unlock();
1955+
return;
1956+
}
1957+
1958+
flags = 0;
1959+
1960+
/* HTC flags */
1961+
if (sta->he_cap.he_cap_elem.mac_cap_info[0] &
1962+
IEEE80211_HE_MAC_CAP0_HTC_HE)
1963+
sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_SUPPORT);
1964+
if ((sta->he_cap.he_cap_elem.mac_cap_info[1] &
1965+
IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION) ||
1966+
(sta->he_cap.he_cap_elem.mac_cap_info[2] &
1967+
IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION)) {
1968+
u8 link_adap =
1969+
((sta->he_cap.he_cap_elem.mac_cap_info[2] &
1970+
IEEE80211_HE_MAC_CAP2_LINK_ADAPTATION) << 1) +
1971+
(sta->he_cap.he_cap_elem.mac_cap_info[1] &
1972+
IEEE80211_HE_MAC_CAP1_LINK_ADAPTATION);
1973+
1974+
if (link_adap == 2)
1975+
sta_ctxt_cmd.htc_flags |=
1976+
cpu_to_le32(IWL_HE_HTC_LINK_ADAP_UNSOLICITED);
1977+
else if (link_adap == 3)
1978+
sta_ctxt_cmd.htc_flags |=
1979+
cpu_to_le32(IWL_HE_HTC_LINK_ADAP_BOTH);
1980+
}
1981+
if (sta->he_cap.he_cap_elem.mac_cap_info[2] &
1982+
IEEE80211_HE_MAC_CAP2_UL_MU_RESP_SCHED)
1983+
sta_ctxt_cmd.htc_flags |=
1984+
cpu_to_le32(IWL_HE_HTC_UL_MU_RESP_SCHED);
1985+
if (sta->he_cap.he_cap_elem.mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
1986+
sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_BSR_SUPP);
1987+
if (sta->he_cap.he_cap_elem.mac_cap_info[3] &
1988+
IEEE80211_HE_MAC_CAP3_OMI_CONTROL)
1989+
sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_OMI_SUPP);
1990+
if (sta->he_cap.he_cap_elem.mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)
1991+
sta_ctxt_cmd.htc_flags |= cpu_to_le32(IWL_HE_HTC_BQR_SUPP);
1992+
1993+
/* If PPE Thresholds exist, parse them into a FW-familiar format */
1994+
if (sta->he_cap.he_cap_elem.phy_cap_info[6] &
1995+
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
1996+
u8 nss = (sta->he_cap.ppe_thres[0] &
1997+
IEEE80211_PPE_THRES_NSS_MASK) + 1;
1998+
u8 ru_index_bitmap =
1999+
(sta->he_cap.ppe_thres[0] &
2000+
IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK) >>
2001+
IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS;
2002+
u8 *ppe = &sta->he_cap.ppe_thres[0];
2003+
u8 ppe_pos_bit = 7; /* Starting after PPE header */
2004+
2005+
/*
2006+
* FW currently supports only nss == MAX_HE_SUPP_NSS
2007+
*
2008+
* If nss > MAX: we can ignore values we don't support
2009+
* If nss < MAX: we can set zeros in other streams
2010+
*/
2011+
if (nss > MAX_HE_SUPP_NSS) {
2012+
IWL_INFO(mvm, "Got NSS = %d - trimming to %d\n", nss,
2013+
MAX_HE_SUPP_NSS);
2014+
nss = MAX_HE_SUPP_NSS;
2015+
}
2016+
2017+
for (i = 0; i < nss; i++) {
2018+
u8 ru_index_tmp = ru_index_bitmap << 1;
2019+
u8 bw;
2020+
2021+
for (bw = 0; bw < MAX_HE_CHANNEL_BW_INDX; bw++) {
2022+
ru_index_tmp >>= 1;
2023+
if (!(ru_index_tmp & 1))
2024+
continue;
2025+
2026+
sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i][bw][1] =
2027+
iwl_mvm_he_get_ppe_val(ppe,
2028+
ppe_pos_bit);
2029+
ppe_pos_bit +=
2030+
IEEE80211_PPE_THRES_INFO_PPET_SIZE;
2031+
sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th[i][bw][0] =
2032+
iwl_mvm_he_get_ppe_val(ppe,
2033+
ppe_pos_bit);
2034+
ppe_pos_bit +=
2035+
IEEE80211_PPE_THRES_INFO_PPET_SIZE;
2036+
}
2037+
}
2038+
2039+
flags |= STA_CTXT_HE_PACKET_EXT;
2040+
}
2041+
rcu_read_unlock();
2042+
2043+
/* Mark MU EDCA as enabled, unless none detected on some AC */
2044+
flags |= STA_CTXT_HE_MU_EDCA_CW;
2045+
for (i = 0; i < AC_NUM; i++) {
2046+
struct ieee80211_he_mu_edca_param_ac_rec *mu_edca =
2047+
&mvmvif->queue_params[i].mu_edca_param_rec;
2048+
2049+
if (!mvmvif->queue_params[i].mu_edca) {
2050+
flags &= ~STA_CTXT_HE_MU_EDCA_CW;
2051+
break;
2052+
}
2053+
2054+
sta_ctxt_cmd.trig_based_txf[i].cwmin =
2055+
cpu_to_le16(mu_edca->ecw_min_max & 0xf);
2056+
sta_ctxt_cmd.trig_based_txf[i].cwmax =
2057+
cpu_to_le16((mu_edca->ecw_min_max & 0xf0) >> 4);
2058+
sta_ctxt_cmd.trig_based_txf[i].aifsn =
2059+
cpu_to_le16(mu_edca->aifsn);
2060+
sta_ctxt_cmd.trig_based_txf[i].mu_time =
2061+
cpu_to_le16(mu_edca->mu_edca_timer);
2062+
}
2063+
2064+
if (vif->bss_conf.multi_sta_back_32bit)
2065+
flags |= STA_CTXT_HE_32BIT_BA_BITMAP;
2066+
2067+
if (vif->bss_conf.ack_enabled)
2068+
flags |= STA_CTXT_HE_ACK_ENABLED;
2069+
2070+
if (vif->bss_conf.uora_exists) {
2071+
flags |= STA_CTXT_HE_TRIG_RND_ALLOC;
2072+
2073+
sta_ctxt_cmd.rand_alloc_ecwmin =
2074+
vif->bss_conf.uora_ocw_range & 0x7;
2075+
sta_ctxt_cmd.rand_alloc_ecwmax =
2076+
(vif->bss_conf.uora_ocw_range >> 3) & 0x7;
2077+
}
2078+
2079+
/* TODO: support Multi BSSID IE */
2080+
2081+
sta_ctxt_cmd.flags = cpu_to_le32(flags);
2082+
2083+
if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(STA_HE_CTXT_CMD,
2084+
DATA_PATH_GROUP, 0),
2085+
0, sizeof(sta_ctxt_cmd), &sta_ctxt_cmd))
2086+
IWL_ERR(mvm, "Failed to config FW to work HE!\n");
2087+
}
2088+
19002089
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
19012090
struct ieee80211_vif *vif,
19022091
struct ieee80211_bss_conf *bss_conf,
@@ -1910,8 +2099,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
19102099
* beacon interval, which was not known when the station interface was
19112100
* added.
19122101
*/
1913-
if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
2102+
if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) {
2103+
if (vif->bss_conf.he_support)
2104+
iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id);
2105+
19142106
iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
2107+
}
19152108

19162109
/*
19172110
* If we're not associated yet, take the (new) BSSID before associating

drivers/net/wireless/intel/iwlwifi/mvm/mvm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ struct iwl_mvm_tcm {
654654
struct iwl_mvm_reorder_buffer {
655655
u16 head_sn;
656656
u16 num_stored;
657-
u8 buf_size;
657+
u16 buf_size;
658658
int queue;
659659
u16 last_amsdu;
660660
u8 last_sub_index;

drivers/net/wireless/intel/iwlwifi/mvm/ops.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {
448448
HCMD_NAME(DQA_ENABLE_CMD),
449449
HCMD_NAME(UPDATE_MU_GROUPS_CMD),
450450
HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD),
451+
HCMD_NAME(STA_HE_CTXT_CMD),
451452
HCMD_NAME(STA_PM_NOTIF),
452453
HCMD_NAME(MU_GROUP_MGMT_NOTIF),
453454
HCMD_NAME(RX_QUEUES_NOTIFICATION),

0 commit comments

Comments
 (0)