mbox series

[0/7] wifi: ath12k: add support for 6 GHz AP for various power modes

Message ID 20230919071724.15505-1-quic_aisr@quicinc.com
Headers show
Series wifi: ath12k: add support for 6 GHz AP for various power modes | expand

Message

Aishwarya R Sept. 19, 2023, 7:17 a.m. UTC
Add support for 6 GHz for various modes. Supports various power type of
AP(STANDARD_POWER_AP, INDOOR_AP, VERY_LOW_POWER_AP), power type of
STATION(DEFAULT_CLIENT, SUBORDINATE_CLIENT) and Power Spectral Density(PSD).

Implement the new rules for 6 GHz band in ath12k.
ath12k parse the transmit power envelope element in beacon of AP
and then set new wmi cmd WMI_VDEV_SET_TPC_POWER_CMDID to firmware
when connect to 6 GHz AP, also support backward compatibility with
firmware which not support new wmi cmd WMI_VDEV_SET_TPC_POWER_CMDID.

Aishwarya R (7):
  wifi: ath12k: add support to select 6 GHz Regulatory type
  wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type
  wifi: ath12k: get 6 GHz power type from HE operation element
  wifi: ath12k: save power spectral density(PSD) of regulatory rule
  wifi: ath12k: add parse of transmit power envelope element
  wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
  wifi: ath12k: send TPC power to firmware for 6 GHz VDEV

 drivers/net/wireless/ath/ath12k/core.h |  39 ++
 drivers/net/wireless/ath/ath12k/mac.c  | 515 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h  |   4 +
 drivers/net/wireless/ath/ath12k/reg.c  |  79 +++-
 drivers/net/wireless/ath/ath12k/reg.h  |   6 +-
 drivers/net/wireless/ath/ath12k/wmi.c  | 320 +++++++++++++--
 drivers/net/wireless/ath/ath12k/wmi.h  |  94 ++++-
 7 files changed, 1003 insertions(+), 54 deletions(-)

Comments

Jeff Johnson Sept. 19, 2023, 7:59 p.m. UTC | #1
On 9/19/2023 12:17 AM, Aishwarya R wrote:
> When 6 GHz AP or STA is assigned a channel ctx, it needs to

here again, what is "it"?
and why does "it" need the power type?

> extract the power type from HE operation element.
> If unset power type is present, by default IEEE80211_REG_LPI_AP
> power mode will be used.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++++
>   1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 5b9af264d305..01f81b087fa2 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5823,6 +5823,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>   	struct ath12k_vif *arvif = (void *)vif->drv_priv;
>   	int ret;
>   	struct ath12k_wmi_peer_create_arg param;
> +	enum ieee80211_ap_reg_power power_type;
>   
>   	mutex_lock(&ar->conf_mutex);
>   
> @@ -5830,6 +5831,16 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>   		   "mac chanctx assign ptr %pK vdev_id %i\n",
>   		   ctx, arvif->vdev_id);
>   
> +	if (ar->supports_6ghz && ctx->def.chan->band == NL80211_BAND_6GHZ &&
> +	    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> +	     arvif->vdev_type == WMI_VDEV_TYPE_AP)) {
> +		power_type = vif->bss_conf.power_type;
> +		ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx power type %d\n",
> +			   power_type);
> +		if (power_type == IEEE80211_REG_UNSET_AP)
> +			power_type = IEEE80211_REG_LPI_AP;
> +	}
> +
>   	/* for some targets bss peer must be created before vdev_start */
>   	if (ab->hw_params->vdev_start_delay &&
>   	    arvif->vdev_type != WMI_VDEV_TYPE_AP &&
Jeff Johnson Sept. 19, 2023, 8:21 p.m. UTC | #2
On 9/19/2023 12:17 AM, Aishwarya R wrote:
> When STATION is connected to a 6 GHz AP, or when AP boots up, it has

what is "it"?

> 2 ways to configure the power limit to firmware. Currently it
> sends 2 wmi command WMI_PDEV_PARAM_TXPOWER_LIMIT2G/
> WMI_PDEV_PARAM_TXPOWER_LIMIT5G to firmware.
> 
> Add support to send WMI_VDEV_SET_TPC_POWER_CMDID to firmware which
> include more parameters for power control. When firmware support
> SERVICE_EXT_TPC_REG, it means firmware support this feature, then ath12k
> discard BSS_CHANGED_TXPOWER flag from mac80211 which is used to the first
> way for 6 GHz band.

I'm not parsing this last sentence. s I mentioned in a previous patch, 
it will be easier to understand if you break it down:
what the current code does
what is wrong with the current code
how to fix the current code

> 
> The second way is to prepare the parameter for wmi command
> WMI_VDEV_SET_TPC_POWER_CMDID and send the firmware after vdev start
> response success from firmware.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Aishwarya R <quic_aisr@quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/mac.c | 25 +++++++++-
>   drivers/net/wireless/ath/ath12k/wmi.c | 67 +++++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h | 36 +++++++++++++-
>   3 files changed, 125 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 35bd472267c1..5505f933a4e1 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -2467,8 +2467,18 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
>   		ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev_id %i txpower %d\n",
>   			   arvif->vdev_id, info->txpower);
>   
> -		arvif->txpower = info->txpower;
> -		ath12k_mac_txpower_recalc(ar);
> +		if (ar->supports_6ghz && info->chandef.chan &&
> +		    info->chandef.chan->band == NL80211_BAND_6GHZ &&
> +		    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> +		     arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
> +		     test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT,
> +			      ar->ab->wmi_ab.svc_map)) {
> +			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
> +				   "discard tx power, change to set TPC power\n");
> +		} else {
> +			arvif->txpower = info->txpower;
> +			ath12k_mac_txpower_recalc(ar);
> +		}
>   	}
>   
>   	if (changed & BSS_CHANGED_MCAST_RATE &&
> @@ -5519,6 +5529,16 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>   		return ret;
>   	}
>   
> +	if (ar->supports_6ghz &&
> +	    chandef->chan->band == NL80211_BAND_6GHZ &&
> +	    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> +	     arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
> +	     test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map)) {

this complex test occurs in two places. can it be refactored into a 
well-named bool imperative function?

> +		ath12k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx);
> +		ath12k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id,
> +						   &arvif->reg_tpc_info);
> +	}
> +
>   	ar->num_started_vdevs++;
>   	ath12k_dbg(ab, ATH12K_DBG_MAC,  "vdev %pM started, vdev_id %d\n",
>   		   arvif->vif->addr, arvif->vdev_id);
> @@ -6304,6 +6324,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>   		if (power_type == IEEE80211_REG_UNSET_AP)
>   			power_type = IEEE80211_REG_LPI_AP;
>   
> +		arvif->chanctx = *ctx;
>   		if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
>   			ath12k_mac_parse_tx_pwr_env(ar, vif, ctx);
>   	}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 5bfca2513730..582c7e80c76b 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -2311,6 +2311,73 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>   	return ret;
>   }
>   
> +int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
> +				       u32 vdev_id,
> +				       struct ath12k_reg_tpc_power_info *param)
> +{
> +	struct ath12k_wmi_pdev *wmi = ar->wmi;
> +	struct wmi_vdev_set_tpc_power_cmd *cmd;
> +	struct wmi_vdev_ch_power_info_params *ch;
> +	struct sk_buff *skb;
> +	struct wmi_tlv *tlv;
> +	u8 *ptr;
> +	int i, ret, len;
> +
> +	len = sizeof(*cmd) + TLV_HDR_SIZE;
> +	len += (sizeof(*ch) * param->num_pwr_levels);
> +
> +	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	ptr = skb->data;
> +
> +	cmd = (struct wmi_vdev_set_tpc_power_cmd *)ptr;
> +	cmd->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
> +						 WMI_TAG_VDEV_SET_TPC_POWER_CMD) |
> +				      FIELD_PREP(WMI_TLV_LEN,
> +						 sizeof(*cmd) - TLV_HDR_SIZE));

use ath12k_wmi_tlv_cmd_hdr() everywhere you are creating a TLV header


> +	cmd->vdev_id = cpu_to_le32(vdev_id);
> +	cmd->psd_power = cpu_to_le32(param->is_psd_power);
> +	cmd->eirp_power = cpu_to_le32(param->eirp_power);
> +	cmd->power_type_6ghz = cpu_to_le32(param->power_type_6ghz);
> +	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
> +		   "wmi TPC vdev_id: %d is_psd_power: %d eirp_power: %d power_type_6ghz: %d\n",
> +		   vdev_id, param->is_psd_power, param->eirp_power,
> +		   param->power_type_6ghz);
> +
> +	ptr += sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)ptr;
> +	tlv->header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
> +				  FIELD_PREP(WMI_TLV_LEN,
> +					     param->num_pwr_levels * sizeof(*ch)));
> +
> +	ptr += TLV_HDR_SIZE;
> +	ch = (struct wmi_vdev_ch_power_info_params *)ptr;
> +
> +	for (i = 0; i < param->num_pwr_levels; i++, ch++) {
> +		ch->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
> +							WMI_TAG_VDEV_CH_POWER_INFO) |
> +					     FIELD_PREP(WMI_TLV_LEN,
> +							sizeof(*ch) - TLV_HDR_SIZE));
> +
> +		ch->chan_cfreq = cpu_to_le32(param->chan_power_info[i].chan_cfreq);
> +		ch->tx_power = cpu_to_le32(param->chan_power_info[i].tx_power);
> +
> +		ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
> +			   "wmi TPC chan_cfreq: %d , tx_power: %d\n",
> +			   ch->chan_cfreq, ch->tx_power);
> +	}
> +
> +	ret = ath12k_wmi_cmd_send(wmi, skb,
> +				  WMI_VDEV_SET_TPC_POWER_CMDID);
> +	if (ret) {
> +		ath12k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n");
> +		dev_kfree_skb(skb);
> +	}
> +	return ret;
> +}
> +
>   int ath12k_wmi_send_scan_stop_cmd(struct ath12k *ar,
>   				  struct ath12k_wmi_scan_cancel_arg *arg)
>   {
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 9f24f8ded52f..a97eb2544ab0 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -24,6 +24,7 @@
>   
>   struct ath12k_base;
>   struct ath12k;
> +struct ath12k_reg_tpc_power_info;
>   
>   /* There is no signed version of __le32, so for a temporary solution come
>    * up with our own version. The idea is from fs/ntfs/endian.h.
> @@ -388,6 +389,7 @@ enum wmi_tlv_cmd_id {
>   	WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID,
>   	WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID,
>   	WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID,
> +	WMI_VDEV_SET_TPC_POWER_CMDID,
>   	WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER),
>   	WMI_PEER_DELETE_CMDID,
>   	WMI_PEER_FLUSH_TIDS_CMDID,
> @@ -1924,6 +1926,8 @@ enum wmi_tlv_tag {
>   	WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
>   	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
>   	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
> +	WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
> +	WMI_TAG_VDEV_CH_POWER_INFO,
>   	WMI_TAG_MAX
>   };
>   
> @@ -2148,7 +2152,8 @@ enum wmi_tlv_service {
>   	WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
>   	WMI_TLV_SERVICE_EXT2_MSG = 220,
>   
> -	WMI_MAX_EXT_SERVICE
> +	WMI_MAX_EXT_SERVICE,
> +	WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT = 280,
>   };
>   
>   enum {
> @@ -3037,6 +3042,32 @@ struct ath12k_wmi_element_info_arg {
>   	u8 *ptr;
>   };
>   
> +struct wmi_vdev_ch_power_info_params {
> +	__le32 tlv_header;
> +	__le32 chan_cfreq; /* Channel center frequency (MHz) */
> +	/* Unit: dBm, either PSD/EIRP power for this frequency or
> +	 * incremental for non-PSD BW
> +	 */
> +	__le32 tx_power;
> +} __packed;
> +
> +struct wmi_vdev_set_tpc_power_cmd {
> +	__le32 tlv_header;
> +	__le32 vdev_id;
> +	__le32 psd_power; /* Value: 0 or 1, is PSD power or not */
> +	__le32 eirp_power;
> +	/* Maximum EIRP power (dBm units), valid only if power is PSD */
> +	__le32 power_type_6ghz; /* Type: WMI_6 GHz_REG_TYPE, used for halphy CTL lookup */
> +	/* This fixed_param TLV is followed by the below TLVs:
> +	 * num_pwr_levels of wmi_vdev_ch_power_info
> +	 * For PSD power, it is the PSD/EIRP power of the frequency (20 MHz chunks).
> +	 * For non-psd power, the power values are for 20, 40, and till
> +	 * BSS BW power levels.
> +	 * The num_pwr_levels will be checked by sw how many elements present
> +	 * in the variable-length array.
> +	 */
> +} __packed;
> +
>   #define WMI_IE_BITMAP_SIZE             8
>   
>   #define WMI_SCAN_MAX_NUM_SSID                0x0A
> @@ -4824,5 +4855,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
>   			       struct sk_buff *tmpl);
>   int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
>   			   enum wmi_host_hw_mode_config_type mode);
> +int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
> +				       u32 vdev_id,
> +				       struct ath12k_reg_tpc_power_info *param);
>   
>   #endif
Kalle Valo Sept. 20, 2023, 1:34 p.m. UTC | #3
"Aishwarya R (QUIC)" <quic_aisr@quicinc.com> writes:

[deleting ~500 lines of unnecessary quotes]

> Thanks for your review. I will address all your comments in next revision.

Please edit your quotes and only include the necessary information in
your reply. These kind of huge mails make use of patchwork very
difficult:

https://patchwork.kernel.org/project/linux-wireless/patch/20230919071724.15505-2-quic_aisr@quicinc.com/