diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath11k/mac.c')
-rw-r--r-- | drivers/net/wireless/ath/ath11k/mac.c | 123 |
1 files changed, 113 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 6640662f5ede..9f8bc19cc5ae 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -178,6 +178,22 @@ u8 ath11k_mac_bw_to_mac80211_bw(u8 bw) return ret; } +enum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw bw) +{ + switch (bw) { + case RATE_INFO_BW_20: + return ATH11K_BW_20; + case RATE_INFO_BW_40: + return ATH11K_BW_40; + case RATE_INFO_BW_80: + return ATH11K_BW_80; + case RATE_INFO_BW_160: + return ATH11K_BW_160; + default: + return ATH11K_BW_20; + } +} + int ath11k_mac_hw_ratecode_to_legacy_rate(u8 hw_rc, u8 preamble, u8 *rateidx, u16 *rate) { @@ -369,8 +385,10 @@ struct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id) flags, ath11k_get_arvif_iter, &arvif_iter); - if (!arvif_iter.arvif) + if (!arvif_iter.arvif) { + ath11k_warn(ar->ab, "No VIF found for vdev %d\n", vdev_id); return NULL; + } return arvif_iter.arvif; } @@ -398,14 +416,12 @@ struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id) { int i; struct ath11k_pdev *pdev; - struct ath11k_vif *arvif; for (i = 0; i < ab->num_radios; i++) { pdev = rcu_dereference(ab->pdevs_active[i]); if (pdev && pdev->ar) { - arvif = ath11k_mac_get_arvif(pdev->ar, vdev_id); - if (arvif) - return arvif->ar; + if (pdev->ar->allocated_vdev_map & (1LL << vdev_id)) + return pdev->ar; } } @@ -1940,6 +1956,31 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ath11k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id, &info->he_obss_pd); + if (changed & BSS_CHANGED_HE_BSS_COLOR) { + if (vif->type == NL80211_IFTYPE_AP) { + ret = ath11k_wmi_send_obss_color_collision_cfg_cmd( + ar, arvif->vdev_id, info->he_bss_color.color, + ATH11K_BSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS, + !info->he_bss_color.disabled); + if (ret) + ath11k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n", + arvif->vdev_id, ret); + } else if (vif->type == NL80211_IFTYPE_STATION) { + ret = ath11k_wmi_send_bss_color_change_enable_cmd(ar, + arvif->vdev_id, + 1); + if (ret) + ath11k_warn(ar->ab, "failed to enable bss color change on vdev %i: %d\n", + arvif->vdev_id, ret); + ret = ath11k_wmi_send_obss_color_collision_cfg_cmd( + ar, arvif->vdev_id, 0, + ATH11K_BSS_COLOR_COLLISION_DETECTION_STA_PERIOD_MS, 1); + if (ret) + ath11k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n", + arvif->vdev_id, ret); + } + } + mutex_unlock(&ar->conf_mutex); } @@ -2309,6 +2350,7 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_peer *peer; + struct ath11k_sta *arsta; const u8 *peer_addr; int ret = 0; u32 flags = 0; @@ -2366,15 +2408,53 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, goto exit; } + ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key); + if (ret) { + ath11k_warn(ab, "failed to offload PN replay detection %d\n", ret); + goto exit; + } + spin_lock_bh(&ab->base_lock); peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr); - if (peer && cmd == SET_KEY) + if (peer && cmd == SET_KEY) { peer->keys[key->keyidx] = key; - else if (peer && cmd == DISABLE_KEY) + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { + peer->ucast_keyidx = key->keyidx; + peer->sec_type = ath11k_dp_tx_get_encrypt_type(key->cipher); + } else { + peer->mcast_keyidx = key->keyidx; + peer->sec_type_grp = ath11k_dp_tx_get_encrypt_type(key->cipher); + } + } else if (peer && cmd == DISABLE_KEY) { peer->keys[key->keyidx] = NULL; - else if (!peer) + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + peer->ucast_keyidx = 0; + else + peer->mcast_keyidx = 0; + } else if (!peer) /* impossible unless FW goes crazy */ ath11k_warn(ab, "peer %pM disappeared!\n", peer_addr); + + if (sta) { + arsta = (struct ath11k_sta *)sta->drv_priv; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + if (cmd == SET_KEY) + arsta->pn_type = HAL_PN_TYPE_WPA; + else + arsta->pn_type = HAL_PN_TYPE_NONE; + break; + default: + arsta->pn_type = HAL_PN_TYPE_NONE; + break; + } + } + spin_unlock_bh(&ab->base_lock); exit: @@ -2786,6 +2866,7 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv; + struct ath11k_peer *peer; int ret = 0; /* cancel must be done outside the mutex to avoid deadlock */ @@ -2818,6 +2899,17 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, sta->addr, arvif->vdev_id); ath11k_mac_dec_num_stations(arvif, sta); + spin_lock_bh(&ar->ab->base_lock); + peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr); + if (peer && peer->sta == sta) { + ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n", + vif->addr, arvif->vdev_id); + peer->sta = NULL; + list_del(&peer->list); + kfree(peer); + ar->num_peers--; + } + spin_unlock_bh(&ar->ab->base_lock); kfree(arsta->tx_stats); arsta->tx_stats = NULL; @@ -3874,6 +3966,7 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw) ar->num_started_vdevs = 0; ar->num_created_vdevs = 0; ar->num_peers = 0; + ar->allocated_vdev_map = 0; /* Configure monitor status ring with default rx_filter to get rx status * such as rssi, rx_duration. @@ -3885,6 +3978,9 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw) goto err; } + /* Configure the hash seed for hash based reo dest ring selection */ + ath11k_wmi_pdev_lro_cfg(ar, ar->pdev->pdev_id); + mutex_unlock(&ar->conf_mutex); rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], @@ -4112,8 +4208,9 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, } ar->num_created_vdevs++; - + ar->allocated_vdev_map |= 1LL << arvif->vdev_id; ab->free_vdev_map &= ~(1LL << arvif->vdev_id); + spin_lock_bh(&ar->data_lock); list_add(&arvif->list, &ar->arvifs); spin_unlock_bh(&ar->data_lock); @@ -4227,6 +4324,7 @@ err_peer_del: err_vdev_del: ath11k_wmi_vdev_delete(ar, arvif->vdev_id); ar->num_created_vdevs--; + ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); ab->free_vdev_map |= 1LL << arvif->vdev_id; spin_lock_bh(&ar->data_lock); list_del(&arvif->list); @@ -4263,7 +4361,6 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", arvif->vdev_id); - ab->free_vdev_map |= 1LL << (arvif->vdev_id); spin_lock_bh(&ar->data_lock); list_del(&arvif->list); spin_unlock_bh(&ar->data_lock); @@ -4281,6 +4378,8 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); ar->num_created_vdevs--; + ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); + ab->free_vdev_map |= 1LL << (arvif->vdev_id); ath11k_peer_cleanup(ar, arvif->vdev_id); @@ -5699,6 +5798,7 @@ static int __ath11k_mac_register(struct ath11k *ar) ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER); ieee80211_hw_set(ar->hw, SUPPORTS_AMSDU_IN_AMPDU); + ieee80211_hw_set(ar->hw, USES_RSS); } ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; @@ -5730,6 +5830,7 @@ static int __ath11k_mac_register(struct ath11k *ar) ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; ar->hw->queues = ATH11K_HW_MAX_QUEUES; + ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN; ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1; ar->hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; @@ -5873,6 +5974,8 @@ int ath11k_mac_allocate(struct ath11k_base *ab) init_completion(&ar->bss_survey_done); init_completion(&ar->scan.started); init_completion(&ar->scan.completed); + init_completion(&ar->thermal.wmi_sync); + INIT_DELAYED_WORK(&ar->scan.timeout, ath11k_scan_timeout_work); INIT_WORK(&ar->regd_update_work, ath11k_regd_update_work); |