* [PATCH nxpwifi-next v3 1/3] wifi: nl80211: vendor-cmd: add NXP vendor command definitions
2026-10-05 5:44 [PATCH nxpwifi-next v3 0/3] wifi: nxpwifi: add TX power limit configuration support jeff.chen_1
@ 2026-10-05 5:44 ` jeff.chen_1
2026-10-05 5:49 ` Johannes Berg
2026-10-05 8:31 ` jeff.chen_1
2026-10-05 5:44 ` [PATCH nxpwifi-next v3 2/3] wifi: nxpwifi: add firmware TRPC command support jeff.chen_1
2026-10-05 5:44 ` [PATCH nxpwifi-next v3 3/3] wifi: nxpwifi: add netlink vendor command for TX power limits jeff.chen_1
2 siblings, 2 replies; 6+ messages in thread
From: jeff.chen_1 @ 2026-10-05 5:44 UTC (permalink / raw)
To: linux-wireless
Cc: johannes, francesco, kees+treewide, arend.vanspriel,
benjamin.berg, Jeff Chen
From: Jeff Chen <jeff.chen_1@nxp.com>
Add NXP vendor command and attribute definitions for use with
NL80211_CMD_VENDOR.
The initial user of this interface is the Transmit Rate-based Power
Control (TRPC) configuration command.
The TRPC table is a firmware-defined ABI that contains TX power limit
data. Existing nl80211 TX power interfaces allow TX power levels to be
configured, but do not provide an interface for exchanging TRPC table
data between userspace and firmware.
Therefore, the TRPC configuration interface is exposed through a vendor
command. The kernel does not interpret the TRPC table contents and only
passes the table data between userspace and firmware.
Example use cases include:
- Reading firmware TX power limit configuration for verification.
- Updating platform-specific TX power limit tables.
- Supporting manufacturing, validation, regulatory, and platform
bring-up workflows that require access to firmware-defined TX power
limit data.
Assisted-by: LLM
Signed-off-by: Jeff Chen <jeff.chen_1@nxp.com>
---
include/uapi/linux/nl80211-vnd-nxp.h | 81 ++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
create mode 100644 include/uapi/linux/nl80211-vnd-nxp.h
diff --git a/include/uapi/linux/nl80211-vnd-nxp.h b/include/uapi/linux/nl80211-vnd-nxp.h
new file mode 100644
index 000000000000..4e18d0f5af03
--- /dev/null
+++ b/include/uapi/linux/nl80211-vnd-nxp.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * NXP vendor command definitions for nl80211
+ *
+ * Copyright 2026 NXP
+ */
+
+#ifndef __VENDOR_CMD_NXP_H__
+#define __VENDOR_CMD_NXP_H__
+
+#define NXP_OUI 0x006037
+
+/**
+ * enum nxp_vendor_cmd - supported NXP vendor commands
+ *
+ * @NXP_VENDOR_CMD_TXPOWER_LIMIT: Access firmware Transmit Rate-based
+ * Power Control (TRPC) configuration. The command uses the
+ * attributes defined by &enum nxp_txpwrlimit_attrs.
+ *
+ * SET operations provide TRPC table data through
+ * %NXP_ATTR_TXPWRLIMIT_DATA. GET operations return the requested TRPC
+ * table in %NXP_ATTR_TXPWRLIMIT_DATA.
+ *
+ * The kernel does not interpret the TRPC table contents and only
+ * passes the table data between userspace and firmware.
+ */
+enum nxp_vendor_cmd {
+ NXP_VENDOR_CMD_TXPOWER_LIMIT,
+};
+
+/**
+ * enum nxp_txpwrlimit_action - operation for %NXP_ATTR_TXPWRLIMIT_ACTION
+ *
+ * @NXP_TXPWRLIMIT_ACTION_GET: Retrieve the TRPC table for the selected
+ * subband.
+ * @NXP_TXPWRLIMIT_ACTION_SET: Update the TRPC table for the selected
+ * subband using data from %NXP_ATTR_TXPWRLIMIT_DATA.
+ */
+enum nxp_txpwrlimit_action {
+ NXP_TXPWRLIMIT_ACTION_GET,
+ NXP_TXPWRLIMIT_ACTION_SET,
+};
+
+/**
+ * enum nxp_txpwrlimit_subband - firmware TRPC subband selectors
+ *
+ * The selector values are defined by the firmware Transmit Rate-based
+ * Power Control (TRPC) interface.
+ *
+ * @NXP_TXPWRLIMIT_SUBBAND_2G: 2.4 GHz band.
+ * @NXP_TXPWRLIMIT_SUBBAND_5G_0: 5 GHz subband 0.
+ * @NXP_TXPWRLIMIT_SUBBAND_5G_1: 5 GHz subband 1.
+ * @NXP_TXPWRLIMIT_SUBBAND_5G_2: 5 GHz subband 2.
+ * @NXP_TXPWRLIMIT_SUBBAND_5G_3: 5 GHz subband 3.
+ */
+enum nxp_txpwrlimit_subband {
+ NXP_TXPWRLIMIT_SUBBAND_2G = 0x00,
+ NXP_TXPWRLIMIT_SUBBAND_5G_0 = 0x10,
+ NXP_TXPWRLIMIT_SUBBAND_5G_1 = 0x11,
+ NXP_TXPWRLIMIT_SUBBAND_5G_2 = 0x12,
+ NXP_TXPWRLIMIT_SUBBAND_5G_3 = 0x13,
+};
+
+/**
+ * enum nxp_txpwrlimit_attrs - TX power limit vendor attributes
+ * @NXP_ATTR_TXPWRLIMIT_UNSPEC: Unspecified attribute.
+ * @NXP_ATTR_TXPWRLIMIT_ACTION: Operation from &enum nxp_txpwrlimit_action.
+ * @NXP_ATTR_TXPWRLIMIT_SUBBAND: Target subband.
+ * @NXP_ATTR_TXPWRLIMIT_DATA: Firmware-defined TRPC table data.
+ */
+enum nxp_txpwrlimit_attrs {
+ NXP_ATTR_TXPWRLIMIT_UNSPEC,
+ NXP_ATTR_TXPWRLIMIT_ACTION,
+ NXP_ATTR_TXPWRLIMIT_SUBBAND,
+ NXP_ATTR_TXPWRLIMIT_DATA,
+
+ __NXP_ATTR_TXPWRLIMIT_AFTER_LAST,
+ NXP_ATTR_TXPWRLIMIT_MAX = __NXP_ATTR_TXPWRLIMIT_AFTER_LAST - 1
+};
+
+#endif /* __VENDOR_CMD_NXP_H__ */
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH nxpwifi-next v3 1/3] wifi: nl80211: vendor-cmd: add NXP vendor command definitions
2026-10-05 5:44 ` [PATCH nxpwifi-next v3 1/3] wifi: nl80211: vendor-cmd: add NXP vendor command definitions jeff.chen_1
@ 2026-10-05 5:49 ` Johannes Berg
2026-10-05 8:31 ` jeff.chen_1
1 sibling, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2026-10-05 5:49 UTC (permalink / raw)
To: jeff.chen_1, linux-wireless
Cc: francesco, arend.vanspriel, benjamin.berg, Jeff Chen
On Mon, 2026-10-05 at 13:44 +0800, jeff.chen_1@oss.nxp.com wrote:
> From: Jeff Chen <jeff.chen_1@nxp.com>
>
> Add NXP vendor command and attribute definitions for use with
> NL80211_CMD_VENDOR.
>
> The initial user of this interface is the Transmit Rate-based Power
> Control (TRPC) configuration command.
>
> The TRPC table is a firmware-defined ABI that contains TX power limit
> data. Existing nl80211 TX power interfaces allow TX power levels to be
> configured, but do not provide an interface for exchanging TRPC table
> data between userspace and firmware.
>
> Therefore, the TRPC configuration interface is exposed through a vendor
> command. The kernel does not interpret the TRPC table contents and only
> passes the table data between userspace and firmware.
>
> Example use cases include:
> - Reading firmware TX power limit configuration for verification.
> - Updating platform-specific TX power limit tables.
> - Supporting manufacturing, validation, regulatory, and platform
> bring-up workflows that require access to firmware-defined TX power
> limit data.
But ... none of this really needs full support on every production
device, so it could just be debugfs?
johannes
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re:[PATCH nxpwifi-next v3 1/3] wifi: nl80211: vendor-cmd: add NXP vendor command definitions
2026-10-05 5:44 ` [PATCH nxpwifi-next v3 1/3] wifi: nl80211: vendor-cmd: add NXP vendor command definitions jeff.chen_1
2026-10-05 5:49 ` Johannes Berg
@ 2026-10-05 8:31 ` jeff.chen_1
1 sibling, 0 replies; 6+ messages in thread
From: jeff.chen_1 @ 2026-10-05 8:31 UTC (permalink / raw)
To: johannes
Cc: linux-wireless, francesco, kees+treewide, arend.vanspriel,
benjamin.berg
On 10/5/2026 1:49 PM, Johannes Berg wrote:
>> Example use cases include:
>> - Reading firmware TX power limit configuration for verification.
>> - Updating platform-specific TX power limit tables.
>> - Supporting manufacturing, validation, regulatory, and platform
>> bring-up workflows that require access to firmware-defined TX power
>> limit data.
>
> But ... none of this really needs full support on every production
> device, so it could just be debugfs?
>
> johannes
Hi Johannes
Sorry, the examples were not very precise.
The TRPC table is product-specific and is typically provided by the
module vendor or OEM. It depends on the RF characteristics of the
final product and may also vary by regulatory region.
This is not intended only for manufacturing or validation. It is used
to read and update firmware TX power limit configuration on deployed
systems.
I can clarify this in the next revision if needed.
rgards,
Jeff
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH nxpwifi-next v3 2/3] wifi: nxpwifi: add firmware TRPC command support
2026-10-05 5:44 [PATCH nxpwifi-next v3 0/3] wifi: nxpwifi: add TX power limit configuration support jeff.chen_1
2026-10-05 5:44 ` [PATCH nxpwifi-next v3 1/3] wifi: nl80211: vendor-cmd: add NXP vendor command definitions jeff.chen_1
@ 2026-10-05 5:44 ` jeff.chen_1
2026-10-05 5:44 ` [PATCH nxpwifi-next v3 3/3] wifi: nxpwifi: add netlink vendor command for TX power limits jeff.chen_1
2 siblings, 0 replies; 6+ messages in thread
From: jeff.chen_1 @ 2026-10-05 5:44 UTC (permalink / raw)
To: linux-wireless
Cc: johannes, francesco, kees+treewide, arend.vanspriel,
benjamin.berg, Jeff Chen
From: Jeff Chen <jeff.chen_1@nxp.com>
Add support for the firmware TRPC configuration command used to
retrieve and update TX power limit data.
Assisted-by: LLM
Signed-off-by: Jeff Chen <jeff.chen_1@nxp.com>
---
drivers/net/wireless/nxp/nxpwifi/cfg.h | 11 ++++
drivers/net/wireless/nxp/nxpwifi/fw.h | 8 +++
drivers/net/wireless/nxp/nxpwifi/main.h | 2 +
drivers/net/wireless/nxp/nxpwifi/sta_cfg.c | 8 +++
drivers/net/wireless/nxp/nxpwifi/sta_cmd.c | 67 ++++++++++++++++++++++
5 files changed, 96 insertions(+)
diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg.h b/drivers/net/wireless/nxp/nxpwifi/cfg.h
index 8627a3372978..4c0558ed483e 100644
--- a/drivers/net/wireless/nxp/nxpwifi/cfg.h
+++ b/drivers/net/wireless/nxp/nxpwifi/cfg.h
@@ -755,6 +755,17 @@ struct nxpwifi_ds_coalesce_cfg {
struct nxpwifi_coalesce_rule rule[NXPWIFI_COALESCE_MAX_RULES];
};
+/* Host-side helper for the channel TRPC command. */
+struct nxpwifi_ds_chan_trpc_cfg {
+ u32 len;
+ u16 action;
+ u16 subband;
+ u8 tlvbuffer[];
+};
+
+/* Upper bound on the TRPC TLV table exchanged with the firmware. */
+#define NXPWIFI_MAX_TRPC_BUF (4 * 1024)
+
struct nxpwifi_11ax_he_cap_cfg {
u16 id;
u16 len;
diff --git a/drivers/net/wireless/nxp/nxpwifi/fw.h b/drivers/net/wireless/nxp/nxpwifi/fw.h
index 188110b020cf..0de5d2fc9242 100644
--- a/drivers/net/wireless/nxp/nxpwifi/fw.h
+++ b/drivers/net/wireless/nxp/nxpwifi/fw.h
@@ -386,6 +386,7 @@ enum NXPWIFI_802_11_PRIVACY_FILTER {
#define HOST_CMD_CAU_REG_ACCESS 0x00ed
#define HOST_CMD_SET_BSS_MODE 0x00f7
#define HOST_CMD_PCIE_DESC_DETAILS 0x00fa
+#define HOST_CMD_CHAN_TRPC_CONFIG 0x00fb
#define HOST_CMD_802_11_NET_MONITOR 0x0102
#define HOST_CMD_802_11_SCAN_EXT 0x0107
#define HOST_CMD_COALESCE_CFG 0x010a
@@ -2373,6 +2374,12 @@ struct host_cmd_twt_cfg {
u8 val[];
} __packed;
+struct host_cmd_chan_trpc_cfg {
+ __le16 action;
+ __le16 subband;
+ u8 tlvbuffer[];
+} __packed;
+
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@@ -2447,6 +2454,7 @@ struct host_cmd_ds_command {
struct host_cmd_11ax_cmd ax_cmd;
struct host_cmd_ds_802_11_net_monitor net_mon;
struct host_cmd_twt_cfg twt_cfg;
+ struct host_cmd_chan_trpc_cfg ch_trpc_cfg;
} params;
} __packed;
diff --git a/drivers/net/wireless/nxp/nxpwifi/main.h b/drivers/net/wireless/nxp/nxpwifi/main.h
index b25a6a4f2936..9ae017bdc6ca 100644
--- a/drivers/net/wireless/nxp/nxpwifi/main.h
+++ b/drivers/net/wireless/nxp/nxpwifi/main.h
@@ -1415,6 +1415,8 @@ int nxpwifi_get_wakeup_reason(struct nxpwifi_private *priv, u16 action,
struct nxpwifi_ds_wakeup_reason *wakeup_reason);
int nxpwifi_get_chan_info(struct nxpwifi_private *priv,
struct nxpwifi_channel_band *channel_band);
+int nxpwifi_chan_trpc_cfg(struct nxpwifi_private *priv, int cmd_type,
+ struct nxpwifi_ds_chan_trpc_cfg *ch_trpc);
void nxpwifi_coex_ampdu_rxwinsize(struct nxpwifi_adapter *adapter);
void nxpwifi_11n_delba(struct nxpwifi_private *priv, int tid);
int nxpwifi_send_domain_info_cmd_fw(struct wiphy *wiphy, enum nl80211_band band);
diff --git a/drivers/net/wireless/nxp/nxpwifi/sta_cfg.c b/drivers/net/wireless/nxp/nxpwifi/sta_cfg.c
index 56cf63fbf7fe..650de6156912 100644
--- a/drivers/net/wireless/nxp/nxpwifi/sta_cfg.c
+++ b/drivers/net/wireless/nxp/nxpwifi/sta_cfg.c
@@ -1175,3 +1175,11 @@ int nxpwifi_get_chan_info(struct nxpwifi_private *priv,
HOST_ACT_GEN_GET, 0, channel_band,
NXPWIFI_SYNC_CMD);
}
+
+int nxpwifi_chan_trpc_cfg(struct nxpwifi_private *priv, int cmd_type,
+ struct nxpwifi_ds_chan_trpc_cfg *ch_trpc)
+{
+ return nxpwifi_send_cmd(priv, HOST_CMD_CHAN_TRPC_CONFIG,
+ ch_trpc->action, 0, ch_trpc,
+ cmd_type == NXPWIFI_SYNC_CMD);
+}
diff --git a/drivers/net/wireless/nxp/nxpwifi/sta_cmd.c b/drivers/net/wireless/nxp/nxpwifi/sta_cmd.c
index 9bfa4aebc3e5..8ac5008e0081 100644
--- a/drivers/net/wireless/nxp/nxpwifi/sta_cmd.c
+++ b/drivers/net/wireless/nxp/nxpwifi/sta_cmd.c
@@ -3033,6 +3033,70 @@ nxpwifi_ret_sta_twt_cfg(struct nxpwifi_private *priv,
return nxpwifi_ret_twt_cfg(priv, resp, data_buf);
}
+static int nxpwifi_cmd_chan_trpc_cfg(struct nxpwifi_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_no, void *data_buf, u16 cmd_action,
+ u32 cmd_type)
+{
+ struct host_cmd_chan_trpc_cfg *chan_trpc_cfg = &cmd->params.ch_trpc_cfg;
+ struct nxpwifi_ds_chan_trpc_cfg *usr_chan_trpc_cfg =
+ (struct nxpwifi_ds_chan_trpc_cfg *)data_buf;
+ u32 hdr_len = sizeof(chan_trpc_cfg->action) +
+ sizeof(chan_trpc_cfg->subband);
+
+ /* usr_chan_trpc_cfg->len covers action, subband, and TRPC data.
+ * Reject lengths outside the supported command payload range.
+ */
+ if (usr_chan_trpc_cfg->len < hdr_len ||
+ usr_chan_trpc_cfg->len > hdr_len + NXPWIFI_MAX_TRPC_BUF)
+ return -EINVAL;
+
+ cmd->command = cpu_to_le16(cmd_no);
+ cmd->size = cpu_to_le16(S_DS_GEN + usr_chan_trpc_cfg->len);
+
+ memcpy(chan_trpc_cfg, &usr_chan_trpc_cfg->action,
+ usr_chan_trpc_cfg->len);
+
+ return 0;
+}
+
+static int nxpwifi_ret_chan_trpc_cfg(struct nxpwifi_private *priv,
+ struct host_cmd_ds_command *resp,
+ u16 cmdresp_no, void *data_buf)
+{
+ struct host_cmd_chan_trpc_cfg *chan_trpc_cfg =
+ &resp->params.ch_trpc_cfg;
+ struct nxpwifi_ds_chan_trpc_cfg *usr_chan_trpc_cfg =
+ (struct nxpwifi_ds_chan_trpc_cfg *)data_buf;
+
+ if (chan_trpc_cfg->action == HOST_ACT_GEN_GET) {
+ u16 resp_size = le16_to_cpu(resp->size);
+ u16 resp_len;
+
+ if (resp_size < S_DS_GEN)
+ return -EIO;
+
+ resp_len = resp_size - S_DS_GEN;
+ /* The firmware response contains action, subband, and TRPC
+ * data. Validate that the payload length is within bounds.
+ */
+ if (resp_len < sizeof(chan_trpc_cfg->action) +
+ sizeof(chan_trpc_cfg->subband) ||
+ resp_len > sizeof(chan_trpc_cfg->action) +
+ sizeof(chan_trpc_cfg->subband) +
+ NXPWIFI_MAX_TRPC_BUF) {
+ nxpwifi_dbg(priv->adapter, ERROR,
+ "chan_trpc bad resp len: %u\n", resp_len);
+ return -EIO;
+ }
+
+ usr_chan_trpc_cfg->len = resp_len;
+ memcpy(&usr_chan_trpc_cfg->action, chan_trpc_cfg, resp_len);
+ }
+
+ return 0;
+}
+
static const struct nxpwifi_cmd_entry cmd_table_sta[] = {
{.cmd_no = HOST_CMD_GET_HW_SPEC,
.prepare_cmd = nxpwifi_cmd_sta_get_hw_spec,
@@ -3217,6 +3281,9 @@ static const struct nxpwifi_cmd_entry cmd_table_sta[] = {
{.cmd_no = HOST_CMD_TWT_CFG,
.prepare_cmd = nxpwifi_cmd_sta_twt_cfg,
.cmd_resp = nxpwifi_ret_sta_twt_cfg},
+ {.cmd_no = HOST_CMD_CHAN_TRPC_CONFIG,
+ .prepare_cmd = nxpwifi_cmd_chan_trpc_cfg,
+ .cmd_resp = nxpwifi_ret_chan_trpc_cfg},
};
/*
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH nxpwifi-next v3 3/3] wifi: nxpwifi: add netlink vendor command for TX power limits
2026-10-05 5:44 [PATCH nxpwifi-next v3 0/3] wifi: nxpwifi: add TX power limit configuration support jeff.chen_1
2026-10-05 5:44 ` [PATCH nxpwifi-next v3 1/3] wifi: nl80211: vendor-cmd: add NXP vendor command definitions jeff.chen_1
2026-10-05 5:44 ` [PATCH nxpwifi-next v3 2/3] wifi: nxpwifi: add firmware TRPC command support jeff.chen_1
@ 2026-10-05 5:44 ` jeff.chen_1
2 siblings, 0 replies; 6+ messages in thread
From: jeff.chen_1 @ 2026-10-05 5:44 UTC (permalink / raw)
To: linux-wireless
Cc: johannes, francesco, kees+treewide, arend.vanspriel,
benjamin.berg, Jeff Chen
From: Jeff Chen <jeff.chen_1@nxp.com>
Add support for the NXP TX power limit vendor command.
The command provides userspace access to firmware Transmit Rate-based
Power Control (TRPC) configuration through NL80211_CMD_VENDOR.
Signed-off-by: Jeff Chen <jeff.chen_1@nxp.com>
---
drivers/net/wireless/nxp/nxpwifi/Makefile | 1 +
drivers/net/wireless/nxp/nxpwifi/cfg80211.c | 5 +-
drivers/net/wireless/nxp/nxpwifi/main.h | 1 +
drivers/net/wireless/nxp/nxpwifi/vendor.c | 152 ++++++++++++++++++++
drivers/net/wireless/nxp/nxpwifi/vendor.h | 14 ++
5 files changed, 172 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/wireless/nxp/nxpwifi/vendor.c
create mode 100644 drivers/net/wireless/nxp/nxpwifi/vendor.h
diff --git a/drivers/net/wireless/nxp/nxpwifi/Makefile b/drivers/net/wireless/nxp/nxpwifi/Makefile
index 8f581429f28d..f82435253a72 100644
--- a/drivers/net/wireless/nxp/nxpwifi/Makefile
+++ b/drivers/net/wireless/nxp/nxpwifi/Makefile
@@ -28,6 +28,7 @@ nxpwifi-y += sta_tx.o
nxpwifi-y += sta_rx.o
nxpwifi-y += uap_txrx.o
nxpwifi-y += cfg80211.o
+nxpwifi-y += vendor.o
nxpwifi-y += ethtool.o
nxpwifi-y += 11h.o
nxpwifi-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
index 8805439c0b4b..16b970227e9c 100644
--- a/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
+++ b/drivers/net/wireless/nxp/nxpwifi/cfg80211.c
@@ -10,6 +10,7 @@
#include "cmdevt.h"
#include "11n.h"
#include "wmm.h"
+#include "vendor.h"
static const struct ieee80211_iface_limit nxpwifi_ap_sta_limits[] = {
{
@@ -91,7 +92,7 @@ u8 nxpwifi_get_chan_type(struct nxpwifi_private *priv)
}
/* Retrieve the driver private data from the wiphy */
-static void *nxpwifi_cfg80211_get_adapter(struct wiphy *wiphy)
+void *nxpwifi_cfg80211_get_adapter(struct wiphy *wiphy)
{
return (void *)(*(unsigned long *)wiphy_priv(wiphy));
}
@@ -3834,6 +3835,8 @@ int nxpwifi_register_cfg80211(struct nxpwifi_adapter *adapter)
wiphy->cipher_suites = nxpwifi_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(nxpwifi_cipher_suites);
+ nxpwifi_set_vendor_commands(wiphy);
+
if (adapter->regd) {
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS |
diff --git a/drivers/net/wireless/nxp/nxpwifi/main.h b/drivers/net/wireless/nxp/nxpwifi/main.h
index 9ae017bdc6ca..bbfc4266c48d 100644
--- a/drivers/net/wireless/nxp/nxpwifi/main.h
+++ b/drivers/net/wireless/nxp/nxpwifi/main.h
@@ -1435,4 +1435,5 @@ void nxpwifi_dev_debugfs_remove(struct nxpwifi_private *priv);
int nxpwifi_reinit_sw(struct nxpwifi_adapter *adapter);
void nxpwifi_shutdown_sw(struct nxpwifi_adapter *adapter);
bool nxpwifi_is_valid_region_code(enum nxpwifi_region_code code);
+void *nxpwifi_cfg80211_get_adapter(struct wiphy *wiphy);
#endif /* !_NXPWIFI_MAIN_H_ */
diff --git a/drivers/net/wireless/nxp/nxpwifi/vendor.c b/drivers/net/wireless/nxp/nxpwifi/vendor.c
new file mode 100644
index 000000000000..3f1834cf8844
--- /dev/null
+++ b/drivers/net/wireless/nxp/nxpwifi/vendor.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * NXP Wireless LAN device driver: vendor command interface
+ *
+ * Copyright 2026 NXP
+ */
+
+#include <net/mac80211.h>
+#include <net/netlink.h>
+#include "vendor.h"
+#include "main.h"
+
+/* Attributes for NXP_VENDOR_CMD_TXPOWER_LIMIT. */
+static const struct nla_policy
+nxpwifi_txpwrlimit_policy[NXP_ATTR_TXPWRLIMIT_MAX + 1] = {
+ [NXP_ATTR_TXPWRLIMIT_ACTION] =
+ NLA_POLICY_MAX(NLA_U8, NXP_TXPWRLIMIT_ACTION_SET),
+ [NXP_ATTR_TXPWRLIMIT_SUBBAND] = { .type = NLA_U8 },
+ [NXP_ATTR_TXPWRLIMIT_DATA] = { .type = NLA_BINARY,
+ .len = NXPWIFI_MAX_TRPC_BUF },
+};
+
+static bool nxpwifi_txpwrlimit_subband_valid(u8 subband)
+{
+ switch (subband) {
+ case NXP_TXPWRLIMIT_SUBBAND_2G:
+ case NXP_TXPWRLIMIT_SUBBAND_5G_0:
+ case NXP_TXPWRLIMIT_SUBBAND_5G_1:
+ case NXP_TXPWRLIMIT_SUBBAND_5G_2:
+ case NXP_TXPWRLIMIT_SUBBAND_5G_3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int nxpwifi_vendor_txpower_limit(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy);
+ struct nlattr *tb[NXP_ATTR_TXPWRLIMIT_MAX + 1];
+ struct nxpwifi_ds_chan_trpc_cfg *ch_trpc;
+ struct nxpwifi_private *priv;
+ struct sk_buff *resp;
+ u8 action, subband = 0;
+ u16 tlv_len = 0;
+ int ret;
+
+ ret = nla_parse(tb, NXP_ATTR_TXPWRLIMIT_MAX, data, data_len,
+ nxpwifi_txpwrlimit_policy, NULL);
+ if (ret)
+ return ret;
+
+ if (!tb[NXP_ATTR_TXPWRLIMIT_ACTION])
+ return -EINVAL;
+ action = nla_get_u8(tb[NXP_ATTR_TXPWRLIMIT_ACTION]);
+
+ if (tb[NXP_ATTR_TXPWRLIMIT_SUBBAND]) {
+ subband = nla_get_u8(tb[NXP_ATTR_TXPWRLIMIT_SUBBAND]);
+ if (!nxpwifi_txpwrlimit_subband_valid(subband))
+ return -EINVAL;
+ } else if (action == NXP_TXPWRLIMIT_ACTION_GET) {
+ /* A subband selector is required for GET operations. */
+ return -EINVAL;
+ }
+
+ if (action == NXP_TXPWRLIMIT_ACTION_SET) {
+ if (!tb[NXP_ATTR_TXPWRLIMIT_DATA])
+ return -EINVAL;
+ tlv_len = nla_len(tb[NXP_ATTR_TXPWRLIMIT_DATA]);
+ }
+
+ priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA);
+ if (!priv)
+ return -ENODEV;
+
+ /* Reserve space for the returned TRPC table on GET requests. */
+ ch_trpc = kzalloc_flex(*ch_trpc, tlvbuffer,
+ (action == NXP_TXPWRLIMIT_ACTION_SET) ?
+ tlv_len : NXPWIFI_MAX_TRPC_BUF, GFP_KERNEL);
+ if (!ch_trpc)
+ return -ENOMEM;
+
+ ch_trpc->action = (action == NXP_TXPWRLIMIT_ACTION_SET) ?
+ HOST_ACT_GEN_SET : HOST_ACT_GEN_GET;
+ ch_trpc->subband = subband;
+
+ if (tlv_len)
+ memcpy(ch_trpc->tlvbuffer,
+ nla_data(tb[NXP_ATTR_TXPWRLIMIT_DATA]), tlv_len);
+
+ ch_trpc->len = sizeof(ch_trpc->action) + sizeof(ch_trpc->subband) +
+ tlv_len;
+
+ ret = nxpwifi_chan_trpc_cfg(priv, NXPWIFI_SYNC_CMD, ch_trpc);
+ if (ret)
+ goto done;
+
+ if (action == NXP_TXPWRLIMIT_ACTION_GET) {
+ u16 hdr_len = sizeof(ch_trpc->action) +
+ sizeof(ch_trpc->subband);
+ u16 resp_len, skb_len;
+
+ if (ch_trpc->len < hdr_len ||
+ ch_trpc->len > hdr_len + NXPWIFI_MAX_TRPC_BUF) {
+ ret = -EIO;
+ goto done;
+ }
+
+ resp_len = ch_trpc->len - hdr_len;
+ skb_len = nla_total_size(resp_len);
+
+ resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
+ if (!resp) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (nla_put(resp, NXP_ATTR_TXPWRLIMIT_DATA, resp_len,
+ ch_trpc->tlvbuffer)) {
+ kfree_skb(resp);
+ ret = -ENOBUFS;
+ goto done;
+ }
+
+ ret = cfg80211_vendor_cmd_reply(resp);
+ }
+
+done:
+ kfree(ch_trpc);
+ return ret;
+}
+
+static const struct wiphy_vendor_command nxpwifi_vendor_commands[] = {
+ {
+ .info = {
+ .vendor_id = NXP_OUI,
+ .subcmd = NXP_VENDOR_CMD_TXPOWER_LIMIT,
+ },
+ .flags = 0,
+ .doit = nxpwifi_vendor_txpower_limit,
+ .policy = nxpwifi_txpwrlimit_policy,
+ .maxattr = NXP_ATTR_TXPWRLIMIT_MAX,
+ },
+};
+
+void nxpwifi_set_vendor_commands(struct wiphy *wiphy)
+{
+ wiphy->vendor_commands = nxpwifi_vendor_commands;
+ wiphy->n_vendor_commands = ARRAY_SIZE(nxpwifi_vendor_commands);
+}
diff --git a/drivers/net/wireless/nxp/nxpwifi/vendor.h b/drivers/net/wireless/nxp/nxpwifi/vendor.h
new file mode 100644
index 000000000000..fdde8e1a7a40
--- /dev/null
+++ b/drivers/net/wireless/nxp/nxpwifi/vendor.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * NXP Wireless LAN device driver: vendor command interface
+ *
+ * Copyright 2026 NXP
+ */
+
+#ifndef __NXPWIFI_VENDOR_H__
+#define __NXPWIFI_VENDOR_H__
+
+#include <uapi/linux/nl80211-vnd-nxp.h>
+
+void nxpwifi_set_vendor_commands(struct wiphy *wiphy);
+#endif /* __NXPWIFI_VENDOR_H__ */
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread