Search Linux Wireless

Re: [PATCH 2/8] wifi: ath12k: MLO vdev bringup changes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10/23/2024 6:29 AM, Kalle Valo wrote:
> From: Sriram R <quic_srirrama@xxxxxxxxxxx>
> 
> Add changes to add the link vdevs dynamically whenever a channel is assigned
> from mac80211 for a link vdev. During vdev create, update ML address of the
> vdev to firmware using the new WMI parameter (WMI_TAG_MLO_VDEV_CREATE_PARAMS).
> 
> During vdev start, notify the firmware that this link vdev is newly added and
> also indicate all its known partners so that the firmware can take necessary
> actions to internally update the partners on the new link being added.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
> 
> Signed-off-by: Sriram R <quic_srirrama@xxxxxxxxxxx>
> Co-developed-by: Rameshkumar Sundaram <quic_ramess@xxxxxxxxxxx>
> Signed-off-by: Rameshkumar Sundaram <quic_ramess@xxxxxxxxxxx>
> Signed-off-by: Kalle Valo <quic_kvalo@xxxxxxxxxxx>
> ---
>  drivers/net/wireless/ath/ath12k/mac.c | 90 ++++++++++++++++++++++++++-
>  drivers/net/wireless/ath/ath12k/wmi.c | 85 ++++++++++++++++++++++++-
>  drivers/net/wireless/ath/ath12k/wmi.h | 74 ++++++++++++++++++++++
>  3 files changed, 244 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index f45f32f3b5f6..d4aa4540c8e6 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -648,6 +648,18 @@ struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id)
>  	return NULL;
>  }
>  
> +static bool ath12k_mac_is_ml_arvif(struct ath12k_link_vif *arvif)
> +{
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +
> +	lockdep_assert_wiphy(ahvif->ah->hw->wiphy);

should we have helper functions ath12k_<foo>_to_wiphy() to abstract out the
underlying linkages?

> +
> +	if (ahvif->vif->valid_links & BIT(arvif->link_id))
> +		return true;
> +
> +	return false;
> +}
> +
>  static struct ath12k *ath12k_mac_get_ar_by_chan(struct ieee80211_hw *hw,
>  						struct ieee80211_channel *channel)
>  {
> @@ -1512,7 +1524,8 @@ static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_link_vif *arvif)
>  	tx_ahvif = ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif);
>  	tx_arvif = &tx_ahvif->deflink;
>  	beacons = ieee80211_beacon_get_template_ema_list(ath12k_ar_to_hw(tx_arvif->ar),
> -							 tx_ahvif->vif, 0);
> +							 tx_ahvif->vif,
> +							 tx_arvif->link_id);
>  	if (!beacons || !beacons->cnt) {
>  		ath12k_warn(arvif->ar->ab,
>  			    "failed to get ema beacon templates from mac80211\n");
> @@ -1577,7 +1590,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_link_vif *arvif)
>  	}
>  
>  	bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_ahvif->vif,
> -					    &offs, 0);
> +					    &offs, tx_arvif->link_id);
>  	if (!bcn) {
>  		ath12k_warn(ab, "failed to get beacon template from mac80211\n");
>  		return -EPERM;
> @@ -1658,7 +1671,7 @@ static void ath12k_control_beaconing(struct ath12k_link_vif *arvif,
>  
>  	ahvif->aid = 0;
>  
> -	ether_addr_copy(arvif->bssid, info->bssid);
> +	ether_addr_copy(arvif->bssid, info->addr);
>  
>  	params.vdev_id = arvif->vdev_id;
>  	params.aid = ahvif->aid;
> @@ -6671,6 +6684,8 @@ static int ath12k_mac_setup_vdev_create_arg(struct ath12k_link_vif *arvif,
>  	struct ath12k_vif *ahvif = arvif->ahvif;
>  	int ret;
>  
> +	lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
> +
>  	arg->if_id = arvif->vdev_id;
>  	arg->type = ahvif->vdev_type;
>  	arg->subtype = ahvif->vdev_subtype;
> @@ -6702,6 +6717,17 @@ static int ath12k_mac_setup_vdev_create_arg(struct ath12k_link_vif *arvif,
>  	}
>  
>  	arg->if_stats_id = ath12k_mac_get_vdev_stats_id(arvif);
> +
> +	if (ath12k_mac_is_ml_arvif(arvif)) {
> +		if (hweight16(ahvif->vif->valid_links) > ATH12K_WMI_MLO_MAX_LINKS) {
> +			ath12k_warn(ar->ab, "too many MLO links during setting up vdev: %d",
> +				    ahvif->vif->valid_links);
> +			return -EINVAL;
> +		}
> +
> +		ether_addr_copy(arg->mld_addr, ahvif->vif->addr);
> +	}
> +
>  	return 0;
>  }
>  
> @@ -7639,6 +7665,61 @@ ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar,
>  	return down_mode;
>  }
>  
> +static void
> +ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif,
> +			     struct wmi_ml_arg *ml_arg)
> +{
> +	struct ath12k_vif *ahvif = arvif->ahvif;
> +	struct wmi_ml_partner_info *partner_info;
> +	struct ieee80211_bss_conf *link_conf;
> +	struct ath12k_link_vif *arvif_p;
> +	unsigned long links;
> +	u8 link_id;
> +
> +	lockdep_assert_wiphy(ahvif->ah->hw->wiphy);
> +
> +	if (!ath12k_mac_is_ml_arvif(arvif))
> +		return;
> +
> +	if (hweight16(ahvif->vif->valid_links) > ATH12K_WMI_MLO_MAX_LINKS)
> +		return;
> +
> +	rcu_read_lock();

what is this protecting?

do all of the statements between here and the for loop really need RCU protection?

> +
> +	ml_arg->enabled = true;
> +
> +	/* Driver always add a new link via VDEV START, FW takes
> +	 * care of internally adding this link to existing
> +	 * link vdevs which are advertised as partners below
> +	 */
> +	ml_arg->link_add = true;
> +	partner_info = ml_arg->partner_info;
> +
> +	links = ahvif->links_map;
> +	for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
> +		arvif_p = rcu_dereference(ahvif->link[link_id]);
> +
> +		if (WARN_ON(!arvif_p))
> +			continue;
> +
> +		if (arvif == arvif_p)
> +			continue;
> +
> +		link_conf = rcu_dereference(ahvif->vif->link_conf[arvif_p->link_id]);
> +
> +		if (!link_conf)
> +			continue;
> +
> +		partner_info->vdev_id = arvif_p->vdev_id;
> +		partner_info->hw_link_id = arvif_p->ar->pdev->hw_link_id;
> +		ether_addr_copy(partner_info->addr, link_conf->addr);
> +		ml_arg->num_partner_links++;
> +		partner_info++;
> +	}
> +
> +	rcu_read_unlock();
> +}
> +
>  static int
>  ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif,
>  			      struct ieee80211_chanctx_conf *ctx,
> @@ -7717,6 +7798,9 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif,
>  
>  	arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR);
>  
> +	if (!restart)
> +		ath12k_mac_mlo_get_vdev_args(arvif, &arg.ml);
> +
>  	ath12k_dbg(ab, ATH12K_DBG_MAC,
>  		   "mac vdev %d start center_freq %d phymode %s punct_bitmap 0x%x\n",
>  		   arg.vdev_id, arg.freq,
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index dced2aa9ba1a..e089b58bbea1 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -821,6 +821,8 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr,
>  	struct wmi_vdev_create_cmd *cmd;
>  	struct sk_buff *skb;
>  	struct ath12k_wmi_vdev_txrx_streams_params *txrx_streams;
> +	bool is_ml_vdev = is_valid_ether_addr(args->mld_addr);
> +	struct wmi_vdev_create_mlo_params *ml_params;
>  	struct wmi_tlv *tlv;
>  	int ret, len;
>  	void *ptr;
> @@ -830,7 +832,8 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr,
>  	 * both the bands.
>  	 */
>  	len = sizeof(*cmd) + TLV_HDR_SIZE +
> -		(WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams));
> +		(WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams)) +
> +		(is_ml_vdev ? TLV_HDR_SIZE + sizeof(*ml_params) : 0);
>  
>  	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
>  	if (!skb)
> @@ -879,6 +882,21 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr,
>  	txrx_streams->supported_rx_streams =
>  				cpu_to_le32(args->chains[NL80211_BAND_5GHZ].rx);
>  
> +	ptr += WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams);
> +
> +	if (is_ml_vdev) {
> +		tlv = ptr;
> +		tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT,
> +						 sizeof(*ml_params));
> +		ptr += TLV_HDR_SIZE;
> +		ml_params = ptr;
> +
> +		ml_params->tlv_header =
> +			ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_VDEV_CREATE_PARAMS,
> +					       sizeof(*ml_params));
> +		ether_addr_copy(ml_params->mld_macaddr.addr, args->mld_addr);
> +	}
> +
>  	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
>  		   "WMI vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n",
>  		   args->if_id, args->type, args->subtype,
> @@ -1020,19 +1038,27 @@ static void ath12k_wmi_put_wmi_channel(struct ath12k_wmi_channel_params *chan,
>  int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,
>  			  bool restart)
>  {
> +	struct wmi_vdev_start_mlo_params *ml_params;
> +	struct wmi_partner_link_info *partner_info;
>  	struct ath12k_wmi_pdev *wmi = ar->wmi;
>  	struct wmi_vdev_start_request_cmd *cmd;
>  	struct sk_buff *skb;
>  	struct ath12k_wmi_channel_params *chan;
>  	struct wmi_tlv *tlv;
>  	void *ptr;
> -	int ret, len;
> +	int ret, len, i, ml_arg_size = 0;
>  
>  	if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
>  		return -EINVAL;
>  
>  	len = sizeof(*cmd) + sizeof(*chan) + TLV_HDR_SIZE;
>  
> +	if (!restart && arg->ml.enabled) {
> +		ml_arg_size = TLV_HDR_SIZE + sizeof(*ml_params) +
> +			      TLV_HDR_SIZE + (arg->ml.num_partner_links *
> +					      sizeof(*partner_info));
> +		len += ml_arg_size;
> +	}
>  	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
>  	if (!skb)
>  		return -ENOMEM;
> @@ -1085,6 +1111,61 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,
>  
>  	ptr += sizeof(*tlv);
>  
> +	if (ml_arg_size) {
> +		tlv = ptr;
> +		tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT,
> +						 sizeof(*ml_params));
> +		ptr += TLV_HDR_SIZE;
> +
> +		ml_params = ptr;
> +
> +		ml_params->tlv_header =
> +			ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_VDEV_START_PARAMS,
> +					       sizeof(*ml_params));
> +
> +		ml_params->flags = le32_encode_bits(arg->ml.enabled,
> +						    ATH12K_WMI_FLAG_MLO_ENABLED) |
> +				   le32_encode_bits(arg->ml.assoc_link,
> +						    ATH12K_WMI_FLAG_MLO_ASSOC_LINK) |
> +				   le32_encode_bits(arg->ml.mcast_link,
> +						    ATH12K_WMI_FLAG_MLO_MCAST_VDEV) |
> +				   le32_encode_bits(arg->ml.link_add,
> +						    ATH12K_WMI_FLAG_MLO_LINK_ADD);
> +
> +		ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "vdev %d start ml flags 0x%x\n",
> +			   arg->vdev_id, ml_params->flags);
> +
> +		ptr += sizeof(*ml_params);
> +
> +		tlv = ptr;
> +		tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT,
> +						 arg->ml.num_partner_links *
> +						 sizeof(*partner_info));
> +		ptr += TLV_HDR_SIZE;
> +
> +		partner_info = ptr;
> +
> +		for (i = 0; i < arg->ml.num_partner_links; i++) {
> +			partner_info->tlv_header =
> +				ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_PARTNER_LINK_PARAMS,
> +						       sizeof(*partner_info));
> +			partner_info->vdev_id =
> +				cpu_to_le32(arg->ml.partner_info[i].vdev_id);
> +			partner_info->hw_link_id =
> +				cpu_to_le32(arg->ml.partner_info[i].hw_link_id);
> +			ether_addr_copy(partner_info->vdev_addr.addr,
> +					arg->ml.partner_info[i].addr);
> +
> +			ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "partner vdev %d hw_link_id %d macaddr%pM\n",
> +				   partner_info->vdev_id, partner_info->hw_link_id,
> +				   partner_info->vdev_addr.addr);
> +
> +			partner_info++;
> +		}
> +
> +		ptr = partner_info;
> +	}
> +
>  	ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "vdev %s id 0x%x freq 0x%x mode 0x%x\n",
>  		   restart ? "restart" : "start", arg->vdev_id,
>  		   arg->freq, arg->mode);
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 6f55dbdf629d..33b9643644c6 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -1929,6 +1929,19 @@ enum wmi_tlv_tag {
>  	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
>  	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
>  	WMI_TAG_EHT_RATE_SET = 0x3C4,
> +	WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5,
> +	WMI_TAG_MLO_TX_SEND_PARAMS,
> +	WMI_TAG_MLO_PARTNER_LINK_PARAMS,
> +	WMI_TAG_MLO_PARTNER_LINK_PARAMS_PEER_ASSOC,
> +	WMI_TAG_MLO_SETUP_CMD = 0x3C9,
> +	WMI_TAG_MLO_SETUP_COMPLETE_EVENT,
> +	WMI_TAG_MLO_READY_CMD,
> +	WMI_TAG_MLO_TEARDOWN_CMD,
> +	WMI_TAG_MLO_TEARDOWN_COMPLETE,
> +	WMI_TAG_MLO_PEER_ASSOC_PARAMS = 0x3D0,
> +	WMI_TAG_MLO_PEER_CREATE_PARAMS = 0x3D5,
> +	WMI_TAG_MLO_VDEV_START_PARAMS = 0x3D6,
> +	WMI_TAG_MLO_VDEV_CREATE_PARAMS = 0x3D7,
>  	WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8,
>  	WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD = 0x3D9,
>  	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD = 0x3FB,
> @@ -2740,6 +2753,7 @@ struct ath12k_wmi_vdev_create_arg {
>  	u8 if_stats_id;
>  	u32 mbssid_flags;
>  	u32 mbssid_tx_vdev_id;
> +	u8 mld_addr[ETH_ALEN];
>  };
>  
>  #define ATH12K_MAX_VDEV_STATS_ID	0x30
> @@ -2766,6 +2780,44 @@ struct ath12k_wmi_vdev_txrx_streams_params {
>  	__le32 supported_rx_streams;
>  } __packed;
>  
> +/* 2 word representation of MAC addr */
> +struct wmi_mac_addr {
> +	union {
> +		u8 addr[6];
> +		struct {
> +			u32 word0;
> +			u32 word1;
> +		} __packed;
> +	} __packed;
> +} __packed;

we already have:
/* 2 word representation of MAC addr */
struct ath12k_wmi_mac_addr_params {
	u8 addr[ETH_ALEN];
	u8 padding[2];
} __packed;

why aren't we consistently using that?

> +
> +struct wmi_vdev_create_mlo_params {
> +	__le32 tlv_header;
> +	struct wmi_mac_addr mld_macaddr;
> +} __packed;
> +
> +#define ATH12K_WMI_FLAG_MLO_ENABLED			BIT(0)
> +#define ATH12K_WMI_FLAG_MLO_ASSOC_LINK			BIT(1)
> +#define ATH12K_WMI_FLAG_MLO_PRIMARY_UMAC		BIT(2)
> +#define ATH12K_WMI_FLAG_MLO_LOGICAL_LINK_IDX_VALID	BIT(3)
> +#define ATH12K_WMI_FLAG_MLO_PEER_ID_VALID		BIT(4)
> +#define ATH12K_WMI_FLAG_MLO_MCAST_VDEV			BIT(5)
> +#define ATH12K_WMI_FLAG_MLO_EMLSR_SUPPORT		BIT(6)
> +#define ATH12K_WMI_FLAG_MLO_FORCED_INACTIVE		BIT(7)
> +#define ATH12K_WMI_FLAG_MLO_LINK_ADD			BIT(8)
> +
> +struct wmi_vdev_start_mlo_params {
> +	__le32 tlv_header;
> +	__le32 flags;
> +} __packed;
> +
> +struct wmi_partner_link_info {
> +	__le32 tlv_header;
> +	__le32 vdev_id;
> +	__le32 hw_link_id;
> +	struct wmi_mac_addr vdev_addr;
> +} __packed;
> +
>  struct wmi_vdev_delete_cmd {
>  	__le32 tlv_header;
>  	__le32 vdev_id;
> @@ -2909,6 +2961,27 @@ enum wmi_phy_mode {
>  	MODE_MAX = 33,
>  };
>  
> +#define ATH12K_WMI_MLO_MAX_LINKS 4
> +
> +struct wmi_ml_partner_info {
> +	u32 vdev_id;
> +	u32 hw_link_id;
> +	u8 addr[ETH_ALEN];
> +	bool assoc_link;
> +	bool primary_umac;
> +	bool logical_link_idx_valid;
> +	u32 logical_link_idx;
> +};
> +
> +struct wmi_ml_arg {
> +	bool enabled;
> +	bool assoc_link;
> +	bool mcast_link;
> +	bool link_add;
> +	u8 num_partner_links;
> +	struct wmi_ml_partner_info partner_info[ATH12K_WMI_MLO_MAX_LINKS];
> +};
> +
>  struct wmi_vdev_start_req_arg {
>  	u32 vdev_id;
>  	u32 freq;
> @@ -2946,6 +3019,7 @@ struct wmi_vdev_start_req_arg {
>  	u32 mbssid_flags;
>  	u32 mbssid_tx_vdev_id;
>  	u32 punct_bitmap;
> +	struct wmi_ml_arg ml;
>  };
>  
>  struct ath12k_wmi_peer_create_arg {





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux