[openwrt/openwrt] mac80211: backport SAR power limit support

LEDE Commits lede-commits at lists.infradead.org
Tue Nov 23 09:44:17 PST 2021


nbd pushed a commit to openwrt/openwrt.git, branch openwrt-21.02:
https://git.openwrt.org/52300733cd4a8e603e5d545a7e63b25889b895c2

commit 52300733cd4a8e603e5d545a7e63b25889b895c2
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Wed Jul 14 17:14:35 2021 +0200

    mac80211: backport SAR power limit support
    
    Needed for an upcoming mt76 update
    
    Signed-off-by: Felix Fietkau <nbd at nbd.name>
    (cherry-picked from commit 890bf06cef20015e2cec0274c87a9a2232691b6b)
---
 ...-common-API-to-configure-SAR-power-limita.patch | 398 +++++++++++++++++++++
 .../385-mac80211-add-ieee80211_set_sar_specs.patch |  51 +++
 .../500-mac80211_configure_antenna_gain.patch      |  12 +-
 3 files changed, 455 insertions(+), 6 deletions(-)

diff --git a/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch b/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch
new file mode 100644
index 0000000000..a47e29794c
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch
@@ -0,0 +1,398 @@
+From: Carl Huang <cjhuang at codeaurora.org>
+Date: Thu, 3 Dec 2020 05:37:26 -0500
+Subject: [PATCH] nl80211: add common API to configure SAR power limitations
+
+NL80211_CMD_SET_SAR_SPECS is added to configure SAR from
+user space. NL80211_ATTR_SAR_SPEC is used to pass the SAR
+power specification when used with NL80211_CMD_SET_SAR_SPECS.
+
+Wireless driver needs to register SAR type, supported frequency
+ranges to wiphy, so user space can query it. The index in
+frequency range is used to specify which sub band the power
+limitation applies to. The SAR type is for compatibility, so later
+other SAR mechanism can be implemented without breaking the user
+space SAR applications.
+
+Normal process is user space queries the SAR capability, and
+gets the index of supported frequency ranges and associates the
+power limitation with this index and sends to kernel.
+
+Here is an example of message send to kernel:
+8c 00 00 00 08 00 01 00 00 00 00 00 38 00 2b 81
+08 00 01 00 00 00 00 00 2c 00 02 80 14 00 00 80
+08 00 02 00 00 00 00 00 08 00 01 00 38 00 00 00
+14 00 01 80 08 00 02 00 01 00 00 00 08 00 01 00
+48 00 00 00
+
+NL80211_CMD_SET_SAR_SPECS:  0x8c
+NL80211_ATTR_WIPHY:     0x01(phy idx is 0)
+NL80211_ATTR_SAR_SPEC:  0x812b (NLA_NESTED)
+NL80211_SAR_ATTR_TYPE:  0x00 (NL80211_SAR_TYPE_POWER)
+NL80211_SAR_ATTR_SPECS: 0x8002 (NLA_NESTED)
+freq range 0 power: 0x38 in 0.25dbm unit (14dbm)
+freq range 1 power: 0x48 in 0.25dbm unit (18dbm)
+
+Signed-off-by: Carl Huang <cjhuang at codeaurora.org>
+Reviewed-by: Brian Norris <briannorris at chromium.org>
+Reviewed-by: Abhishek Kumar <kuabhs at chromium.org>
+Link: https://lore.kernel.org/r/20201203103728.3034-2-cjhuang@codeaurora.org
+[minor edits, NLA parse cleanups]
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -1737,6 +1737,54 @@ struct station_info {
+ 	u8 connected_to_as;
+ };
+ 
++/**
++ * struct cfg80211_sar_sub_specs - sub specs limit
++ * @power: power limitation in 0.25dbm
++ * @freq_range_index: index the power limitation applies to
++ */
++struct cfg80211_sar_sub_specs {
++	s32 power;
++	u32 freq_range_index;
++};
++
++/**
++ * struct cfg80211_sar_specs - sar limit specs
++ * @type: it's set with power in 0.25dbm or other types
++ * @num_sub_specs: number of sar sub specs
++ * @sub_specs: memory to hold the sar sub specs
++ */
++struct cfg80211_sar_specs {
++	enum nl80211_sar_type type;
++	u32 num_sub_specs;
++	struct cfg80211_sar_sub_specs sub_specs[];
++};
++
++
++/**
++ * @struct cfg80211_sar_chan_ranges - sar frequency ranges
++ * @start_freq:  start range edge frequency
++ * @end_freq:    end range edge frequency
++ */
++struct cfg80211_sar_freq_ranges {
++	u32 start_freq;
++	u32 end_freq;
++};
++
++/**
++ * struct cfg80211_sar_capa - sar limit capability
++ * @type: it's set via power in 0.25dbm or other types
++ * @num_freq_ranges: number of frequency ranges
++ * @freq_ranges: memory to hold the freq ranges.
++ *
++ * Note: WLAN driver may append new ranges or split an existing
++ * range to small ones and then append them.
++ */
++struct cfg80211_sar_capa {
++	enum nl80211_sar_type type;
++	u32 num_freq_ranges;
++	const struct cfg80211_sar_freq_ranges *freq_ranges;
++};
++
+ #if IS_ENABLED(CPTCFG_CFG80211)
+ /**
+  * cfg80211_get_station - retrieve information about a given station
+@@ -4259,6 +4307,8 @@ struct cfg80211_ops {
+ 				  struct cfg80211_tid_config *tid_conf);
+ 	int	(*reset_tid_config)(struct wiphy *wiphy, struct net_device *dev,
+ 				    const u8 *peer, u8 tids);
++	int	(*set_sar_specs)(struct wiphy *wiphy,
++				 struct cfg80211_sar_specs *sar);
+ };
+ 
+ /*
+@@ -5030,6 +5080,8 @@ struct wiphy {
+ 
+ 	u8 max_data_retry_count;
+ 
++	const struct cfg80211_sar_capa *sar_capa;
++
+ 	char priv[] __aligned(NETDEV_ALIGN);
+ };
+ 
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -405,6 +405,18 @@ nl80211_unsol_bcast_probe_resp_policy[NL
+ 						       .len = IEEE80211_MAX_DATA_LEN }
+ };
+ 
++static const struct nla_policy
++sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = {
++	[NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 },
++	[NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 },
++};
++
++static const struct nla_policy
++sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
++	[NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE),
++	[NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
++};
++
+ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
+ 	[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
+ 	[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
+@@ -739,6 +751,7 @@ static const struct nla_policy nl80211_p
+ 	[NL80211_ATTR_SAE_PWE] =
+ 		NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
+ 				 NL80211_SAE_PWE_BOTH),
++	[NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
+ 	[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
+ };
+ 
+@@ -2117,6 +2130,56 @@ fail:
+ 	return -ENOBUFS;
+ }
+ 
++static int
++nl80211_put_sar_specs(struct cfg80211_registered_device *rdev,
++		      struct sk_buff *msg)
++{
++	struct nlattr *sar_capa, *specs, *sub_freq_range;
++	u8 num_freq_ranges;
++	int i;
++
++	if (!rdev->wiphy.sar_capa)
++		return 0;
++
++	num_freq_ranges = rdev->wiphy.sar_capa->num_freq_ranges;
++
++	sar_capa = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC);
++	if (!sar_capa)
++		return -ENOSPC;
++
++	if (nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, rdev->wiphy.sar_capa->type))
++		goto fail;
++
++	specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS);
++	if (!specs)
++		goto fail;
++
++	/* report supported freq_ranges */
++	for (i = 0; i < num_freq_ranges; i++) {
++		sub_freq_range = nla_nest_start(msg, i + 1);
++		if (!sub_freq_range)
++			goto fail;
++
++		if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_START_FREQ,
++				rdev->wiphy.sar_capa->freq_ranges[i].start_freq))
++			goto fail;
++
++		if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_END_FREQ,
++				rdev->wiphy.sar_capa->freq_ranges[i].end_freq))
++			goto fail;
++
++		nla_nest_end(msg, sub_freq_range);
++	}
++
++	nla_nest_end(msg, specs);
++	nla_nest_end(msg, sar_capa);
++
++	return 0;
++fail:
++	nla_nest_cancel(msg, sar_capa);
++	return -ENOBUFS;
++}
++
+ struct nl80211_dump_wiphy_state {
+ 	s64 filter_wiphy;
+ 	long start;
+@@ -2366,6 +2429,8 @@ static int nl80211_send_wiphy(struct cfg
+ 			CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
+ 			CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
+ 			CMD(update_ft_ies, UPDATE_FT_IES);
++			if (rdev->wiphy.sar_capa)
++				CMD(set_sar_specs, SET_SAR_SPECS);
+ 		}
+ #undef CMD
+ 
+@@ -2691,6 +2756,11 @@ static int nl80211_send_wiphy(struct cfg
+ 
+ 		if (nl80211_put_tid_config_support(rdev, msg))
+ 			goto nla_put_failure;
++		state->split_start++;
++		break;
++	case 16:
++		if (nl80211_put_sar_specs(rdev, msg))
++			goto nla_put_failure;
+ 
+ 		/* done */
+ 		state->split_start = 0;
+@@ -14712,6 +14782,111 @@ static void nl80211_post_doit(__genl_con
+ 	}
+ }
+ 
++static int nl80211_set_sar_sub_specs(struct cfg80211_registered_device *rdev,
++				     struct cfg80211_sar_specs *sar_specs,
++				     struct nlattr *spec[], int index)
++{
++	u32 range_index, i;
++
++	if (!sar_specs || !spec)
++		return -EINVAL;
++
++	if (!spec[NL80211_SAR_ATTR_SPECS_POWER] ||
++	    !spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX])
++		return -EINVAL;
++
++	range_index = nla_get_u32(spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]);
++
++	/* check if range_index exceeds num_freq_ranges */
++	if (range_index >= rdev->wiphy.sar_capa->num_freq_ranges)
++		return -EINVAL;
++
++	/* check if range_index duplicates */
++	for (i = 0; i < index; i++) {
++		if (sar_specs->sub_specs[i].freq_range_index == range_index)
++			return -EINVAL;
++	}
++
++	sar_specs->sub_specs[index].power =
++		nla_get_s32(spec[NL80211_SAR_ATTR_SPECS_POWER]);
++
++	sar_specs->sub_specs[index].freq_range_index = range_index;
++
++	return 0;
++}
++
++static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info)
++{
++	struct cfg80211_registered_device *rdev = info->user_ptr[0];
++	struct nlattr *spec[NL80211_SAR_ATTR_SPECS_MAX + 1];
++	struct nlattr *tb[NL80211_SAR_ATTR_MAX + 1];
++	struct cfg80211_sar_specs *sar_spec;
++	enum nl80211_sar_type type;
++	struct nlattr *spec_list;
++	u32 specs;
++	int rem, err;
++
++	if (!rdev->wiphy.sar_capa || !rdev->ops->set_sar_specs)
++		return -EOPNOTSUPP;
++
++	if (!info->attrs[NL80211_ATTR_SAR_SPEC])
++		return -EINVAL;
++
++	nla_parse_nested(tb, NL80211_SAR_ATTR_MAX,
++			 info->attrs[NL80211_ATTR_SAR_SPEC],
++			 NULL, NULL);
++
++	if (!tb[NL80211_SAR_ATTR_TYPE] || !tb[NL80211_SAR_ATTR_SPECS])
++		return -EINVAL;
++
++	type = nla_get_u32(tb[NL80211_SAR_ATTR_TYPE]);
++	if (type != rdev->wiphy.sar_capa->type)
++		return -EINVAL;
++
++	specs = 0;
++	nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem)
++		specs++;
++
++	if (specs > rdev->wiphy.sar_capa->num_freq_ranges)
++		return -EINVAL;
++
++	sar_spec = kzalloc(sizeof(*sar_spec) +
++			   specs * sizeof(struct cfg80211_sar_sub_specs),
++			   GFP_KERNEL);
++	if (!sar_spec)
++		return -ENOMEM;
++
++	sar_spec->type = type;
++	specs = 0;
++	nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) {
++		nla_parse_nested(spec, NL80211_SAR_ATTR_SPECS_MAX,
++				 spec_list, NULL, NULL);
++
++		switch (type) {
++		case NL80211_SAR_TYPE_POWER:
++			if (nl80211_set_sar_sub_specs(rdev, sar_spec,
++						      spec, specs)) {
++				err = -EINVAL;
++				goto error;
++			}
++			break;
++		default:
++			err = -EINVAL;
++			goto error;
++		}
++		specs++;
++	}
++
++	sar_spec->num_sub_specs = specs;
++
++	rdev->cur_cmd_info = info;
++	err = rdev_set_sar_specs(rdev, sar_spec);
++	rdev->cur_cmd_info = NULL;
++error:
++	kfree(sar_spec);
++	return err;
++}
++
+ static __genl_const struct genl_ops nl80211_ops[] = {
+ 	{
+ 		.cmd = NL80211_CMD_GET_WIPHY,
+@@ -15575,6 +15750,14 @@ static const struct genl_small_ops nl802
+ 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
+ 				  NL80211_FLAG_NEED_RTNL,
+ 	},
++	{
++		.cmd = NL80211_CMD_SET_SAR_SPECS,
++		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
++		.doit = nl80211_set_sar_specs,
++		.flags = GENL_UNS_ADMIN_PERM,
++		.internal_flags = NL80211_FLAG_NEED_WIPHY |
++				  NL80211_FLAG_NEED_RTNL,
++	},
+ };
+ 
+ static struct genl_family nl80211_fam __genl_ro_after_init = {
+--- a/net/wireless/rdev-ops.h
++++ b/net/wireless/rdev-ops.h
+@@ -1356,4 +1356,16 @@ static inline int rdev_reset_tid_config(
+ 	return ret;
+ }
+ 
++static inline int rdev_set_sar_specs(struct cfg80211_registered_device *rdev,
++				     struct cfg80211_sar_specs *sar)
++{
++	int ret;
++
++	trace_rdev_set_sar_specs(&rdev->wiphy, sar);
++	ret = rdev->ops->set_sar_specs(&rdev->wiphy, sar);
++	trace_rdev_return_int(&rdev->wiphy, ret);
++
++	return ret;
++}
++
+ #endif /* __CFG80211_RDEV_OPS */
+--- a/net/wireless/trace.h
++++ b/net/wireless/trace.h
+@@ -3551,6 +3551,25 @@ TRACE_EVENT(rdev_reset_tid_config,
+ 	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x",
+ 		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids)
+ );
++
++TRACE_EVENT(rdev_set_sar_specs,
++	TP_PROTO(struct wiphy *wiphy, struct cfg80211_sar_specs *sar),
++	TP_ARGS(wiphy, sar),
++	TP_STRUCT__entry(
++		WIPHY_ENTRY
++		__field(u16, type)
++		__field(u16, num)
++	),
++	TP_fast_assign(
++		WIPHY_ASSIGN;
++		__entry->type = sar->type;
++		__entry->num = sar->num_sub_specs;
++
++	),
++	TP_printk(WIPHY_PR_FMT ", Set type:%d, num_specs:%d",
++		  WIPHY_PR_ARG, __entry->type, __entry->num)
++);
++
+ #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
+ 
+ #undef TRACE_INCLUDE_PATH
diff --git a/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch b/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch
new file mode 100644
index 0000000000..c351bc812a
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch
@@ -0,0 +1,51 @@
+From: Carl Huang <cjhuang at codeaurora.org>
+Date: Thu, 3 Dec 2020 05:37:27 -0500
+Subject: [PATCH] mac80211: add ieee80211_set_sar_specs
+
+This change registers ieee80211_set_sar_specs to
+mac80211_config_ops, so cfg80211 can call it.
+
+Signed-off-by: Carl Huang <cjhuang at codeaurora.org>
+Reviewed-by: Brian Norris <briannorris at chromium.org>
+Reviewed-by: Abhishek Kumar <kuabhs at chromium.org>
+Link: https://lore.kernel.org/r/20201203103728.3034-3-cjhuang@codeaurora.org
+Signed-off-by: Johannes Berg <johannes.berg at intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -4207,6 +4207,8 @@ struct ieee80211_ops {
+ 				   struct ieee80211_vif *vif);
+ 	void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 			      struct ieee80211_sta *sta, bool enabled);
++	int (*set_sar_specs)(struct ieee80211_hw *hw,
++			     const struct cfg80211_sar_specs *sar);
+ 	void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
+ 				      struct ieee80211_vif *vif,
+ 				      struct ieee80211_sta *sta, bool enabled);
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -4136,6 +4136,17 @@ static int ieee80211_reset_tid_config(st
+ 	return ret;
+ }
+ 
++static int ieee80211_set_sar_specs(struct wiphy *wiphy,
++				   struct cfg80211_sar_specs *sar)
++{
++	struct ieee80211_local *local = wiphy_priv(wiphy);
++
++	if (!local->ops->set_sar_specs)
++		return -EOPNOTSUPP;
++
++	return local->ops->set_sar_specs(&local->hw, sar);
++}
++
+ const struct cfg80211_ops mac80211_config_ops = {
+ 	.add_virtual_intf = ieee80211_add_iface,
+ 	.del_virtual_intf = ieee80211_del_iface,
+@@ -4239,4 +4250,5 @@ const struct cfg80211_ops mac80211_confi
+ 	.probe_mesh_link = ieee80211_probe_mesh_link,
+ 	.set_tid_config = ieee80211_set_tid_config,
+ 	.reset_tid_config = ieee80211_reset_tid_config,
++	.set_sar_specs = ieee80211_set_sar_specs,
+ };
diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
index cff870fcd6..b2ee61a6dc 100644
--- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
+++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
@@ -1,6 +1,6 @@
 --- a/include/net/cfg80211.h
 +++ b/include/net/cfg80211.h
-@@ -3745,6 +3745,7 @@ struct mgmt_frame_regs {
+@@ -3793,6 +3793,7 @@ struct mgmt_frame_regs {
   *	(as advertised by the nl80211 feature flag.)
   * @get_tx_power: store the current TX power into the dbm variable;
   *	return 0 if successful
@@ -8,7 +8,7 @@
   *
   * @set_wds_peer: set the WDS peer for a WDS interface
   *
-@@ -4067,6 +4068,7 @@ struct cfg80211_ops {
+@@ -4115,6 +4116,7 @@ struct cfg80211_ops {
  				enum nl80211_tx_power_setting type, int mbm);
  	int	(*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
  				int *dbm);
@@ -77,7 +77,7 @@
  static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
  				  const u8 *addr)
  {
-@@ -4191,6 +4204,7 @@ const struct cfg80211_ops mac80211_confi
+@@ -4202,6 +4215,7 @@ const struct cfg80211_ops mac80211_confi
  	.set_wiphy_params = ieee80211_set_wiphy_params,
  	.set_tx_power = ieee80211_set_tx_power,
  	.get_tx_power = ieee80211_get_tx_power,
@@ -129,15 +129,15 @@
  	local->hw.max_mtu = IEEE80211_MAX_DATA_LEN;
 --- a/net/wireless/nl80211.c
 +++ b/net/wireless/nl80211.c
-@@ -740,6 +740,7 @@ static const struct nla_policy nl80211_p
- 		NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
+@@ -753,6 +753,7 @@ static const struct nla_policy nl80211_p
  				 NL80211_SAE_PWE_BOTH),
+ 	[NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
  	[NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
 +	[NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
  };
  
  /* policy for the key attributes */
-@@ -3248,6 +3249,20 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -3318,6 +3319,20 @@ static int nl80211_set_wiphy(struct sk_b
  		if (result)
  			return result;
  	}



More information about the lede-commits mailing list