From patchwork Tue Dec 17 16:04:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Crispin X-Patchwork-Id: 11298047 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 40D68139A for ; Tue, 17 Dec 2019 16:05:14 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 1EA4721835 for ; Tue, 17 Dec 2019 16:05:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="NI6CtQE2" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1EA4721835 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=phrozen.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=ath11k-bounces+patchwork-ath11k=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:To :From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=O0HjZ5ykbgIdV7Ijh7dBujo025oyeFIGSGMinAZe4Go=; b=NI6CtQE2Kolxqo R6cHy8KzS7bFuiGmPj1Zfbo+X7gMIjJK6wWPpRq6KLD7ceHVx1/2t3g7P9/e4OduKOXxjBYKaBkFq BydCbsXx+up5KRpQSnUgG2yfUPxU1C0PgfIsJuNUcXCZu32q627cPKi6IgvsB/0qFT7h2Xg4qUJAe TL5Ocq82LO/mpm5vjX5QKKwccXRbi1v06bGnMufrNEKiI4yMg3KNvErxDJlrnS2N10WUQra8lYdPo K66d9UVtw1WYnBh6ObkPpnorMz/3+fk8GrQN896t+aE9RzKjE8rM06S4Zv76EFymtAbQqf4IMluIu +l846xctP5WswMp5WmNQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ihFLU-0004Kg-Ps; Tue, 17 Dec 2019 16:05:12 +0000 Received: from nbd.name ([2a01:4f8:221:3d45::2]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ihFLR-0003x8-Cl for ath11k@lists.infradead.org; Tue, 17 Dec 2019 16:05:11 +0000 Received: from pd95fd66b.dip0.t-ipconnect.de ([217.95.214.107] helo=bertha.fritz.box) by ds12 with esmtpa (Exim 4.89) (envelope-from ) id 1ihFLL-0002Ku-NX; Tue, 17 Dec 2019 17:05:03 +0100 From: John Crispin To: Johannes Berg , Kalle Valo Subject: [PATCH 1/3] nl80211: add support for setting fixed HE rate/gi/ltf Date: Tue, 17 Dec 2019 17:04:53 +0100 Message-Id: <20191217160455.311-1-john@phrozen.org> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20191217_080509_602244_855F8E4A X-CRM114-Status: GOOD ( 15.42 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-BeenThere: ath11k@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Miles Hu , linux-wireless@vger.kernel.org, ath11k@lists.infradead.org, John Crispin Sender: "ath11k" Errors-To: ath11k-bounces+patchwork-ath11k=patchwork.kernel.org@lists.infradead.org From: Miles Hu This patch adds the nl80211 structs, definitions, policies and parsing code required to pass fixed HE rate, gi and ltf settings. Signed-off-by: John Crispin Signed-off-by: Miles Hu --- include/net/cfg80211.h | 4 ++ include/uapi/linux/nl80211.h | 28 +++++++++ net/wireless/nl80211.c | 111 ++++++++++++++++++++++++++++++++++- 3 files changed, 141 insertions(+), 2 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index fed307d9a4fe..cf2350dd7a79 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -386,6 +386,7 @@ struct ieee80211_supported_band { int n_bitrates; struct ieee80211_sta_ht_cap ht_cap; struct ieee80211_sta_vht_cap vht_cap; + struct ieee80211_sta_he_cap he_cap; u16 n_iftype_data; const struct ieee80211_sband_iftype_data *iftype_data; }; @@ -888,7 +889,10 @@ struct cfg80211_bitrate_mask { u32 legacy; u8 ht_mcs[IEEE80211_HT_MCS_MASK_LEN]; u16 vht_mcs[NL80211_VHT_NSS_MAX]; + u16 he_mcs[NL80211_HE_NSS_MAX]; enum nl80211_txrate_gi gi; + enum nl80211_he_gi he_gi; + enum nl80211_he_ltf he_ltf; } control[NUM_NL80211_BANDS]; }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index fd5028459c3a..4c7c5c881f24 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3013,6 +3013,18 @@ enum nl80211_he_gi { NL80211_RATE_INFO_HE_GI_3_2, }; +/** + * enum nl80211_he_ltf - HE long training field + * @NL80211_RATE_INFO_HE_1xLTF: 3.2 usec + * @NL80211_RATE_INFO_HE_2xLTF: 6.4 usec + * @NL80211_RATE_INFO_HE_4xLTF: 12.8 usec + */ +enum nl80211_he_ltf { + NL80211_RATE_INFO_HE_1XLTF, + NL80211_RATE_INFO_HE_2XLTF, + NL80211_RATE_INFO_HE_4XLTF, +}; + /** * enum nl80211_he_ru_alloc - HE RU allocation values * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation @@ -4510,6 +4522,10 @@ enum nl80211_key_attributes { * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection, * see &struct nl80211_txrate_vht * @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi + * @NL80211_TXRATE_HE: HE rates allowed for TX rate selection, + * see &struct nl80211_txrate_he + * @NL80211_TXRATE_HE_GI: configure HE GI, 0.8us, 1.6us and 3.2us. + * @NL80211_TXRATE_HE_LTF: configure HE LTF, 1XLTF, 2XLTF and 4XLTF. * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ @@ -4519,6 +4535,9 @@ enum nl80211_tx_rate_attributes { NL80211_TXRATE_HT, NL80211_TXRATE_VHT, NL80211_TXRATE_GI, + NL80211_TXRATE_HE, + NL80211_TXRATE_HE_GI, + NL80211_TXRATE_HE_LTF, /* keep last */ __NL80211_TXRATE_AFTER_LAST, @@ -4536,6 +4555,15 @@ struct nl80211_txrate_vht { __u16 mcs[NL80211_VHT_NSS_MAX]; }; +#define NL80211_HE_NSS_MAX 8 +/** + * struct nl80211_txrate_he - HE MCS/NSS txrate bitmap + * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.) + */ +struct nl80211_txrate_he { + __u16 mcs[NL80211_HE_NSS_MAX]; +}; + enum nl80211_txrate_gi { NL80211_TXRATE_DEFAULT_GI, NL80211_TXRATE_FORCE_SGI, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 65e33db93633..de4e33869061 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4161,6 +4161,80 @@ static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband, return true; } +static u16 he_mcs_map_to_mcs_mask(u8 he_mcs_map) +{ + switch (he_mcs_map) { + case IEEE80211_HE_MCS_NOT_SUPPORTED: + return 0; + case IEEE80211_HE_MCS_SUPPORT_0_7: + return 0x00FF; + case IEEE80211_HE_MCS_SUPPORT_0_9: + return 0x03FF; + case IEEE80211_HE_MCS_SUPPORT_0_11: + return 0xFFF; + default: + break; + } + return 0; +} + +static void he_build_mcs_mask(u16 he_mcs_map, + u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +{ + u8 nss; + + for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) { + he_mcs_mask[nss] = he_mcs_map_to_mcs_mask(he_mcs_map & 0x03); + he_mcs_map >>= 2; + } +} + +static u16 he_get_txmcsmap(struct genl_info *info, + const struct ieee80211_sta_he_cap *he_cap) +{ + struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + switch (wdev->chandef.width) { + case NL80211_CHAN_WIDTH_80P80: + return he_cap->he_mcs_nss_supp.tx_mcs_80p80; + case NL80211_CHAN_WIDTH_160: + return he_cap->he_mcs_nss_supp.tx_mcs_160; + default: + break; + } + return he_cap->he_mcs_nss_supp.tx_mcs_80; +} + +static bool he_set_mcs_mask(struct genl_info *info, + struct ieee80211_supported_band *sband, + struct nl80211_txrate_he *txrate, + u16 mcs[NL80211_HE_NSS_MAX]) +{ + u16 tx_mcs_map = 0; + u16 tx_mcs_mask[NL80211_HE_NSS_MAX] = {}; + u8 i; + + if (!sband->iftype_data->he_cap.has_he) + return false; + + memset(mcs, 0, sizeof(u16) * NL80211_HE_NSS_MAX); + + tx_mcs_map = le16_to_cpu(he_get_txmcsmap(info, &sband->iftype_data->he_cap)); + + /* Build he_mcs_mask from HE capabilities */ + he_build_mcs_mask(tx_mcs_map, tx_mcs_mask); + + for (i = 0; i < NL80211_HE_NSS_MAX; i++) { + if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i]) + mcs[i] = txrate->mcs[i]; + else + return false; + } + + return true; +} + static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_RATES }, @@ -4170,6 +4244,10 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = { .type = NLA_EXACT_LEN_WARN, .len = sizeof(struct nl80211_txrate_vht), }, + [NL80211_TXRATE_HE] = { + .type = NLA_EXACT_LEN_WARN, + .len = sizeof(struct nl80211_txrate_he), + }, [NL80211_TXRATE_GI] = { .type = NLA_U8 }, }; @@ -4181,7 +4259,7 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, int rem, i; struct nlattr *tx_rates; struct ieee80211_supported_band *sband; - u16 vht_tx_mcs_map; + u16 vht_tx_mcs_map, he_tx_mcs_map; memset(mask, 0, sizeof(*mask)); /* Default to all rates enabled */ @@ -4201,6 +4279,13 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs); + + he_tx_mcs_map = he_get_txmcsmap(info, &sband->iftype_data->he_cap); + he_tx_mcs_map = le16_to_cpu(he_tx_mcs_map); + he_build_mcs_mask(he_tx_mcs_map, mask->control[i].he_mcs); + + mask->control[i].he_gi = 0xFF; + mask->control[i].he_ltf = 0xFF; } /* if no rates are given set it back to the defaults */ @@ -4256,13 +4341,31 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI) return -EINVAL; } + if (tb[NL80211_TXRATE_HE]) { + if (!he_set_mcs_mask(info, sband, nla_data(tb[NL80211_TXRATE_HE]), + mask->control[band].he_mcs)) + return -EINVAL; + } + if (tb[NL80211_TXRATE_HE_GI]) { + mask->control[band].he_gi = + nla_get_u8(tb[NL80211_TXRATE_HE_GI]); + if (mask->control[band].he_gi > NL80211_RATE_INFO_HE_GI_3_2) + return -EINVAL; + } + if (tb[NL80211_TXRATE_HE_LTF]) { + mask->control[band].he_ltf = + nla_get_u8(tb[NL80211_TXRATE_HE_LTF]); + if (mask->control[band].he_ltf > NL80211_RATE_INFO_HE_4XLTF) + return -EINVAL; + } if (mask->control[band].legacy == 0) { /* don't allow empty legacy rates if HT or VHT * are not even supported. */ if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported || - rdev->wiphy.bands[band]->vht_cap.vht_supported)) + rdev->wiphy.bands[band]->vht_cap.vht_supported || + rdev->wiphy.bands[band]->he_cap.has_he)) return -EINVAL; for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) @@ -4273,6 +4376,10 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info, if (mask->control[band].vht_mcs[i]) goto out; + for (i = 0; i < NL80211_HE_NSS_MAX; i++) + if (mask->control[band].he_mcs[i]) + goto out; + /* legacy and mcs rates may not be both empty */ return -EINVAL; } From patchwork Tue Dec 17 16:04:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Crispin X-Patchwork-Id: 11298045 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 33E1A6C1 for ; Tue, 17 Dec 2019 16:05:14 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 113BA206B7 for ; Tue, 17 Dec 2019 16:05:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="HUMr7dCG" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 113BA206B7 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=phrozen.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=ath11k-bounces+patchwork-ath11k=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=n4Gb/lIyklSLSuqgx8n9G5PXZz8ll29ladq0JmtarDU=; b=HUMr7dCGQz35/H cBXLVRiu0aigHR56hBctuyKqtcL2OvvVQkvZtGB32o6gMWqVcbn+LQFkJL65vTyQ1qv8xlQ0a4+F9 RwOpEUcrEuzlVnlw8l3MeTCjYvn78x+AV6HPpXl+hCNwwjr+K8MhwSd0PFaEypgiUuT9hzkztVt4R BjzqkXsj43B5iEqg4n3/INwAAD7IF1kIin2pgtG1Felj9FhkjLxfncawBshsYehtpVVwe9cAonZpN MqEtQvDpBVs/kpjpEhXJdEroEr9aGpzSdJJwI4603PJg/U5KNevqyoVLZCWkUTfKGNmaMjKt06p+D yqqXqx4DfukoA3orqg5A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ihFLU-0004KO-ID; Tue, 17 Dec 2019 16:05:12 +0000 Received: from nbd.name ([2a01:4f8:221:3d45::2]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ihFLR-0003wv-Cn for ath11k@lists.infradead.org; Tue, 17 Dec 2019 16:05:10 +0000 Received: from pd95fd66b.dip0.t-ipconnect.de ([217.95.214.107] helo=bertha.fritz.box) by ds12 with esmtpa (Exim 4.89) (envelope-from ) id 1ihFLM-0002Ku-9l; Tue, 17 Dec 2019 17:05:04 +0100 From: John Crispin To: Johannes Berg , Kalle Valo Subject: [PATCH 2/3] mac80211: add support for setting fixed HE rate/gi/ltf Date: Tue, 17 Dec 2019 17:04:54 +0100 Message-Id: <20191217160455.311-2-john@phrozen.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191217160455.311-1-john@phrozen.org> References: <20191217160455.311-1-john@phrozen.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20191217_080509_600249_FF1C6E96 X-CRM114-Status: GOOD ( 11.61 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-BeenThere: ath11k@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Miles Hu , linux-wireless@vger.kernel.org, ath11k@lists.infradead.org, John Crispin Sender: "ath11k" Errors-To: ath11k-bounces+patchwork-ath11k=patchwork.kernel.org@lists.infradead.org From: Miles Hu With nl80211 now able to receive fixed HE rate/gi/ltf settings we want to propagate these further down the stack into the mac80211 drivers. This patch copies the values into the sdata struct. Signed-off-by: John Crispin Signed-off-by: Miles Hu --- net/mac80211/cfg.c | 11 +++++++++++ net/mac80211/ieee80211_i.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e109b47c4219..463eef8aae3e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2905,9 +2905,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, memcpy(sdata->rc_rateidx_vht_mcs_mask[i], mask->control[i].vht_mcs, sizeof(mask->control[i].vht_mcs)); + memcpy(sdata->rc_rateidx_he_mcs_mask[i], + mask->control[i].he_mcs, + sizeof(mask->control[i].he_mcs)); sdata->rc_has_mcs_mask[i] = false; sdata->rc_has_vht_mcs_mask[i] = false; + sdata->rc_has_he_mcs_mask[i] = false; if (!sband) continue; @@ -2924,6 +2928,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, break; } } + + for (j = 0; j < NL80211_HE_NSS_MAX; j++) { + if (~sdata->rc_rateidx_he_mcs_mask[i][j]) { + sdata->rc_has_he_mcs_mask[i] = true; + break; + } + } } return 0; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 791ce58d0f09..6cc6637cec96 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -963,6 +963,9 @@ struct ieee80211_sub_if_data { bool rc_has_vht_mcs_mask[NUM_NL80211_BANDS]; u16 rc_rateidx_vht_mcs_mask[NUM_NL80211_BANDS][NL80211_VHT_NSS_MAX]; + bool rc_has_he_mcs_mask[NUM_NL80211_BANDS]; + u16 rc_rateidx_he_mcs_mask[NUM_NL80211_BANDS][NL80211_HE_NSS_MAX]; + union { struct ieee80211_if_ap ap; struct ieee80211_if_wds wds; From patchwork Tue Dec 17 16:04:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Crispin X-Patchwork-Id: 11298049 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D15206C1 for ; Tue, 17 Dec 2019 16:05:15 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id ABEFD206B7 for ; Tue, 17 Dec 2019 16:05:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="NjFkiMn+" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org ABEFD206B7 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=phrozen.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=ath11k-bounces+patchwork-ath11k=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=saZ/q7VzXo180s9xb3hK8nE6pQxW9HbnVoW/4kXZ+JY=; b=NjFkiMn+cIG9o3 7rmkz0rO7Wh7cXUHKuSdg35W9loHNrOzyZ6g00wP6uVu9rjDcf+DDPgogqpNCuONXf5+Qx87/FvCA eeDmSQCzKXGyfYDRqVjch3u6ZxJnBvpKVk3WbCr6i5/LfBWmZnWnSVPQVytif1C667pstSMR3+XA2 /ON4jJeN0gqF7DjrkcGOJsNopBDc7eOGh7T6QVmrA5j9ZUMFs4FcdRyK73vm71Uwgfp8eDxSWOi5U IJjQJDN74kK4HPtgpha1Ye3pBDAtQp6sz7kVojNXlVvafp0dYL93T5GMwSyz/KkBYJoV2PRg4rjXg M7YiYD25+8+IFZwpixUg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1ihFLW-0004Lc-29; Tue, 17 Dec 2019 16:05:14 +0000 Received: from nbd.name ([2a01:4f8:221:3d45::2]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1ihFLR-000405-Co for ath11k@lists.infradead.org; Tue, 17 Dec 2019 16:05:13 +0000 Received: from pd95fd66b.dip0.t-ipconnect.de ([217.95.214.107] helo=bertha.fritz.box) by ds12 with esmtpa (Exim 4.89) (envelope-from ) id 1ihFLN-0002Ku-0o; Tue, 17 Dec 2019 17:05:05 +0100 From: John Crispin To: Johannes Berg , Kalle Valo Subject: [PATCH 3/3] ath11k: add support for setting fixed HE rate/gi/ltf Date: Tue, 17 Dec 2019 17:04:55 +0100 Message-Id: <20191217160455.311-3-john@phrozen.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191217160455.311-1-john@phrozen.org> References: <20191217160455.311-1-john@phrozen.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20191217_080509_791551_16304600 X-CRM114-Status: GOOD ( 21.62 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-BeenThere: ath11k@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Miles Hu , linux-wireless@vger.kernel.org, ath11k@lists.infradead.org, John Crispin Sender: "ath11k" Errors-To: ath11k-bounces+patchwork-ath11k=patchwork.kernel.org@lists.infradead.org From: Miles Hu This patch adds ath11k support for setting fixed HE rate/gi/ltf values that we are now able to send to the kernel using nl80211. The added code is reusing parts of the existing code path already used for HT/VHT. The new helpers are symmetric to how we do it for HT/VHT. Signed-off-by: John Crispin Signed-off-by: Miles Hu --- drivers/net/wireless/ath/ath11k/mac.c | 350 +++++++++++++++++++++++--- drivers/net/wireless/ath/ath11k/wmi.h | 1 + 2 files changed, 323 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 59eeaf1d37ec..d849d7feda02 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -252,6 +252,18 @@ ath11k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) return 1; } +static u32 +ath11k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +{ + int nss; + + for (nss = NL80211_HE_NSS_MAX - 1; nss >= 0; nss--) + if (he_mcs_mask[nss]) + return nss + 1; + + return 1; +} + static u8 ath11k_parse_mpdudensity(u8 mpdudensity) { /* 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": @@ -1138,17 +1150,98 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar, /* TODO: rxnss_override */ } +static int ath11k_mac_get_max_he_mcs_map(u16 mcs_map, int nss) +{ + switch ((mcs_map >> (2 * nss)) & 0x3) { + case IEEE80211_HE_MCS_SUPPORT_0_7: return BIT(8) - 1; + case IEEE80211_HE_MCS_SUPPORT_0_9: return BIT(10) - 1; + case IEEE80211_HE_MCS_SUPPORT_0_11: return BIT(12) - 1; + } + return 0; +} + +static u16 ath11k_peer_assoc_h_he_limit(u16 tx_mcs_set, + const u16 he_mcs_limit[NL80211_HE_NSS_MAX]) +{ + int idx_limit; + int nss; + u16 mcs_map; + u16 mcs; + + for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) { + mcs_map = ath11k_mac_get_max_he_mcs_map(tx_mcs_set, nss) & + he_mcs_limit[nss]; + + if (mcs_map) + idx_limit = fls(mcs_map) - 1; + else + idx_limit = -1; + + switch (idx_limit) { + case 0 ... 7: + mcs = IEEE80211_HE_MCS_SUPPORT_0_7; + break; + case 8: + case 9: + mcs = IEEE80211_HE_MCS_SUPPORT_0_9; + break; + case 10: + case 11: + mcs = IEEE80211_HE_MCS_SUPPORT_0_11; + break; + default: + WARN_ON(1); + /* fall through */ + case -1: + mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; + break; + } + + tx_mcs_set &= ~(0x3 << (nss * 2)); + tx_mcs_set |= mcs << (nss * 2); + } + + return tx_mcs_set; +} + +static bool +ath11k_peer_assoc_h_he_masked(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +{ + int nss; + + for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) + if (he_mcs_mask[nss]) + return false; + + return true; +} + static void ath11k_peer_assoc_h_he(struct ath11k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct peer_assoc_params *arg) { + struct ath11k_vif *arvif = (void *)vif->drv_priv; + struct cfg80211_chan_def def; const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap; - u16 v; + enum nl80211_band band; + const u16 *he_mcs_mask; + u8 max_nss, he_mcs; + __le16 he_tx_mcs = 0, v = 0; + int i; + + if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) + return; if (!he_cap->has_he) return; + band = def.chan->band; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; + + if (ath11k_peer_assoc_h_he_masked(he_mcs_mask)) + return; + arg->he_flag = true; memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info, @@ -1205,17 +1298,22 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80); + v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; arg->peer_he_mcs_count++; + he_tx_mcs = v; } v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); + v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; arg->peer_he_mcs_count++; + if (!he_tx_mcs) + he_tx_mcs = v; /* fall through */ default: @@ -1223,11 +1321,29 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); + v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; arg->peer_he_mcs_count++; + if (!he_tx_mcs) + he_tx_mcs = v; break; } + /* Calculate peer NSS capability from HE capabilities if STA + * supports HE. + */ + for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) { + he_mcs = __le16_to_cpu(he_tx_mcs) >> (2 * i) & 3; + + if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED && + he_mcs_mask[i]) + max_nss = i + 1; + } + arg->peer_nss = min(sta->rx_nss, max_nss); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac he peer %pM nss %d mcs cnt %d\n", + sta->addr, arg->peer_nss, arg->peer_he_mcs_count); } static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta, @@ -1430,6 +1546,7 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar, enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; + const u16 *he_mcs_mask; enum wmi_phy_mode phymode = MODE_UNKNOWN; if (WARN_ON(ath11k_mac_vif_chan(vif, &def))) @@ -1438,10 +1555,12 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar, band = def.chan->band; ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; switch (band) { case NL80211_BAND_2GHZ: - if (sta->he_cap.has_he) { + if (sta->he_cap.has_he && + !ath11k_peer_assoc_h_he_masked(he_mcs_mask)) { if (sta->bandwidth == IEEE80211_STA_RX_BW_80) phymode = MODE_11AX_HE80_2G; else if (sta->bandwidth == IEEE80211_STA_RX_BW_40) @@ -1468,7 +1587,8 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar, break; case NL80211_BAND_5GHZ: /* Check HE first */ - if (sta->he_cap.has_he) { + if (sta->he_cap.has_he && + !ath11k_peer_assoc_h_he_masked(he_mcs_mask)) { phymode = ath11k_mac_get_phymode_he(ar, sta); } else if (sta->vht_cap.vht_supported && !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) { @@ -2480,6 +2600,20 @@ ath11k_mac_bitrate_mask_num_vht_rates(struct ath11k *ar, return num_rates; } +static int +ath11k_mac_bitrate_mask_num_he_rates(struct ath11k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int num_rates = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) + num_rates += hweight16(mask->control[band].he_mcs[i]); + + return num_rates; +} + static int ath11k_mac_set_peer_vht_fixed_rate(struct ath11k_vif *arvif, struct ieee80211_sta *sta, @@ -2526,6 +2660,52 @@ ath11k_mac_set_peer_vht_fixed_rate(struct ath11k_vif *arvif, return ret; } +static int +ath11k_mac_set_peer_he_fixed_rate(struct ath11k_vif *arvif, + struct ieee80211_sta *sta, + const struct cfg80211_bitrate_mask *mask, + enum nl80211_band band) +{ + struct ath11k *ar = arvif->ar; + u8 he_rate, nss; + u32 rate_code; + int ret, i; + + lockdep_assert_held(&ar->conf_mutex); + + nss = 0; + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { + if (hweight16(mask->control[band].he_mcs[i]) == 1) { + nss = i + 1; + he_rate = ffs(mask->control[band].he_mcs[i]) - 1; + } + } + + if (!nss) { + ath11k_warn(ar->ab, "No single HE Fixed rate found to set for %pM", + sta->addr); + return -EINVAL; + } + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "Setting Fixed HE Rate for peer %pM. Device will not switch to any other selected rates", + sta->addr); + + rate_code = ATH11K_HW_RATE_CODE(he_rate, nss - 1, + WMI_RATE_PREAMBLE_HE); + ret = ath11k_wmi_set_peer_param(ar, sta->addr, + arvif->vdev_id, + WMI_PEER_PARAM_FIXED_RATE, + rate_code); + if (ret) + ath11k_warn(ar->ab, + "failed to update STA %pM Fixed Rate %d: %d\n", + sta->addr, rate_code, ret); + + return ret; +} + static int ath11k_station_assoc(struct ath11k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2644,8 +2824,9 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; + const u16 *he_mcs_mask; u32 changed, bw, nss, smps; - int err, num_vht_rates; + int err, num_vht_rates, num_he_rates; const struct cfg80211_bitrate_mask *mask; struct peer_assoc_params peer_arg; @@ -2660,6 +2841,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) band = def.chan->band; ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; spin_lock_bh(&ar->data_lock); @@ -2675,8 +2857,9 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) mutex_lock(&ar->conf_mutex); nss = max_t(u32, 1, nss); - nss = min(nss, max(ath11k_mac_max_ht_nss(ht_mcs_mask), - ath11k_mac_max_vht_nss(vht_mcs_mask))); + nss = min(nss, max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), + ath11k_mac_max_vht_nss(vht_mcs_mask)), + ath11k_mac_max_he_nss(he_mcs_mask))); if (changed & IEEE80211_RC_BW_CHANGED) { err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, @@ -2712,6 +2895,8 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) mask = &arvif->bitrate_mask; num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask); + num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, + mask); /* Peer_assoc_prepare will reject vht rates in * bitrate_mask if its not available in range format and @@ -2727,6 +2912,9 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) if (sta->vht_cap.vht_supported && num_vht_rates == 1) { ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, band); + } else if (sta->he_cap.has_he && num_he_rates == 1) { + ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, + band); } else { /* If the peer is non-VHT or no fixed VHT rate * is provided in the new bitrate mask we set the @@ -4087,6 +4275,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, sizeof(arvif->bitrate_mask.control[i].ht_mcs)); memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, sizeof(arvif->bitrate_mask.control[i].vht_mcs)); + memset(arvif->bitrate_mask.control[i].he_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].he_mcs)); } bit = __ffs64(ab->free_vdev_map); @@ -5015,9 +5205,25 @@ ath11k_mac_has_single_legacy_rate(struct ath11k *ar, if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask)) return false; + if (ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask)) + return false; + return num_rates == 1; } +u16 ath11k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap) +{ + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) + return he_cap->he_mcs_nss_supp.tx_mcs_80p80; + + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) + return he_cap->he_mcs_nss_supp.tx_mcs_160; + + return he_cap->he_mcs_nss_supp.tx_mcs_80; +} + static bool ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar, enum nl80211_band band, @@ -5026,8 +5232,10 @@ ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar, { struct ieee80211_supported_band *sband = &ar->mac.sbands[band]; u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); + u16 he_mcs_map = 0; u8 ht_nss_mask = 0; u8 vht_nss_mask = 0; + u8 he_nss_mask = 0; int i; /* No need to consider legacy here. Basic rates are always present @@ -5054,7 +5262,19 @@ ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar, return false; } - if (ht_nss_mask != vht_nss_mask) + he_mcs_map = le16_to_cpu(ath11k_mac_get_tx_mcs_map(&sband->iftype_data->he_cap)); + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { + if (mask->control[band].he_mcs[i] == 0) + continue; + else if (mask->control[band].he_mcs[i] == + ath11k_mac_get_max_he_mcs_map(he_mcs_map, i)) + he_nss_mask |= BIT(i); + else + return false; + } + + if (ht_nss_mask != vht_nss_mask || ht_nss_mask != he_nss_mask) return false; if (ht_nss_mask == 0) @@ -5102,7 +5322,8 @@ ath11k_mac_get_single_legacy_rate(struct ath11k *ar, } static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif, - u32 rate, u8 nss, u8 sgi, u8 ldpc) + u32 rate, u8 nss, u8 sgi, u8 ldpc, + u8 he_gi, u8 he_ltf) { struct ath11k *ar = arvif->ar; u32 vdev_param; @@ -5113,15 +5334,16 @@ static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif, ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n", arvif->vdev_id, rate, nss, sgi); - vdev_param = WMI_VDEV_PARAM_FIXED_RATE; - ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, rate); - if (ret) { - ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", - rate, ret); - return ret; + if (!arvif->vif->bss_conf.he_support) { + vdev_param = WMI_VDEV_PARAM_FIXED_RATE; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + vdev_param, rate); + if (ret) { + ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", + rate, ret); + return ret; + } } - vdev_param = WMI_VDEV_PARAM_NSS; ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, nss); @@ -5131,15 +5353,6 @@ static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif, return ret; } - vdev_param = WMI_VDEV_PARAM_SGI; - ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, sgi); - if (ret) { - ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n", - sgi, ret); - return ret; - } - vdev_param = WMI_VDEV_PARAM_LDPC; ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, ldpc); @@ -5149,6 +5362,43 @@ static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif, return ret; } + if (arvif->vif->bss_conf.he_support) { + if (he_gi != 0xFF) { + vdev_param = WMI_VDEV_PARAM_SGI; + /* 0.8 = 0, 1.6 = 2 and 3.2 = 3. */ + if (he_gi) + he_gi += 1; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + vdev_param, he_gi); + if (ret) { + ath11k_warn(ar->ab, "failed to set hegi param %d: %d\n", + sgi, ret); + return ret; + } + } + if (he_ltf != 0xFF) { + vdev_param = WMI_VDEV_PARAM_HE_LTF; + /* start from 1 */ + he_ltf += 1; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + vdev_param, he_ltf); + if (ret) { + ath11k_warn(ar->ab, "failed to set heltf param %d: %d\n", + he_ltf, ret); + return ret; + } + } + } else { + vdev_param = WMI_VDEV_PARAM_SGI; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + vdev_param, sgi); + if (ret) { + ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n", + sgi, ret); + return ret; + } + } + return 0; } @@ -5177,6 +5427,31 @@ ath11k_mac_vht_mcs_range_present(struct ath11k *ar, return true; } +static bool +ath11k_mac_he_mcs_range_present(struct ath11k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int i; + u16 he_mcs; + + for (i = 0; i < NL80211_HE_NSS_MAX; i++) { + he_mcs = mask->control[band].he_mcs[i]; + + switch (he_mcs) { + case 0: + case BIT(8) - 1: + case BIT(10) - 1: + case BIT(12) - 1: + break; + default: + return false; + } + } + + return true; +} + static void ath11k_mac_set_bitrate_mask_iter(void *data, struct ieee80211_sta *sta) { @@ -5219,6 +5494,9 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; + const u16 *he_mcs_mask; + u8 he_ltf = 0; + u8 he_gi = 0; u32 rate; u8 nss; u8 sgi; @@ -5233,12 +5511,16 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, band = def.chan->band; ht_mcs_mask = mask->control[band].ht_mcs; vht_mcs_mask = mask->control[band].vht_mcs; + he_mcs_mask = mask->control[band].he_mcs; ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); sgi = mask->control[band].gi; if (sgi == NL80211_TXRATE_FORCE_LGI) return -EINVAL; + he_gi = mask->control[band].he_gi; + he_ltf = mask->control[band].he_ltf; + /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it * requires passing atleast one of used basic rates along with them. * Fixed rate setting across different preambles(legacy, HT, VHT) is @@ -5265,8 +5547,9 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, } else { rate = WMI_FIXED_RATE_NONE; nss = min_t(u32, ar->num_tx_chains, - max(ath11k_mac_max_ht_nss(ht_mcs_mask), - ath11k_mac_max_vht_nss(vht_mcs_mask))); + max(max(ath11k_mac_max_ht_nss(ht_mcs_mask), + ath11k_mac_max_vht_nss(vht_mcs_mask)), + ath11k_mac_max_he_nss(he_mcs_mask))); /* If multiple rates across different preambles are given * we can reconfigure this info with all peers using PEER_ASSOC @@ -5301,6 +5584,16 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, return -EINVAL; } + num_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, + mask); + + if (!ath11k_mac_he_mcs_range_present(ar, band, mask) && + num_rates > 1) { + ath11k_warn(ar->ab, + "Setting more than one HE MCS Value in bitrate mask not supported\n"); + return -EINVAL; + } + ieee80211_iterate_stations_atomic(ar->hw, ath11k_mac_disable_peer_fixed_rate, arvif); @@ -5317,7 +5610,8 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); - ret = ath11k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); + ret = ath11k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc, + he_gi, he_ltf); if (ret) { ath11k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n", arvif->vdev_id, ret); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index cd5b7a33a73f..ac48f3f3425c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1012,6 +1012,7 @@ enum wmi_tlv_vdev_param { WMI_VDEV_PARAM_HE_RANGE_EXT, WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, + WMI_VDEV_PARAM_HE_LTF = 0x74, WMI_VDEV_PARAM_BA_MODE = 0x7e, WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87, WMI_VDEV_PARAM_PROTOTYPE = 0x8000,