-: ------------ > 1: bd85cab0820e wifi: nl80211: vendor-cmd: add NXP vendor command definitions 1: 8c1582d6688a ! 2: 792480fef7c7 wifi: nxpwifi: add TX power limit host command support @@ Metadata Author: Jeff Chen   ## Commit message ## - wifi: nxpwifi: add TX power limit host command support + wifi: nxpwifi: add firmware TRPC command support  Add support for the firmware channel TRPC configuration command used to retrieve and update TX power limit data.  + Assisted-by: LLM Signed-off-by: Jeff Chen   ## drivers/net/wireless/nxp/nxpwifi/cfg.h ## @@ drivers/net/wireless/nxp/nxpwifi/cfg.h: struct nxpwifi_ds_coalesce_cfg { struct nxpwifi_coalesce_rule rule[NXPWIFI_COALESCE_MAX_RULES]; };  -+/* Host-side helper for the channel TRPC (TX power limit) command. -+ * This is not a firmware wire structure; @len counts the bytes from -+ * @action onwards (action + subband + tlvbuffer). -+ */ ++/* Host-side helper for the channel TRPC command. */  +struct nxpwifi_ds_chan_trpc_cfg {  + u32 len;  + u16 action; @@ drivers/net/wireless/nxp/nxpwifi/fw.h: struct host_cmd_twt_cfg { } __packed;   +struct host_cmd_chan_trpc_cfg { -+ u16 action; -+ u16 subband; ++ __le16 action; ++ __le16 subband;  + u8 tlvbuffer[];  +} __packed;  + @@ drivers/net/wireless/nxp/nxpwifi/sta_cmd.c: nxpwifi_ret_sta_twt_cfg(struct nxpwi  + u32 hdr_len = sizeof(chan_trpc_cfg->action) +  + sizeof(chan_trpc_cfg->subband);  + -+ /* usr_chan_trpc_cfg->len covers action + subband + the TLV table. -+ * Reject a length that cannot hold the fixed fields or that would -+ * grow the command past the TLV buffer bound, so an untrusted @len -+ * can neither underflow the TLV size nor overflow the command body. ++ /* 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) @@ drivers/net/wireless/nxp/nxpwifi/sta_cmd.c: nxpwifi_ret_sta_twt_cfg(struct nxpwi  + cmd->command = cpu_to_le16(cmd_no);  + cmd->size = cpu_to_le16(S_DS_GEN + usr_chan_trpc_cfg->len);  + -+ /* Copy action + subband + the TLV table verbatim into the firmware -+ * command body. -+ */  + memcpy(chan_trpc_cfg, &usr_chan_trpc_cfg->action,  + usr_chan_trpc_cfg->len);  + @@ drivers/net/wireless/nxp/nxpwifi/sta_cmd.c: nxpwifi_ret_sta_twt_cfg(struct nxpwi  + return -EINVAL;  +  + resp_len = resp_size - S_DS_GEN; -+ /* The firmware response carries action + subband followed by -+ * the TLV table. Reject a response that is too short to hold -+ * those fields or larger than the caller's TLV buffer. ++ /* 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) || @@ drivers/net/wireless/nxp/nxpwifi/sta_cmd.c: nxpwifi_ret_sta_twt_cfg(struct nxpwi  + return -EINVAL;  + }  + -+ /* Copy action + subband + the TLV table back to the caller. */  + usr_chan_trpc_cfg->len = resp_len;  + memcpy(&usr_chan_trpc_cfg->action, chan_trpc_cfg, resp_len);  + } 2: d810850b5bd3 ! 3: 2839ca529dbb wifi: nxpwifi: add netlink vendor command for TX power limits @@ Metadata ## Commit message ## wifi: nxpwifi: add netlink vendor command for TX power limits  - Add a cfg80211 vendor command that allows user space to retrieve and - update firmware TX power limit data through a stable netlink interface. + Add support for the NXP TX power limit vendor command.  - The firmware exposes TX power limits through the channel TRPC command. - The associated payload is a firmware-defined, chipset-specific table - containing TX power limit information. - - The table format is part of the firmware ABI and has no equivalent - representation in the generic nl80211 TX power interface. Therefore, - the payload is carried as an opaque binary attribute through a vendor - command. - - The driver forwards the firmware-defined payload between user space and - the firmware without interpreting its contents. + The command provides userspace access to firmware Transmit Rate-based + Power Control (TRPC) configuration through NL80211_CMD_VENDOR.  Signed-off-by: Jeff Chen   @@ drivers/net/wireless/nxp/nxpwifi/vendor.c (new)  +/*  + * NXP Wireless LAN device driver: vendor command interface  + * -+ * Copyright 2011-2026 NXP ++ * Copyright 2026 NXP  + */  +  +#include  @@ drivers/net/wireless/nxp/nxpwifi/vendor.c (new)  +#include "vendor.h"  +#include "main.h"  + ++/* Attributes for NXP_VENDOR_CMD_TXPOWER_LIMIT. */  +static const struct nla_policy -+nxpwifi_txpwr_policy[NXPWIFI_ATTR_TXPWR_MAX + 1] = { -+ [NXPWIFI_ATTR_TXPWR_ACTION] = NLA_POLICY_MAX(NLA_U8, -+ NXPWIFI_TXPWR_ACTION_SET), -+ [NXPWIFI_ATTR_TXPWR_SUBBAND] = { .type = NLA_U8 }, -+ [NXPWIFI_ATTR_TXPWR_DATA] = { .type = NLA_BINARY, -+ .len = NXPWIFI_MAX_TRPC_BUF }, ++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 },  +};  + -+/* The subband selector is not a contiguous range: 0x00 selects the 2.4 GHz -+ * band and 0x10..0x13 select the four 5 GHz subbands. Validate it explicitly -+ * instead of relying on a simple min/max policy bound. -+ */  +static bool nxpwifi_txpwr_subband_valid(u8 subband)  +{  + switch (subband) { -+ case NXPWIFI_TXPWR_SUBBAND_2G: -+ case NXPWIFI_TXPWR_SUBBAND_5G_0: -+ case NXPWIFI_TXPWR_SUBBAND_5G_1: -+ case NXPWIFI_TXPWR_SUBBAND_5G_2: -+ case NXPWIFI_TXPWR_SUBBAND_5G_3: ++ 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; @@ drivers/net/wireless/nxp/nxpwifi/vendor.c (new)  + const void *data, int data_len)  +{  + struct nxpwifi_adapter *adapter = nxpwifi_cfg80211_get_adapter(wiphy); -+ struct nlattr *tb[NXPWIFI_ATTR_TXPWR_MAX + 1]; ++ struct nlattr *tb[NXP_ATTR_TXPWR_MAX + 1];  + struct nxpwifi_ds_chan_trpc_cfg *ch_trpc;  + struct nxpwifi_private *priv;  + struct sk_buff *resp; @@ drivers/net/wireless/nxp/nxpwifi/vendor.c (new)  + u16 tlv_len = 0;  + int ret;  + -+ ret = nla_parse(tb, NXPWIFI_ATTR_TXPWR_MAX, data, data_len, ++ ret = nla_parse(tb, NXP_ATTR_TXPWR_MAX, data, data_len,  + nxpwifi_txpwr_policy, NULL);  + if (ret)  + return ret;  + -+ if (!tb[NXPWIFI_ATTR_TXPWR_ACTION]) ++ if (!tb[NXP_ATTR_TXPWR_ACTION])  + return -EINVAL; -+ action = nla_get_u8(tb[NXPWIFI_ATTR_TXPWR_ACTION]); ++ action = nla_get_u8(tb[NXP_ATTR_TXPWR_ACTION]);  + -+ if (tb[NXPWIFI_ATTR_TXPWR_SUBBAND]) { -+ subband = nla_get_u8(tb[NXPWIFI_ATTR_TXPWR_SUBBAND]); ++ 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 == NXPWIFI_TXPWR_ACTION_GET) { -+ /* A GET selects which per-subband table to read back, so the -+ * subband selector is mandatory for a GET. -+ */ ++ } else if (action == NXP_TXPWR_ACTION_GET) { ++ /* A subband selector is required for GET operations. */  + return -EINVAL;  + }  + -+ if (action == NXPWIFI_TXPWR_ACTION_SET) { -+ if (!tb[NXPWIFI_ATTR_TXPWR_DATA]) ++ if (action == NXP_TXPWR_ACTION_SET) { ++ if (!tb[NXP_ATTR_TXPWR_DATA])  + return -EINVAL; -+ tlv_len = nla_len(tb[NXPWIFI_ATTR_TXPWR_DATA]); ++ tlv_len = nla_len(tb[NXP_ATTR_TXPWR_DATA]);  + }  +  + priv = nxpwifi_get_priv(adapter, NXPWIFI_BSS_ROLE_STA);  + if (!priv)  + return -ENODEV;  + -+ /* A SET only needs room for the supplied TLVs; a GET needs room for -+ * the firmware to write back the full per-subband table. -+ */ ++ /* Reserve space for the returned TRPC table on GET requests. */  + ch_trpc = kzalloc_flex(*ch_trpc, tlvbuffer, -+ (action == NXPWIFI_TXPWR_ACTION_SET) ? ++ (action == NXP_TXPWR_ACTION_SET) ?  + tlv_len : NXPWIFI_MAX_TRPC_BUF, GFP_KERNEL);  + if (!ch_trpc)  + return -ENOMEM;  + -+ ch_trpc->action = (action == NXPWIFI_TXPWR_ACTION_SET) ? ++ 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[NXPWIFI_ATTR_TXPWR_DATA]), tlv_len); -+ /* Firmware payload is action + subband followed by the TLV table. */ ++ nla_data(tb[NXP_ATTR_TXPWR_DATA]), tlv_len); ++  + ch_trpc->len = sizeof(ch_trpc->action) + sizeof(ch_trpc->subband) +  + tlv_len;  + @@ drivers/net/wireless/nxp/nxpwifi/vendor.c (new)  + if (ret)  + goto done;  + -+ if (action == NXPWIFI_TXPWR_ACTION_GET) { ++ if (action == NXP_TXPWR_ACTION_GET) {  + u16 hdr_len = sizeof(ch_trpc->action) +  + sizeof(ch_trpc->subband);  + u16 resp_len, skb_len;  + -+ /* Guard against a malformed firmware response before using -+ * ch_trpc->len to size the reply. -+ */  + 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);  + @@ drivers/net/wireless/nxp/nxpwifi/vendor.c (new)  + goto done;  + }  + -+ if (nla_put(resp, NXPWIFI_ATTR_TXPWR_DATA, resp_len, ++ if (nla_put(resp, NXP_ATTR_TXPWR_DATA, resp_len,  + ch_trpc->tlvbuffer)) {  + kfree_skb(resp);  + ret = -ENOBUFS; @@ drivers/net/wireless/nxp/nxpwifi/vendor.c (new)  + {  + .info = {  + .vendor_id = NXP_OUI, -+ .subcmd = NXPWIFI_VENDOR_CMD_TXPOWER_LIMIT, ++ .subcmd = NXP_VENDOR_CMD_TXPOWER_LIMIT,  + }, -+ /* TX power limits are a configuration/calibration setting and -+ * can be programmed while the interface is down, so no -+ * WIPHY_VENDOR_CMD_NEED_RUNNING flag is required. -+ */  + .flags = 0,  + .doit = nxpwifi_vendor_txpower_limit,  + .policy = nxpwifi_txpwr_policy, -+ .maxattr = NXPWIFI_ATTR_TXPWR_MAX, ++ .maxattr = NXP_ATTR_TXPWR_MAX,  + },  +};  + @@ drivers/net/wireless/nxp/nxpwifi/vendor.h (new)  +/*  + * NXP Wireless LAN device driver: vendor command interface  + * -+ * Copyright 2011-2026 NXP ++ * Copyright 2026 NXP  + */  +  +#ifndef __NXPWIFI_VENDOR_H__  +#define __NXPWIFI_VENDOR_H__  + -+#define NXP_OUI 0x006037 -+ -+enum nxpwifi_vendor_commands { -+ NXPWIFI_VENDOR_CMD_TXPOWER_LIMIT, -+}; -+ -+/* Actions for NXPWIFI_ATTR_TXPWR_ACTION. */ -+enum nxpwifi_txpwr_action { -+ NXPWIFI_TXPWR_ACTION_GET, -+ NXPWIFI_TXPWR_ACTION_SET, -+}; -+ -+/* Subband selectors for NXPWIFI_ATTR_TXPWR_SUBBAND: 0x00 is the 2.4 GHz -+ * band and 0x10..0x13 are the four 5 GHz subbands. -+ */ -+enum nxpwifi_txpwr_subband { -+ NXPWIFI_TXPWR_SUBBAND_2G = 0x00, -+ NXPWIFI_TXPWR_SUBBAND_5G_0 = 0x10, -+ NXPWIFI_TXPWR_SUBBAND_5G_1 = 0x11, -+ NXPWIFI_TXPWR_SUBBAND_5G_2 = 0x12, -+ NXPWIFI_TXPWR_SUBBAND_5G_3 = 0x13, -+}; -+ -+/* Attributes for NXPWIFI_VENDOR_CMD_TXPOWER_LIMIT. */ -+enum nxpwifi_txpwr_attrs { -+ NXPWIFI_ATTR_TXPWR_UNSPEC, -+ NXPWIFI_ATTR_TXPWR_ACTION, /* u8, enum nxpwifi_txpwr_action */ -+ NXPWIFI_ATTR_TXPWR_SUBBAND, /* u8, subband selector for GET */ -+ NXPWIFI_ATTR_TXPWR_DATA, /* binary, per-subband TRPC TLVs */ -+ -+ __NXPWIFI_ATTR_TXPWR_AFTER_LAST, -+ NXPWIFI_ATTR_TXPWR_MAX = __NXPWIFI_ATTR_TXPWR_AFTER_LAST - 1 -+}; ++#include   +  +void nxpwifi_set_vendor_commands(struct wiphy *wiphy);  +#endif /* __NXPWIFI_VENDOR_H__ */