diff mbox series

[v4,04/12] wifi: ath12k: vdev statemachine changes for single wiphy

Message ID 20240312135557.1778379-5-quic_ramess@quicinc.com (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show
Series wifi: ath12k: Add single wiphy support | expand

Commit Message

Rameshkumar Sundaram March 12, 2024, 1:55 p.m. UTC
From: Sriram R <quic_srirrama@quicinc.com>

With single wiphy, multiple radios are combined into a single wiphy.
Since any channel can be assigned to a vif being brought up,
the vdev cannot be created during add_interface(). Hence defer the
vdev creation till channel assignment.

If only one radio is part of the wiphy, then the existing logic
is maintained, i.e vdevs are created during add interface and
started during channel assignment. This ensures no functional changes
to single pdev devices which has only one radio in the SoC.

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@quicinc.com>
Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.h |   1 +
 drivers/net/wireless/ath/ath12k/hw.h   |   1 +
 drivers/net/wireless/ath/ath12k/mac.c  | 203 +++++++++++++++++--------
 3 files changed, 144 insertions(+), 61 deletions(-)

Comments

Jeff Johnson March 12, 2024, 10:25 p.m. UTC | #1
On 3/12/2024 6:55 AM, Rameshkumar Sundaram wrote:
> From: Sriram R <quic_srirrama@quicinc.com>
> 
> With single wiphy, multiple radios are combined into a single wiphy.
> Since any channel can be assigned to a vif being brought up,
> the vdev cannot be created during add_interface(). Hence defer the
> vdev creation till channel assignment.
> 
> If only one radio is part of the wiphy, then the existing logic
> is maintained, i.e vdevs are created during add interface and
> started during channel assignment. This ensures no functional changes
> to single pdev devices which has only one radio in the SoC.
> 
> 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@quicinc.com>
> Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
> ---
>  drivers/net/wireless/ath/ath12k/core.h |   1 +
>  drivers/net/wireless/ath/ath12k/hw.h   |   1 +
>  drivers/net/wireless/ath/ath12k/mac.c  | 203 +++++++++++++++++--------
>  3 files changed, 144 insertions(+), 61 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 53bcf9416efd..70daec38d486 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -251,6 +251,7 @@ struct ath12k_vif {
>  		} ap;
>  	} u;
>  
> +	bool is_created;
>  	bool is_started;
>  	bool is_up;
>  	u32 aid;
> diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
> index 87965980b938..e34c4f76c1ec 100644
> --- a/drivers/net/wireless/ath/ath12k/hw.h
> +++ b/drivers/net/wireless/ath/ath12k/hw.h
> @@ -80,6 +80,7 @@
>  #define TARGET_RX_PEER_METADATA_VER_V1A	2
>  #define TARGET_RX_PEER_METADATA_VER_V1B	3
>  
> +#define ATH12K_HW_DEFAULT_QUEUE		0
>  #define ATH12K_HW_MAX_QUEUES		4
>  #define ATH12K_QUEUE_LEN		4096
>  
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 4afaba3ba934..b6afef81a2d8 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5780,64 +5780,24 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
>  	ath12k_mac_update_vif_offload(arvif);
>  }
>  
> -static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
> -				       struct ieee80211_vif *vif)
> +static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
>  {
> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
> -	struct ath12k *ar;
> -	struct ath12k_base *ab;
> +	struct ath12k_hw *ah = ar->ah;
> +	struct ath12k_base *ab = ar->ab;
> +	struct ieee80211_hw *hw = ah->hw;
>  	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>  	struct ath12k_wmi_vdev_create_arg vdev_arg = {0};
>  	struct ath12k_wmi_peer_create_arg peer_param;
>  	u32 param_id, param_value;
>  	u16 nss;
>  	int i;
> -	int ret;
> -	int bit;
> -
> -	vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
> +	int ret, vdev_id;
>  
> -	ar = ath12k_ah_to_ar(ah, 0);
> -	ab = ar->ab;
> -
> -	mutex_lock(&ar->conf_mutex);
> -
> -	if (vif->type == NL80211_IFTYPE_AP &&
> -	    ar->num_peers > (ar->max_num_peers - 1)) {
> -		ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
> -		ret = -ENOBUFS;
> -		goto err;
> -	}
> -
> -	if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
> -		ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
> -			    TARGET_NUM_VDEVS);
> -		ret = -EBUSY;
> -		goto err;
> -	}
> -
> -	memset(arvif, 0, sizeof(*arvif));
> +	lockdep_assert_held(&ar->conf_mutex);
>  
>  	arvif->ar = ar;
> -	arvif->vif = vif;
> -
> -	INIT_LIST_HEAD(&arvif->list);
> -
> -	/* Should we initialize any worker to handle connection loss indication
> -	 * from firmware in sta mode?
> -	 */
> -
> -	for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
> -		arvif->bitrate_mask.control[i].legacy = 0xffffffff;
> -		memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
> -		       sizeof(arvif->bitrate_mask.control[i].ht_mcs));
> -		memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
> -		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
> -	}
> -
> -	bit = __ffs64(ab->free_vdev_map);
> -
> -	arvif->vdev_id = bit;
> +	vdev_id = __ffs64(ab->free_vdev_map);
> +	arvif->vdev_id = vdev_id;
>  	arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
>  
>  	switch (vif->type) {
> @@ -5861,7 +5821,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>  		break;
>  	case NL80211_IFTYPE_MONITOR:
>  		arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
> -		ar->monitor_vdev_id = bit;
> +		ar->monitor_vdev_id = vdev_id;
>  		break;
>  	case NL80211_IFTYPE_P2P_DEVICE:
>  		arvif->vdev_type = WMI_VDEV_TYPE_STA;
> @@ -5872,7 +5832,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>  		break;
>  	}
>  
> -	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac add interface id %d type %d subtype %d map %llx\n",
> +	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev create id %d type %d subtype %d map %llx\n",
>  		   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
>  		   ab->free_vdev_map);
>  
> @@ -5890,6 +5850,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>  	}
>  
>  	ar->num_created_vdevs++;
> +	arvif->is_created = true;
>  	ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM created, vdev_id %d\n",
>  		   vif->addr, arvif->vdev_id);
>  	ar->allocated_vdev_map |= 1LL << arvif->vdev_id;
> @@ -5990,8 +5951,6 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>  	if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled)
>  		ath12k_mac_monitor_vdev_create(ar);
>  
> -	mutex_unlock(&ar->conf_mutex);
> -
>  	return ret;
>  
>  err_peer_del:
> @@ -6017,6 +5976,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>  err_vdev_del:
>  	ath12k_wmi_vdev_delete(ar, arvif->vdev_id);
>  	ar->num_created_vdevs--;
> +	arvif->is_created = false;
>  	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
>  	ab->free_vdev_map |= 1LL << arvif->vdev_id;
>  	ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id);
> @@ -6025,9 +5985,104 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>  	spin_unlock_bh(&ar->data_lock);
>  
>  err:
> +	arvif->ar = NULL;
> +	return ret;
> +}
> +
> +static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
> +						    struct ieee80211_vif *vif,
> +						    struct ieee80211_chanctx_conf *ctx)
> +{
> +	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	struct ath12k_hw *ah = hw->priv;
> +	struct ath12k_base *ab;
> +	struct ath12k *ar;
> +	int ret;
> +	u8 bit;
> +
> +	if (arvif->ar) {
> +		WARN_ON(!arvif->is_created);
> +		goto out;
> +	}
> +
> +	if (ah->num_radio == 1)
> +		ar = ah->radio;
> +	else if (ctx)
> +		ar = ath12k_get_ar_by_ctx(hw, ctx);
> +	else
> +		return NULL;
> +
> +	if (!ar)
> +		goto out;

why does this goto out instead of just return NULL?

> +
> +	ab = ar->ab;
> +
> +	mutex_lock(&ar->conf_mutex);
> +
> +	if (vif->type == NL80211_IFTYPE_AP &&
> +	    ar->num_peers > (ar->max_num_peers - 1)) {
> +		ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
> +		ret = -ENOBUFS;
> +		goto unlock;

nothing is done with ret so setting it is pointless

> +	}
> +
> +	if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
> +		ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
> +			    TARGET_NUM_VDEVS);
> +		ret = -EBUSY;
> +		goto unlock;

nothing is done with ret so setting it is pointless

> +	}
> +
> +	ret = ath12k_mac_vdev_create(ar, vif);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to create vdev %d ret %d", bit, ret);
> +		goto unlock;
> +	}
> +
> +	/* TODO If the vdev is created during channel assign and not during
> +	 * add_interface(), Apply any parameters for the vdev which were received
> +	 * after add_interface, corresponding to this vif.
> +	 */
> +unlock:
>  	mutex_unlock(&ar->conf_mutex);
> +out:
> +	return arvif->ar;
> +}
>  
> -	return ret;
> +static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
> +				       struct ieee80211_vif *vif)
> +{
> +	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
> +	int i;
> +
> +	memset(arvif, 0, sizeof(*arvif));
> +
> +	arvif->vif = vif;
> +
> +	INIT_LIST_HEAD(&arvif->list);
> +
> +	for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
> +		arvif->bitrate_mask.control[i].legacy = 0xffffffff;
> +		memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
> +		       sizeof(arvif->bitrate_mask.control[i].ht_mcs));
> +		memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
> +		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
> +	}
> +
> +	/* Allocate Default Queue now and reassign during actual vdev create */
> +	vif->cab_queue = ATH12K_HW_DEFAULT_QUEUE;
> +	for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
> +		vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE;
> +
> +	vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
> +
> +	/* For single radio wiphy(i.e ah->num_radio is 1), create the vdev
> +	 * during add_interface itself, for multi radio wiphy, defer the vdev
> +	 * creation until channel_assign to determine the radio on which the
> +	 * vdev needs to be created
> +	 */
> +	ath12k_mac_assign_vif_to_vdev(hw, vif, NULL);
> +	return 0;
>  }
>  
>  static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif)
> @@ -6058,14 +6113,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif
>  static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
>  					   struct ieee80211_vif *vif)
>  {
> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>  	struct ath12k_base *ab;
>  	unsigned long time_left;
>  	int ret;
>  
> -	ar = ath12k_ah_to_ar(ah, 0);
> +	if (!arvif->is_created)
> +		return;
> +
> +	ar = arvif->ar;
>  	ab = ar->ab;
>  
>  	mutex_lock(&ar->conf_mutex);
> @@ -6107,6 +6164,7 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
>  	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
>  	ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id);
>  	ar->num_created_vdevs--;
> +	arvif->is_created = false;
>  
>  	ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
>  		   vif->addr, arvif->vdev_id);
> @@ -6759,14 +6817,21 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>  				 struct ieee80211_bss_conf *link_conf,
>  				 struct ieee80211_chanctx_conf *ctx)
>  {
> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  	struct ath12k_base *ab;
>  	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>  	int ret;
>  	struct ath12k_wmi_peer_create_arg param;
>  
> -	ar = ath12k_ah_to_ar(ah, 0);
> +	/* For multi radio wiphy, the vdev was not created during add_interface
> +	 * create now since we have a channel ctx now to assign to a specific ar/fw
> +	 */
> +	ar = ath12k_mac_assign_vif_to_vdev(hw, vif, ctx);
> +	if (!ar) {
> +		WARN_ON(1);
> +		return -EINVAL;
> +	}
> +
>  	ab = ar->ab;
>  
>  	mutex_lock(&ar->conf_mutex);
> @@ -6842,13 +6907,22 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
>  				   struct ieee80211_bss_conf *link_conf,
>  				   struct ieee80211_chanctx_conf *ctx)
>  {
> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  	struct ath12k_base *ab;
>  	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>  	int ret;
>  
> -	ar = ath12k_ah_to_ar(ah, 0);
> +	/* The vif is expected to be attached to an ar's VDEV.
> +	 * We leave the vif/vdev in this function as is
> +	 * and not delete the vdev symmetric to assign_vif_chanctx()
> +	 * the VDEV will be deleted and unassigned either during
> +	 * remove_interface() or when there is a change in channel
> +	 * that moves the vif to a new ar
> +	 */
> +	if (!arvif->is_created)
> +		return;
> +
> +	ar = arvif->ar;
>  	ab = ar->ab;
>  
>  	mutex_lock(&ar->conf_mutex);
> @@ -6900,13 +6974,20 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
>  				 int n_vifs,
>  				 enum ieee80211_chanctx_switch_mode mode)
>  {
> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>  	struct ath12k *ar;
>  
> -	ar = ath12k_ah_to_ar(ah, 0);
> +	ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx);
> +	if (!ar)
> +		return -EINVAL;
>  
>  	mutex_lock(&ar->conf_mutex);
>  
> +	/* Switching channels across radio is not allowed */
> +	if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) {
> +		mutex_unlock(&ar->conf_mutex);
> +		return -EINVAL;
> +	}
> +
>  	ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
>  		   "mac chanctx switch n_vifs %d mode %d\n",
>  		   n_vifs, mode);
Rameshkumar Sundaram March 13, 2024, 2:36 p.m. UTC | #2
On 3/13/2024 3:55 AM, Jeff Johnson wrote:
> On 3/12/2024 6:55 AM, Rameshkumar Sundaram wrote:
>> From: Sriram R <quic_srirrama@quicinc.com>
>>
>> With single wiphy, multiple radios are combined into a single wiphy.
>> Since any channel can be assigned to a vif being brought up,
>> the vdev cannot be created during add_interface(). Hence defer the
>> vdev creation till channel assignment.
>>
>> If only one radio is part of the wiphy, then the existing logic
>> is maintained, i.e vdevs are created during add interface and
>> started during channel assignment. This ensures no functional changes
>> to single pdev devices which has only one radio in the SoC.
>>
>> 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@quicinc.com>
>> Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
>> ---
>>   drivers/net/wireless/ath/ath12k/core.h |   1 +
>>   drivers/net/wireless/ath/ath12k/hw.h   |   1 +
>>   drivers/net/wireless/ath/ath12k/mac.c  | 203 +++++++++++++++++--------
>>   3 files changed, 144 insertions(+), 61 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
>> index 53bcf9416efd..70daec38d486 100644
>> --- a/drivers/net/wireless/ath/ath12k/core.h
>> +++ b/drivers/net/wireless/ath/ath12k/core.h
>> @@ -251,6 +251,7 @@ struct ath12k_vif {
>>   		} ap;
>>   	} u;
>>   
>> +	bool is_created;
>>   	bool is_started;
>>   	bool is_up;
>>   	u32 aid;
>> diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
>> index 87965980b938..e34c4f76c1ec 100644
>> --- a/drivers/net/wireless/ath/ath12k/hw.h
>> +++ b/drivers/net/wireless/ath/ath12k/hw.h
>> @@ -80,6 +80,7 @@
>>   #define TARGET_RX_PEER_METADATA_VER_V1A	2
>>   #define TARGET_RX_PEER_METADATA_VER_V1B	3
>>   
>> +#define ATH12K_HW_DEFAULT_QUEUE		0
>>   #define ATH12K_HW_MAX_QUEUES		4
>>   #define ATH12K_QUEUE_LEN		4096
>>   
>> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
>> index 4afaba3ba934..b6afef81a2d8 100644
>> --- a/drivers/net/wireless/ath/ath12k/mac.c
>> +++ b/drivers/net/wireless/ath/ath12k/mac.c
>> @@ -5780,64 +5780,24 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
>>   	ath12k_mac_update_vif_offload(arvif);
>>   }
>>   
>> -static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>> -				       struct ieee80211_vif *vif)
>> +static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
>>   {
>> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>> -	struct ath12k *ar;
>> -	struct ath12k_base *ab;
>> +	struct ath12k_hw *ah = ar->ah;
>> +	struct ath12k_base *ab = ar->ab;
>> +	struct ieee80211_hw *hw = ah->hw;
>>   	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>>   	struct ath12k_wmi_vdev_create_arg vdev_arg = {0};
>>   	struct ath12k_wmi_peer_create_arg peer_param;
>>   	u32 param_id, param_value;
>>   	u16 nss;
>>   	int i;
>> -	int ret;
>> -	int bit;
>> -
>> -	vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
>> +	int ret, vdev_id;
>>   
>> -	ar = ath12k_ah_to_ar(ah, 0);
>> -	ab = ar->ab;
>> -
>> -	mutex_lock(&ar->conf_mutex);
>> -
>> -	if (vif->type == NL80211_IFTYPE_AP &&
>> -	    ar->num_peers > (ar->max_num_peers - 1)) {
>> -		ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
>> -		ret = -ENOBUFS;
>> -		goto err;
>> -	}
>> -
>> -	if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
>> -		ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
>> -			    TARGET_NUM_VDEVS);
>> -		ret = -EBUSY;
>> -		goto err;
>> -	}
>> -
>> -	memset(arvif, 0, sizeof(*arvif));
>> +	lockdep_assert_held(&ar->conf_mutex);
>>   
>>   	arvif->ar = ar;
>> -	arvif->vif = vif;
>> -
>> -	INIT_LIST_HEAD(&arvif->list);
>> -
>> -	/* Should we initialize any worker to handle connection loss indication
>> -	 * from firmware in sta mode?
>> -	 */
>> -
>> -	for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
>> -		arvif->bitrate_mask.control[i].legacy = 0xffffffff;
>> -		memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
>> -		       sizeof(arvif->bitrate_mask.control[i].ht_mcs));
>> -		memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
>> -		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
>> -	}
>> -
>> -	bit = __ffs64(ab->free_vdev_map);
>> -
>> -	arvif->vdev_id = bit;
>> +	vdev_id = __ffs64(ab->free_vdev_map);
>> +	arvif->vdev_id = vdev_id;
>>   	arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
>>   
>>   	switch (vif->type) {
>> @@ -5861,7 +5821,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>>   		break;
>>   	case NL80211_IFTYPE_MONITOR:
>>   		arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
>> -		ar->monitor_vdev_id = bit;
>> +		ar->monitor_vdev_id = vdev_id;
>>   		break;
>>   	case NL80211_IFTYPE_P2P_DEVICE:
>>   		arvif->vdev_type = WMI_VDEV_TYPE_STA;
>> @@ -5872,7 +5832,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>>   		break;
>>   	}
>>   
>> -	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac add interface id %d type %d subtype %d map %llx\n",
>> +	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev create id %d type %d subtype %d map %llx\n",
>>   		   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
>>   		   ab->free_vdev_map);
>>   
>> @@ -5890,6 +5850,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>>   	}
>>   
>>   	ar->num_created_vdevs++;
>> +	arvif->is_created = true;
>>   	ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM created, vdev_id %d\n",
>>   		   vif->addr, arvif->vdev_id);
>>   	ar->allocated_vdev_map |= 1LL << arvif->vdev_id;
>> @@ -5990,8 +5951,6 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>>   	if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled)
>>   		ath12k_mac_monitor_vdev_create(ar);
>>   
>> -	mutex_unlock(&ar->conf_mutex);
>> -
>>   	return ret;
>>   
>>   err_peer_del:
>> @@ -6017,6 +5976,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>>   err_vdev_del:
>>   	ath12k_wmi_vdev_delete(ar, arvif->vdev_id);
>>   	ar->num_created_vdevs--;
>> +	arvif->is_created = false;
>>   	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
>>   	ab->free_vdev_map |= 1LL << arvif->vdev_id;
>>   	ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id);
>> @@ -6025,9 +5985,104 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>>   	spin_unlock_bh(&ar->data_lock);
>>   
>>   err:
>> +	arvif->ar = NULL;
>> +	return ret;
>> +}
>> +
>> +static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
>> +						    struct ieee80211_vif *vif,
>> +						    struct ieee80211_chanctx_conf *ctx)
>> +{
>> +	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>> +	struct ath12k_hw *ah = hw->priv;
>> +	struct ath12k_base *ab;
>> +	struct ath12k *ar;
>> +	int ret;
>> +	u8 bit;
>> +
>> +	if (arvif->ar) {
>> +		WARN_ON(!arvif->is_created);
>> +		goto out;
>> +	}
>> +
>> +	if (ah->num_radio == 1)
>> +		ar = ah->radio;
>> +	else if (ctx)
>> +		ar = ath12k_get_ar_by_ctx(hw, ctx);
>> +	else
>> +		return NULL;
>> +
>> +	if (!ar)
>> +		goto out;
> 
> why does this goto out instead of just return NULL?
yeah, we can. Thanks for pointing out, will fix it in next version.
> 
>> +
>> +	ab = ar->ab;
>> +
>> +	mutex_lock(&ar->conf_mutex);
>> +
>> +	if (vif->type == NL80211_IFTYPE_AP &&
>> +	    ar->num_peers > (ar->max_num_peers - 1)) {
>> +		ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
>> +		ret = -ENOBUFS;
>> +		goto unlock;
> 
> nothing is done with ret so setting it is pointless
> 
Sure, will remove this and below instance too.
>> +	}
>> +
>> +	if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
>> +		ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
>> +			    TARGET_NUM_VDEVS);
>> +		ret = -EBUSY;
>> +		goto unlock;
> 
> nothing is done with ret so setting it is pointless
> 
>> +	}
>> +
>> +	ret = ath12k_mac_vdev_create(ar, vif);
>> +	if (ret) {
>> +		ath12k_warn(ab, "failed to create vdev %d ret %d", bit, ret);
>> +		goto unlock;
>> +	}
>> +
>> +	/* TODO If the vdev is created during channel assign and not during
>> +	 * add_interface(), Apply any parameters for the vdev which were received
>> +	 * after add_interface, corresponding to this vif.
>> +	 */
>> +unlock:
>>   	mutex_unlock(&ar->conf_mutex);
>> +out:
>> +	return arvif->ar;
>> +}
>>   
>> -	return ret;
>> +static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
>> +				       struct ieee80211_vif *vif)
>> +{
>> +	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>> +	int i;
>> +
>> +	memset(arvif, 0, sizeof(*arvif));
>> +
>> +	arvif->vif = vif;
>> +
>> +	INIT_LIST_HEAD(&arvif->list);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
>> +		arvif->bitrate_mask.control[i].legacy = 0xffffffff;
>> +		memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
>> +		       sizeof(arvif->bitrate_mask.control[i].ht_mcs));
>> +		memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
>> +		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
>> +	}
>> +
>> +	/* Allocate Default Queue now and reassign during actual vdev create */
>> +	vif->cab_queue = ATH12K_HW_DEFAULT_QUEUE;
>> +	for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
>> +		vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE;
>> +
>> +	vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
>> +
>> +	/* For single radio wiphy(i.e ah->num_radio is 1), create the vdev
>> +	 * during add_interface itself, for multi radio wiphy, defer the vdev
>> +	 * creation until channel_assign to determine the radio on which the
>> +	 * vdev needs to be created
>> +	 */
>> +	ath12k_mac_assign_vif_to_vdev(hw, vif, NULL);
>> +	return 0;
>>   }
>>   
>>   static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif)
>> @@ -6058,14 +6113,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif
>>   static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
>>   					   struct ieee80211_vif *vif)
>>   {
>> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>>   	struct ath12k *ar;
>>   	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>>   	struct ath12k_base *ab;
>>   	unsigned long time_left;
>>   	int ret;
>>   
>> -	ar = ath12k_ah_to_ar(ah, 0);
>> +	if (!arvif->is_created)
>> +		return;
>> +
>> +	ar = arvif->ar;
>>   	ab = ar->ab;
>>   
>>   	mutex_lock(&ar->conf_mutex);
>> @@ -6107,6 +6164,7 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
>>   	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
>>   	ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id);
>>   	ar->num_created_vdevs--;
>> +	arvif->is_created = false;
>>   
>>   	ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
>>   		   vif->addr, arvif->vdev_id);
>> @@ -6759,14 +6817,21 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>>   				 struct ieee80211_bss_conf *link_conf,
>>   				 struct ieee80211_chanctx_conf *ctx)
>>   {
>> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>>   	struct ath12k *ar;
>>   	struct ath12k_base *ab;
>>   	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>>   	int ret;
>>   	struct ath12k_wmi_peer_create_arg param;
>>   
>> -	ar = ath12k_ah_to_ar(ah, 0);
>> +	/* For multi radio wiphy, the vdev was not created during add_interface
>> +	 * create now since we have a channel ctx now to assign to a specific ar/fw
>> +	 */
>> +	ar = ath12k_mac_assign_vif_to_vdev(hw, vif, ctx);
>> +	if (!ar) {
>> +		WARN_ON(1);
>> +		return -EINVAL;
>> +	}
>> +
>>   	ab = ar->ab;
>>   
>>   	mutex_lock(&ar->conf_mutex);
>> @@ -6842,13 +6907,22 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
>>   				   struct ieee80211_bss_conf *link_conf,
>>   				   struct ieee80211_chanctx_conf *ctx)
>>   {
>> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>>   	struct ath12k *ar;
>>   	struct ath12k_base *ab;
>>   	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
>>   	int ret;
>>   
>> -	ar = ath12k_ah_to_ar(ah, 0);
>> +	/* The vif is expected to be attached to an ar's VDEV.
>> +	 * We leave the vif/vdev in this function as is
>> +	 * and not delete the vdev symmetric to assign_vif_chanctx()
>> +	 * the VDEV will be deleted and unassigned either during
>> +	 * remove_interface() or when there is a change in channel
>> +	 * that moves the vif to a new ar
>> +	 */
>> +	if (!arvif->is_created)
>> +		return;
>> +
>> +	ar = arvif->ar;
>>   	ab = ar->ab;
>>   
>>   	mutex_lock(&ar->conf_mutex);
>> @@ -6900,13 +6974,20 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
>>   				 int n_vifs,
>>   				 enum ieee80211_chanctx_switch_mode mode)
>>   {
>> -	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
>>   	struct ath12k *ar;
>>   
>> -	ar = ath12k_ah_to_ar(ah, 0);
>> +	ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx);
>> +	if (!ar)
>> +		return -EINVAL;
>>   
>>   	mutex_lock(&ar->conf_mutex);
>>   
>> +	/* Switching channels across radio is not allowed */
>> +	if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) {
>> +		mutex_unlock(&ar->conf_mutex);
>> +		return -EINVAL;
>> +	}
>> +
>>   	ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
>>   		   "mac chanctx switch n_vifs %d mode %d\n",
>>   		   n_vifs, mode);
>
kernel test robot March 14, 2024, 10:17 a.m. UTC | #3
Hi Rameshkumar,

kernel test robot noticed the following build warnings:

[auto build test WARNING on kvalo-ath/ath-next]
[also build test WARNING on wireless/main wireless-next/main linus/master next-20240314]
[cannot apply to v6.8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Rameshkumar-Sundaram/wifi-ath12k-add-multiple-radio-support-in-a-single-MAC-HW-un-register/20240312-215924
base:   https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git ath-next
patch link:    https://lore.kernel.org/r/20240312135557.1778379-5-quic_ramess%40quicinc.com
patch subject: [PATCH v4 04/12] wifi: ath12k: vdev statemachine changes for single wiphy
config: powerpc-allyesconfig (https://download.01.org/0day-ci/archive/20240314/202403141850.4ccwnsut-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 503c55e17037436dcd45ac69dea8967e67e3f5e8)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240314/202403141850.4ccwnsut-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202403141850.4ccwnsut-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/net/mac80211.h:18:
   In file included from include/linux/if_ether.h:19:
   In file included from include/linux/skbuff.h:17:
   In file included from include/linux/bvec.h:10:
   In file included from include/linux/highmem.h:8:
   In file included from include/linux/cacheflush.h:5:
   In file included from arch/powerpc/include/asm/cacheflush.h:7:
   In file included from include/linux/mm.h:2188:
   include/linux/vmstat.h:508:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     508 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     509 |                            item];
         |                            ~~~~
   include/linux/vmstat.h:515:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     515 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     516 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:522:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     522 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
   include/linux/vmstat.h:527:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     527 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     528 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:536:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     536 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     537 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   In file included from drivers/net/wireless/ath/ath12k/mac.c:7:
   In file included from include/net/mac80211.h:20:
   In file included from include/linux/ieee80211.h:20:
   In file included from include/linux/etherdevice.h:21:
   In file included from include/linux/netdevice.h:45:
   In file included from include/uapi/linux/neighbour.h:6:
   In file included from include/linux/netlink.h:9:
   In file included from include/net/scm.h:9:
   In file included from include/linux/security.h:35:
   include/linux/bpf.h:742:48: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_arg_type') [-Wenum-enum-conversion]
     742 |         ARG_PTR_TO_MAP_VALUE_OR_NULL    = PTR_MAYBE_NULL | ARG_PTR_TO_MAP_VALUE,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:743:43: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_arg_type') [-Wenum-enum-conversion]
     743 |         ARG_PTR_TO_MEM_OR_NULL          = PTR_MAYBE_NULL | ARG_PTR_TO_MEM,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
   include/linux/bpf.h:744:43: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_arg_type') [-Wenum-enum-conversion]
     744 |         ARG_PTR_TO_CTX_OR_NULL          = PTR_MAYBE_NULL | ARG_PTR_TO_CTX,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
   include/linux/bpf.h:745:45: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_arg_type') [-Wenum-enum-conversion]
     745 |         ARG_PTR_TO_SOCKET_OR_NULL       = PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:746:44: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_arg_type') [-Wenum-enum-conversion]
     746 |         ARG_PTR_TO_STACK_OR_NULL        = PTR_MAYBE_NULL | ARG_PTR_TO_STACK,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~
   include/linux/bpf.h:747:45: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_arg_type') [-Wenum-enum-conversion]
     747 |         ARG_PTR_TO_BTF_ID_OR_NULL       = PTR_MAYBE_NULL | ARG_PTR_TO_BTF_ID,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:751:38: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_arg_type') [-Wenum-enum-conversion]
     751 |         ARG_PTR_TO_UNINIT_MEM           = MEM_UNINIT | ARG_PTR_TO_MEM,
         |                                           ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
   include/linux/bpf.h:753:45: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_arg_type') [-Wenum-enum-conversion]
     753 |         ARG_PTR_TO_FIXED_SIZE_MEM       = MEM_FIXED_SIZE | ARG_PTR_TO_MEM,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
   include/linux/bpf.h:776:48: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_return_type') [-Wenum-enum-conversion]
     776 |         RET_PTR_TO_MAP_VALUE_OR_NULL    = PTR_MAYBE_NULL | RET_PTR_TO_MAP_VALUE,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:777:45: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_return_type') [-Wenum-enum-conversion]
     777 |         RET_PTR_TO_SOCKET_OR_NULL       = PTR_MAYBE_NULL | RET_PTR_TO_SOCKET,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:778:47: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_return_type') [-Wenum-enum-conversion]
     778 |         RET_PTR_TO_TCP_SOCK_OR_NULL     = PTR_MAYBE_NULL | RET_PTR_TO_TCP_SOCK,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:779:50: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_return_type') [-Wenum-enum-conversion]
     779 |         RET_PTR_TO_SOCK_COMMON_OR_NULL  = PTR_MAYBE_NULL | RET_PTR_TO_SOCK_COMMON,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:781:49: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_return_type') [-Wenum-enum-conversion]
     781 |         RET_PTR_TO_DYNPTR_MEM_OR_NULL   = PTR_MAYBE_NULL | RET_PTR_TO_MEM,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
   include/linux/bpf.h:782:45: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_return_type') [-Wenum-enum-conversion]
     782 |         RET_PTR_TO_BTF_ID_OR_NULL       = PTR_MAYBE_NULL | RET_PTR_TO_BTF_ID,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:783:43: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_return_type') [-Wenum-enum-conversion]
     783 |         RET_PTR_TO_BTF_ID_TRUSTED       = PTR_TRUSTED    | RET_PTR_TO_BTF_ID,
         |                                           ~~~~~~~~~~~    ^ ~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:894:44: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_reg_type') [-Wenum-enum-conversion]
     894 |         PTR_TO_MAP_VALUE_OR_NULL        = PTR_MAYBE_NULL | PTR_TO_MAP_VALUE,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~
   include/linux/bpf.h:895:42: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_reg_type') [-Wenum-enum-conversion]
     895 |         PTR_TO_SOCKET_OR_NULL           = PTR_MAYBE_NULL | PTR_TO_SOCKET,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~
   include/linux/bpf.h:896:46: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_reg_type') [-Wenum-enum-conversion]
     896 |         PTR_TO_SOCK_COMMON_OR_NULL      = PTR_MAYBE_NULL | PTR_TO_SOCK_COMMON,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~
   include/linux/bpf.h:897:44: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_reg_type') [-Wenum-enum-conversion]
     897 |         PTR_TO_TCP_SOCK_OR_NULL         = PTR_MAYBE_NULL | PTR_TO_TCP_SOCK,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
   include/linux/bpf.h:898:42: warning: bitwise operation between different enumeration types ('enum bpf_type_flag' and 'enum bpf_reg_type') [-Wenum-enum-conversion]
     898 |         PTR_TO_BTF_ID_OR_NULL           = PTR_MAYBE_NULL | PTR_TO_BTF_ID,
         |                                           ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~
>> drivers/net/wireless/ath/ath12k/mac.c:6038:54: warning: variable 'bit' is uninitialized when used here [-Wuninitialized]
    6038 |                 ath12k_warn(ab, "failed to create vdev %d ret %d", bit, ret);
         |                                                                    ^~~
   drivers/net/wireless/ath/ath12k/mac.c:6001:8: note: initialize the variable 'bit' to silence this warning
    6001 |         u8 bit;
         |               ^
         |                = '\0'
   26 warnings generated.


vim +/bit +6038 drivers/net/wireless/ath/ath12k/mac.c

  5991	
  5992	static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
  5993							    struct ieee80211_vif *vif,
  5994							    struct ieee80211_chanctx_conf *ctx)
  5995	{
  5996		struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
  5997		struct ath12k_hw *ah = hw->priv;
  5998		struct ath12k_base *ab;
  5999		struct ath12k *ar;
  6000		int ret;
  6001		u8 bit;
  6002	
  6003		if (arvif->ar) {
  6004			WARN_ON(!arvif->is_created);
  6005			goto out;
  6006		}
  6007	
  6008		if (ah->num_radio == 1)
  6009			ar = ah->radio;
  6010		else if (ctx)
  6011			ar = ath12k_get_ar_by_ctx(hw, ctx);
  6012		else
  6013			return NULL;
  6014	
  6015		if (!ar)
  6016			goto out;
  6017	
  6018		ab = ar->ab;
  6019	
  6020		mutex_lock(&ar->conf_mutex);
  6021	
  6022		if (vif->type == NL80211_IFTYPE_AP &&
  6023		    ar->num_peers > (ar->max_num_peers - 1)) {
  6024			ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
  6025			ret = -ENOBUFS;
  6026			goto unlock;
  6027		}
  6028	
  6029		if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
  6030			ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
  6031				    TARGET_NUM_VDEVS);
  6032			ret = -EBUSY;
  6033			goto unlock;
  6034		}
  6035	
  6036		ret = ath12k_mac_vdev_create(ar, vif);
  6037		if (ret) {
> 6038			ath12k_warn(ab, "failed to create vdev %d ret %d", bit, ret);
  6039			goto unlock;
  6040		}
  6041	
  6042		/* TODO If the vdev is created during channel assign and not during
  6043		 * add_interface(), Apply any parameters for the vdev which were received
  6044		 * after add_interface, corresponding to this vif.
  6045		 */
  6046	unlock:
  6047		mutex_unlock(&ar->conf_mutex);
  6048	out:
  6049		return arvif->ar;
  6050	}
  6051
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 53bcf9416efd..70daec38d486 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -251,6 +251,7 @@  struct ath12k_vif {
 		} ap;
 	} u;
 
+	bool is_created;
 	bool is_started;
 	bool is_up;
 	u32 aid;
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index 87965980b938..e34c4f76c1ec 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -80,6 +80,7 @@ 
 #define TARGET_RX_PEER_METADATA_VER_V1A	2
 #define TARGET_RX_PEER_METADATA_VER_V1B	3
 
+#define ATH12K_HW_DEFAULT_QUEUE		0
 #define ATH12K_HW_MAX_QUEUES		4
 #define ATH12K_QUEUE_LEN		4096
 
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 4afaba3ba934..b6afef81a2d8 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5780,64 +5780,24 @@  static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
 	ath12k_mac_update_vif_offload(arvif);
 }
 
-static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
-				       struct ieee80211_vif *vif)
+static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif)
 {
-	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
-	struct ath12k *ar;
-	struct ath12k_base *ab;
+	struct ath12k_hw *ah = ar->ah;
+	struct ath12k_base *ab = ar->ab;
+	struct ieee80211_hw *hw = ah->hw;
 	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
 	struct ath12k_wmi_vdev_create_arg vdev_arg = {0};
 	struct ath12k_wmi_peer_create_arg peer_param;
 	u32 param_id, param_value;
 	u16 nss;
 	int i;
-	int ret;
-	int bit;
-
-	vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+	int ret, vdev_id;
 
-	ar = ath12k_ah_to_ar(ah, 0);
-	ab = ar->ab;
-
-	mutex_lock(&ar->conf_mutex);
-
-	if (vif->type == NL80211_IFTYPE_AP &&
-	    ar->num_peers > (ar->max_num_peers - 1)) {
-		ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
-		ret = -ENOBUFS;
-		goto err;
-	}
-
-	if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
-		ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
-			    TARGET_NUM_VDEVS);
-		ret = -EBUSY;
-		goto err;
-	}
-
-	memset(arvif, 0, sizeof(*arvif));
+	lockdep_assert_held(&ar->conf_mutex);
 
 	arvif->ar = ar;
-	arvif->vif = vif;
-
-	INIT_LIST_HEAD(&arvif->list);
-
-	/* Should we initialize any worker to handle connection loss indication
-	 * from firmware in sta mode?
-	 */
-
-	for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
-		arvif->bitrate_mask.control[i].legacy = 0xffffffff;
-		memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
-		       sizeof(arvif->bitrate_mask.control[i].ht_mcs));
-		memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
-		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
-	}
-
-	bit = __ffs64(ab->free_vdev_map);
-
-	arvif->vdev_id = bit;
+	vdev_id = __ffs64(ab->free_vdev_map);
+	arvif->vdev_id = vdev_id;
 	arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
 
 	switch (vif->type) {
@@ -5861,7 +5821,7 @@  static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 		break;
 	case NL80211_IFTYPE_MONITOR:
 		arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
-		ar->monitor_vdev_id = bit;
+		ar->monitor_vdev_id = vdev_id;
 		break;
 	case NL80211_IFTYPE_P2P_DEVICE:
 		arvif->vdev_type = WMI_VDEV_TYPE_STA;
@@ -5872,7 +5832,7 @@  static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 		break;
 	}
 
-	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac add interface id %d type %d subtype %d map %llx\n",
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev create id %d type %d subtype %d map %llx\n",
 		   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
 		   ab->free_vdev_map);
 
@@ -5890,6 +5850,7 @@  static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 	}
 
 	ar->num_created_vdevs++;
+	arvif->is_created = true;
 	ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM created, vdev_id %d\n",
 		   vif->addr, arvif->vdev_id);
 	ar->allocated_vdev_map |= 1LL << arvif->vdev_id;
@@ -5990,8 +5951,6 @@  static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 	if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled)
 		ath12k_mac_monitor_vdev_create(ar);
 
-	mutex_unlock(&ar->conf_mutex);
-
 	return ret;
 
 err_peer_del:
@@ -6017,6 +5976,7 @@  static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 err_vdev_del:
 	ath12k_wmi_vdev_delete(ar, arvif->vdev_id);
 	ar->num_created_vdevs--;
+	arvif->is_created = false;
 	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
 	ab->free_vdev_map |= 1LL << arvif->vdev_id;
 	ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id);
@@ -6025,9 +5985,104 @@  static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 	spin_unlock_bh(&ar->data_lock);
 
 err:
+	arvif->ar = NULL;
+	return ret;
+}
+
+static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
+						    struct ieee80211_vif *vif,
+						    struct ieee80211_chanctx_conf *ctx)
+{
+	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+	struct ath12k_hw *ah = hw->priv;
+	struct ath12k_base *ab;
+	struct ath12k *ar;
+	int ret;
+	u8 bit;
+
+	if (arvif->ar) {
+		WARN_ON(!arvif->is_created);
+		goto out;
+	}
+
+	if (ah->num_radio == 1)
+		ar = ah->radio;
+	else if (ctx)
+		ar = ath12k_get_ar_by_ctx(hw, ctx);
+	else
+		return NULL;
+
+	if (!ar)
+		goto out;
+
+	ab = ar->ab;
+
+	mutex_lock(&ar->conf_mutex);
+
+	if (vif->type == NL80211_IFTYPE_AP &&
+	    ar->num_peers > (ar->max_num_peers - 1)) {
+		ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
+		ret = -ENOBUFS;
+		goto unlock;
+	}
+
+	if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
+		ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
+			    TARGET_NUM_VDEVS);
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	ret = ath12k_mac_vdev_create(ar, vif);
+	if (ret) {
+		ath12k_warn(ab, "failed to create vdev %d ret %d", bit, ret);
+		goto unlock;
+	}
+
+	/* TODO If the vdev is created during channel assign and not during
+	 * add_interface(), Apply any parameters for the vdev which were received
+	 * after add_interface, corresponding to this vif.
+	 */
+unlock:
 	mutex_unlock(&ar->conf_mutex);
+out:
+	return arvif->ar;
+}
 
-	return ret;
+static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
+				       struct ieee80211_vif *vif)
+{
+	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
+	int i;
+
+	memset(arvif, 0, sizeof(*arvif));
+
+	arvif->vif = vif;
+
+	INIT_LIST_HEAD(&arvif->list);
+
+	for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
+		arvif->bitrate_mask.control[i].legacy = 0xffffffff;
+		memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
+		       sizeof(arvif->bitrate_mask.control[i].ht_mcs));
+		memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
+		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
+	}
+
+	/* Allocate Default Queue now and reassign during actual vdev create */
+	vif->cab_queue = ATH12K_HW_DEFAULT_QUEUE;
+	for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
+		vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE;
+
+	vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+
+	/* For single radio wiphy(i.e ah->num_radio is 1), create the vdev
+	 * during add_interface itself, for multi radio wiphy, defer the vdev
+	 * creation until channel_assign to determine the radio on which the
+	 * vdev needs to be created
+	 */
+	ath12k_mac_assign_vif_to_vdev(hw, vif, NULL);
+	return 0;
 }
 
 static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif)
@@ -6058,14 +6113,16 @@  static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif
 static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
 					   struct ieee80211_vif *vif)
 {
-	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
 	struct ath12k *ar;
 	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
 	struct ath12k_base *ab;
 	unsigned long time_left;
 	int ret;
 
-	ar = ath12k_ah_to_ar(ah, 0);
+	if (!arvif->is_created)
+		return;
+
+	ar = arvif->ar;
 	ab = ar->ab;
 
 	mutex_lock(&ar->conf_mutex);
@@ -6107,6 +6164,7 @@  static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
 	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
 	ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id);
 	ar->num_created_vdevs--;
+	arvif->is_created = false;
 
 	ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
 		   vif->addr, arvif->vdev_id);
@@ -6759,14 +6817,21 @@  ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
 				 struct ieee80211_bss_conf *link_conf,
 				 struct ieee80211_chanctx_conf *ctx)
 {
-	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
 	struct ath12k *ar;
 	struct ath12k_base *ab;
 	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
 	int ret;
 	struct ath12k_wmi_peer_create_arg param;
 
-	ar = ath12k_ah_to_ar(ah, 0);
+	/* For multi radio wiphy, the vdev was not created during add_interface
+	 * create now since we have a channel ctx now to assign to a specific ar/fw
+	 */
+	ar = ath12k_mac_assign_vif_to_vdev(hw, vif, ctx);
+	if (!ar) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
 	ab = ar->ab;
 
 	mutex_lock(&ar->conf_mutex);
@@ -6842,13 +6907,22 @@  ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
 				   struct ieee80211_bss_conf *link_conf,
 				   struct ieee80211_chanctx_conf *ctx)
 {
-	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
 	struct ath12k *ar;
 	struct ath12k_base *ab;
 	struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif);
 	int ret;
 
-	ar = ath12k_ah_to_ar(ah, 0);
+	/* The vif is expected to be attached to an ar's VDEV.
+	 * We leave the vif/vdev in this function as is
+	 * and not delete the vdev symmetric to assign_vif_chanctx()
+	 * the VDEV will be deleted and unassigned either during
+	 * remove_interface() or when there is a change in channel
+	 * that moves the vif to a new ar
+	 */
+	if (!arvif->is_created)
+		return;
+
+	ar = arvif->ar;
 	ab = ar->ab;
 
 	mutex_lock(&ar->conf_mutex);
@@ -6900,13 +6974,20 @@  ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
 				 int n_vifs,
 				 enum ieee80211_chanctx_switch_mode mode)
 {
-	struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
 	struct ath12k *ar;
 
-	ar = ath12k_ah_to_ar(ah, 0);
+	ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx);
+	if (!ar)
+		return -EINVAL;
 
 	mutex_lock(&ar->conf_mutex);
 
+	/* Switching channels across radio is not allowed */
+	if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) {
+		mutex_unlock(&ar->conf_mutex);
+		return -EINVAL;
+	}
+
 	ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
 		   "mac chanctx switch n_vifs %d mode %d\n",
 		   n_vifs, mode);