diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath11k/mac.c')
-rw-r--r-- | drivers/net/wireless/ath/ath11k/mac.c | 213 |
1 files changed, 210 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 2bc93456b34e..07f499d5ec92 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -246,6 +246,93 @@ static const u32 ath11k_smps_map[] = { static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +enum nl80211_he_ru_alloc ath11k_mac_phy_he_ru_to_nl80211_he_ru_alloc(u16 ru_phy) +{ + enum nl80211_he_ru_alloc ret; + + switch (ru_phy) { + case RU_26: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; + break; + case RU_52: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_52; + break; + case RU_106: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_106; + break; + case RU_242: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_242; + break; + case RU_484: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_484; + break; + case RU_996: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + default: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; + break; + } + + return ret; +} + +enum nl80211_he_ru_alloc ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones) +{ + enum nl80211_he_ru_alloc ret; + + switch (ru_tones) { + case 26: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; + break; + case 52: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_52; + break; + case 106: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_106; + break; + case 242: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_242; + break; + case 484: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_484; + break; + case 996: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_996; + break; + case (996 * 2): + ret = NL80211_RATE_INFO_HE_RU_ALLOC_2x996; + break; + default: + ret = NL80211_RATE_INFO_HE_RU_ALLOC_26; + break; + } + + return ret; +} + +enum nl80211_he_gi ath11k_mac_he_gi_to_nl80211_he_gi(u8 sgi) +{ + enum nl80211_he_gi ret; + + switch (sgi) { + case RX_MSDU_START_SGI_0_8_US: + ret = NL80211_RATE_INFO_HE_GI_0_8; + break; + case RX_MSDU_START_SGI_1_6_US: + ret = NL80211_RATE_INFO_HE_GI_1_6; + break; + case RX_MSDU_START_SGI_3_2_US: + ret = NL80211_RATE_INFO_HE_GI_3_2; + break; + default: + ret = NL80211_RATE_INFO_HE_GI_0_8; + break; + } + + return ret; +} + u8 ath11k_mac_bw_to_mac80211_bw(u8 bw) { u8 ret = 0; @@ -2541,8 +2628,12 @@ static void ath11k_peer_assoc_prepare(struct ath11k *ar, struct peer_assoc_params *arg, bool reassoc) { + struct ath11k_sta *arsta; + lockdep_assert_held(&ar->conf_mutex); + arsta = (struct ath11k_sta *)sta->drv_priv; + memset(arg, 0, sizeof(*arg)); reinit_completion(&ar->peer_assoc_done); @@ -2559,6 +2650,8 @@ static void ath11k_peer_assoc_prepare(struct ath11k *ar, ath11k_peer_assoc_h_qos(ar, vif, sta, arg); ath11k_peer_assoc_h_smps(sta, arg); + arsta->peer_nss = arg->peer_nss; + /* TODO: amsdu_disable req? */ } @@ -5478,6 +5571,63 @@ static int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb, return 0; } +int ath11k_mac_rfkill_config(struct ath11k *ar) +{ + struct ath11k_base *ab = ar->ab; + u32 param; + int ret; + + if (ab->hw_params.rfkill_pin == 0) + return -EOPNOTSUPP; + + ath11k_dbg(ab, ATH11K_DBG_MAC, + "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d", + ab->hw_params.rfkill_pin, ab->hw_params.rfkill_cfg, + ab->hw_params.rfkill_on_level); + + param = FIELD_PREP(WMI_RFKILL_CFG_RADIO_LEVEL, + ab->hw_params.rfkill_on_level) | + FIELD_PREP(WMI_RFKILL_CFG_GPIO_PIN_NUM, + ab->hw_params.rfkill_pin) | + FIELD_PREP(WMI_RFKILL_CFG_PIN_AS_GPIO, + ab->hw_params.rfkill_cfg); + + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_HW_RFKILL_CONFIG, + param, ar->pdev->pdev_id); + if (ret) { + ath11k_warn(ab, + "failed to set rfkill config 0x%x: %d\n", + param, ret); + return ret; + } + + return 0; +} + +int ath11k_mac_rfkill_enable_radio(struct ath11k *ar, bool enable) +{ + enum wmi_rfkill_enable_radio param; + int ret; + + if (enable) + param = WMI_RFKILL_ENABLE_RADIO_ON; + else + param = WMI_RFKILL_ENABLE_RADIO_OFF; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac %d rfkill enable %d", + ar->pdev_idx, param); + + ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RFKILL_ENABLE, + param, ar->pdev->pdev_id); + if (ret) { + ath11k_warn(ar->ab, "failed to set rfkill enable param %d: %d\n", + param, ret); + return ret; + } + + return 0; +} + static void ath11k_mac_op_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -5710,6 +5860,7 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw) cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); cancel_work_sync(&ar->ab->update_11d_work); + cancel_work_sync(&ar->ab->rfkill_work); spin_lock_bh(&ar->data_lock); list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { @@ -7775,12 +7926,45 @@ exit: return ret; } +static void ath11k_mac_put_chain_rssi(struct station_info *sinfo, + struct ath11k_sta *arsta, + char *pre, + bool clear) +{ + struct ath11k *ar = arsta->arvif->ar; + int i; + s8 rssi; + + for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { + sinfo->chains &= ~BIT(i); + rssi = arsta->chain_signal[i]; + if (clear) + arsta->chain_signal[i] = ATH11K_INVALID_RSSI_FULL; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac sta statistics %s rssi[%d] %d\n", pre, i, rssi); + + if (rssi != ATH11K_DEFAULT_NOISE_FLOOR && + rssi != ATH11K_INVALID_RSSI_FULL && + rssi != ATH11K_INVALID_RSSI_EMPTY && + rssi != 0) { + sinfo->chain_signal[i] = rssi; + sinfo->chains |= BIT(i); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL); + } + } +} + static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct station_info *sinfo) { struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; + struct ath11k *ar = arsta->arvif->ar; + s8 signal; + bool db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, + ar->ab->wmi_ab.svc_map); sinfo->rx_duration = arsta->rx_duration; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); @@ -7803,9 +7987,32 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } - /* TODO: Use real NF instead of default one. */ - sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); + ath11k_mac_put_chain_rssi(sinfo, arsta, "ppdu", false); + + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && + arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA && + ar->ab->hw_params.supports_rssi_stats && + !ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0, + WMI_REQUEST_RSSI_PER_CHAIN_STAT)) { + ath11k_mac_put_chain_rssi(sinfo, arsta, "fw stats", true); + } + + signal = arsta->rssi_comb; + if (!signal && + arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA && + ar->ab->hw_params.supports_rssi_stats && + !(ath11k_debugfs_get_fw_stats(ar, ar->pdev->pdev_id, 0, + WMI_REQUEST_VDEV_STAT))) + signal = arsta->rssi_beacon; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "mac sta statistics db2dbm %u rssi comb %d rssi beacon %d\n", + db2dbm, arsta->rssi_comb, arsta->rssi_beacon); + + if (signal) { + sinfo->signal = db2dbm ? signal : signal + ATH11K_DEFAULT_NOISE_FLOOR; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); + } } static const struct ieee80211_ops ath11k_ops = { |