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 |
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);
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); >
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 --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);