From: jeff.chen_1@oss.nxp.com
To: linux-wireless@vger.kernel.org
Cc: johannes@sipsolutions.net, francesco@dolcini.it,
kees+treewide@kernel.org, arend.vanspriel@broadcom.com,
benjamin.berg@intel.com, Jeff Chen <jeff.chen_1@nxp.com>
Subject: [PATCH nxpwifi-next v2 3/3] wifi: nxpwifi: add netlink vendor command for TX power limits
Date: Mon, 5 Oct 2026 00:46:29 +0800 [thread overview]
Message-ID: <20261004164629.2860677-4-jeff.chen_1@oss.nxp.com> (raw)
In-Reply-To: <20261004164629.2860677-1-jeff.chen_1@oss.nxp.com>
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..ac31cfd38941
--- /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_txpwr_policy[NXP_ATTR_TXPWR_MAX + 1] = {
+ [NXP_ATTR_TXPWR_ACTION] = NLA_POLICY_MAX(NLA_U8,
+ NXP_TXPWR_ACTION_SET),
+ [NXP_ATTR_TXPWR_SUBBAND] = { .type = NLA_U8 },
+ [NXP_ATTR_TXPWR_DATA] = { .type = NLA_BINARY,
+ .len = NXPWIFI_MAX_TRPC_BUF },
+};
+
+static bool nxpwifi_txpwr_subband_valid(u8 subband)
+{
+ switch (subband) {
+ case NXP_TXPWR_SUBBAND_2G:
+ case NXP_TXPWR_SUBBAND_5G_0:
+ case NXP_TXPWR_SUBBAND_5G_1:
+ case NXP_TXPWR_SUBBAND_5G_2:
+ case NXP_TXPWR_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_TXPWR_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_TXPWR_MAX, data, data_len,
+ nxpwifi_txpwr_policy, NULL);
+ if (ret)
+ return ret;
+
+ if (!tb[NXP_ATTR_TXPWR_ACTION])
+ return -EINVAL;
+ action = nla_get_u8(tb[NXP_ATTR_TXPWR_ACTION]);
+
+ if (tb[NXP_ATTR_TXPWR_SUBBAND]) {
+ subband = nla_get_u8(tb[NXP_ATTR_TXPWR_SUBBAND]);
+ if (!nxpwifi_txpwr_subband_valid(subband))
+ return -EINVAL;
+ } else if (action == NXP_TXPWR_ACTION_GET) {
+ /* A subband selector is required for GET operations. */
+ return -EINVAL;
+ }
+
+ if (action == NXP_TXPWR_ACTION_SET) {
+ if (!tb[NXP_ATTR_TXPWR_DATA])
+ return -EINVAL;
+ tlv_len = nla_len(tb[NXP_ATTR_TXPWR_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_TXPWR_ACTION_SET) ?
+ tlv_len : NXPWIFI_MAX_TRPC_BUF, GFP_KERNEL);
+ if (!ch_trpc)
+ return -ENOMEM;
+
+ ch_trpc->action = (action == NXP_TXPWR_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_TXPWR_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_TXPWR_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_TXPWR_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_txpwr_policy,
+ .maxattr = NXP_ATTR_TXPWR_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
prev parent reply other threads:[~2026-10-04 16:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-04 16:46 [PATCH nxpwifi-next v2 0/3] wifi: nxpwifi: add TX power limit configuration support jeff.chen_1
2026-10-04 16:46 ` [PATCH nxpwifi-next v2 1/3] wifi: nl80211: vendor-cmd: add NXP vendor command definitions jeff.chen_1
2026-10-04 16:46 ` [PATCH nxpwifi-next v2 2/3] wifi: nxpwifi: add firmware TRPC command support jeff.chen_1
2026-10-04 16:46 ` jeff.chen_1 [this message]
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=20261004164629.2860677-4-jeff.chen_1@oss.nxp.com \
--to=jeff.chen_1@oss.nxp.com \
--cc=arend.vanspriel@broadcom.com \
--cc=benjamin.berg@intel.com \
--cc=francesco@dolcini.it \
--cc=jeff.chen_1@nxp.com \
--cc=johannes@sipsolutions.net \
--cc=kees+treewide@kernel.org \
--cc=linux-wireless@vger.kernel.org \
/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