From f41c7cab8727d99a2376450d233f128f23060b98 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 3 May 2024 13:34:36 +0300 Subject: [PATCH 01/69] wifi: ath11k: ath11k_mac_op_ipv6_changed(): use list_for_each_entry() Simplify the loop by using list_for_each_entry(). No functional changes. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.37 Signed-off-by: Kalle Valo Acked-by: Jeff Johnson Link: https://msgid.link/20240411165516.4070649-3-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/mac.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 4f62e38ba48b..a71195344288 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9104,7 +9104,6 @@ static void ath11k_mac_op_ipv6_changed(struct ieee80211_hw *hw, struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct inet6_ifaddr *ifa6; struct ifacaddr6 *ifaca6; - struct list_head *p; u32 count, scope; ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "op ipv6 changed\n"); @@ -9120,11 +9119,10 @@ static void ath11k_mac_op_ipv6_changed(struct ieee80211_hw *hw, memcpy(offload->mac_addr, vif->addr, ETH_ALEN); /* get unicast address */ - list_for_each(p, &idev->addr_list) { + list_for_each_entry(ifa6, &idev->addr_list, if_list) { if (count >= ATH11K_IPV6_MAX_COUNT) goto generate; - ifa6 = list_entry(p, struct inet6_ifaddr, if_list); if (ifa6->flags & IFA_F_DADFAILED) continue; scope = ipv6_addr_src_scope(&ifa6->addr); From ecd509b6f263e4f0d86876320c36260dc28bb53b Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Fri, 3 May 2024 13:34:36 +0300 Subject: [PATCH 02/69] wifi: ath12k: Refactor the hardware recovery procedure Currently, in multi-wiphy models, the recovery handler access mac80211 HW from the radio/link structure. This will be incorrect for single wiphy model, as they will hold multiple link/radio structures. To fix this, access mac80211 HW based on the number of hardware in the SoC/chip. This approach makes the recovery handler compatible with both multi wiphy and single wiphy models. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240425090307.3233434-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 119 +++++++++++++------------ drivers/net/wireless/ath/ath12k/mac.c | 23 +++-- 2 files changed, 80 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 6663f4e1792d..ae14614c3568 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -994,9 +994,8 @@ void ath12k_core_halt(struct ath12k *ar) static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) { struct ath12k *ar; - struct ath12k_pdev *pdev; struct ath12k_hw *ah; - int i; + int i, j; spin_lock_bh(&ab->base_lock); ab->stats.fw_crash_counter++; @@ -1006,35 +1005,34 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags); for (i = 0; i < ab->num_hw; i++) { - if (!ab->ah[i]) - continue; - ah = ab->ah[i]; - ieee80211_stop_queues(ah->hw); - } - - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar || ar->state == ATH12K_STATE_OFF) + if (!ah) continue; - ath12k_mac_drain_tx(ar); - complete(&ar->scan.started); - complete(&ar->scan.completed); - complete(&ar->scan.on_channel); - complete(&ar->peer_assoc_done); - complete(&ar->peer_delete_done); - complete(&ar->install_key_done); - complete(&ar->vdev_setup_done); - complete(&ar->vdev_delete_done); - complete(&ar->bss_survey_done); + ieee80211_stop_queues(ah->hw); - wake_up(&ar->dp.tx_empty_waitq); - idr_for_each(&ar->txmgmt_idr, - ath12k_mac_tx_mgmt_pending_free, ar); - idr_destroy(&ar->txmgmt_idr); - wake_up(&ar->txmgmt_empty_waitq); + for (j = 0; j < ah->num_radio; j++) { + ar = &ah->radio[j]; + if (ar->state == ATH12K_STATE_OFF) + continue; + + ath12k_mac_drain_tx(ar); + complete(&ar->scan.started); + complete(&ar->scan.completed); + complete(&ar->scan.on_channel); + complete(&ar->peer_assoc_done); + complete(&ar->peer_delete_done); + complete(&ar->install_key_done); + complete(&ar->vdev_setup_done); + complete(&ar->vdev_delete_done); + complete(&ar->bss_survey_done); + + wake_up(&ar->dp.tx_empty_waitq); + idr_for_each(&ar->txmgmt_idr, + ath12k_mac_tx_mgmt_pending_free, ar); + idr_destroy(&ar->txmgmt_idr); + wake_up(&ar->txmgmt_empty_waitq); + } } wake_up(&ab->wmi_ab.tx_credits_wq); @@ -1043,41 +1041,52 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) { + struct ath12k_hw *ah; struct ath12k *ar; - struct ath12k_pdev *pdev; - int i; + int i, j; + u8 restart_count; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar || ar->state == ATH12K_STATE_OFF) + for (i = 0; i < ab->num_hw; i++) { + ah = ab->ah[i]; + if (!ah) continue; - mutex_lock(&ar->conf_mutex); + for (j = 0, restart_count = 0; j < ah->num_radio; j++) { + ar = &ah->radio[j]; + if (ar->state == ATH12K_STATE_OFF) + continue; - switch (ar->state) { - case ATH12K_STATE_ON: - ar->state = ATH12K_STATE_RESTARTING; - ath12k_core_halt(ar); - ieee80211_restart_hw(ath12k_ar_to_hw(ar)); - break; - case ATH12K_STATE_OFF: - ath12k_warn(ab, - "cannot restart radio %d that hasn't been started\n", - i); - break; - case ATH12K_STATE_RESTARTING: - break; - case ATH12K_STATE_RESTARTED: - ar->state = ATH12K_STATE_WEDGED; - fallthrough; - case ATH12K_STATE_WEDGED: - ath12k_warn(ab, - "device is wedged, will not restart radio %d\n", i); - break; + mutex_lock(&ar->conf_mutex); + + switch (ar->state) { + case ATH12K_STATE_ON: + ar->state = ATH12K_STATE_RESTARTING; + ath12k_core_halt(ar); + restart_count++; + break; + case ATH12K_STATE_OFF: + ath12k_warn(ab, + "cannot restart radio %d that hasn't been started\n", + j); + break; + case ATH12K_STATE_RESTARTING: + break; + case ATH12K_STATE_RESTARTED: + ar->state = ATH12K_STATE_WEDGED; + fallthrough; + case ATH12K_STATE_WEDGED: + ath12k_warn(ab, + "device is wedged, will not restart radio %d\n", j); + break; + } + mutex_unlock(&ar->conf_mutex); } - mutex_unlock(&ar->conf_mutex); + + /* Restart after all the link/radio got restart */ + if (restart_count == ah->num_radio) + ieee80211_restart_hw(ah->hw); } + complete(&ab->driver_recovery); } diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 805cb084484a..6d19b6003aea 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7920,26 +7920,33 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, struct ath12k *ar; struct ath12k_base *ab; struct ath12k_vif *arvif; - int recovery_count; + int recovery_count, i; if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; - ar = ath12k_ah_to_ar(ah, 0); - ab = ar->ab; + for_each_ar(ah, ar, i) { + mutex_lock(&ar->conf_mutex); - mutex_lock(&ar->conf_mutex); + if (ar->state != ATH12K_STATE_RESTARTED) { + mutex_unlock(&ar->conf_mutex); + continue; + } + + ab = ar->ab; - if (ar->state == ATH12K_STATE_RESTARTED) { ath12k_warn(ar->ab, "pdev %d successfully recovered\n", ar->pdev->pdev_id); + ar->state = ATH12K_STATE_ON; ieee80211_wake_queues(hw); if (ab->is_reset) { recovery_count = atomic_inc_return(&ab->recovery_count); + ath12k_dbg(ab, ATH12K_DBG_BOOT, "recovery count %d\n", recovery_count); + /* When there are multiple radios in an SOC, * the recovery has to be done for each radio */ @@ -7958,6 +7965,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, arvif->key_cipher, arvif->is_up, arvif->vdev_type); + /* After trigger disconnect, then upper layer will * trigger connect again, then the PN number of * upper layer will be reset to keep up with AP @@ -7967,13 +7975,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, arvif->vdev_type == WMI_VDEV_TYPE_STA && arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { ieee80211_hw_restart_disconnect(arvif->vif); + ath12k_dbg(ab, ATH12K_DBG_BOOT, "restart disconnect\n"); } } - } - mutex_unlock(&ar->conf_mutex); + mutex_unlock(&ar->conf_mutex); + } } static void From 9b4e5caaf5905edb7c184e8d14a9fab09f2f865b Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Fri, 3 May 2024 13:34:37 +0300 Subject: [PATCH 03/69] wifi: ath12k: Refactor the hardware state Currently, in multi wiphy models, the mac80211 hardware state is maintained within the radio/link structure. However, in single wiphy models, the mac80211 hardware state is needed at the hardware abstraction layer (ath12k_hw). Therefore, move the hardware state from the radio/link structure to the hardware abstraction layer (ath12k_hw). Additionally, update the naming convention of the state enums to enhance clarity and consistency. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240425090307.3233434-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 59 +++++++++++-------------- drivers/net/wireless/ath/ath12k/core.h | 22 ++++++---- drivers/net/wireless/ath/ath12k/mac.c | 61 ++++++++++++++------------ drivers/net/wireless/ath/ath12k/reg.c | 19 ++++---- 4 files changed, 83 insertions(+), 78 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index ae14614c3568..a685cfd6fd92 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1006,15 +1006,13 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) for (i = 0; i < ab->num_hw; i++) { ah = ab->ah[i]; - if (!ah) + if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; ieee80211_stop_queues(ah->hw); for (j = 0; j < ah->num_radio; j++) { ar = &ah->radio[j]; - if (ar->state == ATH12K_STATE_OFF) - continue; ath12k_mac_drain_tx(ar); complete(&ar->scan.started); @@ -1044,47 +1042,42 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) struct ath12k_hw *ah; struct ath12k *ar; int i, j; - u8 restart_count; for (i = 0; i < ab->num_hw; i++) { ah = ab->ah[i]; - if (!ah) + if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; - for (j = 0, restart_count = 0; j < ah->num_radio; j++) { - ar = &ah->radio[j]; - if (ar->state == ATH12K_STATE_OFF) - continue; + switch (ah->state) { + case ATH12K_HW_STATE_ON: + ah->state = ATH12K_HW_STATE_RESTARTING; - mutex_lock(&ar->conf_mutex); + for (j = 0; j < ah->num_radio; j++) { + ar = &ah->radio[j]; - switch (ar->state) { - case ATH12K_STATE_ON: - ar->state = ATH12K_STATE_RESTARTING; + mutex_lock(&ar->conf_mutex); ath12k_core_halt(ar); - restart_count++; - break; - case ATH12K_STATE_OFF: - ath12k_warn(ab, - "cannot restart radio %d that hasn't been started\n", - j); - break; - case ATH12K_STATE_RESTARTING: - break; - case ATH12K_STATE_RESTARTED: - ar->state = ATH12K_STATE_WEDGED; - fallthrough; - case ATH12K_STATE_WEDGED: - ath12k_warn(ab, - "device is wedged, will not restart radio %d\n", j); - break; + mutex_unlock(&ar->conf_mutex); } - mutex_unlock(&ar->conf_mutex); - } - /* Restart after all the link/radio got restart */ - if (restart_count == ah->num_radio) + /* Restart after all the link/radio halt */ ieee80211_restart_hw(ah->hw); + break; + case ATH12K_HW_STATE_OFF: + ath12k_warn(ab, + "cannot restart hw %d that hasn't been started\n", + i); + break; + case ATH12K_HW_STATE_RESTARTING: + break; + case ATH12K_HW_STATE_RESTARTED: + ah->state = ATH12K_HW_STATE_WEDGED; + fallthrough; + case ATH12K_HW_STATE_WEDGED: + ath12k_warn(ab, + "device is wedged, will not restart hw %d\n", i); + break; + } } complete(&ab->driver_recovery); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 47dde4401210..c4eb8b25398c 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -457,12 +457,12 @@ struct ath12k_sta { #define ATH12K_NUM_CHANS 100 #define ATH12K_MAX_5G_CHAN 173 -enum ath12k_state { - ATH12K_STATE_OFF, - ATH12K_STATE_ON, - ATH12K_STATE_RESTARTING, - ATH12K_STATE_RESTARTED, - ATH12K_STATE_WEDGED, +enum ath12k_hw_state { + ATH12K_HW_STATE_OFF, + ATH12K_HW_STATE_ON, + ATH12K_HW_STATE_RESTARTING, + ATH12K_HW_STATE_RESTARTED, + ATH12K_HW_STATE_WEDGED, /* Add other states as required */ }; @@ -511,7 +511,6 @@ struct ath12k { u32 ht_cap_info; u32 vht_cap_info; struct ath12k_he ar_he; - enum ath12k_state state; bool supports_6ghz; struct { struct completion started; @@ -636,10 +635,12 @@ struct ath12k { struct ath12k_hw { struct ieee80211_hw *hw; + struct ath12k_base *ab; + enum ath12k_hw_state state; bool regd_updated; bool use_6ghz_regd; - u8 num_radio; + struct ath12k radio[] __aligned(sizeof(void *)); }; @@ -1037,6 +1038,11 @@ static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah, u8 hw_link_id return &ah->radio[hw_link_id]; } +static inline struct ath12k_hw *ath12k_ar_to_ah(struct ath12k *ar) +{ + return ar->ah; +} + static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar) { return ar->ah->hw; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 6d19b6003aea..0cb2e0435cc0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5269,6 +5269,7 @@ static void ath12k_mac_setup_sband_iftype_data(struct ath12k *ar, static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) { + struct ath12k_hw *ah = ath12k_ar_to_ah(ar); int ret; lockdep_assert_held(&ar->conf_mutex); @@ -5289,8 +5290,8 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) ar->cfg_tx_chainmask = tx_ant; ar->cfg_rx_chainmask = rx_ant; - if (ar->state != ATH12K_STATE_ON && - ar->state != ATH12K_STATE_RESTARTED) + if (ah->state != ATH12K_HW_STATE_ON && + ah->state != ATH12K_HW_STATE_RESTARTED) return 0; ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_TX_CHAIN_MASK, @@ -5620,22 +5621,6 @@ static int ath12k_mac_start(struct ath12k *ar) mutex_lock(&ar->conf_mutex); - switch (ar->state) { - case ATH12K_STATE_OFF: - ar->state = ATH12K_STATE_ON; - break; - case ATH12K_STATE_RESTARTING: - ar->state = ATH12K_STATE_RESTARTED; - ath12k_mac_wait_reconfigure(ab); - break; - case ATH12K_STATE_RESTARTED: - case ATH12K_STATE_WEDGED: - case ATH12K_STATE_ON: - WARN_ON(1); - ret = -EINVAL; - goto err; - } - ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1, pdev->pdev_id); @@ -5726,7 +5711,6 @@ static int ath12k_mac_start(struct ath12k *ar) return 0; err: - ar->state = ATH12K_STATE_OFF; mutex_unlock(&ar->conf_mutex); return ret; @@ -5749,9 +5733,28 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) ath12k_drain_tx(ah); + switch (ah->state) { + case ATH12K_HW_STATE_OFF: + ah->state = ATH12K_HW_STATE_ON; + break; + case ATH12K_HW_STATE_RESTARTING: + ah->state = ATH12K_HW_STATE_RESTARTED; + ath12k_mac_wait_reconfigure(ah->ab); + break; + case ATH12K_HW_STATE_RESTARTED: + case ATH12K_HW_STATE_WEDGED: + case ATH12K_HW_STATE_ON: + ah->state = ATH12K_HW_STATE_OFF; + + WARN_ON(1); + return -EINVAL; + } + for_each_ar(ah, ar, i) { ret = ath12k_mac_start(ar); if (ret) { + ah->state = ATH12K_HW_STATE_OFF; + ath12k_err(ar->ab, "fail to start mac operations in pdev idx %d ret %d\n", ar->pdev_idx, ret); goto fail_start; @@ -5759,11 +5762,13 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) } return 0; + fail_start: for (; i > 0; i--) { ar = ath12k_ah_to_ar(ah, i - 1); ath12k_mac_stop(ar); } + return ret; } @@ -5836,7 +5841,6 @@ static void ath12k_mac_stop(struct ath12k *ar) ret); clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); - ar->state = ATH12K_STATE_OFF; mutex_unlock(&ar->conf_mutex); cancel_delayed_work_sync(&ar->scan.timeout); @@ -5865,6 +5869,8 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw) ath12k_drain_tx(ah); + ah->state = ATH12K_HW_STATE_OFF; + for_each_ar(ah, ar, i) ath12k_mac_stop(ar); } @@ -7925,22 +7931,20 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; + if (ah->state != ATH12K_HW_STATE_RESTARTED) + return; + + ah->state = ATH12K_HW_STATE_ON; + ieee80211_wake_queues(hw); + for_each_ar(ah, ar, i) { mutex_lock(&ar->conf_mutex); - if (ar->state != ATH12K_STATE_RESTARTED) { - mutex_unlock(&ar->conf_mutex); - continue; - } - ab = ar->ab; ath12k_warn(ar->ab, "pdev %d successfully recovered\n", ar->pdev->pdev_id); - ar->state = ATH12K_STATE_ON; - ieee80211_wake_queues(hw); - if (ab->is_reset) { recovery_count = atomic_inc_return(&ab->recovery_count); @@ -8926,6 +8930,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab, ah = ath12k_hw_to_ah(hw); ah->hw = hw; + ah->ab = ab; ah->num_radio = num_pdev_map; for (i = 0; i < num_pdev_map; i++) { diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index fbf38044938c..439d61f284d8 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -206,9 +206,9 @@ static void ath12k_copy_regd(struct ieee80211_regdomain *regd_orig, int ath12k_regd_update(struct ath12k *ar, bool init) { - struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + struct ath12k_hw *ah = ath12k_ar_to_ah(ar); + struct ieee80211_hw *hw = ah->hw; struct ieee80211_regdomain *regd, *regd_copy = NULL; - struct ath12k_hw *ah = ar->ah; int ret, regd_len, pdev_id; struct ath12k_base *ab; int i; @@ -286,19 +286,20 @@ int ath12k_regd_update(struct ath12k *ar, bool init) if (ret) goto err; + if (ah->state != ATH12K_HW_STATE_ON) + goto skip; + ah->regd_updated = true; /* Apply the new regd to all the radios, this is expected to be received only once * since we check for ah->regd_updated and allow here only once. */ for_each_ar(ah, ar, i) { - if (ar->state == ATH12K_STATE_ON) { - ab = ar->ab; - ret = ath12k_reg_update_chan_list(ar); - if (ret) - goto err; - } + ab = ar->ab; + ret = ath12k_reg_update_chan_list(ar); + if (ret) + goto err; } - +skip: return 0; err: ath12k_warn(ab, "failed to perform regd update : %d\n", ret); From acaa84009fade2ae80922861aa9464e89c9d3ef0 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Fri, 3 May 2024 13:34:37 +0300 Subject: [PATCH 04/69] wifi: ath12k: Add lock to protect the hardware state Currently, hardware state is not protected across the reconfigure operations. However, in single wiphy models, multiple radio/links is exposed as a MAC hardware (ieee80211_hw) through the driver hardware abstraction (ath12k_hw) layer. In such scenario, we need to protect hardware state across the multiple radio/link at the driver hardware abstraction (ath12k_hw) layer. Therefore, introduce a new mutex in the ath12k_hw layer. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240425090307.3233434-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 4 ++++ drivers/net/wireless/ath/ath12k/core.h | 6 ++++++ drivers/net/wireless/ath/ath12k/mac.c | 16 ++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index a685cfd6fd92..e9aabdb9341c 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1048,6 +1048,8 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; + mutex_lock(&ah->hw_mutex); + switch (ah->state) { case ATH12K_HW_STATE_ON: ah->state = ATH12K_HW_STATE_RESTARTING; @@ -1078,6 +1080,8 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) "device is wedged, will not restart hw %d\n", i); break; } + + mutex_unlock(&ah->hw_mutex); } complete(&ab->driver_recovery); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index c4eb8b25398c..d833361948b7 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -636,11 +636,17 @@ struct ath12k { struct ath12k_hw { struct ieee80211_hw *hw; struct ath12k_base *ab; + + /* Protect the write operation of the hardware state ath12k_hw::state + * between hardware start<=>reconfigure<=>stop transitions. + */ + struct mutex hw_mutex; enum ath12k_hw_state state; bool regd_updated; bool use_6ghz_regd; u8 num_radio; + /* Keep last */ struct ath12k radio[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 0cb2e0435cc0..4f07ac8c0287 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5615,10 +5615,13 @@ static void ath12k_mac_wait_reconfigure(struct ath12k_base *ab) static int ath12k_mac_start(struct ath12k *ar) { + struct ath12k_hw *ah = ar->ah; struct ath12k_base *ab = ar->ab; struct ath12k_pdev *pdev = ar->pdev; int ret; + lockdep_assert_held(&ah->hw_mutex); + mutex_lock(&ar->conf_mutex); ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, @@ -5733,6 +5736,8 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) ath12k_drain_tx(ah); + guard(mutex)(&ah->hw_mutex); + switch (ah->state) { case ATH12K_HW_STATE_OFF: ah->state = ATH12K_HW_STATE_ON; @@ -5831,9 +5836,12 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable) static void ath12k_mac_stop(struct ath12k *ar) { + struct ath12k_hw *ah = ar->ah; struct htt_ppdu_stats_info *ppdu_stats, *tmp; int ret; + lockdep_assert_held(&ah->hw_mutex); + mutex_lock(&ar->conf_mutex); ret = ath12k_mac_config_mon_status_default(ar, false); if (ret && (ret != -EOPNOTSUPP)) @@ -5869,10 +5877,14 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw) ath12k_drain_tx(ah); + mutex_lock(&ah->hw_mutex); + ah->state = ATH12K_HW_STATE_OFF; for_each_ar(ah, ar, i) ath12k_mac_stop(ar); + + mutex_unlock(&ah->hw_mutex); } static u8 @@ -7931,6 +7943,8 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; + guard(mutex)(&ah->hw_mutex); + if (ah->state != ATH12K_HW_STATE_RESTARTED) return; @@ -8933,6 +8947,8 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab, ah->ab = ab; ah->num_radio = num_pdev_map; + mutex_init(&ah->hw_mutex); + for (i = 0; i < num_pdev_map; i++) { ab = pdev_map[i].ab; pdev_idx = pdev_map[i].pdev_idx; From 8b9ea752a9d67b0b668b38e7efa34fffba8b5331 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 3 May 2024 13:34:37 +0300 Subject: [PATCH 05/69] wifi: ath11k: refactor CE remap & unmap Currently the logic that handles hw_params->ce_remap is inline code, both for doing the remap and the unmap. An upcoming change needs to do the unmap in a second place, so refactor the unmap logic into a separate function. And although it is only called from one place, refactor the remap logic as well to have functional symmetry. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430-ce-unmap-v1-1-e468328f95d9@quicinc.com --- drivers/net/wireless/ath/ath11k/ahb.c | 52 +++++++++++++++++---------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index ca0f17ddebba..88dfef71c2b5 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -954,6 +954,36 @@ static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab) return 0; } +static int ath11k_ahb_ce_remap(struct ath11k_base *ab) +{ + const struct ce_remap *ce_remap = ab->hw_params.ce_remap; + struct platform_device *pdev = ab->pdev; + + if (!ce_remap) { + /* no separate CE register space */ + ab->mem_ce = ab->mem; + return 0; + } + + /* ce register space is moved out of wcss unlike ipq8074 or ipq6018 + * and the space is not contiguous, hence remapping the CE registers + * to a new space for accessing them. + */ + ab->mem_ce = ioremap(ce_remap->base, ce_remap->size); + if (!ab->mem_ce) { + dev_err(&pdev->dev, "ce ioremap error\n"); + return -ENOMEM; + } + + return 0; +} + +static void ath11k_ahb_ce_unmap(struct ath11k_base *ab) +{ + if (ab->hw_params.ce_remap) + iounmap(ab->mem_ce); +} + static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab) { struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab); @@ -1146,21 +1176,9 @@ static int ath11k_ahb_probe(struct platform_device *pdev) if (ret) goto err_core_free; - ab->mem_ce = ab->mem; - - if (ab->hw_params.ce_remap) { - const struct ce_remap *ce_remap = ab->hw_params.ce_remap; - /* ce register space is moved out of wcss unlike ipq8074 or ipq6018 - * and the space is not contiguous, hence remapping the CE registers - * to a new space for accessing them. - */ - ab->mem_ce = ioremap(ce_remap->base, ce_remap->size); - if (!ab->mem_ce) { - dev_err(&pdev->dev, "ce ioremap error\n"); - ret = -ENOMEM; - goto err_core_free; - } - } + ret = ath11k_ahb_ce_remap(ab); + if (ret) + goto err_core_free; ret = ath11k_ahb_fw_resources_init(ab); if (ret) @@ -1248,9 +1266,7 @@ static void ath11k_ahb_free_resources(struct ath11k_base *ab) ath11k_ahb_release_smp2p_handle(ab); ath11k_ahb_fw_resource_deinit(ab); ath11k_ce_free_pipes(ab); - - if (ab->hw_params.ce_remap) - iounmap(ab->mem_ce); + ath11k_ahb_ce_unmap(ab); ath11k_core_free(ab); platform_set_drvdata(pdev, NULL); From c57d00a4d3d80a6af376bf37527c93654afadc02 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Fri, 3 May 2024 13:34:38 +0300 Subject: [PATCH 06/69] wifi: ath11k: unmap the CE in ath11k_ahb_probe() error path Currently, in ath11k_ahb_probe(), if a failure occurs after ath11k_ahb_ce_remap() is called, and if hw_params->ce_remap is enabled, the CE register memory is not unmapped. So add a call to ath11k_ahb_ce_unmap() in the error path. This issue was identified by smatch/smatch_scripts/kchecker: drivers/net/wireless/ath/ath11k/ahb.c:1218 ath11k_ahb_probe() warn: 'ab->mem_ce' from ioremap() not released on lines: 1218. Since this is a rare error path with no simple way to test, and since the change is trivial to review, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430-ce-unmap-v1-2-e468328f95d9@quicinc.com --- drivers/net/wireless/ath/ath11k/ahb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 88dfef71c2b5..e3ff4786c714 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1182,7 +1182,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev) ret = ath11k_ahb_fw_resources_init(ab); if (ret) - goto err_core_free; + goto err_ce_unmap; ret = ath11k_ahb_setup_smp2p_handle(ab); if (ret) @@ -1234,6 +1234,9 @@ static int ath11k_ahb_probe(struct platform_device *pdev) err_fw_deinit: ath11k_ahb_fw_resource_deinit(ab); +err_ce_unmap: + ath11k_ahb_ce_unmap(ab); + err_core_free: ath11k_core_free(ab); platform_set_drvdata(pdev, NULL); From 5f6c3a418b401187c36536dae235beaf322dc7fc Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Fri, 3 May 2024 13:34:38 +0300 Subject: [PATCH 07/69] wifi: ath12k: Replace "chip" with "device" in hal Rx return buffer manager Prefer the term "device" over "chip". Therefore, modify the relevant terms in hal Rx return buffer manager to use "device" instead. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430165811.1377182-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 4 ++-- drivers/net/wireless/ath/ath12k/hal.h | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 75df622f25d8..fc4b95324955 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -3071,7 +3071,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, ath12k_hal_rx_buf_addr_info_set(&reo_ent_ring->buf_addr_info, link_paddr, cookie, - HAL_RX_BUF_RBM_WBM_CHIP0_IDLE_DESC_LIST); + HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST); mpdu_info = u32_encode_bits(1, RX_MPDU_DESC_INFO0_MSDU_COUNT) | u32_encode_bits(0, RX_MPDU_DESC_INFO0_FRAG_FLAG) | @@ -3451,7 +3451,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, (paddr - link_desc_banks[desc_bank].paddr); ath12k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, &rbm); - if (rbm != HAL_RX_BUF_RBM_WBM_CHIP0_IDLE_DESC_LIST && + if (rbm != HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST && rbm != HAL_RX_BUF_RBM_SW3_BM && rbm != ab->hw_params->hal_params->rx_buf_rbm) { ab->soc_stats.invalid_rbm++; diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index dbb9205bfa10..f364b2938ef8 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -770,12 +770,12 @@ struct hal_srng_config { * enum hal_rx_buf_return_buf_manager - manager for returned rx buffers * * @HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST: Buffer returned to WBM idle buffer list - * @HAL_RX_BUF_RBM_WBM_CHIP0_IDLE_DESC_LIST: Descriptor returned to WBM idle - * descriptor list, where the chip 0 WBM is chosen in case of a multi-chip config - * @HAL_RX_BUF_RBM_WBM_CHIP1_IDLE_DESC_LIST: Descriptor returned to WBM idle - * descriptor list, where the chip 1 WBM is chosen in case of a multi-chip config - * @HAL_RX_BUF_RBM_WBM_CHIP2_IDLE_DESC_LIST: Descriptor returned to WBM idle - * descriptor list, where the chip 2 WBM is chosen in case of a multi-chip config + * @HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST: Descriptor returned to WBM idle + * descriptor list, where the device 0 WBM is chosen in case of a multi-device config + * @HAL_RX_BUF_RBM_WBM_DEV1_IDLE_DESC_LIST: Descriptor returned to WBM idle + * descriptor list, where the device 1 WBM is chosen in case of a multi-device config + * @HAL_RX_BUF_RBM_WBM_DEV2_IDLE_DESC_LIST: Descriptor returned to WBM idle + * descriptor list, where the device 2 WBM is chosen in case of a multi-device config * @HAL_RX_BUF_RBM_FW_BM: Buffer returned to FW * @HAL_RX_BUF_RBM_SW0_BM: For ring 0 -- returned to host * @HAL_RX_BUF_RBM_SW1_BM: For ring 1 -- returned to host @@ -788,9 +788,9 @@ struct hal_srng_config { enum hal_rx_buf_return_buf_manager { HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST, - HAL_RX_BUF_RBM_WBM_CHIP0_IDLE_DESC_LIST, - HAL_RX_BUF_RBM_WBM_CHIP1_IDLE_DESC_LIST, - HAL_RX_BUF_RBM_WBM_CHIP2_IDLE_DESC_LIST, + HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST, + HAL_RX_BUF_RBM_WBM_DEV1_IDLE_DESC_LIST, + HAL_RX_BUF_RBM_WBM_DEV2_IDLE_DESC_LIST, HAL_RX_BUF_RBM_FW_BM, HAL_RX_BUF_RBM_SW0_BM, HAL_RX_BUF_RBM_SW1_BM, From acc6afb31c3f999076d998f2d1678c0899f0bfb1 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Fri, 3 May 2024 13:34:38 +0300 Subject: [PATCH 08/69] wifi: ath12k: Refactor idle ring descriptor setup Currently, the WBM idle ring descriptor setup uses implicit value HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST for the return buffer manager parameter. To support inter-device MLO (Multi-link operation), this parameter needs to be configure dynamically based on the device identifier within the MLO group. Therefore, introduce a new argument to the helper function ath12k_hal_set_link_desc_addr(). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430165811.1377182-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 9 ++++++--- drivers/net/wireless/ath/ath12k/dp.h | 1 + drivers/net/wireless/ath/ath12k/dp_rx.c | 5 +++-- drivers/net/wireless/ath/ath12k/hal.c | 5 +++-- drivers/net/wireless/ath/ath12k/hal.h | 3 ++- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 7843c76a82c1..f41b3f9dac3d 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -616,6 +616,7 @@ static int ath12k_dp_scatter_idle_link_desc_setup(struct ath12k_base *ab, int i; int ret = 0; u32 end_offset, cookie; + enum hal_rx_buf_return_buf_manager rbm = dp->idle_link_rbm; n_entries_per_buf = HAL_WBM_IDLE_SCATTER_BUF_SIZE / ath12k_hal_srng_get_entrysize(ab, HAL_WBM_IDLE_LINK); @@ -646,7 +647,8 @@ static int ath12k_dp_scatter_idle_link_desc_setup(struct ath12k_base *ab, paddr = link_desc_banks[i].paddr; while (n_entries) { cookie = DP_LINK_DESC_COOKIE_SET(n_entries, i); - ath12k_hal_set_link_desc_addr(scatter_buf, cookie, paddr); + ath12k_hal_set_link_desc_addr(scatter_buf, cookie, + paddr, rbm); n_entries--; paddr += HAL_LINK_DESC_SIZE; if (rem_entries) { @@ -790,6 +792,7 @@ int ath12k_dp_link_desc_setup(struct ath12k_base *ab, u32 paddr; int i, ret; u32 cookie; + enum hal_rx_buf_return_buf_manager rbm = ab->dp.idle_link_rbm; tot_mem_sz = n_link_desc * HAL_LINK_DESC_SIZE; tot_mem_sz += HAL_LINK_DESC_ALIGN; @@ -850,8 +853,7 @@ int ath12k_dp_link_desc_setup(struct ath12k_base *ab, while (n_entries && (desc = ath12k_hal_srng_src_get_next_entry(ab, srng))) { cookie = DP_LINK_DESC_COOKIE_SET(n_entries, i); - ath12k_hal_set_link_desc_addr(desc, - cookie, paddr); + ath12k_hal_set_link_desc_addr(desc, cookie, paddr, rbm); n_entries--; paddr += HAL_LINK_DESC_SIZE; } @@ -1603,6 +1605,7 @@ int ath12k_dp_alloc(struct ath12k_base *ab) spin_lock_init(&dp->reo_cmd_lock); dp->reo_cmd_cache_flush_count = 0; + dp->idle_link_rbm = HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST; ret = ath12k_wbm_idle_ring_setup(ab, &n_link_desc); if (ret) { diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 5cf0d21ef184..e9880b34a7ab 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -325,6 +325,7 @@ struct ath12k_dp { u8 htt_tgt_ver_major; u8 htt_tgt_ver_minor; struct dp_link_desc_bank link_desc_banks[DP_LINK_DESC_BANKS_MAX]; + enum hal_rx_buf_return_buf_manager idle_link_rbm; struct dp_srng wbm_idle_ring; struct dp_srng wbm_desc_rel_ring; struct dp_srng tcl_cmd_ring; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index fc4b95324955..18030c9e735d 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2994,6 +2994,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, u32 cookie, hal_rx_desc_sz, dest_ring_info0; int ret; struct ath12k_rx_desc_info *desc_info; + enum hal_rx_buf_return_buf_manager idle_link_rbm = dp->idle_link_rbm; u8 dst_ind; hal_rx_desc_sz = ab->hal.hal_desc_sz; @@ -3071,7 +3072,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, ath12k_hal_rx_buf_addr_info_set(&reo_ent_ring->buf_addr_info, link_paddr, cookie, - HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST); + idle_link_rbm); mpdu_info = u32_encode_bits(1, RX_MPDU_DESC_INFO0_MSDU_COUNT) | u32_encode_bits(0, RX_MPDU_DESC_INFO0_FRAG_FLAG) | @@ -3451,7 +3452,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, (paddr - link_desc_banks[desc_bank].paddr); ath12k_hal_rx_msdu_link_info_get(link_desc_va, &num_msdus, msdu_cookies, &rbm); - if (rbm != HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST && + if (rbm != dp->idle_link_rbm && rbm != HAL_RX_BUF_RBM_SW3_BM && rbm != ab->hw_params->hal_params->rx_buf_rbm) { ab->soc_stats.invalid_rbm++; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 78310da8cfe8..ca04bfae8bdc 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -1969,14 +1969,15 @@ u32 ath12k_hal_ce_dst_status_get_length(struct hal_ce_srng_dst_status_desc *desc } void ath12k_hal_set_link_desc_addr(struct hal_wbm_link_desc *desc, u32 cookie, - dma_addr_t paddr) + dma_addr_t paddr, + enum hal_rx_buf_return_buf_manager rbm) { desc->buf_addr_info.info0 = le32_encode_bits((paddr & HAL_ADDR_LSB_REG_MASK), BUFFER_ADDR_INFO0_ADDR); desc->buf_addr_info.info1 = le32_encode_bits(((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT), BUFFER_ADDR_INFO1_ADDR) | - le32_encode_bits(1, BUFFER_ADDR_INFO1_RET_BUF_MGR) | + le32_encode_bits(rbm, BUFFER_ADDR_INFO1_RET_BUF_MGR) | le32_encode_bits(cookie, BUFFER_ADDR_INFO1_SW_COOKIE); } diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index f364b2938ef8..8a78bb9a10bc 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1113,7 +1113,8 @@ dma_addr_t ath12k_hal_srng_get_tp_addr(struct ath12k_base *ab, dma_addr_t ath12k_hal_srng_get_hp_addr(struct ath12k_base *ab, struct hal_srng *srng); void ath12k_hal_set_link_desc_addr(struct hal_wbm_link_desc *desc, u32 cookie, - dma_addr_t paddr); + dma_addr_t paddr, + enum hal_rx_buf_return_buf_manager rbm); u32 ath12k_hal_ce_get_desc_size(enum hal_ce_desc type); void ath12k_hal_ce_src_set_desc(struct hal_ce_srng_src_desc *desc, dma_addr_t paddr, u32 len, u32 id, u8 byte_swap_data); From b2d54ca73a5a177490f3f1ee2d23ff6ab6045b25 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Fri, 3 May 2024 13:34:38 +0300 Subject: [PATCH 09/69] wifi: ath12k: Introduce device index Introduce a device index parameter in the ath12k_base structure. This value is used as unique identifier for devices involved in Inter-device MLO. It is also used to configure the MLO parameter within the QMI host capability send request. While currently set to zero, future logic will be added for inter device support to populate this parameter with non-zero values. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430165811.1377182-4-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 10 ++++++++++ drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/qmi.c | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index e9aabdb9341c..9482d5db71e7 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1268,6 +1268,16 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, ab->qmi.num_radios = U8_MAX; ab->mlo_capable_flags = ATH12K_INTRA_DEVICE_MLO_SUPPORT; + /* Device index used to identify the devices in a group. + * + * In Intra-device MLO, only one device present in a group, + * so it is always zero. + * + * In Inter-device MLO, Multiple device present in a group, + * expect non-zero value. + */ + ab->device_id = 0; + return ab; err_free_wq: diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index d833361948b7..3cfc65b36579 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -754,6 +754,7 @@ struct ath12k_base { struct ath12k_qmi qmi; struct ath12k_wmi_base wmi_ab; struct completion fw_ready; + u8 device_id; int num_radios; /* HW channel counters frequency value in hertz common to all MACs */ u32 cc_freq_hz; diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 5484112859a6..3bb730326a02 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2041,7 +2041,7 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, req->mlo_capable_valid = 1; req->mlo_capable = 1; req->mlo_chip_id_valid = 1; - req->mlo_chip_id = 0; + req->mlo_chip_id = ab->device_id; req->mlo_group_id_valid = 1; req->mlo_group_id = 0; req->max_mlo_peer_valid = 1; @@ -2053,7 +2053,7 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, req->mlo_num_chips = 1; info = &req->mlo_chip_info[0]; - info->chip_id = 0; + info->chip_id = ab->device_id; info->num_local_links = ab->qmi.num_radios; for (i = 0; i < info->num_local_links; i++) { From 53bf4a14f8c55e84d200f8328fde39ab6bdf1bf5 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Fri, 3 May 2024 13:34:39 +0300 Subject: [PATCH 10/69] wifi: ath12k: add multi device support for WBM idle ring buffer setup Currently, inter device MLO is not supported. Therefore, the WBM idle ring buffers choose the implicit return buffer manager (DEV0_IDLE_DESC_LIST). However, this implicit return buffer manager design is not meeting the requirements to support inter device MLO. In inter device MLO, multiple devices participate. The device specific WBM idle ring buffers transmit to multiple device REO rings. To distinguish between device specific WBM idle buffers, the setup configuration need to choose a different return buffer manager based on the unique identifier (device index). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430165811.1377182-5-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index f41b3f9dac3d..72ea9baaf8d7 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1589,6 +1589,24 @@ static int ath12k_dp_reoq_lut_setup(struct ath12k_base *ab) return 0; } +static enum hal_rx_buf_return_buf_manager +ath12k_dp_get_idle_link_rbm(struct ath12k_base *ab) +{ + switch (ab->device_id) { + case 0: + return HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST; + case 1: + return HAL_RX_BUF_RBM_WBM_DEV1_IDLE_DESC_LIST; + case 2: + return HAL_RX_BUF_RBM_WBM_DEV2_IDLE_DESC_LIST; + default: + ath12k_warn(ab, "invalid %d device id, so choose default rbm\n", + ab->device_id); + WARN_ON(1); + return HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST; + } +} + int ath12k_dp_alloc(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; @@ -1605,7 +1623,7 @@ int ath12k_dp_alloc(struct ath12k_base *ab) spin_lock_init(&dp->reo_cmd_lock); dp->reo_cmd_cache_flush_count = 0; - dp->idle_link_rbm = HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST; + dp->idle_link_rbm = ath12k_dp_get_idle_link_rbm(ab); ret = ath12k_wbm_idle_ring_setup(ab, &n_link_desc); if (ret) { From 5453bbd6fef4ca2fea3b4b338fc715d7135afc6f Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 3 May 2024 13:34:39 +0300 Subject: [PATCH 11/69] wifi: ath12k: Don't drop tx_status in failure case When a station idles for a long time, hostapd will try to send a QoS Null frame to the station as "poll". NL80211_CMD_PROBE_CLIENT is used for this purpose. And the skb will be added to ack_status_frame - waiting for a completion via ieee80211_report_ack_skb(). But when the peer was already removed before the tx_complete arrives, the peer will be missing. And when using dev_kfree_skb_any (instead of going through mac80211), the entry will stay inside ack_status_frames thus not clean up related information in its internal data structures. This IDR will therefore run full after 8K request were generated for such clients. At this point, the access point will then just stall and not allow any new clients because idr_alloc() for ack_status_frame will fail. ieee80211_free_txskb() on the other hand will (when required) call ieee80211_report_ack_skb() and make sure that (when required) remove the entry from the ack_status_frame and clean up related information in its internal data structures. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Sven Eckelmann Signed-off-by: Sarika Sharma Signed-off-by: Karthikeyan Kathirvel Link: https://lore.kernel.org/r/20230802-ath11k-ack_status_leak-v2-1-c0af729d6229@narfation.org Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430074313.885807-2-quic_kathirve@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_tx.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 9b6d7d72f57c..81a85d5946f5 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -352,15 +352,15 @@ static void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab, u8 pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); skb_cb = ATH12K_SKB_CB(msdu); + ar = ab->pdevs[pdev_id].ar; dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); if (skb_cb->paddr_ext_desc) dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc, sizeof(struct hal_tx_msdu_ext_desc), DMA_TO_DEVICE); - dev_kfree_skb_any(msdu); + ieee80211_free_txskb(ar->ah->hw, msdu); - ar = ab->pdevs[pdev_id].ar; if (atomic_dec_and_test(&ar->dp.num_tx_pending)) wake_up(&ar->dp.tx_empty_waitq); } @@ -448,6 +448,7 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, struct hal_tx_status *ts) { struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ar->ah; struct ieee80211_tx_info *info; struct ath12k_skb_cb *skb_cb; @@ -466,12 +467,12 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, rcu_read_lock(); if (!rcu_dereference(ab->pdevs_active[ar->pdev_idx])) { - dev_kfree_skb_any(msdu); + ieee80211_free_txskb(ah->hw, msdu); goto exit; } if (!skb_cb->vif) { - dev_kfree_skb_any(msdu); + ieee80211_free_txskb(ah->hw, msdu); goto exit; } From 50971dc6694c0845fcddfe337ea39c5b723d5a92 Mon Sep 17 00:00:00 2001 From: Karthikeyan Kathirvel Date: Fri, 3 May 2024 13:34:39 +0300 Subject: [PATCH 12/69] wifi: ath12k: drop failed transmitted frames from metric calculation. In mesh node traffic, internal firmware-transmitted failures are reported as transmitted failures in mesh metric calculation, leading to the breakage of the mesh link. Fix the issue by dropping the internal firmware-transmitted failures before updating the TX completion status to mac80211, in order to prevent false failure averaging in mesh metric calculation. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Karthikeyan Kathirvel Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430074313.885807-3-quic_kathirve@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_tx.c | 38 ++++++++++++++++------ drivers/net/wireless/ath/ath12k/hal_desc.h | 22 ++++++++++++- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 81a85d5946f5..a7c7a868c14c 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -482,18 +482,36 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, /* skip tx rate update from ieee80211_status*/ info->status.rates[0].idx = -1; - if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED && - !(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ATH12K_DEFAULT_NOISE_FLOOR + - ts->ack_rssi; - info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; + switch (ts->status) { + case HAL_WBM_TQM_REL_REASON_FRAME_ACKED: + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ATH12K_DEFAULT_NOISE_FLOOR + + ts->ack_rssi; + info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; + } + break; + case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX: + if (info->flags & IEEE80211_TX_CTL_NO_ACK) { + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + break; + } + fallthrough; + case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_MPDU: + case HAL_WBM_TQM_REL_REASON_DROP_THRESHOLD: + case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_AGED_FRAMES: + /* The failure status is due to internal firmware tx failure + * hence drop the frame; do not update the status of frame to + * the upper layer + */ + ieee80211_free_txskb(ah->hw, msdu); + goto exit; + default: + ath12k_dbg(ab, ATH12K_DBG_DP_TX, "tx frame is not acked status %d\n", + ts->status); + break; } - if (ts->status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX && - (info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - /* NOTE: Tx rate status reporting. Tx completion status does not have * necessary information (for example nss) to build the tx rate. * Might end up reporting it out-of-band from HTT stats. diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 63340256d3f6..814c02f876d6 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -2048,6 +2048,19 @@ struct hal_wbm_release_ring { * fw with fw_reason2. * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON3: Remove command initiated by * fw with fw_reason3. + * @HAL_WBM_TQM_REL_REASON_CMD_DISABLE_QUEUE: Remove command initiated by + * fw with disable queue. + * @HAL_WBM_TQM_REL_REASON_CMD_TILL_NONMATCHING: Remove command initiated by + * fw to remove all mpdu until 1st non-match. + * @HAL_WBM_TQM_REL_REASON_DROP_THRESHOLD: Dropped due to drop threshold + * criteria + * @HAL_WBM_TQM_REL_REASON_DROP_LINK_DESC_UNAVAIL: Dropped due to link desc + * not available + * @HAL_WBM_TQM_REL_REASON_DROP_OR_INVALID_MSDU: Dropped due drop bit set or + * null flow + * @HAL_WBM_TQM_REL_REASON_MULTICAST_DROP: Dropped due mcast drop set for VDEV + * @HAL_WBM_TQM_REL_REASON_VDEV_MISMATCH_DROP: Dropped due to being set with + * 'TCL_drop_reason' */ enum hal_wbm_tqm_rel_reason { HAL_WBM_TQM_REL_REASON_FRAME_ACKED, @@ -2058,6 +2071,13 @@ enum hal_wbm_tqm_rel_reason { HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON1, HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON2, HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON3, + HAL_WBM_TQM_REL_REASON_CMD_DISABLE_QUEUE, + HAL_WBM_TQM_REL_REASON_CMD_TILL_NONMATCHING, + HAL_WBM_TQM_REL_REASON_DROP_THRESHOLD, + HAL_WBM_TQM_REL_REASON_DROP_LINK_DESC_UNAVAIL, + HAL_WBM_TQM_REL_REASON_DROP_OR_INVALID_MSDU, + HAL_WBM_TQM_REL_REASON_MULTICAST_DROP, + HAL_WBM_TQM_REL_REASON_VDEV_MISMATCH_DROP, }; struct hal_wbm_buffer_ring { From 4c2b796be3a12a11ab611917fafdabc9d3862a1d Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Fri, 3 May 2024 16:24:16 +0300 Subject: [PATCH 13/69] wifi: ath11k: skip status ring entry processing If STATUS_BUFFER_DONE is not set for a monitor status ring entry, we don't process the status ring until STATUS_BUFFER_DONE set for that status ring entry. During LMAC reset it may happen that hardware will not write STATUS_BUFFER_DONE tlv in status buffer, in that case we end up waiting for STATUS_BUFFER_DONE leading to backpressure on monitor status ring. To fix the issue, when HP (Head Pointer) + 1 entry is peeked and if DMA is not done and if HP + 2 entry's DMA done is set, replenish HP + 1 entry and start processing in next interrupt. If HP + 2 entry's DMA done is not set, poll onto HP + 1 entry DMA done to be set. Also, during monitor attach HP points to the end of the ring and TP (Tail Pointer) points to the start of the ring. Using ath11k_hal_srng_src_peek() may result in processing invalid buffer for the very first interrupt. Since, HW starts writing buffer from TP. To avoid this issue call ath11k_hal_srng_src_next_peek() instead of calling ath11k_hal_srng_src_peek(). Tested-on: IPQ5018 hw1.0 AHB WLAN.HK.2.6.0.1-00861-QCAHKSWPL_SILICONZ-1 Signed-off-by: Venkateswara Naralasetty Co-developed-by: Tamizh Chelvam Raja Signed-off-by: Tamizh Chelvam Raja Signed-off-by: Kalle Valo Link: https://msgid.link/20240429073624.736147-1-quic_tamizhr@quicinc.com --- drivers/net/wireless/ath/ath11k/dp_rx.c | 82 ++++++++++++++++++++++--- drivers/net/wireless/ath/ath11k/hal.c | 16 ++++- drivers/net/wireless/ath/ath11k/hal.h | 2 + 3 files changed, 90 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index afd481f5858f..8a860a17d7e4 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2990,11 +2990,52 @@ ath11k_dp_rx_mon_update_status_buf_state(struct ath11k_mon_data *pmon, } } +static enum dp_mon_status_buf_state +ath11k_dp_rx_mon_buf_done(struct ath11k_base *ab, struct hal_srng *srng, + struct dp_rxdma_ring *rx_ring) +{ + struct ath11k_skb_rxcb *rxcb; + struct hal_tlv_hdr *tlv; + struct sk_buff *skb; + void *status_desc; + dma_addr_t paddr; + u32 cookie; + int buf_id; + u8 rbm; + + status_desc = ath11k_hal_srng_src_next_peek(ab, srng); + if (!status_desc) + return DP_MON_STATUS_NO_DMA; + + ath11k_hal_rx_buf_addr_info_get(status_desc, &paddr, &cookie, &rbm); + + buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie); + + spin_lock_bh(&rx_ring->idr_lock); + skb = idr_find(&rx_ring->bufs_idr, buf_id); + spin_unlock_bh(&rx_ring->idr_lock); + + if (!skb) + return DP_MON_STATUS_NO_DMA; + + rxcb = ATH11K_SKB_RXCB(skb); + dma_sync_single_for_cpu(ab->dev, rxcb->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + + tlv = (struct hal_tlv_hdr *)skb->data; + if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != HAL_RX_STATUS_BUFFER_DONE) + return DP_MON_STATUS_NO_DMA; + + return DP_MON_STATUS_REPLINISH; +} + static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, int *budget, struct sk_buff_head *skb_list) { struct ath11k *ar; const struct ath11k_hw_hal_params *hal_params; + enum dp_mon_status_buf_state reap_status; struct ath11k_pdev_dp *dp; struct dp_rxdma_ring *rx_ring; struct ath11k_mon_data *pmon; @@ -3057,15 +3098,38 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, ath11k_warn(ab, "mon status DONE not set %lx, buf_id %d\n", FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl), buf_id); - /* If done status is missing, hold onto status - * ring until status is done for this status - * ring buffer. - * Keep HP in mon_status_ring unchanged, - * and break from here. - * Check status for same buffer for next time + /* RxDMA status done bit might not be set even + * though tp is moved by HW. */ - pmon->buf_state = DP_MON_STATUS_NO_DMA; - break; + + /* If done status is missing: + * 1. As per MAC team's suggestion, + * when HP + 1 entry is peeked and if DMA + * is not done and if HP + 2 entry's DMA done + * is set. skip HP + 1 entry and + * start processing in next interrupt. + * 2. If HP + 2 entry's DMA done is not set, + * poll onto HP + 1 entry DMA done to be set. + * Check status for same buffer for next time + * dp_rx_mon_status_srng_process + */ + + reap_status = ath11k_dp_rx_mon_buf_done(ab, srng, + rx_ring); + if (reap_status == DP_MON_STATUS_NO_DMA) + continue; + + spin_lock_bh(&rx_ring->idr_lock); + idr_remove(&rx_ring->bufs_idr, buf_id); + spin_unlock_bh(&rx_ring->idr_lock); + + dma_unmap_single(ab->dev, rxcb->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + + dev_kfree_skb_any(skb); + pmon->buf_state = DP_MON_STATUS_REPLINISH; + goto move_next; } spin_lock_bh(&rx_ring->idr_lock); diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index f3d04568c221..f02599bd1c36 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include "hal_tx.h" @@ -796,6 +796,20 @@ u32 *ath11k_hal_srng_src_get_next_reaped(struct ath11k_base *ab, return desc; } +u32 *ath11k_hal_srng_src_next_peek(struct ath11k_base *ab, struct hal_srng *srng) +{ + u32 next_hp; + + lockdep_assert_held(&srng->lock); + + next_hp = (srng->u.src_ring.hp + srng->entry_size) % srng->ring_size; + + if (next_hp != srng->u.src_ring.cached_tp) + return srng->ring_base_vaddr + next_hp; + + return NULL; +} + u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng) { lockdep_assert_held(&srng->lock); diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index e453c137385e..dc8bbe073017 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -947,6 +947,8 @@ u32 *ath11k_hal_srng_dst_peek(struct ath11k_base *ab, struct hal_srng *srng); int ath11k_hal_srng_dst_num_free(struct ath11k_base *ab, struct hal_srng *srng, bool sync_hw_ptr); u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng); +u32 *ath11k_hal_srng_src_next_peek(struct ath11k_base *ab, + struct hal_srng *srng); u32 *ath11k_hal_srng_src_get_next_reaped(struct ath11k_base *ab, struct hal_srng *srng); u32 *ath11k_hal_srng_src_reap_next(struct ath11k_base *ab, From 10d2b4f4aa0b9a1ac55d2313d2c682add25e31c6 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 3 May 2024 03:32:56 -0700 Subject: [PATCH 14/69] wifi: wil6210: Do not use embedded netdev in wil6210_priv Embedding net_device into structures prohibits the usage of flexible arrays in the net_device structure. For more details, see the discussion at [1]. Un-embed the net_device from struct wil6210_priv by converting it into a pointer. Then use the leverage alloc_netdev_dummy() to allocate the net_device object at wil_if_add(). The free of the device occurs at wil_if_remove(). Link: https://lore.kernel.org/all/20240229225910.79e224cf@kernel.org/ [1] Signed-off-by: Breno Leitao Signed-off-by: Kalle Valo Link: https://msgid.link/20240503103304.339489-1-leitao@debian.org --- drivers/net/wireless/ath/wil6210/netdev.c | 21 +++++++++++++++------ drivers/net/wireless/ath/wil6210/wil6210.h | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index ee7d7e9c2718..d5d364683c0e 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -453,16 +453,21 @@ int wil_if_add(struct wil6210_priv *wil) return rc; } - init_dummy_netdev(&wil->napi_ndev); + wil->napi_ndev = alloc_netdev_dummy(0); + if (!wil->napi_ndev) { + wil_err(wil, "failed to allocate dummy netdev"); + rc = -ENOMEM; + goto out_wiphy; + } if (wil->use_enhanced_dma_hw) { - netif_napi_add(&wil->napi_ndev, &wil->napi_rx, + netif_napi_add(wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx_edma); - netif_napi_add_tx(&wil->napi_ndev, + netif_napi_add_tx(wil->napi_ndev, &wil->napi_tx, wil6210_netdev_poll_tx_edma); } else { - netif_napi_add(&wil->napi_ndev, &wil->napi_rx, + netif_napi_add(wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx); - netif_napi_add_tx(&wil->napi_ndev, + netif_napi_add_tx(wil->napi_ndev, &wil->napi_tx, wil6210_netdev_poll_tx); } @@ -474,10 +479,12 @@ int wil_if_add(struct wil6210_priv *wil) wiphy_unlock(wiphy); rtnl_unlock(); if (rc < 0) - goto out_wiphy; + goto free_dummy; return 0; +free_dummy: + free_netdev(wil->napi_ndev); out_wiphy: wiphy_unregister(wiphy); return rc; @@ -554,5 +561,7 @@ void wil_if_remove(struct wil6210_priv *wil) netif_napi_del(&wil->napi_tx); netif_napi_del(&wil->napi_rx); + free_netdev(wil->napi_ndev); + wiphy_unregister(wiphy); } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 22a6eb3e12b7..9bd1286d2857 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -983,7 +983,7 @@ struct wil6210_priv { spinlock_t eap_lock; /* guarding access to eap rekey fields */ struct napi_struct napi_rx; struct napi_struct napi_tx; - struct net_device napi_ndev; /* dummy net_device serving all VIFs */ + struct net_device *napi_ndev; /* dummy net_device serving all VIFs */ /* DMA related */ struct wil_ring ring_rx; From 9f74e7b306dcd7a163822ecb3b1587e9bd3f9c62 Mon Sep 17 00:00:00 2001 From: Tamizh Chelvam Raja Date: Tue, 30 Apr 2024 14:44:12 +0530 Subject: [PATCH 15/69] wifi: ath12k: fix calling correct function for rx monitor mode Currently in ath12k_dp_tx_htt_monitor_mode_ring_config() ath12k_dp_tx_htt_tx_monitor_mode_ring_config() function wrongly called twice. Fix that by calling ath12k_dp_tx_htt_rx_monitor_mode_ring_config(). Currently monitor mode is disabled in driver so the change is compile tested and boot sequence verified. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Tamizh Chelvam Raja Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430091414.2486196-2-quic_tamizhr@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index a7c7a868c14c..7adfdefc3bdc 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -1069,7 +1069,7 @@ int ath12k_dp_tx_htt_monitor_mode_ring_config(struct ath12k *ar, bool reset) return ret; } - ret = ath12k_dp_tx_htt_tx_monitor_mode_ring_config(ar, reset); + ret = ath12k_dp_tx_htt_rx_monitor_mode_ring_config(ar, reset); if (ret) { ath12k_err(ab, "failed to setup rx monitor filter %d\n", ret); return ret; From ed07ff6745092f36cd996658bd64d74e4331d331 Mon Sep 17 00:00:00 2001 From: Tamizh Chelvam Raja Date: Tue, 30 Apr 2024 14:44:13 +0530 Subject: [PATCH 16/69] wifi: ath12k: Remove unsupported tx monitor handling Currently tx monitor is not supported in driver. So remove the tx monitor ring configuration, allocation and handling. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Tamizh Chelvam Raja Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430091414.2486196-3-quic_tamizhr@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_mon.c | 40 +--------------- drivers/net/wireless/ath/ath12k/dp_rx.c | 59 +----------------------- drivers/net/wireless/ath/ath12k/dp_tx.c | 42 ----------------- drivers/net/wireless/ath/ath12k/dp_tx.h | 3 +- 4 files changed, 3 insertions(+), 141 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 6b0b72477540..5c6749bc4039 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1903,43 +1903,6 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab, break; } - case HAL_MON_BUF_ADDR: { - struct dp_rxdma_mon_ring *buf_ring = &ab->dp.tx_mon_buf_ring; - struct dp_mon_packet_info *packet_info = - (struct dp_mon_packet_info *)tlv_data; - int buf_id = u32_get_bits(packet_info->cookie, - DP_RXDMA_BUF_COOKIE_BUF_ID); - struct sk_buff *msdu; - struct dp_mon_mpdu *mon_mpdu = tx_ppdu_info->tx_mon_mpdu; - struct ath12k_skb_rxcb *rxcb; - - spin_lock_bh(&buf_ring->idr_lock); - msdu = idr_remove(&buf_ring->bufs_idr, buf_id); - spin_unlock_bh(&buf_ring->idr_lock); - - if (unlikely(!msdu)) { - ath12k_warn(ab, "monitor destination with invalid buf_id %d\n", - buf_id); - return DP_MON_TX_STATUS_PPDU_NOT_DONE; - } - - rxcb = ATH12K_SKB_RXCB(msdu); - dma_unmap_single(ab->dev, rxcb->paddr, - msdu->len + skb_tailroom(msdu), - DMA_FROM_DEVICE); - - if (!mon_mpdu->head) - mon_mpdu->head = msdu; - else if (mon_mpdu->tail) - mon_mpdu->tail->next = msdu; - - mon_mpdu->tail = msdu; - - ath12k_dp_mon_buf_replenish(ab, buf_ring, 1); - status = DP_MON_TX_BUFFER_ADDR; - break; - } - case HAL_TX_MPDU_END: list_add_tail(&tx_ppdu_info->tx_mon_mpdu->list, &tx_ppdu_info->dp_tx_mon_mpdu_list); @@ -2088,8 +2051,7 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id, int *budget, mon_dst_ring = &pdev_dp->rxdma_mon_dst_ring[srng_id]; buf_ring = &dp->rxdma_mon_buf_ring; } else { - mon_dst_ring = &pdev_dp->tx_mon_dst_ring[srng_id]; - buf_ring = &dp->tx_mon_buf_ring; + return 0; } srng = &ab->hal.srng_list[mon_dst_ring->ring_id]; diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 18030c9e735d..952a377b5491 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -422,8 +422,6 @@ static int ath12k_dp_rxdma_buf_free(struct ath12k_base *ab) ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->rxdma_mon_buf_ring); - ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->tx_mon_buf_ring); - return 0; } @@ -476,15 +474,6 @@ static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab) "failed to setup HAL_RXDMA_MONITOR_BUF\n"); return ret; } - - ret = ath12k_dp_rxdma_mon_ring_buf_setup(ab, - &dp->tx_mon_buf_ring, - HAL_TX_MONITOR_BUF); - if (ret) { - ath12k_warn(ab, - "failed to setup HAL_TX_MONITOR_BUF\n"); - return ret; - } } return 0; @@ -496,10 +485,8 @@ static void ath12k_dp_rx_pdev_srng_free(struct ath12k *ar) struct ath12k_base *ab = ar->ab; int i; - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) ath12k_dp_srng_cleanup(ab, &dp->rxdma_mon_dst_ring[i]); - ath12k_dp_srng_cleanup(ab, &dp->tx_mon_dst_ring[i]); - } } void ath12k_dp_rx_pdev_reo_cleanup(struct ath12k_base *ab) @@ -554,17 +541,6 @@ static int ath12k_dp_rx_pdev_srng_alloc(struct ath12k *ar) "failed to setup HAL_RXDMA_MONITOR_DST\n"); return ret; } - - ret = ath12k_dp_srng_setup(ar->ab, - &dp->tx_mon_dst_ring[i], - HAL_TX_MONITOR_DST, - 0, mac_id + i, - DP_TX_MONITOR_DEST_RING_SIZE); - if (ret) { - ath12k_warn(ar->ab, - "failed to setup HAL_TX_MONITOR_DST\n"); - return ret; - } } return 0; @@ -3971,7 +3947,6 @@ void ath12k_dp_rx_free(struct ath12k_base *ab) ath12k_dp_srng_cleanup(ab, &dp->rxdma_err_dst_ring[i]); ath12k_dp_srng_cleanup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring); - ath12k_dp_srng_cleanup(ab, &dp->tx_mon_buf_ring.refill_buf_ring); ath12k_dp_rxdma_buf_free(ab); } @@ -4114,15 +4089,6 @@ int ath12k_dp_rx_htt_setup(struct ath12k_base *ab) ret); return ret; } - - ring_id = dp->tx_mon_buf_ring.refill_buf_ring.ring_id; - ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, - 0, HAL_TX_MONITOR_BUF); - if (ret) { - ath12k_warn(ab, "failed to configure rxdma_mon_buf_ring %d\n", - ret); - return ret; - } } ret = ab->hw_params->hw_ops->rxdma_ring_sel_config(ab); @@ -4142,9 +4108,6 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) idr_init(&dp->rxdma_mon_buf_ring.bufs_idr); spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock); - idr_init(&dp->tx_mon_buf_ring.bufs_idr); - spin_lock_init(&dp->tx_mon_buf_ring.idr_lock); - ret = ath12k_dp_srng_setup(ab, &dp->rx_refill_buf_ring.refill_buf_ring, HAL_RXDMA_BUF, 0, 0, @@ -4187,15 +4150,6 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) ath12k_warn(ab, "failed to setup HAL_RXDMA_MONITOR_BUF\n"); return ret; } - - ret = ath12k_dp_srng_setup(ab, - &dp->tx_mon_buf_ring.refill_buf_ring, - HAL_TX_MONITOR_BUF, 0, 0, - DP_TX_MONITOR_BUF_RING_SIZE); - if (ret) { - ath12k_warn(ab, "failed to setup DP_TX_MONITOR_BUF_RING_SIZE\n"); - return ret; - } } ret = ath12k_dp_rxdma_buf_setup(ab); @@ -4235,17 +4189,6 @@ int ath12k_dp_rx_pdev_alloc(struct ath12k_base *ab, int mac_id) i, ret); return ret; } - - ring_id = dp->tx_mon_dst_ring[i].ring_id; - ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, - mac_id + i, - HAL_TX_MONITOR_DST); - if (ret) { - ath12k_warn(ab, - "failed to configure tx_mon_dst_ring %d %d\n", - i, ret); - return ret; - } } out: return 0; diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 7adfdefc3bdc..a22fa43c87ec 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -688,14 +688,6 @@ ath12k_dp_tx_get_ring_id_type(struct ath12k_base *ab, *htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING; *htt_ring_type = HTT_SW_TO_HW_RING; break; - case HAL_TX_MONITOR_BUF: - *htt_ring_id = HTT_TX_MON_HOST2MON_BUF_RING; - *htt_ring_type = HTT_SW_TO_HW_RING; - break; - case HAL_TX_MONITOR_DST: - *htt_ring_id = HTT_TX_MON_MON2HOST_DEST_RING; - *htt_ring_type = HTT_HW_TO_SW_RING; - break; default: ath12k_warn(ab, "Unsupported ring type in DP :%d\n", ring_type); ret = -EINVAL; @@ -1063,12 +1055,6 @@ int ath12k_dp_tx_htt_monitor_mode_ring_config(struct ath12k *ar, bool reset) struct ath12k_base *ab = ar->ab; int ret; - ret = ath12k_dp_tx_htt_tx_monitor_mode_ring_config(ar, reset); - if (ret) { - ath12k_err(ab, "failed to setup tx monitor filter %d\n", ret); - return ret; - } - ret = ath12k_dp_tx_htt_rx_monitor_mode_ring_config(ar, reset); if (ret) { ath12k_err(ab, "failed to setup rx monitor filter %d\n", ret); @@ -1228,31 +1214,3 @@ int ath12k_dp_tx_htt_tx_filter_setup(struct ath12k_base *ab, u32 ring_id, dev_kfree_skb_any(skb); return ret; } - -int ath12k_dp_tx_htt_tx_monitor_mode_ring_config(struct ath12k *ar, bool reset) -{ - struct ath12k_base *ab = ar->ab; - struct ath12k_dp *dp = &ab->dp; - struct htt_tx_ring_tlv_filter tlv_filter = {0}; - int ret, ring_id; - - ring_id = dp->tx_mon_buf_ring.refill_buf_ring.ring_id; - - /* TODO: Need to set upstream/downstream tlv filters - * here - */ - - if (ab->hw_params->rxdma1_enable) { - ret = ath12k_dp_tx_htt_tx_filter_setup(ar->ab, ring_id, 0, - HAL_TX_MONITOR_BUF, - DP_RXDMA_REFILL_RING_SIZE, - &tlv_filter); - if (ret) { - ath12k_err(ab, - "failed to setup filter for monitor buf %d\n", ret); - return ret; - } - } - - return 0; -} diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.h b/drivers/net/wireless/ath/ath12k/dp_tx.h index 436d77e5e9ee..7faa81faf6a7 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.h +++ b/drivers/net/wireless/ath/ath12k/dp_tx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_TX_H @@ -36,6 +36,5 @@ int ath12k_dp_tx_htt_tx_filter_setup(struct ath12k_base *ab, u32 ring_id, int mac_id, enum hal_ring_type ring_type, int tx_buf_size, struct htt_tx_ring_tlv_filter *htt_tlv_filter); -int ath12k_dp_tx_htt_tx_monitor_mode_ring_config(struct ath12k *ar, bool reset); int ath12k_dp_tx_htt_monitor_mode_ring_config(struct ath12k *ar, bool reset); #endif From 582e94ebe230afa35baef06833006b24b601ab11 Mon Sep 17 00:00:00 2001 From: Tamizh Chelvam Raja Date: Tue, 30 Apr 2024 14:44:14 +0530 Subject: [PATCH 17/69] wifi: ath12k: Remove unused tcl_*_ring configuration Currently memory allocation for multiple hardware rings done in host as these memory will be used by firmware/hardware. But in case of tcl_cmd_ring and tcl_status_ring neither firmware nor hardware uses host allocated memory and it uses memory allocated by firmware itself. So avoid tcl_cmd_ring and tcl_status_ring setup in host. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Tamizh Chelvam Raja Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240430091414.2486196-4-quic_tamizhr@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 16 ---------------- drivers/net/wireless/ath/ath12k/dp.h | 2 -- 2 files changed, 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 72ea9baaf8d7..ca41f4431394 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -457,8 +457,6 @@ static void ath12k_dp_srng_common_cleanup(struct ath12k_base *ab) ath12k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_comp_ring); ath12k_dp_srng_cleanup(ab, &dp->tx_ring[i].tcl_data_ring); } - ath12k_dp_srng_cleanup(ab, &dp->tcl_status_ring); - ath12k_dp_srng_cleanup(ab, &dp->tcl_cmd_ring); ath12k_dp_srng_cleanup(ab, &dp->wbm_desc_rel_ring); } @@ -479,20 +477,6 @@ static int ath12k_dp_srng_common_setup(struct ath12k_base *ab) goto err; } - ret = ath12k_dp_srng_setup(ab, &dp->tcl_cmd_ring, HAL_TCL_CMD, 0, 0, - DP_TCL_CMD_RING_SIZE); - if (ret) { - ath12k_warn(ab, "failed to set up tcl_cmd ring :%d\n", ret); - goto err; - } - - ret = ath12k_dp_srng_setup(ab, &dp->tcl_status_ring, HAL_TCL_STATUS, - 0, 0, DP_TCL_STATUS_RING_SIZE); - if (ret) { - ath12k_warn(ab, "failed to set up tcl_status ring :%d\n", ret); - goto err; - } - for (i = 0; i < ab->hw_params->max_tx_ring; i++) { map = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map; tx_comp_ring_num = map[i].wbm_ring_num; diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index e9880b34a7ab..43589c3dd4bc 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -328,8 +328,6 @@ struct ath12k_dp { enum hal_rx_buf_return_buf_manager idle_link_rbm; struct dp_srng wbm_idle_ring; struct dp_srng wbm_desc_rel_ring; - struct dp_srng tcl_cmd_ring; - struct dp_srng tcl_status_ring; struct dp_srng reo_reinject_ring; struct dp_srng rx_rel_ring; struct dp_srng reo_except_ring; From 782615f280ce8ad4e3effb42d70304f4dd2d487f Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 29 Apr 2024 16:15:21 +0800 Subject: [PATCH 18/69] wifi: ath12k: remove unused variable monitor_flags monitor_flags is defined in struct ath12k. Although it is changed in some places, but it is not actually used. So remove related code. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240429081525.983-2-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 5 ----- drivers/net/wireless/ath/ath12k/mac.c | 10 +--------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 3cfc65b36579..bb6c1b562baf 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -212,10 +212,6 @@ enum ath12k_dev_flags { ATH12K_FLAG_EXT_IRQ_ENABLED, }; -enum ath12k_monitor_flags { - ATH12K_FLAG_MONITOR_ENABLED, -}; - struct ath12k_tx_conf { bool changed; u16 ac; @@ -532,7 +528,6 @@ struct ath12k { unsigned long dev_flags; unsigned int filter_flags; - unsigned long monitor_flags; u32 min_tx_power; u32 max_tx_power; u32 txpower_limit_2g; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 4f07ac8c0287..a2b5aa86ec0b 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -6510,7 +6510,6 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif) /* Recalc txpower for remaining vdev */ ath12k_mac_txpower_recalc(ar); - clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); /* TODO: recal traffic pause state based on the available vdevs */ arvif->is_created = false; @@ -6581,15 +6580,9 @@ static void ath12k_mac_configure_filter(struct ath12k *ar, reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC); ret = ath12k_dp_tx_htt_monitor_mode_ring_config(ar, reset_flag); - if (!ret) { - if (!reset_flag) - set_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); - else - clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); - } else { + if (ret) ath12k_warn(ar->ab, "fail to set monitor filter: %d\n", ret); - } ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "total_flags:0x%x, reset_flag:%d\n", @@ -8869,7 +8862,6 @@ static void ath12k_mac_setup(struct ath12k *ar) INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); skb_queue_head_init(&ar->wmi_mgmt_tx_queue); - clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); } int ath12k_mac_register(struct ath12k_base *ab) From 3b0989e925f38df733a03ff5a320d6841006b3f9 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 29 Apr 2024 16:15:22 +0800 Subject: [PATCH 19/69] wifi: ath12k: avoid duplicated vdev stop ath12k_mac_op_unassign_vif_chanctx() will do vdev stop in ath12k_mac_monitor_stop(). This ath12k_mac_vdev_stop() will do vdev stop again, then might trigger firmware crash. So add judgement to avoid duplicated vdev stop. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Fixes: c9e4e41e71ff ("wifi: ath12k: move peer delete after vdev stop of station for WCN7850") Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240429081525.983-3-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a2b5aa86ec0b..cdea47faef74 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7397,7 +7397,8 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = false; } - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA && + arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { ath12k_bss_disassoc(ar, arvif); ret = ath12k_mac_vdev_stop(arvif); if (ret) From f40aaca07bf7b52e82ca8e5ddb29190466b5dcbd Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 29 Apr 2024 16:15:23 +0800 Subject: [PATCH 20/69] wifi: ath12k: avoid duplicated vdev down ath12k_mac_op_unassign_vif_chanctx() will do vdev down in function ath12k_mac_monitor_stop(). So no need to do vdev down again. remove the duplicated one. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240429081525.983-4-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index cdea47faef74..1fc727b614d6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7407,10 +7407,6 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, } arvif->is_started = false; - if (ab->hw_params->vdev_start_delay && - arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) - ath12k_wmi_vdev_down(ar, arvif->vdev_id); - if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->num_started_vdevs == 1 && ar->monitor_vdev_created) ath12k_mac_monitor_stop(ar); From efd920f48d1f9c41368579d1a278e88c082cc233 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Mon, 29 Apr 2024 16:15:25 +0800 Subject: [PATCH 21/69] wifi: ath12k: remove invalid peer create logic In ath12k_mac_op_assign_vif_chanctx(), there is a logic to create peer using ar->mac_addr for a STA vdev. This is invalid because a STA vdev should have a peer created using AP's MAC address. Besides, if we run into that logic, it means a peer has already been created earlier, we should not create it again. So remove it. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240429081525.983-6-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 1fc727b614d6..96dc5c2e096f 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7270,7 +7270,6 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; - struct ath12k_wmi_peer_create_arg param; /* 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 @@ -7306,21 +7305,6 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - if (ab->hw_params->vdev_start_delay && - arvif->vdev_type != WMI_VDEV_TYPE_AP && - arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { - param.vdev_id = arvif->vdev_id; - param.peer_type = WMI_PEER_TYPE_DEFAULT; - param.peer_addr = ar->mac_addr; - - ret = ath12k_peer_create(ar, arvif, NULL, ¶m); - if (ret) { - ath12k_warn(ab, "failed to create peer after vdev start delay: %d", - ret); - goto out; - } - } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath12k_mac_monitor_start(ar); if (ret) From bb0b0a6b96e6de854cb1e349e17bd0e8bf421a59 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 4 May 2024 11:52:08 -0700 Subject: [PATCH 22/69] wifi: ath12k: initialize 'ret' in ath12k_qmi_load_file_target_mem() smatch flagged the following issue: drivers/net/wireless/ath/ath12k/qmi.c:2619 ath12k_qmi_load_file_target_mem() error: uninitialized symbol 'ret'. The reality is that 'ret' is initialized in every path through ath12k_qmi_load_file_target_mem() except one, the case where the input 'len' is 0, and hence the "while (remaining)" loop is never entered. But to make sure this case is also handled, add an initializer to the declaration of 'ret'. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240504-qmi_load_file_target_mem-v1-1-069fc44c45eb@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 3bb730326a02..f273cb93dedb 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2538,7 +2538,7 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab, struct qmi_wlanfw_bdf_download_resp_msg_v01 resp = {}; struct qmi_txn txn; const u8 *temp = data; - int ret; + int ret = 0; u32 remaining = len; req = kzalloc(sizeof(*req), GFP_KERNEL); From 199f149e97dc7be80e5eed4b232529c1d1aa8055 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 4 May 2024 11:52:09 -0700 Subject: [PATCH 23/69] wifi: ath11k: initialize 'ret' in ath11k_qmi_load_file_target_mem() smatch flagged the following issue: drivers/net/wireless/ath/ath11k/qmi.c:2401 ath11k_qmi_load_file_target_mem() error: uninitialized symbol 'ret'. The reality is that 'ret' is initialized in every path through ath11k_qmi_load_file_target_mem() except one, the case where the input 'len' is 0, and hence the "while (remaining)" loop is never entered. But to make sure this case is also handled, add an initializer to the declaration of 'ret'. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240504-qmi_load_file_target_mem-v1-2-069fc44c45eb@quicinc.com --- drivers/net/wireless/ath/ath11k/qmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index d4a243b64f6c..aa160e6fe24f 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2293,7 +2293,7 @@ static int ath11k_qmi_load_file_target_mem(struct ath11k_base *ab, struct qmi_txn txn; const u8 *temp = data; void __iomem *bdf_addr = NULL; - int ret; + int ret = 0; u32 remaining = len; req = kzalloc(sizeof(*req), GFP_KERNEL); From 2db7a82fd150193849d04592e205b3d178207840 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Mon, 6 May 2024 23:00:17 +0530 Subject: [PATCH 24/69] wifi: ath12k: avoid double SW2HW_MACID conversion Currently, ath12k_wmi_pdev_dma_ring_cfg() fails due to an invalid pdev_id parameter passed to the WMI_PDEV_DMA_RING_CFG_REQ_CMDID WMI command. This invalid pdev_id is caused by a double conversion of the MAC ID. Since the the caller of ath12k_wmi_pdev_dma_ring_cfg() already performs the MAC ID conversion, it is unnecessary to do it again within the function. To fix this, remove the software (SW) to hardware (HW) MAC ID conversion from ath12k_wmi_pdev_dma_ring_cfg() to avoid this redundant conversion. Found in code review. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240506173017.597715-1-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7a52d2082b79..9e9f58b5cbfb 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -3808,7 +3808,7 @@ int ath12k_wmi_pdev_dma_ring_cfg(struct ath12k *ar, cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_DMA_RING_CFG_REQ, sizeof(*cmd)); - cmd->pdev_id = cpu_to_le32(DP_SW2HW_MACID(arg->pdev_id)); + cmd->pdev_id = cpu_to_le32(arg->pdev_id); cmd->module_id = cpu_to_le32(arg->module_id); cmd->base_paddr_lo = cpu_to_le32(arg->base_paddr_lo); cmd->base_paddr_hi = cpu_to_le32(arg->base_paddr_hi); From a6efa4ea06138d04b50ed5a7954a307a91a33478 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 4 May 2024 14:36:35 -0700 Subject: [PATCH 25/69] wifi: ath11k: fix misspelling of "dma" in num_rxmda_per_pdev The ath11k_hw_params member num_rxmda_per_pdev contains a misspelling of "dma" so fix it. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240504-ath11k-num_rxmda_per_pdev-v1-1-7f97bced8495@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 20 ++++++++++---------- drivers/net/wireless/ath/ath11k/debugfs.c | 6 +++--- drivers/net/wireless/ath/ath11k/dp.c | 12 ++++++------ drivers/net/wireless/ath/ath11k/dp_rx.c | 22 +++++++++++----------- drivers/net/wireless/ath/ath11k/dp_tx.c | 6 +++--- drivers/net/wireless/ath/ath11k/hw.h | 4 ++-- drivers/net/wireless/ath/ath11k/mac.c | 2 +- drivers/net/wireless/ath/ath11k/reg.c | 4 ++-- drivers/net/wireless/ath/ath11k/wmi.c | 2 +- 9 files changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 3cc817a3b4a4..d4ef556852c2 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -62,7 +62,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, .single_pdev_only = false, .rxdma1_enable = true, - .num_rxmda_per_pdev = 1, + .num_rxdma_per_pdev = 1, .rx_mac_buf_ring = false, .vdev_start_delay = false, .htt_peer_map_v2 = true, @@ -148,7 +148,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, .single_pdev_only = false, .rxdma1_enable = true, - .num_rxmda_per_pdev = 1, + .num_rxdma_per_pdev = 1, .rx_mac_buf_ring = false, .vdev_start_delay = false, .htt_peer_map_v2 = true, @@ -232,7 +232,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, .single_pdev_only = true, .rxdma1_enable = false, - .num_rxmda_per_pdev = 2, + .num_rxdma_per_pdev = 2, .rx_mac_buf_ring = true, .vdev_start_delay = true, .htt_peer_map_v2 = false, @@ -320,7 +320,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .svc_to_ce_map_len = 18, .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, .rxdma1_enable = true, - .num_rxmda_per_pdev = 1, + .num_rxdma_per_pdev = 1, .rx_mac_buf_ring = false, .vdev_start_delay = false, .htt_peer_map_v2 = true, @@ -404,7 +404,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, .single_pdev_only = true, .rxdma1_enable = false, - .num_rxmda_per_pdev = 2, + .num_rxdma_per_pdev = 2, .rx_mac_buf_ring = true, .vdev_start_delay = true, .htt_peer_map_v2 = false, @@ -492,7 +492,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .svc_to_ce_map_len = 14, .single_pdev_only = true, .rxdma1_enable = false, - .num_rxmda_per_pdev = 2, + .num_rxdma_per_pdev = 2, .rx_mac_buf_ring = true, .vdev_start_delay = true, .htt_peer_map_v2 = false, @@ -580,7 +580,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, .single_pdev_only = true, .rxdma1_enable = false, - .num_rxmda_per_pdev = 1, + .num_rxdma_per_pdev = 1, .rx_mac_buf_ring = true, .vdev_start_delay = true, .htt_peer_map_v2 = false, @@ -673,7 +673,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_ie_addr = &ath11k_ce_ie_addr_ipq5018, .ce_remap = &ath11k_ce_remap_ipq5018, .rxdma1_enable = true, - .num_rxmda_per_pdev = RXDMA_PER_PDEV_5018, + .num_rxdma_per_pdev = RXDMA_PER_PDEV_5018, .rx_mac_buf_ring = false, .vdev_start_delay = false, .htt_peer_map_v2 = true, @@ -744,7 +744,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .ce_ie_addr = &ath11k_ce_ie_addr_ipq8074, .single_pdev_only = true, .rxdma1_enable = false, - .num_rxmda_per_pdev = 2, + .num_rxdma_per_pdev = 2, .rx_mac_buf_ring = true, .vdev_start_delay = true, .htt_peer_map_v2 = false, @@ -1801,7 +1801,7 @@ static int ath11k_core_start(struct ath11k_base *ab) } /* put hardware to DBS mode */ - if (ab->hw_params.single_pdev_only && ab->hw_params.num_rxmda_per_pdev > 1) { + if (ab->hw_params.single_pdev_only && ab->hw_params.num_rxdma_per_pdev > 1) { ret = ath11k_wmi_set_hw_mode(ab, WMI_HOST_HW_MODE_DBS); if (ret) { ath11k_err(ab, "failed to send dbs mode: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 414a5ce279f7..57281a135dd7 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -668,7 +668,7 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file, ar->debug.rx_filter = tlv_filter.rx_filter; - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, HAL_RXDMA_MONITOR_STATUS, @@ -1112,7 +1112,7 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, } /* Clear rx filter set for monitor mode and rx status */ - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id, HAL_RXDMA_MONITOR_STATUS, @@ -1171,7 +1171,7 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, HTT_RX_FP_DATA_FILTER_FLASG3; } - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, ar->dp.mac_id + i, diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 1a62407e5a9f..fbf666d0ecf1 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -830,8 +830,8 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, if (ab->hw_params.ring_mask->rx_mon_status[grp_id]) { for (i = 0; i < ab->num_radios; i++) { - for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { - int id = i * ab->hw_params.num_rxmda_per_pdev + j; + for (j = 0; j < ab->hw_params.num_rxdma_per_pdev; j++) { + int id = i * ab->hw_params.num_rxdma_per_pdev + j; if (ab->hw_params.ring_mask->rx_mon_status[grp_id] & BIT(id)) { @@ -853,8 +853,8 @@ int ath11k_dp_service_srng(struct ath11k_base *ab, ath11k_dp_process_reo_status(ab); for (i = 0; i < ab->num_radios; i++) { - for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { - int id = i * ab->hw_params.num_rxmda_per_pdev + j; + for (j = 0; j < ab->hw_params.num_rxdma_per_pdev; j++) { + int id = i * ab->hw_params.num_rxdma_per_pdev + j; if (ab->hw_params.ring_mask->rxdma2host[grp_id] & BIT(id)) { work_done = ath11k_dp_process_rxdma_err(ab, id, budget); @@ -913,7 +913,7 @@ void ath11k_dp_pdev_pre_alloc(struct ath11k_base *ab) spin_lock_init(&dp->rx_refill_buf_ring.idr_lock); atomic_set(&dp->num_tx_pending, 0); init_waitqueue_head(&dp->tx_empty_waitq); - for (j = 0; j < ab->hw_params.num_rxmda_per_pdev; j++) { + for (j = 0; j < ab->hw_params.num_rxdma_per_pdev; j++) { idr_init(&dp->rx_mon_status_refill_ring[j].bufs_idr); spin_lock_init(&dp->rx_mon_status_refill_ring[j].idr_lock); } diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 8a860a17d7e4..198fb359a688 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -311,7 +311,7 @@ static void ath11k_dp_service_mon_ring(struct timer_list *t) struct ath11k_base *ab = from_timer(ab, t, mon_reap_timer); int i; - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) ath11k_dp_rx_process_mon_rings(ab, i, NULL, DP_MON_SERVICE_BUDGET); mod_timer(&ab->mon_reap_timer, jiffies + @@ -324,7 +324,7 @@ static int ath11k_dp_purge_mon_ring(struct ath11k_base *ab) unsigned long timeout = jiffies + msecs_to_jiffies(DP_MON_PURGE_TIMEOUT_MS); do { - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) reaped += ath11k_dp_rx_process_mon_rings(ab, i, NULL, DP_MON_SERVICE_BUDGET); @@ -468,7 +468,7 @@ static int ath11k_dp_rxdma_pdev_buf_free(struct ath11k *ar) rx_ring = &dp->rxdma_mon_buf_ring; ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { rx_ring = &dp->rx_mon_status_refill_ring[i]; ath11k_dp_rxdma_buf_ring_free(ar, rx_ring); } @@ -506,7 +506,7 @@ static int ath11k_dp_rxdma_pdev_buf_setup(struct ath11k *ar) ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_BUF); } - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { rx_ring = &dp->rx_mon_status_refill_ring[i]; ath11k_dp_rxdma_ring_buf_setup(ar, rx_ring, HAL_RXDMA_MONITOR_STATUS); } @@ -522,7 +522,7 @@ static void ath11k_dp_rx_pdev_srng_free(struct ath11k *ar) ath11k_dp_srng_cleanup(ab, &dp->rx_refill_buf_ring.refill_buf_ring); - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { if (ab->hw_params.rx_mac_buf_ring) ath11k_dp_srng_cleanup(ab, &dp->rx_mac_buf_ring[i]); @@ -585,7 +585,7 @@ static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) } if (ar->ab->hw_params.rx_mac_buf_ring) { - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ret = ath11k_dp_srng_setup(ar->ab, &dp->rx_mac_buf_ring[i], HAL_RXDMA_BUF, 1, @@ -598,7 +598,7 @@ static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) } } - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ret = ath11k_dp_srng_setup(ar->ab, &dp->rxdma_err_dst_ring[i], HAL_RXDMA_DST, 0, dp->mac_id + i, DP_RXDMA_ERR_DST_RING_SIZE); @@ -608,7 +608,7 @@ static int ath11k_dp_rx_pdev_srng_alloc(struct ath11k *ar) } } - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { srng = &dp->rx_mon_status_refill_ring[i].refill_buf_ring; ret = ath11k_dp_srng_setup(ar->ab, srng, @@ -4455,7 +4455,7 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) } if (ab->hw_params.rx_mac_buf_ring) { - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = dp->rx_mac_buf_ring[i].ring_id; ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i, HAL_RXDMA_BUF); @@ -4467,7 +4467,7 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) } } - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = dp->rxdma_err_dst_ring[i].ring_id; ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i, HAL_RXDMA_DST); @@ -4507,7 +4507,7 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id) } config_refill_ring: - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; ret = ath11k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i, HAL_RXDMA_MONITOR_STATUS); diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 272b1c35f98d..21819b741701 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -1035,7 +1035,7 @@ int ath11k_dp_tx_htt_h2t_ppdu_stats_req(struct ath11k *ar, u32 mask) int ret; int i; - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { skb = ath11k_htc_alloc_skb(ab, len); if (!skb) return -ENOMEM; @@ -1218,7 +1218,7 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) &tlv_filter); } else if (!reset) { /* set in monitor mode only */ - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = dp->rx_mac_buf_ring[i].ring_id; ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, dp->mac_id + i, @@ -1231,7 +1231,7 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) if (ret) return ret; - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; if (!reset) { tlv_filter.rx_filter = diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 14ef4eb48f80..300322535766 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_HW_H @@ -167,7 +167,7 @@ struct ath11k_hw_params { bool single_pdev_only; bool rxdma1_enable; - int num_rxmda_per_pdev; + int num_rxdma_per_pdev; bool rx_mac_buf_ring; bool vdev_start_delay; bool htt_peer_map_v2; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index a71195344288..17b06c0cd062 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -6108,7 +6108,7 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar); } - for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) { ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id + i, diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 737fcd450d4b..4c3aefbbabbe 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -878,7 +878,7 @@ int ath11k_reg_handle_chan_list(struct ath11k_base *ab, ath11k_reg_reset_info(reg_info); if (ab->hw_params.single_pdev_only && - pdev_idx < ab->hw_params.num_rxmda_per_pdev) + pdev_idx < ab->hw_params.num_rxdma_per_pdev) return 0; goto fallback; } diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 6ff01c45f165..38f175dd1557 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -9082,7 +9082,7 @@ int ath11k_wmi_attach(struct ath11k_base *ab) ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_MAX; /* It's overwritten when service_ext_ready is handled */ - if (ab->hw_params.single_pdev_only && ab->hw_params.num_rxmda_per_pdev > 1) + if (ab->hw_params.single_pdev_only && ab->hw_params.num_rxdma_per_pdev > 1) ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_SINGLE; /* TODO: Init remaining wmi soc resources required */ From ff5fa958d2fd45de7282a8bd3968426c947591d5 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Sat, 4 May 2024 14:45:17 -0700 Subject: [PATCH 26/69] wifi: ath12k: fix misspelling of "dma" in num_rxmda_per_pdev The ath12k_hw_params member num_rxmda_per_pdev contains a misspelling of "dma" so fix it. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240504-ath12k_dp_rxdma_ring_sel_config_wcn7850-ret-v1-1-44d2843a2857@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 10 +++++----- drivers/net/wireless/ath/ath12k/dp_rx.c | 14 +++++++------- drivers/net/wireless/ath/ath12k/dp_tx.c | 2 +- drivers/net/wireless/ath/ath12k/hw.c | 6 +++--- drivers/net/wireless/ath/ath12k/hw.h | 2 +- drivers/net/wireless/ath/ath12k/wmi.c | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index ca41f4431394..412ab08e6cca 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -907,8 +907,8 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, monitor_mode = ATH12K_DP_RX_MONITOR_MODE; ring_mask = ab->hw_params->ring_mask->rx_mon_dest[grp_id]; for (i = 0; i < ab->num_radios; i++) { - for (j = 0; j < ab->hw_params->num_rxmda_per_pdev; j++) { - int id = i * ab->hw_params->num_rxmda_per_pdev + j; + for (j = 0; j < ab->hw_params->num_rxdma_per_pdev; j++) { + int id = i * ab->hw_params->num_rxdma_per_pdev + j; if (ring_mask & BIT(id)) { work_done = @@ -928,8 +928,8 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, monitor_mode = ATH12K_DP_TX_MONITOR_MODE; ring_mask = ab->hw_params->ring_mask->tx_mon_dest[grp_id]; for (i = 0; i < ab->num_radios; i++) { - for (j = 0; j < ab->hw_params->num_rxmda_per_pdev; j++) { - int id = i * ab->hw_params->num_rxmda_per_pdev + j; + for (j = 0; j < ab->hw_params->num_rxdma_per_pdev; j++) { + int id = i * ab->hw_params->num_rxdma_per_pdev + j; if (ring_mask & BIT(id)) { work_done = @@ -1017,7 +1017,7 @@ static void ath12k_dp_service_mon_ring(struct timer_list *t) struct ath12k_base *ab = from_timer(ab, t, mon_reap_timer); int i; - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) ath12k_dp_mon_process_ring(ab, i, NULL, DP_MON_SERVICE_BUDGET, ATH12K_DP_RX_MONITOR_MODE); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 952a377b5491..e3ff14cd283f 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -485,7 +485,7 @@ static void ath12k_dp_rx_pdev_srng_free(struct ath12k *ar) struct ath12k_base *ab = ar->ab; int i; - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) ath12k_dp_srng_cleanup(ab, &dp->rxdma_mon_dst_ring[i]); } @@ -530,7 +530,7 @@ static int ath12k_dp_rx_pdev_srng_alloc(struct ath12k *ar) int ret; u32 mac_id = dp->mac_id; - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { ret = ath12k_dp_srng_setup(ar->ab, &dp->rxdma_mon_dst_ring[i], HAL_RXDMA_MONITOR_DST, @@ -3938,7 +3938,7 @@ void ath12k_dp_rx_free(struct ath12k_base *ab) ath12k_dp_srng_cleanup(ab, &dp->rx_refill_buf_ring.refill_buf_ring); - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { if (ab->hw_params->rx_mac_buf_ring) ath12k_dp_srng_cleanup(ab, &dp->rx_mac_buf_ring[i]); } @@ -4030,7 +4030,7 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) * and modify the rx_desc struct */ - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { ring_id = dp->rx_mac_buf_ring[i].ring_id; ret = ath12k_dp_tx_htt_rx_filter_setup(ab, ring_id, i, HAL_RXDMA_BUF, @@ -4057,7 +4057,7 @@ int ath12k_dp_rx_htt_setup(struct ath12k_base *ab) } if (ab->hw_params->rx_mac_buf_ring) { - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { ring_id = dp->rx_mac_buf_ring[i].ring_id; ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, i, HAL_RXDMA_BUF); @@ -4118,7 +4118,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) } if (ab->hw_params->rx_mac_buf_ring) { - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { ret = ath12k_dp_srng_setup(ab, &dp->rx_mac_buf_ring[i], HAL_RXDMA_BUF, 1, @@ -4178,7 +4178,7 @@ int ath12k_dp_rx_pdev_alloc(struct ath12k_base *ab, int mac_id) return ret; } - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { ring_id = dp->rxdma_mon_dst_ring[i].ring_id; ret = ath12k_dp_tx_htt_srng_setup(ab, ring_id, mac_id + i, diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index a22fa43c87ec..32496015cf9a 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -865,7 +865,7 @@ int ath12k_dp_tx_htt_h2t_ppdu_stats_req(struct ath12k *ar, u32 mask) int ret; int i; - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { + for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) { skb = ath12k_htc_alloc_skb(ab, len); if (!skb) return -ENOMEM; diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index f4c827015821..06f443216488 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -884,7 +884,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .hal_params = &ath12k_hw_hal_params_qcn9274, .rxdma1_enable = false, - .num_rxmda_per_pdev = 1, + .num_rxdma_per_pdev = 1, .num_rxdma_dst_ring = 0, .rx_mac_buf_ring = false, .vdev_start_delay = false, @@ -956,7 +956,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .hal_params = &ath12k_hw_hal_params_wcn7850, .rxdma1_enable = false, - .num_rxmda_per_pdev = 2, + .num_rxdma_per_pdev = 2, .num_rxdma_dst_ring = 1, .rx_mac_buf_ring = true, .vdev_start_delay = true, @@ -1029,7 +1029,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .hal_params = &ath12k_hw_hal_params_qcn9274, .rxdma1_enable = false, - .num_rxmda_per_pdev = 1, + .num_rxdma_per_pdev = 1, .num_rxdma_dst_ring = 0, .rx_mac_buf_ring = false, .vdev_start_delay = false, diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 3f450ee93f34..2a5a9d638d93 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -174,7 +174,7 @@ struct ath12k_hw_params { const struct ath12k_hw_hal_params *hal_params; bool rxdma1_enable:1; - int num_rxmda_per_pdev; + int num_rxdma_per_pdev; int num_rxdma_dst_ring; bool rx_mac_buf_ring:1; bool vdev_start_delay:1; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 9e9f58b5cbfb..3004c7463be9 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -5693,7 +5693,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk * event. Otherwise, it goes to fallback. */ if (ab->hw_params->single_pdev_only && - pdev_idx < ab->hw_params->num_rxmda_per_pdev) + pdev_idx < ab->hw_params->num_rxdma_per_pdev) goto mem_free; else goto fallback; From 3b9344740843d965e9e37fba30620b3b1c0afa4f Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 7 May 2024 13:45:03 +0300 Subject: [PATCH 27/69] wifi: ath12k: initialize 'ret' in ath12k_dp_rxdma_ring_sel_config_wcn7850() smatch flagged the following issue: drivers/net/wireless/ath/ath12k/dp_rx.c:4065 ath12k_dp_rxdma_ring_sel_config_wcn7850() error: uninitialized symbol 'ret'. In ath12k_dp_rxdma_ring_sel_config_wcn7850() if it were ever the case that ab->hw_params->num_rxdma_per_pdev was 0 then 'ret' would be uninitialized when it is returned. This should never be the case, but to be safe and to quiet smatch, add an initializer to the declaration of 'ret'. No functional changes, compile tested only. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240504-ath12k_dp_rxdma_ring_sel_config_wcn7850-ret-v1-2-44d2843a2857@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index e3ff14cd283f..37205e894afe 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -4004,7 +4004,7 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) struct ath12k_dp *dp = &ab->dp; struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 ring_id; - int ret; + int ret = 0; u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; int i; From 71b6e321e30271beb08772871c4f76777f49e402 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Mon, 29 Apr 2024 16:04:51 +0200 Subject: [PATCH 28/69] dt-bindings: net: wireless: ath10k: add qcom,no-msa-ready-indicator prop The ath10k driver waits for an "MSA_READY" indicator to complete initialization. If the indicator is not received, then the device remains unusable. cf. ath10k_qmi_driver_event_work() Several msm8998-based devices are affected by this issue. Oddly, it seems safe to NOT wait for the indicator, and proceed immediately when QMI_EVENT_SERVER_ARRIVE. Jeff Johnson wrote: The feedback I received was "it might be ok to change all ath10k qmi to skip waiting for msa_ready", and it was pointed out that ath11k (and ath12k) do not wait for it. However with so many deployed devices, "might be ok" isn't a strong argument for changing the default behavior. Kalle Valo first suggested setting a bit in firmware-5.bin to trigger work-around in the driver. However, firmware-5.bin is parsed too late. So we are stuck with a DT property. Signed-off-by: Marc Gonzalez Reviewed-by: Bjorn Andersson Acked-by: Jeff Johnson Acked-by: Rob Herring (Arm) Signed-off-by: Kalle Valo Link: https://msgid.link/54ac2295-36b4-49fc-9583-a10db8d9d5d6@freebox.fr --- .../devicetree/bindings/net/wireless/qcom,ath10k.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml index 5c4498b762c8..070c4c9b8643 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml @@ -128,6 +128,11 @@ properties: Whether to skip executing an SCM call that reassigns the memory region ownership. + qcom,no-msa-ready-indicator: + type: boolean + description: + Don't wait for MSA_READY indicator to complete init. + qcom,smem-states: $ref: /schemas/types.yaml#/definitions/phandle-array description: State bits used by the AP to signal the WLAN Q6. From 6d67d18014a8130defbca1972d7f0e0a8f8f259e Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Mon, 29 Apr 2024 16:06:29 +0200 Subject: [PATCH 29/69] wifi: ath10k: do not always wait for MSA_READY indicator The ath10k driver waits for an "MSA_READY" indicator to complete initialization. If the indicator is not received, then the device remains unusable. Several msm8998-based devices are affected by this issue. Oddly, it seems safe to NOT wait for the indicator, and proceed immediately when QMI_EVENT_SERVER_ARRIVE. fw_version 0x100204b2 fw_build_timestamp 2019-09-04 03:01 fw_build_id QC_IMAGE_VERSION_STRING=WLAN.HL.1.0-01202-QCAHLSWMTPLZ-1.221523.2 Jeff Johnson wrote: The feedback I received was "it might be ok to change all ath10k qmi to skip waiting for msa_ready", and it was pointed out that ath11k (and ath12k) do not wait for it. However with so many deployed devices, "might be ok" isn't a strong argument for changing the default behavior. Signed-off-by: Marc Gonzalez Reviewed-by: Bjorn Andersson Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/23540303-5816-45d5-a1af-5f09d645a73b@freebox.fr --- drivers/net/wireless/ath/ath10k/qmi.c | 11 +++++++++++ drivers/net/wireless/ath/ath10k/qmi.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 38e939f572a9..f1f33af0170a 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -1040,6 +1040,10 @@ static void ath10k_qmi_driver_event_work(struct work_struct *work) switch (event->type) { case ATH10K_QMI_EVENT_SERVER_ARRIVE: ath10k_qmi_event_server_arrive(qmi); + if (qmi->no_msa_ready_indicator) { + ath10k_info(ar, "qmi not waiting for msa_ready indicator"); + ath10k_qmi_event_msa_ready(qmi); + } break; case ATH10K_QMI_EVENT_SERVER_EXIT: ath10k_qmi_event_server_exit(qmi); @@ -1048,6 +1052,10 @@ static void ath10k_qmi_driver_event_work(struct work_struct *work) ath10k_qmi_event_fw_ready_ind(qmi); break; case ATH10K_QMI_EVENT_MSA_READY_IND: + if (qmi->no_msa_ready_indicator) { + ath10k_warn(ar, "qmi unexpected msa_ready indicator"); + break; + } ath10k_qmi_event_msa_ready(qmi); break; default: @@ -1077,6 +1085,9 @@ int ath10k_qmi_init(struct ath10k *ar, u32 msa_size) if (of_property_read_bool(dev->of_node, "qcom,msa-fixed-perm")) qmi->msa_fixed_perm = true; + if (of_property_read_bool(dev->of_node, "qcom,no-msa-ready-indicator")) + qmi->no_msa_ready_indicator = true; + ret = qmi_handle_init(&qmi->qmi_hdl, WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN, &ath10k_qmi_ops, qmi_msg_handler); diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h index 89464239fe96..0816eb4e4a18 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.h +++ b/drivers/net/wireless/ath/ath10k/qmi.h @@ -107,6 +107,7 @@ struct ath10k_qmi { char fw_build_timestamp[MAX_TIMESTAMP_LEN + 1]; struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01]; bool msa_fixed_perm; + bool no_msa_ready_indicator; enum ath10k_qmi_state state; }; From 4f9206e8c2c15a3770e3eb0b9755a05d559fecea Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Wed, 8 May 2024 02:54:09 -0700 Subject: [PATCH 30/69] wifi: ath12k: allocate dummy net_device dynamically Embedding net_device into structures prohibits the usage of flexible arrays in the net_device structure. For more details, see the discussion at [1]. Un-embed the net_device from struct ath12k_ext_irq_grp by converting it into a pointer. Then use the leverage alloc_netdev_dummy() to allocate the net_device object at ath12k_pci_ext_irq_config(). The free of the device occurs at ath12k_pci_free_ext_irq(). Link: https://lore.kernel.org/all/20240229225910.79e224cf@kernel.org/ [1] Signed-off-by: Breno Leitao Signed-off-by: Kalle Valo Link: https://msgid.link/20240508095410.1923198-1-leitao@debian.org --- drivers/net/wireless/ath/ath12k/core.h | 2 +- drivers/net/wireless/ath/ath12k/pci.c | 27 +++++++++++++++++++++----- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index bb6c1b562baf..c6b7524ce3a0 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -146,7 +146,7 @@ struct ath12k_ext_irq_grp { u32 grp_id; u64 timestamp; struct napi_struct napi; - struct net_device napi_ndev; + struct net_device *napi_ndev; }; struct ath12k_smbios_bdf { diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 16af046c33d9..ac75e8e3916b 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -350,6 +350,7 @@ static void ath12k_pci_free_ext_irq(struct ath12k_base *ab) free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); netif_napi_del(&irq_grp->napi); + free_netdev(irq_grp->napi_ndev); } } @@ -560,8 +561,9 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) { struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); - int i, j, ret, num_vectors = 0; + int i, j, n, ret, num_vectors = 0; u32 user_base_data = 0, base_vector = 0, base_idx; + struct ath12k_ext_irq_grp *irq_grp; base_idx = ATH12K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX; ret = ath12k_pci_get_user_msi_assignment(ab, "DP", @@ -572,13 +574,18 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) return ret; for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { - struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + irq_grp = &ab->ext_irq_grp[i]; u32 num_irq = 0; irq_grp->ab = ab; irq_grp->grp_id = i; - init_dummy_netdev(&irq_grp->napi_ndev); - netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + irq_grp->napi_ndev = alloc_netdev_dummy(0); + if (!irq_grp->napi_ndev) { + ret = -ENOMEM; + goto fail_allocate; + } + + netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi, ath12k_pci_ext_grp_napi_poll); if (ab->hw_params->ring_mask->tx[i] || @@ -611,13 +618,23 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) if (ret) { ath12k_err(ab, "failed request irq %d: %d\n", vector, ret); - return ret; + goto fail_request; } } ath12k_pci_ext_grp_disable(irq_grp); } return 0; + +fail_request: + /* i ->napi_ndev was properly allocated. Free it also */ + i += 1; +fail_allocate: + for (n = 0; n < i; n++) { + irq_grp = &ab->ext_irq_grp[n]; + free_netdev(irq_grp->napi_ndev); + } + return ret; } static int ath12k_pci_set_irq_affinity_hint(struct ath12k_pci *ab_pci, From 8e1debd82466a3fe711784ab37e6b54e56011267 Mon Sep 17 00:00:00 2001 From: Sebastian Gottschall Date: Mon, 13 May 2024 17:22:25 +0300 Subject: [PATCH 31/69] wifi: ath10k: add LED and GPIO controlling support for various chipsets Adds LED and GPIO Control support for 988x, 9887, 9888, 99x0, 9984 based chipsets with on chipset connected led's using WMI Firmware API. The LED device will get available named as "ath10k-phyX" at sysfs and can be controlled with various triggers. Adds also debugfs interface for gpio control. Signed-off-by: Sebastian Gottschall Reviewed-by: Steve deRosier [kvalo: major reorg and cleanup] Signed-off-by: Kalle Valo [ansuel: rebase and small cleanup] Signed-off-by: Christian Marangi Tested-by: Stefan Lippers-Hollmann Signed-off-by: Kalle Valo Link: https://msgid.link/20230611080505.17393-1-ansuelsmth@gmail.com --- drivers/net/wireless/ath/ath10k/Kconfig | 6 ++ drivers/net/wireless/ath/ath10k/Makefile | 1 + drivers/net/wireless/ath/ath10k/core.c | 32 ++++++++ drivers/net/wireless/ath/ath10k/core.h | 8 ++ drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/leds.c | 90 +++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/leds.h | 34 +++++++++ drivers/net/wireless/ath/ath10k/mac.c | 1 + drivers/net/wireless/ath/ath10k/wmi-ops.h | 32 ++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 + drivers/net/wireless/ath/ath10k/wmi.c | 54 ++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 35 +++++++++ 12 files changed, 296 insertions(+) create mode 100644 drivers/net/wireless/ath/ath10k/leds.c create mode 100644 drivers/net/wireless/ath/ath10k/leds.h diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index e6ea884cafc1..76572cd2e1ba 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -67,6 +67,12 @@ config ATH10K_DEBUGFS If unsure, say Y to make it easier to debug problems. +config ATH10K_LEDS + bool + depends on ATH10K + depends on LEDS_CLASS=y || LEDS_CLASS=MAC80211 + default y + config ATH10K_SPECTRAL bool "Atheros ath10k spectral scan support" depends on ATH10K_DEBUGFS diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 142c777b287f..02bf9b629038 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -19,6 +19,7 @@ ath10k_core-$(CONFIG_ATH10K_SPECTRAL) += spectral.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o ath10k_core-$(CONFIG_THERMAL) += thermal.o +ath10k_core-$(CONFIG_ATH10K_LEDS) += leds.o ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o ath10k_core-$(CONFIG_PM) += wow.o ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index bdf0552cd1c3..b3294287bce1 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -27,6 +27,7 @@ #include "testmode.h" #include "wmi-ops.h" #include "coredump.h" +#include "leds.h" unsigned int ath10k_debug_mask; EXPORT_SYMBOL(ath10k_debug_mask); @@ -68,6 +69,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .led_pin = 1, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, @@ -108,6 +110,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca988x hw2.0 ubiquiti", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .led_pin = 0, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, @@ -149,6 +152,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca9887 hw1.0", .patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .led_pin = 1, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, @@ -190,6 +194,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.2 sdio", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 19, + .led_pin = 0, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -226,6 +231,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6164 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, + .led_pin = 0, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -266,6 +272,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, + .led_pin = 0, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -306,6 +313,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.0", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .led_pin = 0, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -346,6 +354,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.2", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .led_pin = 0, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -390,6 +399,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca99x0 hw2.0", .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .led_pin = 17, .otp_exe_param = 0x00000700, .continuous_frag_desc = true, .cck_rate_map_rev2 = true, @@ -436,6 +446,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca9984/qca9994 hw1.0", .patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .led_pin = 17, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, .otp_exe_param = 0x00000700, .continuous_frag_desc = true, @@ -488,6 +499,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca9888 hw2.0", .patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .led_pin = 17, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, .otp_exe_param = 0x00000700, .continuous_frag_desc = true, @@ -538,6 +550,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca9377 hw1.0", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .led_pin = 0, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -578,6 +591,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca9377 hw1.1", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .led_pin = 0, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -620,6 +634,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca9377 hw1.1 sdio", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 19, + .led_pin = 0, .otp_exe_param = 0, .channel_counters_freq_hz = 88000, .max_probe_resp_desc_thres = 0, @@ -653,6 +668,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca4019 hw1.0", .patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .led_pin = 0, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, .otp_exe_param = 0x0010000, .continuous_frag_desc = true, @@ -698,6 +714,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .dev_id = 0, .bus = ATH10K_BUS_SNOC, .name = "wcn3990 hw1.0", + .led_pin = 0, .continuous_frag_desc = true, .tx_chain_mask = 0x7, .rx_chain_mask = 0x7, @@ -3224,6 +3241,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_hif_stop; } + status = ath10k_leds_start(ar); + if (status) + goto err_hif_stop; + return 0; err_hif_stop: @@ -3482,9 +3503,18 @@ static void ath10k_core_register_work(struct work_struct *work) goto err_spectral_destroy; } + status = ath10k_leds_register(ar); + if (status) { + ath10k_err(ar, "could not register leds: %d\n", + status); + goto err_thermal_unregister; + } + set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); return; +err_thermal_unregister: + ath10k_thermal_unregister(ar); err_spectral_destroy: ath10k_spectral_destroy(ar); err_debug_destroy: @@ -3520,6 +3550,8 @@ void ath10k_core_unregister(struct ath10k *ar) if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) return; + ath10k_leds_unregister(ar); + ath10k_thermal_unregister(ar); /* Stop spectral before unregistering from mac80211 to remove the * relayfs debugfs file cleanly. Otherwise the parent debugfs tree diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index b00099f0b24e..446dca74f06a 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "htt.h" #include "htc.h" @@ -1258,6 +1259,13 @@ struct ath10k { bool utf_monitor; } testmode; + struct { + struct gpio_led wifi_led; + struct led_classdev cdev; + char label[48]; + u32 gpio_state_pin; + } leds; + struct { /* protected by data_lock */ u32 rx_crc_err_drop; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 48897e5eca06..442091c6dfd2 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -512,6 +512,7 @@ struct ath10k_hw_params { const char *name; u32 patch_load_addr; int uart_pin; + int led_pin; u32 otp_exe_param; /* Type of hw cycle counter wraparound logic, for more info diff --git a/drivers/net/wireless/ath/ath10k/leds.c b/drivers/net/wireless/ath/ath10k/leds.c new file mode 100644 index 000000000000..9b1d04eb4265 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/leds.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018 Sebastian Gottschall + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + */ + +#include + +#include "core.h" +#include "wmi.h" +#include "wmi-ops.h" + +#include "leds.h" + +static int ath10k_leds_set_brightness_blocking(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ath10k *ar = container_of(led_cdev, struct ath10k, + leds.cdev); + struct gpio_led *led = &ar->leds.wifi_led; + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON) + goto out; + + ar->leds.gpio_state_pin = (brightness != LED_OFF) ^ led->active_low; + ath10k_wmi_gpio_output(ar, led->gpio, ar->leds.gpio_state_pin); + +out: + mutex_unlock(&ar->conf_mutex); + + return 0; +} + +int ath10k_leds_start(struct ath10k *ar) +{ + if (ar->hw_params.led_pin == 0) + /* leds not supported */ + return 0; + + /* under some circumstances, the gpio pin gets reconfigured + * to default state by the firmware, so we need to + * reconfigure it this behaviour has only ben seen on + * QCA9984 and QCA99XX devices so far + */ + ath10k_wmi_gpio_config(ar, ar->hw_params.led_pin, 0, + WMI_GPIO_PULL_NONE, WMI_GPIO_INTTYPE_DISABLE); + ath10k_wmi_gpio_output(ar, ar->hw_params.led_pin, 1); + + return 0; +} + +int ath10k_leds_register(struct ath10k *ar) +{ + int ret; + + if (ar->hw_params.led_pin == 0) + /* leds not supported */ + return 0; + + snprintf(ar->leds.label, sizeof(ar->leds.label), "ath10k-%s", + wiphy_name(ar->hw->wiphy)); + ar->leds.wifi_led.active_low = 1; + ar->leds.wifi_led.gpio = ar->hw_params.led_pin; + ar->leds.wifi_led.name = ar->leds.label; + ar->leds.wifi_led.default_state = LEDS_GPIO_DEFSTATE_KEEP; + + ar->leds.cdev.name = ar->leds.label; + ar->leds.cdev.brightness_set_blocking = ath10k_leds_set_brightness_blocking; + ar->leds.cdev.default_trigger = ar->leds.wifi_led.default_trigger; + + ret = led_classdev_register(wiphy_dev(ar->hw->wiphy), &ar->leds.cdev); + if (ret) + return ret; + + return 0; +} + +void ath10k_leds_unregister(struct ath10k *ar) +{ + if (ar->hw_params.led_pin == 0) + /* leds not supported */ + return; + + led_classdev_unregister(&ar->leds.cdev); +} + diff --git a/drivers/net/wireless/ath/ath10k/leds.h b/drivers/net/wireless/ath/ath10k/leds.h new file mode 100644 index 000000000000..56325b0875e5 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/leds.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Copyright (c) 2005-2011 Atheros Communications Inc. + * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018 Sebastian Gottschall + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + */ + +#ifndef _LEDS_H_ +#define _LEDS_H_ + +#include "core.h" + +#ifdef CONFIG_ATH10K_LEDS +void ath10k_leds_unregister(struct ath10k *ar); +int ath10k_leds_start(struct ath10k *ar); +int ath10k_leds_register(struct ath10k *ar); +#else +static inline void ath10k_leds_unregister(struct ath10k *ar) +{ +} + +static inline int ath10k_leds_start(struct ath10k *ar) +{ + return 0; +} + +static inline int ath10k_leds_register(struct ath10k *ar) +{ + return 0; +} + +#endif +#endif /* _LEDS_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e322b528baaf..3bf67b2ecd6d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -25,6 +25,7 @@ #include "wmi-tlv.h" #include "wmi-ops.h" #include "wow.h" +#include "leds.h" /*********/ /* Rates */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index aa57d807491c..f3f6b5954b27 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -226,7 +226,10 @@ struct wmi_ops { const struct wmi_bb_timing_cfg_arg *arg); struct sk_buff *(*gen_per_peer_per_tid_cfg)(struct ath10k *ar, const struct wmi_per_peer_per_tid_cfg_arg *arg); + struct sk_buff *(*gen_gpio_config)(struct ath10k *ar, u32 gpio_num, + u32 input, u32 pull_type, u32 intr_mode); + struct sk_buff *(*gen_gpio_output)(struct ath10k *ar, u32 gpio_num, u32 set); }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -1122,6 +1125,35 @@ ath10k_wmi_force_fw_hang(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); } +static inline int ath10k_wmi_gpio_config(struct ath10k *ar, u32 gpio_num, + u32 input, u32 pull_type, u32 intr_mode) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_gpio_config) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_gpio_config(ar, gpio_num, input, pull_type, intr_mode); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->gpio_config_cmdid); +} + +static inline int ath10k_wmi_gpio_output(struct ath10k *ar, u32 gpio_num, u32 set) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_gpio_config) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_gpio_output(ar, gpio_num, set); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->gpio_output_cmdid); +} + static inline int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u64 module_enable, u32 log_level) { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index aed97fd121ba..dbaf26d6a7a6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -4606,6 +4606,8 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_echo = ath10k_wmi_tlv_op_gen_echo, .gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf, .gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable, + /* .gen_gpio_config not implemented */ + /* .gen_gpio_output not implemented */ }; static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 80d255aaff1b..fe2344598364 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -7493,6 +7493,49 @@ ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, return skb; } +static struct sk_buff *ath10k_wmi_op_gen_gpio_config(struct ath10k *ar, + u32 gpio_num, u32 input, + u32 pull_type, u32 intr_mode) +{ + struct wmi_gpio_config_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_gpio_config_cmd *)skb->data; + cmd->pull_type = __cpu_to_le32(pull_type); + cmd->gpio_num = __cpu_to_le32(gpio_num); + cmd->input = __cpu_to_le32(input); + cmd->intr_mode = __cpu_to_le32(intr_mode); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi gpio_config gpio_num 0x%08x input 0x%08x pull_type 0x%08x intr_mode 0x%08x\n", + gpio_num, input, pull_type, intr_mode); + + return skb; +} + +static struct sk_buff *ath10k_wmi_op_gen_gpio_output(struct ath10k *ar, + u32 gpio_num, u32 set) +{ + struct wmi_gpio_output_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_gpio_output_cmd *)skb->data; + cmd->gpio_num = __cpu_to_le32(gpio_num); + cmd->set = __cpu_to_le32(set); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi gpio_output gpio_num 0x%08x set 0x%08x\n", + gpio_num, set); + + return skb; +} + static struct sk_buff * ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, enum wmi_sta_ps_mode psmode) @@ -9157,6 +9200,9 @@ static const struct wmi_ops wmi_ops = { .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, .gen_echo = ath10k_wmi_op_gen_echo, + .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, + .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, + /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ @@ -9227,6 +9273,8 @@ static const struct wmi_ops wmi_10_1_ops = { .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, .gen_echo = ath10k_wmi_op_gen_echo, + .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, + .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ @@ -9299,6 +9347,8 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_delba_send = ath10k_wmi_op_gen_delba_send, .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, + .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, + .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, /* .gen_pdev_enable_adaptive_cca not implemented */ }; @@ -9370,6 +9420,8 @@ static const struct wmi_ops wmi_10_2_4_ops = { ath10k_wmi_op_gen_pdev_enable_adaptive_cca, .get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype, .gen_bb_timing = ath10k_wmi_10_2_4_op_gen_bb_timing, + .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, + .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ @@ -9451,6 +9503,8 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info, .gen_echo = ath10k_wmi_op_gen_echo, .gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config, + .gen_gpio_config = ath10k_wmi_op_gen_gpio_config, + .gen_gpio_output = ath10k_wmi_op_gen_gpio_output, }; int ath10k_wmi_attach(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 2379501225a4..0faefc0a9a40 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3034,6 +3034,41 @@ enum wmi_10_4_feature_mask { }; +/* WMI_GPIO_CONFIG_CMDID */ +enum { + WMI_GPIO_PULL_NONE, + WMI_GPIO_PULL_UP, + WMI_GPIO_PULL_DOWN, +}; + +enum { + WMI_GPIO_INTTYPE_DISABLE, + WMI_GPIO_INTTYPE_RISING_EDGE, + WMI_GPIO_INTTYPE_FALLING_EDGE, + WMI_GPIO_INTTYPE_BOTH_EDGE, + WMI_GPIO_INTTYPE_LEVEL_LOW, + WMI_GPIO_INTTYPE_LEVEL_HIGH +}; + +/* WMI_GPIO_CONFIG_CMDID */ +struct wmi_gpio_config_cmd { + __le32 gpio_num; /* GPIO number to be setup */ + __le32 input; /* 0 - Output/ 1 - Input */ + __le32 pull_type; /* Pull type defined above */ + __le32 intr_mode; /* Interrupt mode defined above (Input) */ +} __packed; + +/* WMI_GPIO_OUTPUT_CMDID */ +struct wmi_gpio_output_cmd { + __le32 gpio_num; /* GPIO number to be setup */ + __le32 set; /* Set the GPIO pin*/ +} __packed; + +/* WMI_GPIO_INPUT_EVENTID */ +struct wmi_gpio_input_event { + __le32 gpio_num; /* GPIO number which changed state */ +} __packed; + struct wmi_ext_resource_config_10_4_cmd { /* contains enum wmi_host_platform_type */ __le32 host_platform_config; From 3745d7963cc34c08ee4dda4f3c81981e277f0d96 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 8 May 2024 10:36:50 -0700 Subject: [PATCH 32/69] wifi: ath12k: add channel 2 into 6 GHz channel list Add support for the 6 GHz channel 2 with center frequency 5935 MHz and operating class 136 per IEEE Std 802.11ax-2021, Table E-4. 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: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508173655.22191-2-quic_pradeepc@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 +- drivers/net/wireless/ath/ath12k/mac.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index c6b7524ce3a0..6da242c0d51d 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -450,7 +450,7 @@ struct ath12k_sta { #define ATH12K_MIN_5G_FREQ 4150 #define ATH12K_MIN_6G_FREQ 5925 #define ATH12K_MAX_6G_FREQ 7115 -#define ATH12K_NUM_CHANS 100 +#define ATH12K_NUM_CHANS 101 #define ATH12K_MAX_5G_CHAN 173 enum ath12k_hw_state { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 96dc5c2e096f..ae9f41a17b4f 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -91,6 +91,10 @@ static const struct ieee80211_channel ath12k_5ghz_channels[] = { }; static const struct ieee80211_channel ath12k_6ghz_channels[] = { + /* Operating Class 136 */ + CHAN6G(2, 5935, 0), + + /* Operating Classes 131-135 */ CHAN6G(1, 5955, 0), CHAN6G(5, 5975, 0), CHAN6G(9, 5995, 0), From c3c84a74bd797f76d7da036c9fef947d674bbc18 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 8 May 2024 10:36:51 -0700 Subject: [PATCH 33/69] wifi: ath12k: Correct 6 GHz frequency value in rx status The frequency in the rx status is currently being filled incorrectly for the 6 GHz band. The channel number received is invalid in this case, resulting in packet drops. Fix this issue by correcting the frequency calculation. 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 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508173655.22191-3-quic_pradeepc@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 9 ++++++--- drivers/net/wireless/ath/ath12k/wmi.c | 10 +++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 37205e894afe..d8998ac3a482 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2359,8 +2359,10 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct hal_rx_desc *rx_desc, channel_num = meta_data; center_freq = meta_data >> 16; - if (center_freq >= 5935 && center_freq <= 7105) { + if (center_freq >= ATH12K_MIN_6G_FREQ && + center_freq <= ATH12K_MAX_6G_FREQ) { rx_status->band = NL80211_BAND_6GHZ; + rx_status->freq = center_freq; } else if (channel_num >= 1 && channel_num <= 14) { rx_status->band = NL80211_BAND_2GHZ; } else if (channel_num >= 36 && channel_num <= 173) { @@ -2378,8 +2380,9 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct hal_rx_desc *rx_desc, rx_desc, sizeof(*rx_desc)); } - rx_status->freq = ieee80211_channel_to_frequency(channel_num, - rx_status->band); + if (rx_status->band != NL80211_BAND_6GHZ) + rx_status->freq = ieee80211_channel_to_frequency(channel_num, + rx_status->band); ath12k_dp_rx_h_rate(ar, rx_desc, rx_status); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 3004c7463be9..a592b75e5ef3 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6022,8 +6022,10 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) if (rx_ev.status & WMI_RX_STATUS_ERR_MIC) status->flag |= RX_FLAG_MMIC_ERROR; - if (rx_ev.chan_freq >= ATH12K_MIN_6G_FREQ) { + if (rx_ev.chan_freq >= ATH12K_MIN_6G_FREQ && + rx_ev.chan_freq <= ATH12K_MAX_6G_FREQ) { status->band = NL80211_BAND_6GHZ; + status->freq = rx_ev.chan_freq; } else if (rx_ev.channel >= 1 && rx_ev.channel <= 14) { status->band = NL80211_BAND_2GHZ; } else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH12K_MAX_5G_CHAN) { @@ -6044,8 +6046,10 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) sband = &ar->mac.sbands[status->band]; - status->freq = ieee80211_channel_to_frequency(rx_ev.channel, - status->band); + if (status->band != NL80211_BAND_6GHZ) + status->freq = ieee80211_channel_to_frequency(rx_ev.channel, + status->band); + status->signal = rx_ev.snr + ATH12K_DEFAULT_NOISE_FLOOR; status->rate_idx = ath12k_mac_bitrate_to_idx(sband, rx_ev.rate / 100); From 70e3be54bbddc39123b8785408fb9aeb8f822ab6 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 8 May 2024 10:36:52 -0700 Subject: [PATCH 34/69] wifi: ath12k: fix survey dump collection in 6 GHz When ath12k receives survey request, choose the 6 GHz band when enabled. Without this, survey requests do not include any 6 GHz band results, leading to failures in auto channel selection. 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: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508173655.22191-4-quic_pradeepc@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ae9f41a17b4f..8af450cdace6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8031,6 +8031,17 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, if (!sband) sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; + if (sband && idx >= sband->n_channels) { + idx -= sband->n_channels; + sband = NULL; + } + + if (!sband) + sband = hw->wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband || idx >= sband->n_channels) { + idx -= sband->n_channels; + sband = NULL; + } if (!sband || idx >= sband->n_channels) return -ENOENT; From 112dbc6af807021ac65f46300d564163ec4710a9 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 8 May 2024 10:36:53 -0700 Subject: [PATCH 35/69] wifi: ath12k: add 6 GHz params in peer assoc command Currently A-MPDU aggregation parameters are not being configured during peer association for 6 GHz band. Hence, extract these parameters from station's capabilities received in association request and send to firmware. Without this, A-MPDU aggregation is not happening in 6 GHz band. 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 Co-developed-by: Avula Sri Charan Signed-off-by: Avula Sri Charan Signed-off-by: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508173655.22191-5-quic_pradeepc@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 57 ++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 8af450cdace6..b9b9f4d17b34 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2032,6 +2032,60 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, } } +static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ath12k_wmi_peer_assoc_arg *arg) +{ + const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; + struct cfg80211_chan_def def; + enum nl80211_band band; + u8 ampdu_factor, mpdu_density; + + if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + return; + + band = def.chan->band; + + if (!arg->he_flag || band != NL80211_BAND_6GHZ || !sta->deflink.he_6ghz_capa.capa) + return; + + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) + arg->bw_40 = true; + + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) + arg->bw_80 = true; + + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) + arg->bw_160 = true; + + if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) + arg->bw_320 = true; + + arg->peer_he_caps_6ghz = le16_to_cpu(sta->deflink.he_6ghz_capa.capa); + + mpdu_density = u32_get_bits(arg->peer_he_caps_6ghz, + IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); + arg->peer_mpdu_density = ath12k_parse_mpdudensity(mpdu_density); + + /* From IEEE Std 802.11ax-2021 - Section 10.12.2: An HE STA shall be capable of + * receiving A-MPDU where the A-MPDU pre-EOF padding length is up to the value + * indicated by the Maximum A-MPDU Length Exponent Extension field in the HE + * Capabilities element and the Maximum A-MPDU Length Exponent field in HE 6 GHz + * Band Capabilities element in the 6 GHz band. + * + * Here, we are extracting the Max A-MPDU Exponent Extension from HE caps and + * factor is the Maximum A-MPDU Length Exponent from HE 6 GHZ Band capability. + */ + ampdu_factor = u8_get_bits(he_cap->he_cap_elem.mac_cap_info[3], + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) + + u32_get_bits(arg->peer_he_caps_6ghz, + IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); + + arg->peer_max_mpdu = (1u << (IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR + + ampdu_factor)) - 1; +} + static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, struct ath12k_wmi_peer_assoc_arg *arg) { @@ -2504,6 +2558,7 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar, ath12k_peer_assoc_h_ht(ar, vif, sta, arg); ath12k_peer_assoc_h_vht(ar, vif, sta, arg); ath12k_peer_assoc_h_he(ar, vif, sta, arg); + ath12k_peer_assoc_h_he_6ghz(ar, vif, sta, arg); ath12k_peer_assoc_h_eht(ar, vif, sta, arg); ath12k_peer_assoc_h_qos(ar, vif, sta, arg); ath12k_peer_assoc_h_phymode(ar, vif, sta, arg); @@ -8701,7 +8756,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ieee80211_hw_set(hw, SUPPORTS_TX_FRAG); ieee80211_hw_set(hw, REPORTS_LOW_ACK); - if (ht_cap & WMI_HT_CAP_ENABLED) { + if ((ht_cap & WMI_HT_CAP_ENABLED) || ar->supports_6ghz) { ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); From f0e61dc7ecf9a709d22265a17d553fd314e3f986 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 8 May 2024 10:36:54 -0700 Subject: [PATCH 36/69] wifi: ath12k: refactor SMPS configuration Move fetching SMPS value to a new function and use u16_get_bits to extract it from capabilities. This will help in extending the functionality when SMPS support in 6 GHz band gets added in subsequent patches. 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: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508173655.22191-6-quic_pradeepc@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 32 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b9b9f4d17b34..0e9b6b7b83d7 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2086,18 +2086,29 @@ static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar, ampdu_factor)) - 1; } +static int ath12k_get_smps_from_capa(const struct ieee80211_sta_ht_cap *ht_cap, + int *smps) +{ + if (!ht_cap->ht_supported) + return -EOPNOTSUPP; + + *smps = u16_get_bits(ht_cap->cap, IEEE80211_HT_CAP_SM_PS); + + if (*smps >= ARRAY_SIZE(ath12k_smps_map)) + return -EINVAL; + + return 0; +} + static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, struct ath12k_wmi_peer_assoc_arg *arg) { const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; int smps; - if (!ht_cap->ht_supported) + if (ath12k_get_smps_from_capa(ht_cap, &smps)) return; - smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; - smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; - switch (smps) { case WLAN_HT_CAP_SM_PS_STATIC: arg->static_mimops_flag = true; @@ -2571,16 +2582,11 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, const u8 *addr, const struct ieee80211_sta_ht_cap *ht_cap) { - int smps; + int smps, ret = 0; - if (!ht_cap->ht_supported) - return 0; - - smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; - smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; - - if (smps >= ARRAY_SIZE(ath12k_smps_map)) - return -EINVAL; + ret = ath12k_get_smps_from_capa(ht_cap, &smps); + if (ret < 0) + return ret; return ath12k_wmi_set_peer_param(ar, addr, arvif->vdev_id, WMI_PEER_MIMO_PS_STATE, From 97b7cbb7a3cbeee87ed82af67bca881ec8881d83 Mon Sep 17 00:00:00 2001 From: Pradeep Kumar Chitrapu Date: Wed, 8 May 2024 10:36:55 -0700 Subject: [PATCH 37/69] wifi: ath12k: support SMPS configuration for 6 GHz Parse SMPS configuration from IEs and configure. Without this, SMPS is not enabled for 6 GHz band. This is disabled for WCN7850 as hardware does not support it. 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: Pradeep Kumar Chitrapu Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508173655.22191-7-quic_pradeepc@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 3 +++ drivers/net/wireless/ath/ath12k/hw.h | 1 + drivers/net/wireless/ath/ath12k/mac.c | 26 ++++++++++++++++++-------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 06f443216488..b3ba753d4a85 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -926,6 +926,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .supports_sta_ps = false, .acpi_guid = NULL, + .supports_dynamic_smps_6ghz = true, }, { .name = "wcn7850 hw2.0", @@ -1001,6 +1002,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .supports_sta_ps = true, .acpi_guid = &wcn7850_uuid, + .supports_dynamic_smps_6ghz = false, }, { .name = "qcn9274 hw2.0", @@ -1071,6 +1073,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .supports_sta_ps = false, .acpi_guid = NULL, + .supports_dynamic_smps_6ghz = true, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 2a5a9d638d93..7422d3258548 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -215,6 +215,7 @@ struct ath12k_hw_params { bool supports_sta_ps; const guid_t *acpi_guid; + bool supports_dynamic_smps_6ghz; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 0e9b6b7b83d7..ea0a9ccc8e92 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2087,12 +2087,17 @@ static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar, } static int ath12k_get_smps_from_capa(const struct ieee80211_sta_ht_cap *ht_cap, + const struct ieee80211_he_6ghz_capa *he_6ghz_capa, int *smps) { - if (!ht_cap->ht_supported) + if (!ht_cap->ht_supported && !he_6ghz_capa->capa) return -EOPNOTSUPP; - *smps = u16_get_bits(ht_cap->cap, IEEE80211_HT_CAP_SM_PS); + if (ht_cap->ht_supported) + *smps = u16_get_bits(ht_cap->cap, IEEE80211_HT_CAP_SM_PS); + else + *smps = le16_get_bits(he_6ghz_capa->capa, + IEEE80211_HE_6GHZ_CAP_SM_PS); if (*smps >= ARRAY_SIZE(ath12k_smps_map)) return -EINVAL; @@ -2103,10 +2108,11 @@ static int ath12k_get_smps_from_capa(const struct ieee80211_sta_ht_cap *ht_cap, static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, struct ath12k_wmi_peer_assoc_arg *arg) { + const struct ieee80211_he_6ghz_capa *he_6ghz_capa = &sta->deflink.he_6ghz_capa; const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; int smps; - if (ath12k_get_smps_from_capa(ht_cap, &smps)) + if (ath12k_get_smps_from_capa(ht_cap, he_6ghz_capa, &smps)) return; switch (smps) { @@ -2580,11 +2586,12 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar, static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, const u8 *addr, - const struct ieee80211_sta_ht_cap *ht_cap) + const struct ieee80211_sta_ht_cap *ht_cap, + const struct ieee80211_he_6ghz_capa *he_6ghz_capa) { int smps, ret = 0; - ret = ath12k_get_smps_from_capa(ht_cap, &smps); + ret = ath12k_get_smps_from_capa(ht_cap, he_6ghz_capa, &smps); if (ret < 0) return ret; @@ -2637,7 +2644,8 @@ static void ath12k_bss_assoc(struct ath12k *ar, } ret = ath12k_setup_peer_smps(ar, arvif, bss_conf->bssid, - &ap_sta->deflink.ht_cap); + &ap_sta->deflink.ht_cap, + &ap_sta->deflink.he_6ghz_capa); if (ret) { ath12k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n", arvif->vdev_id, ret); @@ -3944,7 +3952,8 @@ static int ath12k_station_assoc(struct ath12k *ar, return 0; ret = ath12k_setup_peer_smps(ar, arvif, sta->addr, - &sta->deflink.ht_cap); + &sta->deflink.ht_cap, + &sta->deflink.he_6ghz_capa); if (ret) { ath12k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n", arvif->vdev_id, ret); @@ -8777,7 +8786,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) * for each band for a dual band capable radio. It will be tricky to * handle it when the ht capability different for each band. */ - if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) + if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS || + (ar->supports_6ghz && ab->hw_params->supports_dynamic_smps_6ghz)) wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; From 519a545cfee790024c623c7aacd165f7431773d5 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:04 -0700 Subject: [PATCH 38/69] wifi: ath12k: advertise driver capabilities for MBSSID and EMA Advertise the driver support for multiple BSSID (MBSSID) and enhanced multi-BSSID advertisements (EMA) by setting extended capabilities. Configure mbssid_max_interfaces and ema_max_profile_periodicity fields in structure wiphy which are used to advertise maximum number of interfaces and profile periodicity supported by the driver. Add new WMI fields to configure maximum vdev count supported for MBSSID and profile periodicity in case of EMA. Set WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET flag to allow firmware to track and update the DTIM counts for each nontransmitted profile. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-2-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.h | 1 + drivers/net/wireless/ath/ath12k/mac.c | 7 +++++++ drivers/net/wireless/ath/ath12k/wmi.c | 7 ++++++- drivers/net/wireless/ath/ath12k/wmi.h | 3 +++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 7422d3258548..af33bf11416b 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -80,6 +80,7 @@ #define TARGET_RX_BATCHMODE 1 #define TARGET_RX_PEER_METADATA_VER_V1A 2 #define TARGET_RX_PEER_METADATA_VER_V1B 3 +#define TARGET_EMA_MAX_PROFILE_PERIOD 8 #define ATH12K_HW_DEFAULT_QUEUE 0 #define ATH12K_HW_MAX_QUEUES 4 diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ea0a9ccc8e92..9d82f289b23b 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -8574,19 +8574,23 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) static const u8 ath12k_if_types_ext_capa[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, }; static const u8 ath12k_if_types_ext_capa_sta[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, }; static const u8 ath12k_if_types_ext_capa_ap[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT, + [10] = WLAN_EXT_CAPA11_EMA_SUPPORT, }; static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { @@ -8826,6 +8830,9 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; wiphy->num_iftype_ext_capab = ARRAY_SIZE(ath12k_iftypes_ext_capa); + wiphy->mbssid_max_interfaces = TARGET_NUM_VDEVS; + wiphy->ema_max_profile_periodicity = TARGET_EMA_MAX_PROFILE_PERIOD; + if (is_6ghz) { wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index a592b75e5ef3..3da16d4abb5a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -228,6 +228,9 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, config->peer_map_unmap_version = 0x32; config->twt_ap_pdev_count = ab->num_radios; config->twt_ap_sta_count = 1000; + config->ema_max_vap_cnt = ab->num_radios; + config->ema_max_profile_period = TARGET_EMA_MAX_PROFILE_PERIOD; + config->beacon_tx_offload_max_vdev += config->ema_max_vap_cnt; if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) config->dp_peer_meta_data_ver = TARGET_RX_PEER_METADATA_VER_V1B; @@ -3475,9 +3478,11 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); wmi_cfg->flags2 = le32_encode_bits(tg_cfg->dp_peer_meta_data_ver, WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION); - wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); + wmi_cfg->ema_max_vap_cnt = cpu_to_le32(tg_cfg->ema_max_vap_cnt); + wmi_cfg->ema_max_profile_period = cpu_to_le32(tg_cfg->ema_max_profile_period); + wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET); } static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 496866673aea..e71e6c73f249 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2356,6 +2356,8 @@ struct ath12k_wmi_resource_config_arg { u32 twt_ap_sta_count; bool is_reg_cc_ext_event_supported; u8 dp_peer_meta_data_ver; + u32 ema_max_vap_cnt; + u32 ema_max_profile_period; }; struct ath12k_wmi_init_cmd_arg { @@ -2410,6 +2412,7 @@ struct wmi_init_cmd { #define WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT 4 #define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) +#define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET BIT(9) struct ath12k_wmi_resource_config_params { __le32 tlv_header; From ea68f1bba61632652f722e5979a8a853cfa55eff Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:05 -0700 Subject: [PATCH 39/69] wifi: ath12k: configure MBSSID params in vdev create/start Configure multiple BSSID flags and vdev_id of the transmited profile in vdev create/start commands depending on the service bit WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-3-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 66 ++++++++++++++++++++++++--- drivers/net/wireless/ath/ath12k/wmi.c | 3 ++ drivers/net/wireless/ath/ath12k/wmi.h | 7 +++ 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 9d82f289b23b..5967c94fe8f2 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5984,17 +5984,59 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) return vdev_stats_id; } -static void ath12k_mac_setup_vdev_create_arg(struct ath12k_vif *arvif, - struct ath12k_wmi_vdev_create_arg *arg) +static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif, + u32 *flags, u32 *tx_vdev_id) +{ + struct ieee80211_vif *tx_vif = arvif->vif->mbssid_tx_vif; + struct ath12k *ar = arvif->ar; + struct ath12k_vif *tx_arvif; + + if (!tx_vif) + return 0; + + tx_arvif = ath12k_vif_to_arvif(tx_vif); + + if (arvif->vif->bss_conf.nontransmitted) { + if (ar->ah->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy) + return -EINVAL; + + *flags = WMI_VDEV_MBSSID_FLAGS_NON_TRANSMIT_AP; + *tx_vdev_id = tx_arvif->vdev_id; + } else if (tx_arvif == arvif) { + *flags = WMI_VDEV_MBSSID_FLAGS_TRANSMIT_AP; + } else { + return -EINVAL; + } + + if (arvif->vif->bss_conf.ema_ap) + *flags |= WMI_VDEV_MBSSID_FLAGS_EMA_MODE; + + return 0; +} + +static int ath12k_mac_setup_vdev_create_arg(struct ath12k_vif *arvif, + struct ath12k_wmi_vdev_create_arg *arg) { struct ath12k *ar = arvif->ar; struct ath12k_pdev *pdev = ar->pdev; + int ret; arg->if_id = arvif->vdev_id; arg->type = arvif->vdev_type; arg->subtype = arvif->vdev_subtype; arg->pdev_id = pdev->pdev_id; + arg->mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP; + arg->mbssid_tx_vdev_id = 0; + if (!test_bit(WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT, + ar->ab->wmi_ab.svc_map)) { + ret = ath12k_mac_setup_vdev_params_mbssid(arvif, + &arg->mbssid_flags, + &arg->mbssid_tx_vdev_id); + if (ret) + return ret; + } + if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) { arg->chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains; arg->chains[NL80211_BAND_2GHZ].rx = ar->num_rx_chains; @@ -6010,6 +6052,7 @@ static void ath12k_mac_setup_vdev_create_arg(struct ath12k_vif *arvif, } arg->if_stats_id = ath12k_mac_get_vdev_stats_id(arvif); + return 0; } static u32 @@ -6191,7 +6234,12 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++) vif->hw_queue[i] = i % (ATH12K_HW_MAX_QUEUES - 1); - ath12k_mac_setup_vdev_create_arg(arvif, &vdev_arg); + ret = ath12k_mac_setup_vdev_create_arg(arvif, &vdev_arg); + if (ret) { + ath12k_warn(ab, "failed to create vdev parameters %d: %d\n", + arvif->vdev_id, ret); + goto err; + } ret = ath12k_wmi_vdev_create(ar, vif->addr, &vdev_arg); if (ret) { @@ -6933,10 +6981,16 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; - /* Fill the MBSSID flags to indicate AP is non MBSSID by default - * Corresponding flags would be updated with MBSSID support. - */ arg.mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP; + arg.mbssid_tx_vdev_id = 0; + if (test_bit(WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT, + ar->ab->wmi_ab.svc_map)) { + ret = ath12k_mac_setup_vdev_params_mbssid(arvif, + &arg.mbssid_flags, + &arg.mbssid_tx_vdev_id); + if (ret) + return ret; + } if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 3da16d4abb5a..e77132d6aa83 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -844,6 +844,8 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr, cmd->vdev_subtype = cpu_to_le32(args->subtype); cmd->num_cfg_txrx_streams = cpu_to_le32(WMI_NUM_SUPPORTED_BAND_MAX); cmd->pdev_id = cpu_to_le32(args->pdev_id); + cmd->mbssid_flags = cpu_to_le32(args->mbssid_flags); + cmd->mbssid_tx_vdev_id = cpu_to_le32(args->mbssid_tx_vdev_id); cmd->vdev_stats_id = cpu_to_le32(args->if_stats_id); ether_addr_copy(cmd->vdev_macaddr.addr, macaddr); @@ -1049,6 +1051,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, cmd->he_ops = cpu_to_le32(arg->he_ops); cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap); cmd->mbssid_flags = cpu_to_le32(arg->mbssid_flags); + cmd->mbssid_tx_vdev_id = cpu_to_le32(arg->mbssid_tx_vdev_id); if (!restart) { if (arg->ssid) { diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index e71e6c73f249..86a0ef09aa39 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2154,6 +2154,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213, WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219, WMI_TLV_SERVICE_EXT2_MSG = 220, + WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253, WMI_MAX_EXT_SERVICE = 256, @@ -2729,6 +2730,8 @@ struct ath12k_wmi_vdev_create_arg { } chains[NUM_NL80211_BANDS]; u32 pdev_id; u8 if_stats_id; + u32 mbssid_flags; + u32 mbssid_tx_vdev_id; }; #define ATH12K_MAX_VDEV_STATS_ID 0x30 @@ -2795,6 +2798,10 @@ struct ath12k_wmi_ssid_params { enum wmi_vdev_mbssid_flags { WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP = BIT(0), + WMI_VDEV_MBSSID_FLAGS_TRANSMIT_AP = BIT(1), + WMI_VDEV_MBSSID_FLAGS_NON_TRANSMIT_AP = BIT(2), + WMI_VDEV_MBSSID_FLAGS_EMA_MODE = BIT(3), + WMI_VDEV_MBSSID_FLAGS_SCAN_MODE_VAP = BIT(4), }; struct wmi_vdev_start_request_cmd { From 5fbd97f25c4c62eba921b8bc13a45f0210437787 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:06 -0700 Subject: [PATCH 40/69] wifi: ath12k: rename MBSSID fields in wmi_vdev_up_cmd Rename trans_bssid to tx_vdev_bssid to make it similar to vdev_bssid. Rename profile_num to nontx_profile_cnt, and profile_idx to nontx_profile_idx which make it clear that these configurations correspond to nontransmitted MBSSID profiles. These members are currently unused in the driver. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-4-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 86a0ef09aa39..4051ed5a0b0a 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2768,9 +2768,9 @@ struct wmi_vdev_up_cmd { __le32 vdev_id; __le32 vdev_assoc_id; struct ath12k_wmi_mac_addr_params vdev_bssid; - struct ath12k_wmi_mac_addr_params trans_bssid; - __le32 profile_idx; - __le32 profile_num; + struct ath12k_wmi_mac_addr_params tx_vdev_bssid; + __le32 nontx_profile_idx; + __le32 nontx_profile_cnt; } __packed; struct wmi_vdev_stop_cmd { From 51c47463543ef4f1f0cf2354527baa297a754995 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:07 -0700 Subject: [PATCH 41/69] wifi: ath12k: create a structure for WMI vdev up parameters Host needs to send multiple BSSID configurations to firmware for each vdev in ath12k_wmi_vdev_up() for AP mode. This function accepts individual input parameters hence any new argument will require changes to all callers. Most of these will use default value (0 or NULL). Create a structure for the function arguments and include objects with all members initialized to zero to minimize future changes. Tested-on : QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-5-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 30 ++++++++++++++++++++------- drivers/net/wireless/ath/ath12k/wmi.c | 10 ++++----- drivers/net/wireless/ath/ath12k/wmi.h | 9 ++++++-- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 5967c94fe8f2..c6fa68aafdd8 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -867,9 +867,12 @@ static int ath12k_mac_vdev_setup_sync(struct ath12k *ar) static int ath12k_monitor_vdev_up(struct ath12k *ar, int vdev_id) { + struct ath12k_wmi_vdev_up_params params = {}; int ret; - ret = ath12k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); + params.vdev_id = vdev_id; + params.bssid = ar->mac_addr; + ret = ath12k_wmi_vdev_up(ar, ¶ms); if (ret) { ath12k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", vdev_id, ret); @@ -886,6 +889,7 @@ static int ath12k_mac_monitor_vdev_start(struct ath12k *ar, int vdev_id, { struct ieee80211_channel *channel; struct wmi_vdev_start_req_arg arg = {}; + struct ath12k_wmi_vdev_up_params params = {}; int ret; lockdep_assert_held(&ar->conf_mutex); @@ -926,7 +930,9 @@ static int ath12k_mac_monitor_vdev_start(struct ath12k *ar, int vdev_id, return ret; } - ret = ath12k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); + params.vdev_id = vdev_id; + params.bssid = ar->mac_addr; + ret = ath12k_wmi_vdev_up(ar, ¶ms); if (ret) { ath12k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", vdev_id, ret); @@ -1362,6 +1368,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) static void ath12k_control_beaconing(struct ath12k_vif *arvif, struct ieee80211_bss_conf *info) { + struct ath12k_wmi_vdev_up_params params = {}; struct ath12k *ar = arvif->ar; int ret; @@ -1389,8 +1396,10 @@ static void ath12k_control_beaconing(struct ath12k_vif *arvif, ether_addr_copy(arvif->bssid, info->bssid); - ret = ath12k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, - arvif->bssid); + params.vdev_id = arvif->vdev_id; + params.aid = arvif->aid; + params.bssid = arvif->bssid; + ret = ath12k_wmi_vdev_up(arvif->ar, ¶ms); if (ret) { ath12k_warn(ar->ab, "failed to bring up vdev %d: %i\n", arvif->vdev_id, ret); @@ -2605,6 +2614,7 @@ static void ath12k_bss_assoc(struct ath12k *ar, struct ieee80211_bss_conf *bss_conf) { struct ieee80211_vif *vif = arvif->vif; + struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_wmi_peer_assoc_arg peer_arg; struct ieee80211_sta *ap_sta; struct ath12k_peer *peer; @@ -2657,7 +2667,10 @@ static void ath12k_bss_assoc(struct ath12k *ar, arvif->aid = vif->cfg.aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); - ret = ath12k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); + params.vdev_id = arvif->vdev_id; + params.aid = arvif->aid; + params.bssid = arvif->bssid; + ret = ath12k_wmi_vdev_up(ar, ¶ms); if (ret) { ath12k_warn(ar->ab, "failed to set vdev %d up: %d\n", arvif->vdev_id, ret); @@ -7184,6 +7197,7 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, struct ieee80211_vif_chanctx_switch *vifs, int n_vifs) { + struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_base *ab = ar->ab; struct ath12k_vif *arvif; int ret; @@ -7264,8 +7278,10 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, ath12k_warn(ab, "failed to update bcn tmpl during csa: %d\n", ret); - ret = ath12k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, - arvif->bssid); + params.vdev_id = arvif->vdev_id; + params.aid = arvif->aid; + params.bssid = arvif->bssid; + ret = ath12k_wmi_vdev_up(arvif->ar, ¶ms); if (ret) { ath12k_warn(ab, "failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index e77132d6aa83..6e73194a849e 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1103,7 +1103,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, return ret; } -int ath12k_wmi_vdev_up(struct ath12k *ar, u32 vdev_id, u32 aid, const u8 *bssid) +int ath12k_wmi_vdev_up(struct ath12k *ar, struct ath12k_wmi_vdev_up_params *params) { struct ath12k_wmi_pdev *wmi = ar->wmi; struct wmi_vdev_up_cmd *cmd; @@ -1118,14 +1118,14 @@ int ath12k_wmi_vdev_up(struct ath12k *ar, u32 vdev_id, u32 aid, const u8 *bssid) cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_UP_CMD, sizeof(*cmd)); - cmd->vdev_id = cpu_to_le32(vdev_id); - cmd->vdev_assoc_id = cpu_to_le32(aid); + cmd->vdev_id = cpu_to_le32(params->vdev_id); + cmd->vdev_assoc_id = cpu_to_le32(params->aid); - ether_addr_copy(cmd->vdev_bssid.addr, bssid); + ether_addr_copy(cmd->vdev_bssid.addr, params->bssid); ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI mgmt vdev up id 0x%x assoc id %d bssid %pM\n", - vdev_id, aid, bssid); + params->vdev_id, params->aid, params->bssid); ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_UP_CMDID); if (ret) { diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 4051ed5a0b0a..12c6cfb943c8 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2763,6 +2763,12 @@ struct wmi_vdev_delete_cmd { __le32 vdev_id; } __packed; +struct ath12k_wmi_vdev_up_params { + u32 vdev_id; + u32 aid; + const u8 *bssid; +}; + struct wmi_vdev_up_cmd { __le32 tlv_header; __le32 vdev_id; @@ -4893,8 +4899,7 @@ int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn); int ath12k_wmi_vdev_down(struct ath12k *ar, u8 vdev_id); -int ath12k_wmi_vdev_up(struct ath12k *ar, u32 vdev_id, u32 aid, - const u8 *bssid); +int ath12k_wmi_vdev_up(struct ath12k *ar, struct ath12k_wmi_vdev_up_params *params); int ath12k_wmi_vdev_stop(struct ath12k *ar, u8 vdev_id); int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, bool restart); From 84edf47bcb31746a4070bc4783546132d855ed4b Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:08 -0700 Subject: [PATCH 42/69] wifi: ath12k: configure MBSSID parameters in AP mode Include MBSSID parameters in WMI vdev up operation. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-6-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 15 ++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.c | 6 ++++++ drivers/net/wireless/ath/ath12k/wmi.h | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index c6fa68aafdd8..3f57acc16c40 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1399,6 +1399,11 @@ static void ath12k_control_beaconing(struct ath12k_vif *arvif, params.vdev_id = arvif->vdev_id; params.aid = arvif->aid; params.bssid = arvif->bssid; + if (arvif->vif->mbssid_tx_vif) { + params.tx_bssid = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif)->bssid; + params.nontx_profile_idx = info->bssid_index; + params.nontx_profile_cnt = 1 << info->bssid_indicator; + } ret = ath12k_wmi_vdev_up(arvif->ar, ¶ms); if (ret) { ath12k_warn(ar->ab, "failed to bring up vdev %d: %i\n", @@ -7199,6 +7204,7 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, { struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_base *ab = ar->ab; + struct ieee80211_vif *vif; struct ath12k_vif *arvif; int ret; int i; @@ -7241,7 +7247,8 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, /* TODO: Update ar->rx_channel */ for (i = 0; i < n_vifs; i++) { - arvif = ath12k_vif_to_arvif(vifs[i].vif); + vif = vifs[i].vif; + arvif = ath12k_vif_to_arvif(vif); if (WARN_ON(!arvif->is_started)) continue; @@ -7278,9 +7285,15 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, ath12k_warn(ab, "failed to update bcn tmpl during csa: %d\n", ret); + memset(¶ms, 0, sizeof(params)); params.vdev_id = arvif->vdev_id; params.aid = arvif->aid; params.bssid = arvif->bssid; + if (vif->mbssid_tx_vif) { + params.tx_bssid = ath12k_vif_to_arvif(vif->mbssid_tx_vif)->bssid; + params.nontx_profile_idx = vif->bss_conf.bssid_index; + params.nontx_profile_cnt = 1 << vif->bss_conf.bssid_indicator; + } ret = ath12k_wmi_vdev_up(arvif->ar, ¶ms); if (ret) { ath12k_warn(ab, "failed to bring vdev up %d: %d\n", diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 6e73194a849e..4d5b02caee13 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1123,6 +1123,12 @@ int ath12k_wmi_vdev_up(struct ath12k *ar, struct ath12k_wmi_vdev_up_params *para ether_addr_copy(cmd->vdev_bssid.addr, params->bssid); + if (params->tx_bssid) { + ether_addr_copy(cmd->tx_vdev_bssid.addr, params->tx_bssid); + cmd->nontx_profile_idx = cpu_to_le32(params->nontx_profile_idx); + cmd->nontx_profile_cnt = cpu_to_le32(params->nontx_profile_cnt); + } + ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI mgmt vdev up id 0x%x assoc id %d bssid %pM\n", params->vdev_id, params->aid, params->bssid); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 12c6cfb943c8..9b0166a5a575 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2767,6 +2767,9 @@ struct ath12k_wmi_vdev_up_params { u32 vdev_id; u32 aid; const u8 *bssid; + const u8 *tx_bssid; + u32 nontx_profile_idx; + u32 nontx_profile_cnt; }; struct wmi_vdev_up_cmd { From 9fd28936b641ab05ab244a85991e95c5be31e1a2 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:09 -0700 Subject: [PATCH 43/69] wifi: ath12k: refactor arvif security parameter configuration Configure security parameters in a separate function to make it easier to support setting the same for nontransmitted profiles. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-7-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 33 +++++++++++++++++---------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 3f57acc16c40..6720ec0d7fdd 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1299,6 +1299,26 @@ static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, return 0; } +static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *bcn) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data; + const u8 *start, *tail; + u16 rem_len; + + start = bcn->data + ieee80211_get_hdrlen_from_skb(bcn) + sizeof(mgmt->u.beacon); + tail = skb_tail_pointer(bcn); + rem_len = tail - start; + + arvif->rsnie_present = false; + arvif->wpaie_present = false; + + if (cfg80211_find_ie(WLAN_EID_RSN, start, rem_len)) + arvif->rsnie_present = true; + if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, + start, rem_len)) + arvif->wpaie_present = true; +} + static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) { struct ath12k *ar = arvif->ar; @@ -1307,8 +1327,6 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; struct sk_buff *bcn; - struct ieee80211_mgmt *mgmt; - u8 *ies; int ret; if (arvif->vdev_type != WMI_VDEV_TYPE_AP) @@ -1320,16 +1338,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) return -EPERM; } - ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); - ies += sizeof(mgmt->u.beacon); - - if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies))) - arvif->rsnie_present = true; - - if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, - WLAN_OUI_TYPE_MICROSOFT_WPA, - ies, (skb_tail_pointer(bcn) - ies))) - arvif->wpaie_present = true; + ath12k_mac_set_arvif_ies(arvif, bcn); if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) { ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn); From 8c6faa56bfb245a165820f46b8ea90e6ae1f24f5 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:10 -0700 Subject: [PATCH 44/69] wifi: ath12k: add MBSSID beacon support - A single beacon template is used for one multiple BSSID group as only one interface from group transmits the beacons. But firmware requires the host to send this template each time a nontransmitted interface is brought up. Hence, modify existing logic to retrieve the template from vif context of the transmitting interface. Also, firmware crashes if host sends a template for a nontransmitted interface which is already up, add a check to avoid this. - Set rsnie_present and wpaie_present fields for nontransmitted VAPs. - Send offset to the multiple BSSID element in the beacon template firmware. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-8-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 97 +++++++++++++++++++++++++-- drivers/net/wireless/ath/ath12k/wmi.c | 1 + 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 6720ec0d7fdd..2cfed85990a9 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1299,11 +1299,14 @@ static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, return 0; } -static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *bcn) +static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *bcn, + u8 bssid_index, bool *nontx_profile_found) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data; + const struct element *elem, *nontx, *index, *nie; const u8 *start, *tail; u16 rem_len; + u8 i; start = bcn->data + ieee80211_get_hdrlen_from_skb(bcn) + sizeof(mgmt->u.beacon); tail = skb_tail_pointer(bcn); @@ -1317,28 +1320,114 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *b if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, start, rem_len)) arvif->wpaie_present = true; + + /* Return from here for the transmitted profile */ + if (!bssid_index) + return; + + /* Initial rsnie_present for the nontransmitted profile is set to be same as that + * of the transmitted profile. It will be changed if security configurations are + * different. + */ + *nontx_profile_found = false; + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, rem_len) { + /* Fixed minimum MBSSID element length with at least one + * nontransmitted BSSID profile is 12 bytes as given below; + * 1 (max BSSID indicator) + + * 2 (Nontransmitted BSSID profile: Subelement ID + length) + + * 4 (Nontransmitted BSSID Capabilities: tag + length + info) + * 2 (Nontransmitted BSSID SSID: tag + length) + * 3 (Nontransmitted BSSID Index: tag + length + BSSID index + */ + if (elem->datalen < 12 || elem->data[0] < 1) + continue; /* Max BSSID indicator must be >=1 */ + + for_each_element(nontx, elem->data + 1, elem->datalen - 1) { + start = nontx->data; + + if (nontx->id != 0 || nontx->datalen < 4) + continue; /* Invalid nontransmitted profile */ + + if (nontx->data[0] != WLAN_EID_NON_TX_BSSID_CAP || + nontx->data[1] != 2) { + continue; /* Missing nontransmitted BSS capabilities */ + } + + if (nontx->data[4] != WLAN_EID_SSID) + continue; /* Missing SSID for nontransmitted BSS */ + + index = cfg80211_find_elem(WLAN_EID_MULTI_BSSID_IDX, + start, nontx->datalen); + if (!index || index->datalen < 1 || index->data[0] == 0) + continue; /* Invalid MBSSID Index element */ + + if (index->data[0] == bssid_index) { + *nontx_profile_found = true; + if (cfg80211_find_ie(WLAN_EID_RSN, + nontx->data, + nontx->datalen)) { + arvif->rsnie_present = true; + return; + } else if (!arvif->rsnie_present) { + return; /* Both tx and nontx BSS are open */ + } + + nie = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, + nontx->data, + nontx->datalen); + if (!nie || nie->datalen < 2) + return; /* Invalid non-inheritance element */ + + for (i = 1; i < nie->datalen - 1; i++) { + if (nie->data[i] == WLAN_EID_RSN) { + arvif->rsnie_present = false; + break; + } + } + + return; + } + } + } } static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) { + struct ath12k_vif *tx_arvif = arvif; struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; + bool nontx_profile_found = false; struct sk_buff *bcn; int ret; if (arvif->vdev_type != WMI_VDEV_TYPE_AP) return 0; - bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); + if (vif->mbssid_tx_vif) { + tx_arvif = ath12k_vif_to_arvif(vif->mbssid_tx_vif); + if (tx_arvif != arvif && arvif->is_up) + return 0; + } + + bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_arvif->vif, + &offs, 0); if (!bcn) { ath12k_warn(ab, "failed to get beacon template from mac80211\n"); return -EPERM; } - ath12k_mac_set_arvif_ies(arvif, bcn); + if (tx_arvif == arvif) { + ath12k_mac_set_arvif_ies(arvif, bcn, 0, NULL); + } else { + ath12k_mac_set_arvif_ies(arvif, bcn, + arvif->vif->bss_conf.bssid_index, + &nontx_profile_found); + if (!nontx_profile_found) + ath12k_warn(ab, + "nontransmitted profile not found in beacon template\n"); + } if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) { ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn); diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 4d5b02caee13..57fb01d66a0d 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1813,6 +1813,7 @@ int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, cmd->csa_switch_count_offset = cpu_to_le32(offs->cntdwn_counter_offs[0]); cmd->ext_csa_switch_count_offset = cpu_to_le32(offs->cntdwn_counter_offs[1]); cmd->buf_len = cpu_to_le32(bcn->len); + cmd->mbssid_ie_offset = cpu_to_le32(offs->mbssid_off); ptr = skb->data + sizeof(*cmd); From f27fbd76a98feca81688175985fbfa31bad8cd75 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:11 -0700 Subject: [PATCH 45/69] wifi: ath12k: add EMA beacon support Add new function ath12k_mac_setup_bcn_tmpl_ema() which retrieves a list of EMA (Enhanced Multi-BSSID Advertisements) beacon templates from mac80211 and sends all to firmware. Add support to send EMA configurations to firmware by adding a new parameter 'ema_params' in struct wmi_bcn_tmpl_cmd. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-9-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 55 ++++++++++++++++++++++++++- drivers/net/wireless/ath/ath12k/wmi.c | 13 ++++++- drivers/net/wireless/ath/ath12k/wmi.h | 18 ++++++++- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 2cfed85990a9..e86af398b359 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1391,6 +1391,56 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *b } } +static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif) +{ + struct ieee80211_bss_conf *bss_conf = &arvif->vif->bss_conf; + struct ath12k_wmi_bcn_tmpl_ema_arg ema_args; + struct ieee80211_ema_beacons *beacons; + struct ath12k_vif *tx_arvif; + bool nontx_profile_found = false; + int ret = 0; + u8 i; + + tx_arvif = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif); + beacons = ieee80211_beacon_get_template_ema_list(ath12k_ar_to_hw(tx_arvif->ar), + tx_arvif->vif, 0); + if (!beacons || !beacons->cnt) { + ath12k_warn(arvif->ar->ab, + "failed to get ema beacon templates from mac80211\n"); + return -EPERM; + } + + if (tx_arvif == arvif) + ath12k_mac_set_arvif_ies(arvif, beacons->bcn[0].skb, 0, NULL); + + for (i = 0; i < beacons->cnt; i++) { + if (tx_arvif != arvif && !nontx_profile_found) + ath12k_mac_set_arvif_ies(arvif, beacons->bcn[i].skb, + bss_conf->bssid_index, + &nontx_profile_found); + + ema_args.bcn_cnt = beacons->cnt; + ema_args.bcn_index = i; + ret = ath12k_wmi_bcn_tmpl(tx_arvif->ar, tx_arvif->vdev_id, + &beacons->bcn[i].offs, + beacons->bcn[i].skb, &ema_args); + if (ret) { + ath12k_warn(tx_arvif->ar->ab, + "failed to set ema beacon template id %i error %d\n", + i, ret); + break; + } + } + + if (tx_arvif != arvif && !nontx_profile_found) + ath12k_warn(arvif->ar->ab, + "nontransmitted bssid index %u not found in beacon template\n", + bss_conf->bssid_index); + + ieee80211_beacon_free_ema_list(beacons); + return ret; +} + static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) { struct ath12k_vif *tx_arvif = arvif; @@ -1409,6 +1459,9 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) tx_arvif = ath12k_vif_to_arvif(vif->mbssid_tx_vif); if (tx_arvif != arvif && arvif->is_up) return 0; + + if (vif->bss_conf.ema_ap) + return ath12k_mac_setup_bcn_tmpl_ema(arvif); } bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_arvif->vif, @@ -1452,7 +1505,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) } } - ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); + ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, NULL); if (ret) ath12k_warn(ab, "failed to submit beacon template command: %d\n", diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 57fb01d66a0d..99106b088311 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -1788,13 +1788,15 @@ int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, - struct sk_buff *bcn) + struct sk_buff *bcn, + struct ath12k_wmi_bcn_tmpl_ema_arg *ema_args) { struct ath12k_wmi_pdev *wmi = ar->wmi; struct wmi_bcn_tmpl_cmd *cmd; struct ath12k_wmi_bcn_prb_info_params *bcn_prb_info; struct wmi_tlv *tlv; struct sk_buff *skb; + u32 ema_params = 0; void *ptr; int ret, len; size_t aligned_len = roundup(bcn->len, 4); @@ -1814,6 +1816,15 @@ int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, cmd->ext_csa_switch_count_offset = cpu_to_le32(offs->cntdwn_counter_offs[1]); cmd->buf_len = cpu_to_le32(bcn->len); cmd->mbssid_ie_offset = cpu_to_le32(offs->mbssid_off); + if (ema_args) { + u32p_replace_bits(&ema_params, ema_args->bcn_cnt, WMI_EMA_BEACON_CNT); + u32p_replace_bits(&ema_params, ema_args->bcn_index, WMI_EMA_BEACON_IDX); + if (ema_args->bcn_index == 0) + u32p_replace_bits(&ema_params, 1, WMI_EMA_BEACON_FIRST); + if (ema_args->bcn_index + 1 == ema_args->bcn_cnt) + u32p_replace_bits(&ema_params, 1, WMI_EMA_BEACON_LAST); + cmd->ema_params = cpu_to_le32(ema_params); + } ptr = skb->data + sizeof(*cmd); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 9b0166a5a575..7f83c4583919 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3533,6 +3533,16 @@ struct ath12k_wmi_p2p_noa_info { #define WMI_BEACON_TX_BUFFER_SIZE 512 +#define WMI_EMA_BEACON_CNT GENMASK(7, 0) +#define WMI_EMA_BEACON_IDX GENMASK(15, 8) +#define WMI_EMA_BEACON_FIRST GENMASK(23, 16) +#define WMI_EMA_BEACON_LAST GENMASK(31, 24) + +struct ath12k_wmi_bcn_tmpl_ema_arg { + u8 bcn_cnt; + u8 bcn_index; +}; + struct wmi_bcn_tmpl_cmd { __le32 tlv_header; __le32 vdev_id; @@ -3543,6 +3553,11 @@ struct wmi_bcn_tmpl_cmd { __le32 csa_event_bitmap; __le32 mbssid_ie_offset; __le32 esp_ie_offset; + __le32 csc_switch_count_offset; + __le32 csc_event_bitmap; + __le32 mu_edca_ie_offset; + __le32 feature_enable_bitmap; + __le32 ema_params; } __packed; struct wmi_p2p_go_set_beacon_ie_cmd { @@ -4900,7 +4915,8 @@ int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, const u8 *p2p_ie); int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, - struct sk_buff *bcn); + struct sk_buff *bcn, + struct ath12k_wmi_bcn_tmpl_ema_arg *ema_args); int ath12k_wmi_vdev_down(struct ath12k *ar, u8 vdev_id); int ath12k_wmi_vdev_up(struct ath12k *ar, struct ath12k_wmi_vdev_up_params *params); int ath12k_wmi_vdev_stop(struct ath12k *ar, u8 vdev_id); From c740a18f62f5bbf2c88c3160d189704cbe001255 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Wed, 8 May 2024 13:29:12 -0700 Subject: [PATCH 46/69] wifi: ath12k: skip sending vdev down for channel switch Remove the unnecessary WMI vdev down operation as firmware internally does so already as part of WMI vdev restart. Repeated vdev down results in a firmware crash during channel switch operation when multiple BSSID advertisements are enabled: ath12k_pci 0000:06:00.0: firmware crashed: MHI_CB_SYS_ERROR ath12k_pci 0000:06:00.0: failed to send WMI_VDEV_SET_PARAM_CMDID ath12k_pci 0000:06:00.0: failed to set vdev 5 HE MU mode: -108 param_value 7b ath12k_pci 0000:06:00.0: failed to set he mode vdev 5 ath12k_pci 0000:06:00.0: failed to restart vdev 5: -108 ath12k_pci 0000:06:00.0: failed to send WMI_VDEV_SET_PARAM_CMDID ath12k_pci 0000:06:00.0: failed to set vdev 4 HE MU mode: -108 param_value 7b ath12k_pci 0000:06:00.0: failed to set he mode vdev 4 ath12k_pci 0000:06:00.0: failed to restart vdev 4: -108 ath12k_pci 0000:06:00.0: failed to send WMI_VDEV_SET_PARAM_CMDID Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240508202912.11902-10-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 29 +++------------------------ 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index e86af398b359..33741ebecdf6 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7364,9 +7364,10 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, lockdep_assert_held(&ar->conf_mutex); for (i = 0; i < n_vifs; i++) { - arvif = ath12k_vif_to_arvif(vifs[i].vif); + vif = vifs[i].vif; + arvif = ath12k_vif_to_arvif(vif); - if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR) + if (vif->type == NL80211_IFTYPE_MONITOR) monitor_vif = true; ath12k_dbg(ab, ATH12K_DBG_MAC, @@ -7377,30 +7378,6 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, vifs[i].old_ctx->def.width, vifs[i].new_ctx->def.width); - if (WARN_ON(!arvif->is_started)) - continue; - - if (WARN_ON(!arvif->is_up)) - continue; - - ret = ath12k_wmi_vdev_down(ar, arvif->vdev_id); - if (ret) { - ath12k_warn(ab, "failed to down vdev %d: %d\n", - arvif->vdev_id, ret); - continue; - } - } - - /* All relevant vdevs are downed and associated channel resources - * should be available for the channel switch now. - */ - - /* TODO: Update ar->rx_channel */ - - for (i = 0; i < n_vifs; i++) { - vif = vifs[i].vif; - arvif = ath12k_vif_to_arvif(vif); - if (WARN_ON(!arvif->is_started)) continue; From 0ce9ab2785e4e9ca0752390d8e5ab65bd08f0e78 Mon Sep 17 00:00:00 2001 From: Nithyanantham Paramasivam Date: Fri, 10 May 2024 12:34:27 +0530 Subject: [PATCH 47/69] wifi: ath12k: Fix tx completion ring (WBM2SW) setup failure We observe intermittent ping failures from the access point (AP) to station (STA) in any mode (AP-STA or Mesh) configured. Specifically, the transmission completion status is not received at tx completion ring id 4 (WBM2SW ring4) for the packets transmitted via TCL DATA ring id 3. This prevents freeing up tx descriptors and leads to buffer exhaustion. Currently, during initialization of the WBM2SW ring, we are directly mapping the ring number to the ring mask to obtain the ring mask group index. This approach is causing setup failures for WBM2SW ring 4. Similarly, during runtime, when receiving incoming transmission completion status, the validation of the ring number by mapping the interrupted ring mask. This is resulting in validation failure. Thereby preventing entry into the completion handler ath12k_dp_tx_completion_handler(). The existing design assumed that the ring numbers would always be sequential and could be directly mapped with the ring mask. However, this assumption does not hold true for WBM2SW ring 4. Therefore, modify the design such that, instead of mapping the ring number, the ring ID is mapped with the ring mask. According to this design: 1. During initialization of the WBM2SW ring, mapping the ring ID to the ring mask will ensure obtaining the correct ring mask group ID. 2. During runtime, validating the interrupted ring mask group ID within the transmission completion group is sufficient. This approach allows the ring ID to be derived from the interrupted ring mask and enables entry into the completion handler. 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 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Nithyanantham Paramasivam Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240510070427.206152-1-quic_nithp@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 18 +++++++++++++----- drivers/net/wireless/ath/ath12k/hw.c | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 412ab08e6cca..c04fa3eb57d6 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -132,7 +132,9 @@ static int ath12k_dp_srng_find_ring_in_mask(int ring_num, const u8 *grp_mask) static int ath12k_dp_srng_calculate_msi_group(struct ath12k_base *ab, enum hal_ring_type type, int ring_num) { + const struct ath12k_hal_tcl_to_wbm_rbm_map *map; const u8 *grp_mask; + int i; switch (type) { case HAL_WBM2SW_RELEASE: @@ -140,6 +142,14 @@ static int ath12k_dp_srng_calculate_msi_group(struct ath12k_base *ab, grp_mask = &ab->hw_params->ring_mask->rx_wbm_rel[0]; ring_num = 0; } else { + map = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map; + for (i = 0; i < ab->hw_params->max_tx_ring; i++) { + if (ring_num == map[i].wbm_ring_num) { + ring_num = i; + break; + } + } + grp_mask = &ab->hw_params->ring_mask->tx[0]; } break; @@ -867,11 +877,9 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, enum dp_monitor_mode monitor_mode; u8 ring_mask; - while (i < ab->hw_params->max_tx_ring) { - if (ab->hw_params->ring_mask->tx[grp_id] & - BIT(ab->hw_params->hal_ops->tcl_to_wbm_rbm_map[i].wbm_ring_num)) - ath12k_dp_tx_completion_handler(ab, i); - i++; + if (ab->hw_params->ring_mask->tx[grp_id]) { + i = fls(ab->hw_params->ring_mask->tx[grp_id]) - 1; + ath12k_dp_tx_completion_handler(ab, i); } if (ab->hw_params->ring_mask->rx_err[grp_id]) { diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index b3ba753d4a85..5a1d406e6b1f 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -580,8 +580,8 @@ static const struct ath12k_hw_ring_mask ath12k_hw_ring_mask_qcn9274 = { static const struct ath12k_hw_ring_mask ath12k_hw_ring_mask_wcn7850 = { .tx = { ATH12K_TX_RING_MASK_0, + ATH12K_TX_RING_MASK_1, ATH12K_TX_RING_MASK_2, - ATH12K_TX_RING_MASK_4, }, .rx_mon_dest = { }, From 3a29442a17413e9e64f00db3b98dbf911324cb86 Mon Sep 17 00:00:00 2001 From: Kang Yang Date: Fri, 10 May 2024 19:12:38 +0800 Subject: [PATCH 48/69] wifi: ath12k: remove redundant peer delete for WCN7850 ath12k_mac_op_unassign_vif_chanctx() will do peer delete for WCN7850's monitor interface. But for host no need to do peer create/delete for monitor interface because firmware doesn't require it, QCN9274 is the same. Also, the first judgement is true only for WCN7850, so this logic won't affect QCN9274 at any time. So remove this peer delete. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Kang Yang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240510111238.1113-1-quic_kangyang@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 33741ebecdf6..784964ae03ec 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -7651,11 +7651,6 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, WARN_ON(!arvif->is_started); - if (ab->hw_params->vdev_start_delay && - arvif->vdev_type == WMI_VDEV_TYPE_MONITOR && - ath12k_peer_find_by_addr(ab, ar->mac_addr)) - ath12k_peer_delete(ar, arvif->vdev_id, ar->mac_addr); - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath12k_mac_monitor_stop(ar); if (ret) { From 28bfc1c9c9d0e2165ee9e3b50793b8b463e52e01 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 14 May 2024 12:04:11 +0530 Subject: [PATCH 49/69] wifi: ath12k: remove duplicate definition of MAX_RADIOS Remove the duplicate definition of MAX_RADIOS from the core header file. No functional changes, compile tested only. Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240514063412.3483723-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 6da242c0d51d..7d20b09c52e6 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -180,8 +180,6 @@ struct ath12k_he { u32 heop_param; }; -#define MAX_RADIOS 3 - enum { WMI_HOST_TP_SCALE_MAX = 0, WMI_HOST_TP_SCALE_50 = 1, From 7678f8bfd74c324bd10499cf1d05e5720d9449b2 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 14 May 2024 12:04:12 +0530 Subject: [PATCH 50/69] wifi: ath12k: use correct MAX_RADIOS The current value of the MAX_RADIOS definition is 3. This is incorrect because no device supports more than 2 radios. An incorrect MAX_RADIOS value can lead to: - unnecessary memory allocation for pdev related entities. - invalid pdev id validation. - Misconceptions for code readers. Therefore, modify the MAX_RADIOS definition as 2. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240514063412.3483723-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 7f83c4583919..c2b86e187a03 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -4804,7 +4804,7 @@ struct wmi_probe_tmpl_cmd { __le32 buf_len; } __packed; -#define MAX_RADIOS 3 +#define MAX_RADIOS 2 #define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ) #define WMI_SEND_TIMEOUT_HZ (3 * HZ) From ed61863debb2df0856524b5c61d2a7f7731c2e83 Mon Sep 17 00:00:00 2001 From: Lingbo Kong Date: Thu, 16 May 2024 11:30:44 +0300 Subject: [PATCH 51/69] wifi: ath12k: fix ack signal strength calculation Currently, the calculation of ack signal strength is incorrect. This is because before calculating the ack signal strength, ath12k need to determine whether the hardware and firmware support db2dbm. If the hardware and firmware support db2dbm, do not need to add noise floor, otherwise, need to add noise floor. Besides, the value of ack_rssi passed by firmware to ath12k should be a signed number, so change its type to s8. This patch affects QCN9274 and WCN7850 because they have the same issue. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Lingbo Kong Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240511030917.65811-1-quic_lingbok@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_tx.c | 16 ++++++++++++---- drivers/net/wireless/ath/ath12k/dp_tx.h | 2 +- drivers/net/wireless/ath/ath12k/hal_tx.h | 4 ++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 32496015cf9a..f57bc8d69715 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -393,8 +393,12 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, if (ts->acked) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ATH12K_DEFAULT_NOISE_FLOOR + - ts->ack_rssi; + info->status.ack_signal = ts->ack_rssi; + + if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, + ab->wmi_ab.svc_map)) + info->status.ack_signal += ATH12K_DEFAULT_NOISE_FLOOR; + info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; } else { info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; @@ -486,8 +490,12 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, case HAL_WBM_TQM_REL_REASON_FRAME_ACKED: if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ATH12K_DEFAULT_NOISE_FLOOR + - ts->ack_rssi; + info->status.ack_signal = ts->ack_rssi; + + if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, + ab->wmi_ab.svc_map)) + info->status.ack_signal += ATH12K_DEFAULT_NOISE_FLOOR; + info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; } break; diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.h b/drivers/net/wireless/ath/ath12k/dp_tx.h index 7faa81faf6a7..55ff8cc721e3 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.h +++ b/drivers/net/wireless/ath/ath12k/dp_tx.h @@ -12,7 +12,7 @@ struct ath12k_dp_htt_wbm_tx_status { bool acked; - int ack_rssi; + s8 ack_rssi; }; int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab); diff --git a/drivers/net/wireless/ath/ath12k/hal_tx.h b/drivers/net/wireless/ath/ath12k/hal_tx.h index 7c837094a6f7..3cf5973771d7 100644 --- a/drivers/net/wireless/ath/ath12k/hal_tx.h +++ b/drivers/net/wireless/ath/ath12k/hal_tx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HAL_TX_H @@ -57,7 +57,7 @@ struct hal_tx_info { struct hal_tx_status { enum hal_wbm_rel_src_module buf_rel_source; enum hal_wbm_tqm_rel_reason status; - u8 ack_rssi; + s8 ack_rssi; u32 flags; /* %HAL_TX_STATUS_FLAGS_ */ u32 ppdu_id; u8 try_cnt; From 26dd8ccdba4d492d00e35c410bc4314e043bdf73 Mon Sep 17 00:00:00 2001 From: Muna Sinada Date: Fri, 17 May 2024 10:00:30 +0300 Subject: [PATCH 52/69] wifi: ath12k: dynamic VLAN support Add support for dynamic VLAN. VLAN group traffic is encapsulated and encrypted in mac80211 and driver needs to set flags for the VLAN group traffic to skip hardware encapsulation and encryption. VLAN group traffic utilizes ext MSDU and HTT Metadata to set encapsulation type to RAW and encryption type to OPEN in order to inform firmware to skip hardware encapsulation and encryption. 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: Muna Sinada Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240515192830.995013-1-quic_msinada@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_tx.c | 60 ++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/hal_desc.h | 25 +++++++++ drivers/net/wireless/ath/ath12k/hw.c | 6 ++- 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index f57bc8d69715..c4cfa7cf7cb9 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -124,6 +124,44 @@ static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab, HAL_TX_MSDU_EXT_INFO1_ENCRYPT_TYPE); } +#define HTT_META_DATA_ALIGNMENT 0x8 + +static void *ath12k_dp_metadata_align_skb(struct sk_buff *skb, u8 tail_len) +{ + struct sk_buff *tail; + void *metadata; + + if (unlikely(skb_cow_data(skb, tail_len, &tail) < 0)) + return NULL; + + metadata = pskb_put(skb, tail, tail_len); + memset(metadata, 0, tail_len); + return metadata; +} + +/* Preparing HTT Metadata when utilized with ext MSDU */ +static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb) +{ + struct hal_tx_msdu_metadata *desc_ext; + u8 htt_desc_size; + /* Size rounded of multiple of 8 bytes */ + u8 htt_desc_size_aligned; + + htt_desc_size = sizeof(struct hal_tx_msdu_metadata); + htt_desc_size_aligned = ALIGN(htt_desc_size, HTT_META_DATA_ALIGNMENT); + + desc_ext = ath12k_dp_metadata_align_skb(skb, htt_desc_size_aligned); + if (!desc_ext) + return -ENOMEM; + + desc_ext->info0 = le32_encode_bits(1, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_FLAG) | + le32_encode_bits(0, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_TYPE) | + le32_encode_bits(1, + HAL_TX_MSDU_METADATA_INFO0_HOST_TX_DESC_POOL); + + return 0; +} + int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, struct sk_buff *skb) { @@ -145,6 +183,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, u8 ring_selector, ring_map = 0; bool tcl_ring_retry; bool msdu_ext_desc = false; + bool add_htt_metadata = false; if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) return -ESHUTDOWN; @@ -248,6 +287,18 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, goto fail_remove_tx_buf; } + if (!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) && + !(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) && + !(skb_cb->flags & ATH12K_SKB_CIPHER_SET) && + ieee80211_has_protected(hdr->frame_control)) { + /* Add metadata for sw encrypted vlan group traffic */ + add_htt_metadata = true; + msdu_ext_desc = true; + ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW); + ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW; + ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN; + } + tx_desc->skb = skb; tx_desc->mac_id = ar->pdev_idx; ti.desc_id = tx_desc->desc_id; @@ -269,6 +320,15 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, msg = (struct hal_tx_msdu_ext_desc *)skb_ext_desc->data; ath12k_hal_tx_cmd_ext_desc_setup(ab, msg, &ti); + if (add_htt_metadata) { + ret = ath12k_dp_prepare_htt_metadata(skb_ext_desc); + if (ret < 0) { + ath12k_dbg(ab, ATH12K_DBG_DP_TX, + "Failed to add HTT meta data, dropping packet\n"); + goto fail_unmap_dma; + } + } + ti.paddr = dma_map_single(ab->dev, skb_ext_desc->data, skb_ext_desc->len, DMA_TO_DEVICE); ret = dma_mapping_error(ab->dev, ti.paddr); diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 814c02f876d6..02b7db06b24e 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -2984,4 +2984,29 @@ struct hal_mon_dest_desc { * updated by SRNG. */ +#define HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_FLAG BIT(8) +#define HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_TYPE GENMASK(16, 15) +#define HAL_TX_MSDU_METADATA_INFO0_HOST_TX_DESC_POOL BIT(31) + +struct hal_tx_msdu_metadata { + __le32 info0; + __le32 rsvd0[6]; +} __packed; + +/* hal_tx_msdu_metadata + * valid_encrypt_type + * if set, encrypt type is valid + * encrypt_type + * 0 = NO_ENCRYPT, + * 1 = ENCRYPT, + * 2 ~ 3 - Reserved + * host_tx_desc_pool + * If set, Firmware allocates tx_descriptors + * in WAL_BUFFERID_TX_HOST_DATA_EXP,instead + * of WAL_BUFFERID_TX_TCL_DATA_EXP. + * Use cases: + * Any time firmware uses TQM-BYPASS for Data + * TID, firmware expect host to set this bit. + */ + #endif /* ATH12K_HAL_DESC_H */ diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 5a1d406e6b1f..b45f929a0204 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -891,7 +891,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_MESH_POINT), + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_AP_VLAN), .supports_monitor = false, .idle_ps = false, @@ -1038,7 +1039,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_MESH_POINT), + BIT(NL80211_IFTYPE_MESH_POINT) | + BIT(NL80211_IFTYPE_AP_VLAN), .supports_monitor = false, .idle_ps = false, From 33370412eced2dc7f81f4324e109d69319cafd82 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Mon, 20 May 2024 14:58:28 +0300 Subject: [PATCH 53/69] wifi: ath12k: fix Smatch warnings on ath12k_core_suspend() Smatch is throwing below warning: Commit 692921ead832 ("wifi: ath12k: flush all packets before suspend") leads to the following Smatch static checker warning: drivers/net/wireless/ath/ath12k/core.c:58 ath12k_core_suspend() warn: sleeping in atomic context and also gives the reason: drivers/net/wireless/ath/ath12k/core.c 48 int ret, i; 49 50 if (!ab->hw_params->supports_suspend) 51 return -EOPNOTSUPP; 52 53 rcu_read_lock(); ^^^^^^^^^^^^^^^ Disables preemption. 54 for (i = 0; i < ab->num_radios; i++) { 55 ar = ath12k_mac_get_ar_by_pdev_id(ab, i); 56 if (!ar) 57 continue; --> 58 ret = ath12k_mac_wait_tx_complete(ar); ^^^^^^^ Sleeping in atomic context. 59 if (ret) { 60 ath12k_warn(ab, "failed to wait tx complete: %d\n", ret); 61 rcu_read_unlock(); 62 return ret; 63 } 64 } 65 rcu_read_unlock(); But it is weird that no warning on this in run time even with CONFIG_DEBUG_ATOMIC_SLEEP=y. With some debug it is found that this is because: when system goes to suspend, ath12k_mac_op_stop() gets called where then in ath12k_mac_stop() ab->pdevs_active[ar->pdev_idx] is cleared. This results in ath12k_mac_get_ar_by_pdev_id() always returning a NULL ar, and thereby ath12k_mac_wait_tx_complete() never gets a chance to run. Fix it by retrieving ar directly from ab->pdevs[].ar instead of using ath12k_mac_get_ar_by_pdev_id(). Since ab->pdevs[].ar is set at boot time and won't get cleared when suspend, ath12k_mac_wait_tx_complete() won't be skipped. In addition, with ath12k_mac_get_ar_by_pdev_id() removed, rcu_read_lock()/unlock() are not needed any more, so remove them. This also fixes the warning above. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Fixes: 692921ead832 ("wifi: ath12k: flush all packets before suspend") Reported-by: Dan Carpenter Closes: https://lore.kernel.org/ath12k/7a96ca11-80b5-4751-8cfc-fa637f3aa63a@moroto.mountain/ Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240511095045.9623-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 9482d5db71e7..e7f628e935e4 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -50,19 +50,16 @@ int ath12k_core_suspend(struct ath12k_base *ab) if (!ab->hw_params->supports_suspend) return -EOPNOTSUPP; - rcu_read_lock(); for (i = 0; i < ab->num_radios; i++) { - ar = ath12k_mac_get_ar_by_pdev_id(ab, i); + ar = ab->pdevs[i].ar; if (!ar) continue; ret = ath12k_mac_wait_tx_complete(ar); if (ret) { ath12k_warn(ab, "failed to wait tx complete: %d\n", ret); - rcu_read_unlock(); return ret; } } - rcu_read_unlock(); /* PM framework skips suspend_late/resume_early callbacks * if other devices report errors in their suspend callbacks. From 4f82a8d5c27748a3b4318af99627f4df248133e8 Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 21 May 2024 11:08:10 +0300 Subject: [PATCH 54/69] wifi: ath12k: refactor rx descriptor CMEM configuration Currently, data path Rx descriptor placed in the CMEM memory respective to the Rx offset. This Rx descriptor CMEM placement is not meeting the requirements to support inter device MLO. In inter device MLO, multiple devices participate in a group. The device specific Rx descriptor buffers transmit to multiple device REO rings. To distinguish between device specific Rx descriptor buffers, the CMEM setup configuration need to choose a different placement based on the unique identifier (device index). Below are the CMEM configuration placement representation: Intra-Device MLO scenario: Device 0 Device 1 +-------------+ +-------------+ | | | | | Tx | | Tx | | | | | +-------------+ +-------------+ | | | | | Rx | | Rx | | | | | +-------------+ +-------------+ Inter-Device MLO scenario: Device 0 Device 1 +-------------+ +-------------+ | | | | | Tx | | Tx | | | | | +-------------+ +-------------+ | | | | | Rx | | Reserved | | Device 0 | | | | | | | +-------------+ +-------------+ | | | Rx | | Reserved | | Device 1 | | | | | +-------------+ +-------------+ 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: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240516000807.1704913-2-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp.c | 12 +++++++++--- drivers/net/wireless/ath/ath12k/dp.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index c04fa3eb57d6..61aa78d8bd8c 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -1349,13 +1349,14 @@ static inline void *ath12k_dp_cc_get_desc_addr_ptr(struct ath12k_base *ab, struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, u32 cookie) { + struct ath12k_dp *dp = &ab->dp; struct ath12k_rx_desc_info **desc_addr_ptr; u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx; ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); - start_ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET; + start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET; end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES; if (ppt_idx < start_ppt_idx || @@ -1363,6 +1364,7 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, spt_idx > ATH12K_MAX_SPT_ENTRIES) return NULL; + ppt_idx = ppt_idx - dp->rx_ppt_base; desc_addr_ptr = ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, spt_idx); return *desc_addr_ptr; @@ -1397,7 +1399,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) struct ath12k_rx_desc_info *rx_descs, **rx_desc_addr; struct ath12k_tx_desc_info *tx_descs, **tx_desc_addr; u32 i, j, pool_id, tx_spt_page; - u32 ppt_idx; + u32 ppt_idx, cookie_ppt_idx; spin_lock_bh(&dp->rx_desc_lock); @@ -1412,10 +1414,11 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) } ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i; + cookie_ppt_idx = dp->rx_ppt_base + ppt_idx; dp->spt_info->rxbaddr[i] = &rx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { - rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(ppt_idx, j); + rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(cookie_ppt_idx, j); rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC; list_add_tail(&rx_descs[j].list, &dp->rx_desc_free_list); @@ -1476,6 +1479,7 @@ static int ath12k_dp_cmem_init(struct ath12k_base *ab, end = start + ATH12K_NUM_TX_SPT_PAGES; break; case ATH12K_DP_RX_DESC: + cmem_base += ATH12K_PPT_ADDR_OFFSET(dp->rx_ppt_base); start = ATH12K_RX_SPT_PAGE_OFFSET; end = start + ATH12K_NUM_RX_SPT_PAGES; break; @@ -1518,6 +1522,8 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) return -ENOMEM; } + dp->rx_ppt_base = ab->device_id * ATH12K_NUM_RX_SPT_PAGES; + for (i = 0; i < dp->num_spt_pages; i++) { dp->spt_info[i].vaddr = dma_alloc_coherent(ab->dev, ATH12K_PAGE_SIZE, diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 43589c3dd4bc..742094545089 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -350,6 +350,7 @@ struct ath12k_dp { struct ath12k_hp_update_timer tx_ring_timer[DP_TCL_NUM_RING_MAX]; struct ath12k_spt_info *spt_info; u32 num_spt_pages; + u32 rx_ppt_base; struct list_head rx_desc_free_list; /* protects the free desc list */ spinlock_t rx_desc_lock; From 35864b62fa129196af4641b8bef50ac4226a22ed Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Tue, 21 May 2024 11:08:10 +0300 Subject: [PATCH 55/69] wifi: ath12k: improve the rx descriptor error information The ath12k_dp_get_rx_desc() failure log currently contains the same information across multiple Rx data paths and lacks sufficient detail for debugging purposes. To address this, change the ath12k_dp_get_rx_desc() failure log to include cookie information along with Rx path details. This will provide more specific data for debugging purposes. 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: Karthikeyan Periyasamy Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240516000807.1704913-3-quic_periyasa@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index d8998ac3a482..000df6edf6b4 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2628,7 +2628,8 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, if (!desc_info) { desc_info = ath12k_dp_get_rx_desc(ab, cookie); if (!desc_info) { - ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); + ath12k_warn(ab, "Invalid cookie in manual descriptor retrieval: 0x%x\n", + cookie); continue; } } @@ -3326,7 +3327,8 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, if (!desc_info) { desc_info = ath12k_dp_get_rx_desc(ab, cookie); if (!desc_info) { - ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); + ath12k_warn(ab, "Invalid cookie in DP rx error descriptor retrieval: 0x%x\n", + cookie); return -EINVAL; } } @@ -3745,7 +3747,8 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, if (!desc_info) { desc_info = ath12k_dp_get_rx_desc(ab, err_info.cookie); if (!desc_info) { - ath12k_warn(ab, "Invalid cookie in manual desc retrieval"); + ath12k_warn(ab, "Invalid cookie in DP WBM rx error descriptor retrieval: 0x%x\n", + err_info.cookie); continue; } } From b363614c0c80f9e2f3ffe8e77270e783a0fb8ab5 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 21 May 2024 11:08:10 +0300 Subject: [PATCH 56/69] wifi: ath11k: refactor setting country code logic ath11k_wmi_send_set_current_country_cmd() is called in several places and all of them are just simply repeating the same logic. Refactor to make code clean. Compile tested only. Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20240520024148.5472-2-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 19 ++++++++----------- drivers/net/wireless/ath/ath11k/mac.c | 13 +++---------- drivers/net/wireless/ath/ath11k/reg.c | 14 ++++++++++---- drivers/net/wireless/ath/ath11k/reg.h | 4 ++-- 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index d4ef556852c2..748e3ad2bec3 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -1978,23 +1978,20 @@ static void ath11k_update_11d(struct work_struct *work) struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); struct ath11k *ar; struct ath11k_pdev *pdev; - struct wmi_set_current_country_params set_current_param = {}; int ret, i; - spin_lock_bh(&ab->base_lock); - memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2); - spin_unlock_bh(&ab->base_lock); - - ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n", - set_current_param.alpha2[0], - set_current_param.alpha2[1]); - for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; - memcpy(&ar->alpha2, &set_current_param.alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + spin_lock_bh(&ab->base_lock); + memcpy(&ar->alpha2, &ab->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c for pdev %d\n", + ar->alpha2[0], ar->alpha2[1], i); + + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "pdev id %d failed set current country code: %d\n", diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 17b06c0cd062..84415187416d 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -8864,12 +8864,8 @@ ath11k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ieee80211_wake_queues(ar->hw); if (ar->ab->hw_params.current_cc_support && - ar->alpha2[0] != 0 && ar->alpha2[1] != 0) { - struct wmi_set_current_country_params set_current_param = {}; - - memcpy(&set_current_param.alpha2, ar->alpha2, 2); - ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); - } + ar->alpha2[0] != 0 && ar->alpha2[1] != 0) + ath11k_reg_set_cc(ar); if (ab->is_reset) { recovery_count = atomic_inc_return(&ab->recovery_count); @@ -10311,11 +10307,8 @@ static int __ath11k_mac_register(struct ath11k *ar) } if (ab->hw_params.current_cc_support && ab->new_alpha2[0]) { - struct wmi_set_current_country_params set_current_param = {}; - - memcpy(&set_current_param.alpha2, ab->new_alpha2, 2); memcpy(&ar->alpha2, ab->new_alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "failed set cc code for mac register: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 4c3aefbbabbe..b0f289784dd3 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -49,7 +49,6 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct wmi_init_country_params init_country_param; - struct wmi_set_current_country_params set_current_param = {}; struct ath11k *ar = hw->priv; int ret; @@ -83,9 +82,8 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) * reg info */ if (ar->ab->hw_params.current_cc_support) { - memcpy(&set_current_param.alpha2, request->alpha2, 2); - memcpy(&ar->alpha2, &set_current_param.alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + memcpy(&ar->alpha2, request->alpha2, 2); + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "failed set current country code: %d\n", ret); @@ -1017,3 +1015,11 @@ void ath11k_reg_free(struct ath11k_base *ab) kfree(ab->new_regd[i]); } } + +int ath11k_reg_set_cc(struct ath11k *ar) +{ + struct wmi_set_current_country_params set_current_param = {}; + + memcpy(&set_current_param.alpha2, ar->alpha2, 2); + return ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); +} diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index 64edb794260a..263ea9061948 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_REG_H @@ -45,5 +45,5 @@ ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); int ath11k_reg_handle_chan_list(struct ath11k_base *ab, struct cur_regulatory_info *reg_info, enum ieee80211_ap_reg_power power_type); - +int ath11k_reg_set_cc(struct ath11k *ar); #endif From 7f0343b7b8710436c1e6355c71782d32ada47e0c Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 21 May 2024 11:08:11 +0300 Subject: [PATCH 57/69] wifi: ath11k: restore country code during resume We got report that regdomain is not correct after return from hibernation: Before hibernation: % iw reg get [...] phy#0 (self-managed) country CH: DFS-ETSI (2402 - 2482 @ 40), (N/A, 20), (N/A) (5170 - 5250 @ 80), (N/A, 23), (N/A), NO-OUTDOOR, AUTO-BW (5250 - 5330 @ 80), (N/A, 23), (0 ms), NO-OUTDOOR, DFS, AUTO-BW (5490 - 5590 @ 80), (N/A, 30), (0 ms), DFS, AUTO-BW (5590 - 5650 @ 40), (N/A, 30), (600000 ms), DFS, AUTO-BW (5650 - 5730 @ 80), (N/A, 30), (0 ms), DFS, AUTO-BW (5735 - 5875 @ 80), (N/A, 14), (N/A), AUTO-BW After hibernation: % iw reg get [...] phy#0 (self-managed) country na: DFS-UNSET (2402 - 2472 @ 40), (N/A, 20), (N/A) (2457 - 2482 @ 20), (N/A, 20), (N/A), PASSIVE-SCAN (5170 - 5330 @ 160), (N/A, 20), (N/A), AUTO-BW, PASSIVE-SCAN (5490 - 5730 @ 160), (N/A, 20), (N/A), AUTO-BW, PASSIVE-SCAN (5735 - 5895 @ 160), (N/A, 20), (N/A), AUTO-BW, PASSIVE-SCAN (5945 - 7125 @ 160), (N/A, 30), (N/A), AUTO-BW, PASSIVE-SCAN The reason is, during resume, firmware is reinitialized but host does not send current country code to firmware. So default reg rules with country code set to 'na' is uploaded to host, as shown above. Fix it by restoring country code to firmware during resume. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30 Fixes: 166a490f59ac ("wifi: ath11k: support hibernation") Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://msgid.link/20240520024148.5472-3-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 748e3ad2bec3..3772e64d4976 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -1009,6 +1009,16 @@ int ath11k_core_resume(struct ath11k_base *ab) return -ETIMEDOUT; } + if (ab->hw_params.current_cc_support && + ar->alpha2[0] != 0 && ar->alpha2[1] != 0) { + ret = ath11k_reg_set_cc(ar); + if (ret) { + ath11k_warn(ab, "failed to set country code during resume: %d\n", + ret); + return ret; + } + } + ret = ath11k_dp_rx_pktlog_start(ab); if (ret) ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n", From 33322e3ef07409278a18c6919c448e369d66a18e Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Mon, 20 May 2024 12:30:43 +0530 Subject: [PATCH 58/69] wifi: ath12k: change DMA direction while mapping reinjected packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For fragmented packets, ath12k reassembles each fragment as a normal packet and then reinjects it into HW ring. In this case, the DMA direction should be DMA_TO_DEVICE, not DMA_FROM_DEVICE. Otherwise, an invalid payload may be reinjected into the HW and subsequently delivered to the host. Given that arbitrary memory can be allocated to the skb buffer, knowledge about the data contained in the reinjected buffer is lacking. Consequently, there’s a risk of private information being leaked. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00209-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Co-developed-by: Baochen Qiang Signed-off-by: Baochen Qiang Signed-off-by: P Praneesh Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240520070045.631029-2-quic_ppranees@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 000df6edf6b4..ffd3f003d003 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -3008,7 +3008,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, buf_paddr = dma_map_single(ab->dev, defrag_skb->data, defrag_skb->len + skb_tailroom(defrag_skb), - DMA_FROM_DEVICE); + DMA_TO_DEVICE); if (dma_mapping_error(ab->dev, buf_paddr)) return -ENOMEM; @@ -3094,7 +3094,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, spin_unlock_bh(&dp->rx_desc_lock); err_unmap_dma: dma_unmap_single(ab->dev, buf_paddr, defrag_skb->len + skb_tailroom(defrag_skb), - DMA_FROM_DEVICE); + DMA_TO_DEVICE); return ret; } From 073f9f249eecd64ab9d59c91c4a23cfdcc02afe4 Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Mon, 20 May 2024 12:30:44 +0530 Subject: [PATCH 59/69] wifi: ath12k: fix invalid memory access while processing fragmented packets The monitor ring and the reo reinject ring share the same ring mask index. When the driver receives an interrupt for the reo reinject ring, the monitor ring is also processed, leading to invalid memory access. Since monitor support is not yet enabled in ath12k, the ring mask for the monitor ring should be removed. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00209-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: P Praneesh Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240520070045.631029-3-quic_ppranees@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index b45f929a0204..2e11ea763574 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -544,9 +544,6 @@ static const struct ath12k_hw_ring_mask ath12k_hw_ring_mask_qcn9274 = { }, .rx_mon_dest = { 0, 0, 0, - ATH12K_RX_MON_RING_MASK_0, - ATH12K_RX_MON_RING_MASK_1, - ATH12K_RX_MON_RING_MASK_2, }, .rx = { 0, 0, 0, 0, @@ -572,8 +569,7 @@ static const struct ath12k_hw_ring_mask ath12k_hw_ring_mask_qcn9274 = { ATH12K_HOST2RXDMA_RING_MASK_0, }, .tx_mon_dest = { - ATH12K_TX_MON_RING_MASK_0, - ATH12K_TX_MON_RING_MASK_1, + 0, 0, 0, }, }; From a57ab7cced454f69b8ee8aa5f5019ea8de4674da Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Mon, 20 May 2024 12:30:45 +0530 Subject: [PATCH 60/69] wifi: ath12k: fix firmware crash during reo reinject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When handling fragmented packets, the ath12k driver reassembles each fragment into a normal packet and then reinjects it into the HW ring. However, a firmware crash occurs during this reinjection process. The issue arises because the driver populates peer metadata in reo_ent_ring->queue_addr_lo, while the firmware expects the physical address obtained from the corresponding peer’s queue descriptor. Fix it by filling peer's queue descriptor's physical address in queue_addr_lo. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.1.1-00209-QCAHKSWPL_SILICONZ-1 Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: P Praneesh Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240520070045.631029-4-quic_ppranees@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index ffd3f003d003..a52b7b273540 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2971,7 +2971,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, struct hal_srng *srng; dma_addr_t link_paddr, buf_paddr; u32 desc_bank, msdu_info, msdu_ext_info, mpdu_info; - u32 cookie, hal_rx_desc_sz, dest_ring_info0; + u32 cookie, hal_rx_desc_sz, dest_ring_info0, queue_addr_hi; int ret; struct ath12k_rx_desc_info *desc_info; enum hal_rx_buf_return_buf_manager idle_link_rbm = dp->idle_link_rbm; @@ -3064,13 +3064,11 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, reo_ent_ring->rx_mpdu_info.peer_meta_data = reo_dest_ring->rx_mpdu_info.peer_meta_data; - /* Firmware expects physical address to be filled in queue_addr_lo in - * the MLO scenario and in case of non MLO peer meta data needs to be - * filled. - * TODO: Need to handle for MLO scenario. - */ - reo_ent_ring->queue_addr_lo = reo_dest_ring->rx_mpdu_info.peer_meta_data; - reo_ent_ring->info0 = le32_encode_bits(dst_ind, + reo_ent_ring->queue_addr_lo = cpu_to_le32(lower_32_bits(rx_tid->paddr)); + queue_addr_hi = upper_32_bits(rx_tid->paddr); + reo_ent_ring->info0 = le32_encode_bits(queue_addr_hi, + HAL_REO_ENTR_RING_INFO0_QUEUE_ADDR_HI) | + le32_encode_bits(dst_ind, HAL_REO_ENTR_RING_INFO0_DEST_IND); reo_ent_ring->info1 = le32_encode_bits(rx_tid->cur_sn, From af69d862a8baa600b018f66aca8174b23c166a5f Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Thu, 23 May 2024 08:18:05 -0700 Subject: [PATCH 61/69] wifi: ath12k: Fix devmem address prefix when logging Currently when ath12k QMI logging is enabled, messages such as the following can be logged: ath12k_pci 0000:03:00.0: devmem [0] start ox113000 size 20480 Replace ox% with 0x% to get a proper hex address prefix: ath12k_pci 0000:03:00.0: devmem [0] start 0x113000 size 20480 Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240523-ox-v1-1-112ae7350059@quicinc.com --- drivers/net/wireless/ath/ath12k/qmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index f273cb93dedb..b93ce9f87f61 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -2503,7 +2503,7 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab) ab->qmi.dev_mem[i].size = resp.dev_mem[i].size; ath12k_dbg(ab, ATH12K_DBG_QMI, - "devmem [%d] start ox%llx size %llu\n", i, + "devmem [%d] start 0x%llx size %llu\n", i, ab->qmi.dev_mem[i].start, ab->qmi.dev_mem[i].size); } From 5714e25f1d1875b300fb337dadfaa75324c1161a Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 24 May 2024 10:15:58 +0800 Subject: [PATCH 62/69] wifi: ath11k: fix wrong definition of CE ring's base address Base address of CE ring is defined as u32, currently this works because coherent DMA mask configured as 32 bit: #define ATH11K_PCI_COHERENT_DMA_MASK 32 However this mask could be changed once firmware bugs are fixed to fully support 36 bit DMA addressing. So to protect against any future changes to the DMA mask, change the type of the fields that are dependent upon it. This is found during code review. Compile tested only. Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240524021558.34452-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath11k/ce.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index 69946fc70077..bcde2fcf02cf 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_CE_H @@ -146,7 +146,7 @@ struct ath11k_ce_ring { /* Host address space */ void *base_addr_owner_space_unaligned; /* CE address space */ - u32 base_addr_ce_space_unaligned; + dma_addr_t base_addr_ce_space_unaligned; /* Actual start of descriptors. * Aligned to descriptor-size boundary. @@ -156,7 +156,7 @@ struct ath11k_ce_ring { void *base_addr_owner_space; /* CE address space */ - u32 base_addr_ce_space; + dma_addr_t base_addr_ce_space; /* HAL ring id */ u32 hal_ring_id; From 0a993772e0f0934d730c0d451622c80e03a40ab1 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 24 May 2024 10:36:42 +0800 Subject: [PATCH 63/69] wifi: ath12k: fix race due to setting ATH12K_FLAG_EXT_IRQ_ENABLED too early Commit 5082b3e3027e ("wifi: ath11k: fix race due to setting ATH11K_FLAG_EXT_IRQ_ENABLED too early") fixes a race in ath11k driver. Since ath12k shares the same logic as ath11k, currently the race also exists in ath12k: in ath12k_pci_ext_irq_enable(), ATH12K_FLAG_EXT_IRQ_ENABLED is set before NAPI is enabled. In cases where only one MSI vector is allocated, this results in a race condition: after ATH12K_FLAG_EXT_IRQ_ENABLED is set but before NAPI enabled, CE interrupt breaks in. Since IRQ is shared by CE and data path, ath12k_pci_ext_interrupt_handler() is also called where we call disable_irq_nosync() to disable IRQ. Then napi_schedule() is called but it does nothing because NAPI is not enabled at that time, meaning that ath12k_pci_ext_grp_napi_poll() will never run, so we have no chance to call enable_irq() to enable IRQ back. Since IRQ is shared, all interrupts are disabled and we would finally get no response from target. So port ath11k fix here, this is done by setting ATH12K_FLAG_EXT_IRQ_ENABLED after all NAPI and IRQ work are done. With the fix, we are sure that by the time ATH12K_FLAG_EXT_IRQ_ENABLED is set, NAPI is enabled. Note that the fix above also introduce some side effects: if ath12k_pci_ext_interrupt_handler() breaks in after NAPI enabled but before ATH12K_FLAG_EXT_IRQ_ENABLED set, nothing will be done by the handler this time, the work will be postponed till the next time the IRQ fires. This is found during code review. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240524023642.37030-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index ac75e8e3916b..11b95d037051 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1107,14 +1107,14 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab) { int i; - set_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); - for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; napi_enable(&irq_grp->napi); ath12k_pci_ext_grp_enable(irq_grp); } + + set_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); } void ath12k_pci_ext_irq_disable(struct ath12k_base *ab) From 0ae570703754858a77cc42b3c9fff42e9f084608 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Fri, 24 May 2024 10:40:21 +0800 Subject: [PATCH 64/69] wifi: ath12k: fix wrong definition of CE ring's base address Base address of CE ring is defined as u32, currently this works because DMA mask configured as 32 bit: #define ATH12K_PCI_DMA_MASK 32 However this mask could be changed once firmware bugs are fixed to fully support 36 bit DMA addressing. So to protect against any future changes to the DMA mask, change the type of the fields that are dependent upon it. This is found during code review. Compile tested only. Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240524024021.37711-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/ce.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h index 79af3b6159f1..857bc5f9e946 100644 --- a/drivers/net/wireless/ath/ath12k/ce.h +++ b/drivers/net/wireless/ath/ath12k/ce.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_CE_H @@ -119,7 +119,7 @@ struct ath12k_ce_ring { /* Host address space */ void *base_addr_owner_space_unaligned; /* CE address space */ - u32 base_addr_ce_space_unaligned; + dma_addr_t base_addr_ce_space_unaligned; /* Actual start of descriptors. * Aligned to descriptor-size boundary. @@ -129,7 +129,7 @@ struct ath12k_ce_ring { void *base_addr_owner_space; /* CE address space */ - u32 base_addr_ce_space; + dma_addr_t base_addr_ce_space; /* HAL ring id */ u32 hal_ring_id; From 3d60041543189438cd1b03a1fa40ff6681c77970 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Sun, 26 May 2024 20:42:26 +0800 Subject: [PATCH 65/69] wifi: ath12k: fix memory leak in ath12k_dp_rx_peer_frag_setup() Currently the resource allocated by crypto_alloc_shash() is not freed in case ath12k_peer_find() fails, resulting in memory leak. Add crypto_free_shash() to fix it. This is found during code review, compile tested only. Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240526124226.24661-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index a52b7b273540..cb1f308f096b 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -2742,6 +2742,7 @@ int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev peer = ath12k_peer_find(ab, vdev_id, peer_mac); if (!peer) { spin_unlock_bh(&ab->base_lock); + crypto_free_shash(tfm); ath12k_warn(ab, "failed to find the peer to set up fragment info\n"); return -ENOENT; } From 43e934360d1d8fd3230d0c1ffa40f0d49deb4cf2 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 28 May 2024 08:46:09 -0500 Subject: [PATCH 66/69] dt-bindings: net: wireless: ath11k: Drop "qcom,ipq8074-wcss-pil" from example Convention for examples is to only show what's covered by the binding, so drop the provider "qcom,ipq8074-wcss-pil". It is also not documented by a schema which caused a warning. Signed-off-by: Rob Herring (Arm) Reviewed-by: Krzysztof Kozlowski Signed-off-by: Kalle Valo Link: https://msgid.link/20240528134610.4075204-1-robh@kernel.org --- .../devicetree/bindings/net/wireless/qcom,ath11k.yaml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml index a2d55bf4c7a5..ff5763dc66a8 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml @@ -265,15 +265,6 @@ allOf: examples: - | - - q6v5_wcss: remoteproc@cd00000 { - compatible = "qcom,ipq8074-wcss-pil"; - reg = <0xcd00000 0x4040>, - <0x4ab000 0x20>; - reg-names = "qdsp6", - "rmb"; - }; - wifi0: wifi@c000000 { compatible = "qcom,ipq8074-wifi"; reg = <0xc000000 0x2000000>; From 8233d2716570b66ab45b6d24e577ee6612002dc4 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Wed, 29 May 2024 09:53:57 +0800 Subject: [PATCH 67/69] wifi: ath12k: do not process consecutive RDDM event Currently we do reset for each RDDM event from MHI, however there are cases, see below log, that we get two or more consecutive events, and it is pointless to do reset for the subsequent ones. What's more, it makes reset process more likely to fail. [ 103.289864] mhi mhi0: System error detected [ 103.289871] ath12k_pci 0000:03:00.0: mhi notify status reason MHI_CB_EE_RDDM [ 103.293144] mhi mhi0: System error detected [ 103.293150] ath12k_pci 0000:03:00.0: mhi notify status reason MHI_CB_EE_RDDM Add a check to avoid reset again and again. This is done by tracking previous MHI status: if we receive a new RDDM event while the previous event is also the same, we treat it as duplicate and ignore it, because normally we should at least receive a MHI_CB_EE_MISSION_MODE event between them. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240529015357.9846-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/mhi.c | 11 +++++++++++ drivers/net/wireless/ath/ath12k/pci.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index fef2f7622033..df96b0f91f54 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -16,6 +16,7 @@ #define MHI_TIMEOUT_DEFAULT_MS 90000 #define OTP_INVALID_BOARD_ID 0xFFFF #define OTP_VALID_DUALMAC_BOARD_ID_MASK 0x1000 +#define MHI_CB_INVALID 0xff static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = { { @@ -268,6 +269,7 @@ static void ath12k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, enum mhi_callback cb) { struct ath12k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev); + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); ath12k_dbg(ab, ATH12K_DBG_BOOT, "mhi notify status reason %s\n", ath12k_mhi_op_callback_to_str(cb)); @@ -277,12 +279,20 @@ static void ath12k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, ath12k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n"); break; case MHI_CB_EE_RDDM: + if (ab_pci->mhi_pre_cb == MHI_CB_EE_RDDM) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "do not queue again for consecutive RDDM event\n"); + break; + } + if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags))) queue_work(ab->workqueue_aux, &ab->reset_work); break; default: break; } + + ab_pci->mhi_pre_cb = cb; } static int ath12k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, @@ -313,6 +323,7 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) if (!mhi_ctrl) return -ENOMEM; + ab_pci->mhi_pre_cb = MHI_CB_INVALID; ab_pci->mhi_ctrl = mhi_ctrl; mhi_ctrl->cntrl_dev = ab->dev; mhi_ctrl->regs = ab->mem; diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index 6186a78038cf..31584a7ad80e 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -104,6 +104,7 @@ struct ath12k_pci { struct mhi_controller *mhi_ctrl; const struct ath12k_msi_config *msi_config; unsigned long mhi_state; + enum mhi_callback mhi_pre_cb; u32 register_window; /* protects register_window above */ From 809055628bce824b7fe18331abb65e44d02b0ecf Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 30 May 2024 18:56:52 +0300 Subject: [PATCH 68/69] wifi: ath12k: add panic handler Currently for ath12k PCI devices, firmware could be running in one of several execution environments, e.g., PBL, SBL and mission mode etc. Among which PBL is the only stage where PCIe link negotiation could happen. So normally firmware runs in PBL in order to be enumerated during system reboot. However it might not work in kernel crash scenario: ath12k target is not found after warm reboot from kernel crash. This is because when kernel crashes, ath12k host does nothing to firmware. And during warm reboot, WLAN power is sustained. So firmware is likely to keep running in mission mode throughout the bootup process. As a result PCIe link is not established and thus target not enumerated. So add a handler in panic notification list for ath12k. When kernel crashes, this handler gets called and tries to reset target to PBL state. Then PCIe link negotiation could happen and target gets enumerated. This change applies to all PCI devices including WCN7850 and QCN9274. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240529021533.10861-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 29 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath12k/core.h | 3 +++ drivers/net/wireless/ath/ath12k/hif.h | 9 ++++++++ drivers/net/wireless/ath/ath12k/pci.c | 8 +++++++ 4 files changed, 49 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index e7f628e935e4..4c3eab4686c2 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1188,6 +1188,29 @@ int ath12k_core_pre_init(struct ath12k_base *ab) return 0; } +static int ath12k_core_panic_handler(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct ath12k_base *ab = container_of(nb, struct ath12k_base, + panic_nb); + + return ath12k_hif_panic_handler(ab); +} + +static int ath12k_core_panic_notifier_register(struct ath12k_base *ab) +{ + ab->panic_nb.notifier_call = ath12k_core_panic_handler; + + return atomic_notifier_chain_register(&panic_notifier_list, + &ab->panic_nb); +} + +static void ath12k_core_panic_notifier_unregister(struct ath12k_base *ab) +{ + atomic_notifier_chain_unregister(&panic_notifier_list, + &ab->panic_nb); +} + int ath12k_core_init(struct ath12k_base *ab) { int ret; @@ -1198,11 +1221,17 @@ int ath12k_core_init(struct ath12k_base *ab) return ret; } + ret = ath12k_core_panic_notifier_register(ab); + if (ret) + ath12k_warn(ab, "failed to register panic handler: %d\n", ret); + return 0; } void ath12k_core_deinit(struct ath12k_base *ab) { + ath12k_core_panic_notifier_unregister(ab); + mutex_lock(&ab->core_lock); ath12k_core_pdev_destroy(ab); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 7d20b09c52e6..44ca30b67fa2 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "qmi.h" #include "htc.h" #include "wmi.h" @@ -924,6 +925,8 @@ struct ath12k_base { #endif /* CONFIG_ACPI */ + struct notifier_block panic_nb; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h index 7f0926fe751d..0e53ec269fa4 100644 --- a/drivers/net/wireless/ath/ath12k/hif.h +++ b/drivers/net/wireless/ath/ath12k/hif.h @@ -30,6 +30,7 @@ struct ath12k_hif_ops { void (*ce_irq_enable)(struct ath12k_base *ab); void (*ce_irq_disable)(struct ath12k_base *ab); void (*get_ce_msi_idx)(struct ath12k_base *ab, u32 ce_id, u32 *msi_idx); + int (*panic_handler)(struct ath12k_base *ab); }; static inline int ath12k_hif_map_service_to_pipe(struct ath12k_base *ab, u16 service_id, @@ -147,4 +148,12 @@ static inline void ath12k_hif_power_down(struct ath12k_base *ab, bool is_suspend ab->hif.ops->power_down(ab, is_suspend); } +static inline int ath12k_hif_panic_handler(struct ath12k_base *ab) +{ + if (!ab->hif.ops->panic_handler) + return NOTIFY_DONE; + + return ab->hif.ops->panic_handler(ab); +} + #endif /* ATH12K_HIF_H */ diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 11b95d037051..876c029f58f6 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1302,6 +1302,13 @@ void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend) ath12k_pci_sw_reset(ab_pci->ab, false); } +static int ath12k_pci_panic_handler(struct ath12k_base *ab) +{ + ath12k_pci_sw_reset(ab, false); + + return NOTIFY_OK; +} + static const struct ath12k_hif_ops ath12k_pci_hif_ops = { .start = ath12k_pci_start, .stop = ath12k_pci_stop, @@ -1319,6 +1326,7 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = { .ce_irq_enable = ath12k_pci_hif_ce_irq_enable, .ce_irq_disable = ath12k_pci_hif_ce_irq_disable, .get_ce_msi_idx = ath12k_pci_get_ce_msi_idx, + .panic_handler = ath12k_pci_panic_handler, }; static From 22767241e64427bbcffea2e2d51531ab467bc4ef Mon Sep 17 00:00:00 2001 From: Karthikeyan Periyasamy Date: Thu, 30 May 2024 18:56:52 +0300 Subject: [PATCH 69/69] wifi: ath12k: add hw_link_id in ath12k_pdev Currently, hw_link_id is sent in WMI service ready event but it is not parsed anywhere. But, in future, for multi-link operation, this parameter would be needed by many WMI commands such as WMI beacon template (WMI_BCN_TMPL_CMDID), WMI vdev start for Multi-link virtual AP interfaces (WMI_VDEV_START_REQUEST_CMDID), WMI peer assoc command (WMI_PEER_ASSOC_CMDID) for Multi-link peer and so on. Hence, add changes to parse and store the hw_link_id received in WMI service ready event in ath12k_pdev structure. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy Signed-off-by: Harshitha Prem Acked-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://msgid.link/20240529054955.4105240-1-quic_hprem@quicinc.com --- drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/mac.c | 2 +- drivers/net/wireless/ath/ath12k/wmi.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 44ca30b67fa2..d03326a68a9f 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -690,6 +690,7 @@ struct mlo_timestamp { struct ath12k_pdev { struct ath12k *ar; u32 pdev_id; + u32 hw_link_id; struct ath12k_pdev_cap cap; u8 mac_addr[ETH_ALEN]; struct mlo_timestamp timestamp; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 784964ae03ec..509c02bffdae 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9229,7 +9229,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab, ar = ath12k_ah_to_ar(ah, i); ar->ah = ah; ar->ab = ab; - ar->hw_link_id = i; + ar->hw_link_id = pdev->hw_link_id; ar->pdev = pdev; ar->pdev_idx = pdev_idx; pdev->ar = ar; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 99106b088311..d6e1d1398cdb 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -500,6 +500,7 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, mac_caps = wmi_mac_phy_caps + phy_idx; pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); + pdev->hw_link_id = ath12k_wmi_mac_phy_get_hw_link_id(mac_caps); pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density);