From: Johannes Berg Most of the time we just return cached statistics, that can be done unlocked. If querying the firmware is needed, return -EAGAIN to fall back to the locked version. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath12k/mac.c | 117 +++++++++++++++------ drivers/net/wireless/ath/ath12k/mac.h | 8 ++ drivers/net/wireless/ath/ath12k/wifi7/hw.c | 2 + 3 files changed, 94 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 196b807210de..c8af44c333cb 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -920,7 +920,8 @@ struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k_link_vif *arvif; - lockdep_assert_wiphy(hw->wiphy); + /* also used under RCU for station statistics */ + lockdep_assert(lockdep_is_held(&hw->wiphy->mtx) || rcu_read_lock_held()); /* If there is one pdev within ah, then we return * ar directly. @@ -931,7 +932,7 @@ struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, if (!(ahvif->links_map & BIT(link_id))) return NULL; - arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + arvif = rcu_dereference_wiphy(hw->wiphy, ahvif->link[link_id]); if (arvif && arvif->is_created) return arvif->ar; @@ -13737,10 +13738,11 @@ static void ath12k_mac_put_chain_rssi(struct station_info *sinfo, } } -void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct station_info *sinfo) +static int ath12k_mac_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo, + bool atomic) { struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); struct ath12k_dp_link_peer_rate_info rate_info = {}; @@ -13752,12 +13754,17 @@ void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ath12k *ar; bool db2dbm; - lockdep_assert_wiphy(hw->wiphy); + /* station interfaces query the firmware, which sleeps */ + if (atomic && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA) + return -EAGAIN; + + if (!atomic) + lockdep_assert_wiphy(hw->wiphy); arsta = &ahsta->deflink; ar = ath12k_get_ar_by_vif(hw, vif, arsta->link_id); if (!ar) - return; + return 0; dp = ath12k_ab_to_dp(ar->ab); ath12k_dp_link_peer_get_sta_rate_info_stats(dp, arsta->addr, &rate_info); @@ -13791,23 +13798,22 @@ void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, /* TODO: Use real NF instead of default one. */ signal = rate_info.rssi_comb; - params.pdev_id = ath12k_mac_get_target_pdev_id(ar); - params.vdev_id = 0; - params.stats_id = WMI_REQUEST_VDEV_STAT; + if (ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA) { + params.pdev_id = ath12k_mac_get_target_pdev_id(ar); + params.vdev_id = 0; + params.stats_id = WMI_REQUEST_VDEV_STAT; - if (!signal && - ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && - !(ath12k_mac_get_fw_stats(ar, ¶ms))) { - signal = arsta->rssi_beacon; - ath12k_fw_stats_reset(ar); - } + if (!signal && !ath12k_mac_get_fw_stats(ar, ¶ms)) { + signal = arsta->rssi_beacon; + ath12k_fw_stats_reset(ar); + } - params.stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; - if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && - ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && - !(ath12k_mac_get_fw_stats(ar, ¶ms))) { - ath12k_mac_put_chain_rssi(sinfo, arsta); - ath12k_fw_stats_reset(ar); + params.stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && + !ath12k_mac_get_fw_stats(ar, ¶ms)) { + ath12k_mac_put_chain_rssi(sinfo, arsta); + ath12k_fw_stats_reset(ar); + } } spin_lock_bh(&ar->data_lock); @@ -13830,7 +13836,7 @@ void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, peer = ath12k_dp_link_peer_find_by_addr(dp, arsta->addr); if (!peer) { spin_unlock_bh(&dp->dp_lock); - return; + return 0; } sinfo->tx_retries = peer->tx_retry_count; @@ -13839,13 +13845,32 @@ void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); spin_unlock_bh(&dp->dp_lock); + return 0; +} + +void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + ath12k_mac_sta_statistics(hw, vif, sta, sinfo, false); } EXPORT_SYMBOL(ath12k_mac_op_sta_statistics); -void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_link_sta *link_sta, - struct link_station_info *link_sinfo) +int ath12k_mac_op_sta_statistics_atomic(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + return ath12k_mac_sta_statistics(hw, vif, sta, sinfo, true); +} +EXPORT_SYMBOL(ath12k_mac_op_sta_statistics_atomic); + +static int ath12k_mac_link_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct link_station_info *link_sinfo, + bool atomic) { struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta); struct ath12k_fw_stats_req_params params = {}; @@ -13855,16 +13880,22 @@ void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, s8 signal; bool db2dbm; - lockdep_assert_wiphy(hw->wiphy); + /* station interfaces query the firmware, which sleeps */ + if (atomic && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA) + return -EAGAIN; - arsta = wiphy_dereference(hw->wiphy, ahsta->link[link_sta->link_id]); + if (!atomic) + lockdep_assert_wiphy(hw->wiphy); + + arsta = rcu_dereference_wiphy(hw->wiphy, + ahsta->link[link_sta->link_id]); if (!arsta) - return; + return 0; ar = ath12k_get_ar_by_vif(hw, vif, arsta->link_id); if (!ar) - return; + return 0; db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, ar->ab->wmi_ab.svc_map); @@ -13873,7 +13904,7 @@ void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, peer = ath12k_dp_link_peer_find_by_addr(ar->ab->dp, arsta->addr); if (!peer) { spin_unlock_bh(&ar->ab->dp->dp_lock); - return; + return 0; } link_sinfo->rx_duration = peer->rx_duration; @@ -13934,9 +13965,29 @@ void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, db2dbm ? signal : signal + ATH12K_DEFAULT_NOISE_FLOOR; link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } + + return 0; +} + +void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct link_station_info *link_sinfo) +{ + ath12k_mac_link_sta_statistics(hw, vif, link_sta, link_sinfo, false); } EXPORT_SYMBOL(ath12k_mac_op_link_sta_statistics); +int ath12k_mac_op_link_sta_statistics_atomic(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct link_station_info *link_sinfo) +{ + return ath12k_mac_link_sta_statistics(hw, vif, link_sta, link_sinfo, + true); +} +EXPORT_SYMBOL(ath12k_mac_op_link_sta_statistics_atomic); + int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index aba98afd4365..530672fd8da7 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -311,10 +311,18 @@ void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct station_info *sinfo); +int ath12k_mac_op_sta_statistics_atomic(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo); void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, struct link_station_info *link_sinfo); +int ath12k_mac_op_link_sta_statistics_atomic(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct link_station_info *link_sinfo); int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c index aec7c652808c..8a721afa05a3 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c @@ -1207,7 +1207,9 @@ static const struct ieee80211_ops ath12k_ops_wifi7 = { .get_survey = ath12k_mac_op_get_survey, .flush = ath12k_mac_op_flush, .sta_statistics = ath12k_mac_op_sta_statistics, + .sta_statistics_atomic = ath12k_mac_op_sta_statistics_atomic, .link_sta_statistics = ath12k_mac_op_link_sta_statistics, + .link_sta_statistics_atomic = ath12k_mac_op_link_sta_statistics_atomic, .remain_on_channel = ath12k_mac_op_remain_on_channel, .cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel, .change_sta_links = ath12k_mac_op_change_sta_links, -- 2.56.0