From: Jeff Chen <jeff.chen_1@nxp.com>
To: linux-wireless@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, briannorris@chromium.org,
johannes@sipsolutions.net, francesco@dolcini.it,
s.hauer@pengutronix.de, Jeff Chen <jeff.chen_1@nxp.com>
Subject: [PATCH v9 02/21] wifi: nxpwifi: add initial support for 802.11ac
Date: Thu, 5 Feb 2026 02:03:39 +0800 [thread overview]
Message-ID: <20260204180358.632281-3-jeff.chen_1@nxp.com> (raw)
In-Reply-To: <20260204180358.632281-1-jeff.chen_1@nxp.com>
Introduce 802.11ac feature support for both client and AP modes,
with coordination between host driver and NXP firmware.
- In client mode, the firmware assists the association process via
HOST_CMD_802_11_ASSOCIATE. The driver converts 802.11ac IEs from
cfg80211 parameters into TLVs and appends them to the host command.
- In AP mode, the driver converts 802.11ac IEs into parameters for
HOST_CMD_11AC_CFG, which are then passed to the firmware for
configuration.
This patch adds logic to handle VHT capabilities, operations, and
operating mode notifications, enabling proper negotiation and setup
of 802.11ac features through firmware interaction.
Signed-off-by: Jeff Chen <jeff.chen_1@nxp.com>
---
drivers/net/wireless/nxp/nxpwifi/11ac.c | 280 ++++++++++++++++++++++++
drivers/net/wireless/nxp/nxpwifi/11ac.h | 33 +++
2 files changed, 313 insertions(+)
create mode 100644 drivers/net/wireless/nxp/nxpwifi/11ac.c
create mode 100644 drivers/net/wireless/nxp/nxpwifi/11ac.h
diff --git a/drivers/net/wireless/nxp/nxpwifi/11ac.c b/drivers/net/wireless/nxp/nxpwifi/11ac.c
new file mode 100644
index 000000000000..117d06c35401
--- /dev/null
+++ b/drivers/net/wireless/nxp/nxpwifi/11ac.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * nxpwifi 802.11ac helpers
+ * Copyright 2011-2024 NXP
+ */
+
+#include "cfg.h"
+#include "fw.h"
+#include "main.h"
+#include "11ac.h"
+
+/* Map VHT MCS/NSS to highest data rate (Mbps), long GI. */
+static const u16 max_rate_lgi_80MHZ[8][3] = {
+ {0x124, 0x15F, 0x186}, /* NSS = 1 */
+ {0x249, 0x2BE, 0x30C}, /* NSS = 2 */
+ {0x36D, 0x41D, 0x492}, /* NSS = 3 */
+ {0x492, 0x57C, 0x618}, /* NSS = 4 */
+ {0x5B6, 0x6DB, 0x79E}, /* NSS = 5 */
+ {0x6DB, 0x83A, 0x0}, /* NSS = 6 */
+ {0x7FF, 0x999, 0xAAA}, /* NSS = 7 */
+ {0x924, 0xAF8, 0xC30} /* NSS = 8 */
+};
+
+static const u16 max_rate_lgi_160MHZ[8][3] = {
+ {0x249, 0x2BE, 0x30C}, /* NSS = 1 */
+ {0x492, 0x57C, 0x618}, /* NSS = 2 */
+ {0x6DB, 0x83A, 0x0}, /* NSS = 3 */
+ {0x924, 0xAF8, 0xC30}, /* NSS = 4 */
+ {0xB6D, 0xDB6, 0xF3C}, /* NSS = 5 */
+ {0xDB6, 0x1074, 0x1248}, /* NSS = 6 */
+ {0xFFF, 0x1332, 0x1554}, /* NSS = 7 */
+ {0x1248, 0x15F0, 0x1860} /* NSS = 8 */
+};
+
+/* Convert 2-bit MCS map to highest long-GI VHT data rate. */
+static u16
+nxpwifi_convert_mcsmap_to_maxrate(struct nxpwifi_private *priv,
+ u16 bands, u16 mcs_map)
+{
+ u8 i, nss, mcs;
+ u16 max_rate = 0;
+ u32 usr_vht_cap_info = 0;
+ struct nxpwifi_adapter *adapter = priv->adapter;
+
+ if (bands & BAND_AAC)
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
+ else
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
+
+ /* Find max supported NSS. */
+ nss = 1;
+ for (i = 1; i <= 8; i++) {
+ mcs = GET_VHTNSSMCS(mcs_map, i);
+ if (mcs < IEEE80211_VHT_MCS_NOT_SUPPORTED)
+ nss = i;
+ }
+ mcs = GET_VHTNSSMCS(mcs_map, nss);
+
+ /* If not supported, fall back to 0-9. */
+ if (mcs == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+ mcs = IEEE80211_VHT_MCS_SUPPORT_0_9;
+
+ if (u32_get_bits(usr_vht_cap_info, IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
+ /* Support 160 MHz. */
+ max_rate = max_rate_lgi_160MHZ[nss - 1][mcs];
+ if (!max_rate)
+ /* MCS9 not supported in NSS6. */
+ max_rate = max_rate_lgi_160MHZ[nss - 1][mcs - 1];
+ } else {
+ max_rate = max_rate_lgi_80MHZ[nss - 1][mcs];
+ if (!max_rate)
+ /* MCS9 not supported in NSS3. */
+ max_rate = max_rate_lgi_80MHZ[nss - 1][mcs - 1];
+ }
+
+ return max_rate;
+}
+
+static void
+nxpwifi_fill_vht_cap_info(struct nxpwifi_private *priv,
+ struct ieee80211_vht_cap *vht_cap, u16 bands)
+{
+ struct nxpwifi_adapter *adapter = priv->adapter;
+
+ if (bands & BAND_A)
+ vht_cap->vht_cap_info =
+ cpu_to_le32(adapter->usr_dot_11ac_dev_cap_a);
+ else
+ vht_cap->vht_cap_info =
+ cpu_to_le32(adapter->usr_dot_11ac_dev_cap_bg);
+}
+
+void
+nxpwifi_fill_vht_cap_tlv(struct nxpwifi_private *priv,
+ struct ieee80211_vht_cap *vht_cap, u16 bands)
+{
+ struct nxpwifi_adapter *adapter = priv->adapter;
+ u16 mcs_map_user, mcs_map_resp, mcs_map_result;
+ u16 mcs_user, mcs_resp, nss, tmp;
+
+ /* Fill VHT capability info. */
+ nxpwifi_fill_vht_cap_info(priv, vht_cap, bands);
+
+ /* RX MCS set: min(user, AP). */
+ mcs_map_user = GET_DEVRXMCSMAP(adapter->usr_dot_11ac_mcs_support);
+ mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.rx_mcs_map);
+ mcs_map_result = 0;
+
+ for (nss = 1; nss <= 8; nss++) {
+ mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+ mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+
+ if (mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED ||
+ mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ IEEE80211_VHT_MCS_NOT_SUPPORTED);
+ else
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ min(mcs_user, mcs_resp));
+ }
+
+ vht_cap->supp_mcs.rx_mcs_map = cpu_to_le16(mcs_map_result);
+
+ tmp = nxpwifi_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
+ vht_cap->supp_mcs.rx_highest = cpu_to_le16(tmp);
+
+ /* TX MCS set: min(user, AP). */
+ mcs_map_user = GET_DEVTXMCSMAP(adapter->usr_dot_11ac_mcs_support);
+ mcs_map_resp = le16_to_cpu(vht_cap->supp_mcs.tx_mcs_map);
+ mcs_map_result = 0;
+
+ for (nss = 1; nss <= 8; nss++) {
+ mcs_user = GET_VHTNSSMCS(mcs_map_user, nss);
+ mcs_resp = GET_VHTNSSMCS(mcs_map_resp, nss);
+ if (mcs_user == IEEE80211_VHT_MCS_NOT_SUPPORTED ||
+ mcs_resp == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ IEEE80211_VHT_MCS_NOT_SUPPORTED);
+ else
+ SET_VHTNSSMCS(mcs_map_result, nss,
+ min(mcs_user, mcs_resp));
+ }
+
+ vht_cap->supp_mcs.tx_mcs_map = cpu_to_le16(mcs_map_result);
+
+ tmp = nxpwifi_convert_mcsmap_to_maxrate(priv, bands, mcs_map_result);
+ vht_cap->supp_mcs.tx_highest = cpu_to_le16(tmp);
+}
+
+int nxpwifi_cmd_append_11ac_tlv(struct nxpwifi_private *priv,
+ struct nxpwifi_bssdescriptor *bss_desc,
+ u8 **buffer)
+{
+ struct nxpwifi_ie_types_vhtcap *vht_cap;
+ struct nxpwifi_ie_types_oper_mode_ntf *oper_ntf;
+ struct ieee_types_oper_mode_ntf *ieee_oper_ntf;
+ struct nxpwifi_ie_types_vht_oper *vht_op;
+ struct nxpwifi_adapter *adapter = priv->adapter;
+ u8 supp_chwd_set;
+ u32 usr_vht_cap_info;
+ int ret_len = 0;
+
+ if (bss_desc->bss_band & BAND_A)
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_a;
+ else
+ usr_vht_cap_info = adapter->usr_dot_11ac_dev_cap_bg;
+
+ /* VHT Capabilities element. */
+ if (bss_desc->bcn_vht_cap) {
+ vht_cap = (struct nxpwifi_ie_types_vhtcap *)*buffer;
+ memset(vht_cap, 0, sizeof(*vht_cap));
+ vht_cap->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY);
+ vht_cap->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_vht_cap));
+ memcpy((u8 *)vht_cap + sizeof(struct nxpwifi_ie_types_header),
+ (u8 *)bss_desc->bcn_vht_cap,
+ le16_to_cpu(vht_cap->header.len));
+
+ nxpwifi_fill_vht_cap_tlv(priv, &vht_cap->vht_cap,
+ bss_desc->bss_band);
+ *buffer += sizeof(*vht_cap);
+ ret_len += sizeof(*vht_cap);
+ }
+
+ /* VHT Operation element. */
+ if (bss_desc->bcn_vht_oper) {
+ if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+ vht_op = (struct nxpwifi_ie_types_vht_oper *)*buffer;
+ memset(vht_op, 0, sizeof(*vht_op));
+ vht_op->header.type =
+ cpu_to_le16(WLAN_EID_VHT_OPERATION);
+ vht_op->header.len = cpu_to_le16(sizeof(*vht_op) -
+ sizeof(struct nxpwifi_ie_types_header));
+ memcpy((u8 *)vht_op +
+ sizeof(struct nxpwifi_ie_types_header),
+ (u8 *)bss_desc->bcn_vht_oper,
+ le16_to_cpu(vht_op->header.len));
+
+ /* Negotiate channel width; keep peer's center freq. */
+ supp_chwd_set = u32_get_bits(usr_vht_cap_info,
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK);
+
+ switch (supp_chwd_set) {
+ case 0:
+ vht_op->chan_width =
+ min_t(u8, IEEE80211_VHT_CHANWIDTH_80MHZ,
+ bss_desc->bcn_vht_oper->chan_width);
+ break;
+ case 1:
+ vht_op->chan_width =
+ min_t(u8, IEEE80211_VHT_CHANWIDTH_160MHZ,
+ bss_desc->bcn_vht_oper->chan_width);
+ break;
+ case 2:
+ vht_op->chan_width =
+ min_t(u8, IEEE80211_VHT_CHANWIDTH_80P80MHZ,
+ bss_desc->bcn_vht_oper->chan_width);
+ break;
+ default:
+ vht_op->chan_width =
+ IEEE80211_VHT_CHANWIDTH_USE_HT;
+ break;
+ }
+
+ *buffer += sizeof(*vht_op);
+ ret_len += sizeof(*vht_op);
+ }
+ }
+
+ /* Operating Mode Notification element. */
+ if (bss_desc->oper_mode) {
+ ieee_oper_ntf = bss_desc->oper_mode;
+ oper_ntf = (void *)*buffer;
+ memset(oper_ntf, 0, sizeof(*oper_ntf));
+ oper_ntf->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF);
+ oper_ntf->header.len = cpu_to_le16(sizeof(u8));
+ oper_ntf->oper_mode = ieee_oper_ntf->oper_mode;
+ *buffer += sizeof(*oper_ntf);
+ ret_len += sizeof(*oper_ntf);
+ }
+
+ return ret_len;
+}
+
+int nxpwifi_cmd_11ac_cfg(struct nxpwifi_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
+ struct nxpwifi_11ac_vht_cfg *cfg)
+{
+ struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg;
+
+ cmd->command = cpu_to_le16(HOST_CMD_11AC_CFG);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) +
+ S_DS_GEN);
+ vhtcfg->action = cpu_to_le16(cmd_action);
+ vhtcfg->band_config = cfg->band_config;
+ vhtcfg->misc_config = cfg->misc_config;
+ vhtcfg->cap_info = cpu_to_le32(cfg->cap_info);
+ vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set);
+ vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set);
+
+ return 0;
+}
+
+/* Initialize BlockAck parameters for 11ac. */
+void nxpwifi_set_11ac_ba_params(struct nxpwifi_private *priv)
+{
+ priv->add_ba_param.timeout = NXPWIFI_DEFAULT_BLOCK_ACK_TIMEOUT;
+
+ if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_UAP) {
+ priv->add_ba_param.tx_win_size =
+ NXPWIFI_11AC_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ NXPWIFI_11AC_UAP_AMPDU_DEF_RXWINSIZE;
+ } else {
+ priv->add_ba_param.tx_win_size =
+ NXPWIFI_11AC_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ NXPWIFI_11AC_STA_AMPDU_DEF_RXWINSIZE;
+ }
+}
diff --git a/drivers/net/wireless/nxp/nxpwifi/11ac.h b/drivers/net/wireless/nxp/nxpwifi/11ac.h
new file mode 100644
index 000000000000..edc01b35d5b8
--- /dev/null
+++ b/drivers/net/wireless/nxp/nxpwifi/11ac.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * nxpwifi: 802.11ac (VHT) definitions
+ *
+ * Copyright 2011-2024 NXP
+ */
+
+#ifndef _NXPWIFI_11AC_H_
+#define _NXPWIFI_11AC_H_
+
+#define VHT_CFG_2GHZ BIT(0)
+#define VHT_CFG_5GHZ BIT(1)
+
+enum vht_cfg_misc_config {
+ VHT_CAP_TX_OPERATION = 1,
+ VHT_CAP_ASSOCIATION,
+ VHT_CAP_UAP_ONLY
+};
+
+#define DEFAULT_VHT_MCS_SET 0xfffe
+#define DISABLE_VHT_MCS_SET 0xffff
+
+#define VHT_BW_80_160_80P80 BIT(2)
+
+int nxpwifi_cmd_append_11ac_tlv(struct nxpwifi_private *priv,
+ struct nxpwifi_bssdescriptor *bss_desc,
+ u8 **buffer);
+int nxpwifi_cmd_11ac_cfg(struct nxpwifi_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
+ struct nxpwifi_11ac_vht_cfg *cfg);
+void nxpwifi_fill_vht_cap_tlv(struct nxpwifi_private *priv,
+ struct ieee80211_vht_cap *vht_cap, u16 bands);
+#endif /* _NXPWIFI_11AC_H_ */
--
2.34.1
next prev parent reply other threads:[~2026-02-04 18:05 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-04 18:03 [PATCH v9 00/21] wifi: nxpwifi: create nxpwifi to support Jeff Chen
2026-02-04 18:03 ` [PATCH v9 01/21] wifi: nxpwifi: Add 802.11n support for client and AP modes Jeff Chen
2026-02-04 18:03 ` Jeff Chen [this message]
2026-02-04 18:03 ` [PATCH v9 03/21] wifi: nxpwifi: add initial support for 802.11ax Jeff Chen
2026-02-04 18:03 ` [PATCH v9 04/21] wifi: nxpwifi: add support for 802.11h (DFS and TPC) Jeff Chen
2026-02-04 18:03 ` [PATCH v9 05/21] wifi: nxpwifi: add support for WMM Jeff Chen
2026-02-04 18:03 ` [PATCH v9 06/21] wifi: nxpwifi: add scan support Jeff Chen
2026-02-04 18:03 ` [PATCH v9 07/21] wifi: nxpwifi: add join and association support Jeff Chen
2026-02-04 18:03 ` [PATCH v9 08/21] wifi: nxpwifi: add channel/frequency/power (cfp) support Jeff Chen
2026-02-04 18:03 ` [PATCH v9 09/21] wifi: nxpwifi: add configuration support Jeff Chen
2026-02-04 18:03 ` [PATCH v9 10/21] wifi: nxpwifi: implement cfg80211 ops for STA and AP modes Jeff Chen
2026-02-04 18:03 ` [PATCH v9 11/21] wifi: nxpwifi: add firmware command and TLV definitions Jeff Chen
2026-02-04 18:03 ` [PATCH v9 12/21] wifi: nxpwifi: introduce command and event handling infrastructure Jeff Chen
2026-02-11 9:39 ` Krzysztof Kozlowski
2026-02-11 13:26 ` Jeff Chen
2026-02-04 18:03 ` [PATCH v9 13/21] wifi: nxpwifi: add data path support for STA and AP modes Jeff Chen
2026-02-04 18:03 ` [PATCH v9 14/21] wifi: nxpwifi: add debugfs support for diagnostics and testing Jeff Chen
2026-02-04 18:03 ` [PATCH v9 15/21] wifi: nxpwifi: add ethtool support for Wake-on-LAN Jeff Chen
2026-02-04 18:03 ` [PATCH v9 16/21] wifi: nxpwifi: add utility and IE handling support Jeff Chen
2026-02-04 18:03 ` [PATCH v9 17/21] wifi: nxpwifi: add driver initialization and shutdown support Jeff Chen
2026-02-04 18:03 ` [PATCH v9 18/21] wifi: nxpwifi: add core driver implementation Jeff Chen
2026-02-11 9:36 ` Krzysztof Kozlowski
2026-02-11 13:18 ` Jeff Chen
2026-02-04 18:03 ` [PATCH v9 19/21] wifi: nxpwifi: add initial SDIO bus driver support Jeff Chen
2026-02-04 18:03 ` [PATCH v9 20/21] wifi: nxpwifi: add Kconfig and Makefile for kernel integration Jeff Chen
2026-02-04 18:03 ` [PATCH v9 21/21] wifi: nxpwifi: add MAINTAINERS entry for nxpwifi driver Jeff Chen
2026-02-04 20:09 ` [PATCH v9 00/21] wifi: nxpwifi: create nxpwifi to support Johannes Berg
2026-02-05 6:48 ` Jeff Chen
2026-02-05 6:51 ` Johannes Berg
2026-02-11 9:42 ` Krzysztof Kozlowski
2026-02-11 13:37 ` jeff.chen_1
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260204180358.632281-3-jeff.chen_1@nxp.com \
--to=jeff.chen_1@nxp.com \
--cc=briannorris@chromium.org \
--cc=francesco@dolcini.it \
--cc=johannes@sipsolutions.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=s.hauer@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox