diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath11k/mac.c')
-rw-r--r-- | drivers/net/wireless/ath/ath11k/mac.c | 232 |
1 files changed, 162 insertions, 70 deletions
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 2d1e3fd9b526..9e923ecb0891 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -241,7 +241,10 @@ const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default = { #define ath11k_a_rates (ath11k_legacy_rates + 4) #define ath11k_a_rates_size (ARRAY_SIZE(ath11k_legacy_rates) - 4) -#define ATH11K_MAC_SCAN_TIMEOUT_MSECS 200 /* in msecs */ +#define ATH11K_MAC_SCAN_CMD_EVT_OVERHEAD 200 /* in msecs */ + +/* Overhead due to the processing of channel switch events from FW */ +#define ATH11K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD 10 /* in msecs */ static const u32 ath11k_smps_map[] = { [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC, @@ -3612,6 +3615,7 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, struct scan_req_params arg; int ret = 0; int i; + u32 scan_timeout; mutex_lock(&ar->conf_mutex); @@ -3681,6 +3685,26 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); } + /* if duration is set, default dwell times will be overwritten */ + if (req->duration) { + arg.dwell_time_active = req->duration; + arg.dwell_time_active_2g = req->duration; + arg.dwell_time_active_6g = req->duration; + arg.dwell_time_passive = req->duration; + arg.dwell_time_passive_6g = req->duration; + arg.burst_duration = req->duration; + + scan_timeout = min_t(u32, arg.max_rest_time * + (arg.num_chan - 1) + (req->duration + + ATH11K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) * + arg.num_chan, arg.max_scan_time); + } else { + scan_timeout = arg.max_scan_time; + } + + /* Add a margin to account for event/command processing */ + scan_timeout += ATH11K_MAC_SCAN_CMD_EVT_OVERHEAD; + ret = ath11k_start_scan(ar, &arg); if (ret) { ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret); @@ -3689,10 +3713,8 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); } - /* Add a 200ms margin to account for event/command processing */ ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, - msecs_to_jiffies(arg.max_scan_time + - ATH11K_MAC_SCAN_TIMEOUT_MSECS)); + msecs_to_jiffies(scan_timeout)); exit: kfree(arg.chan_list); @@ -4215,10 +4237,11 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; const u16 *he_mcs_mask; - u32 changed, bw, nss, smps; + u32 changed, bw, nss, smps, bw_prev; int err, num_vht_rates, num_he_rates; const struct cfg80211_bitrate_mask *mask; struct peer_assoc_params peer_arg; + enum wmi_phy_mode peer_phymode; arsta = container_of(wk, struct ath11k_sta, update_wk); sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); @@ -4239,6 +4262,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) arsta->changed = 0; bw = arsta->bw; + bw_prev = arsta->bw_prev; nss = arsta->nss; smps = arsta->smps; @@ -4252,26 +4276,57 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) ath11k_mac_max_he_nss(he_mcs_mask))); if (changed & IEEE80211_RC_BW_CHANGED) { - /* Send peer assoc command before set peer bandwidth param to - * avoid the mismatch between the peer phymode and the peer - * bandwidth. - */ - ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true); - - peer_arg.is_assoc = false; - err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg); - if (err) { - ath11k_warn(ar->ab, "failed to send peer assoc for STA %pM vdev %i: %d\n", - sta->addr, arvif->vdev_id, err); - } else if (wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) { + /* Get the peer phymode */ + ath11k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg); + peer_phymode = peer_arg.peer_phymode; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM peer bw %d phymode %d\n", + sta->addr, bw, peer_phymode); + + if (bw > bw_prev) { + /* BW is upgraded. In this case we send WMI_PEER_PHYMODE + * followed by WMI_PEER_CHWIDTH + */ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW upgrade for sta %pM new BW %d, old BW %d\n", + sta->addr, bw, bw_prev); + + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, + WMI_PEER_PHYMODE, peer_phymode); + + if (err) { + ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n", + sta->addr, peer_phymode, err); + goto err_rc_bw_changed; + } + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, WMI_PEER_CHWIDTH, bw); + if (err) ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", sta->addr, bw, err); } else { - ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n", - sta->addr, arvif->vdev_id); + /* BW is downgraded. In this case we send WMI_PEER_CHWIDTH + * followed by WMI_PEER_PHYMODE + */ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW downgrade for sta %pM new BW %d,old BW %d\n", + sta->addr, bw, bw_prev); + + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, + WMI_PEER_CHWIDTH, bw); + + if (err) { + ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n", + sta->addr, bw, err); + goto err_rc_bw_changed; + } + + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, + WMI_PEER_PHYMODE, peer_phymode); + + if (err) + ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n", + sta->addr, peer_phymode, err); } } @@ -4352,6 +4407,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) } } +err_rc_bw_changed: mutex_unlock(&ar->conf_mutex); } @@ -4505,6 +4561,34 @@ exit: return ret; } +static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar, + struct ieee80211_sta *sta) +{ + u32 bw = WMI_PEER_CHWIDTH_20MHZ; + + switch (sta->deflink.bandwidth) { + case IEEE80211_STA_RX_BW_20: + bw = WMI_PEER_CHWIDTH_20MHZ; + break; + case IEEE80211_STA_RX_BW_40: + bw = WMI_PEER_CHWIDTH_40MHZ; + break; + case IEEE80211_STA_RX_BW_80: + bw = WMI_PEER_CHWIDTH_80MHZ; + break; + case IEEE80211_STA_RX_BW_160: + bw = WMI_PEER_CHWIDTH_160MHZ; + break; + default: + ath11k_warn(ar->ab, "Invalid bandwidth %d for %pM\n", + sta->deflink.bandwidth, sta->addr); + bw = WMI_PEER_CHWIDTH_20MHZ; + break; + } + + return bw; +} + static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -4590,6 +4674,12 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, if (ret) ath11k_warn(ar->ab, "Failed to associate station: %pM\n", sta->addr); + + spin_lock_bh(&ar->data_lock); + /* Set arsta bw and prev bw */ + arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta); + arsta->bw_prev = arsta->bw; + spin_unlock_bh(&ar->data_lock); } else if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { spin_lock_bh(&ar->ab->base_lock); @@ -4713,28 +4803,8 @@ static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, spin_lock_bh(&ar->data_lock); if (changed & IEEE80211_RC_BW_CHANGED) { - bw = WMI_PEER_CHWIDTH_20MHZ; - - switch (sta->deflink.bandwidth) { - case IEEE80211_STA_RX_BW_20: - bw = WMI_PEER_CHWIDTH_20MHZ; - break; - case IEEE80211_STA_RX_BW_40: - bw = WMI_PEER_CHWIDTH_40MHZ; - break; - case IEEE80211_STA_RX_BW_80: - bw = WMI_PEER_CHWIDTH_80MHZ; - break; - case IEEE80211_STA_RX_BW_160: - bw = WMI_PEER_CHWIDTH_160MHZ; - break; - default: - ath11k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n", - sta->deflink.bandwidth, sta->addr); - bw = WMI_PEER_CHWIDTH_20MHZ; - break; - } - + bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta); + arsta->bw_prev = arsta->bw; arsta->bw = bw; } @@ -6163,6 +6233,40 @@ void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab) } } +static int ath11k_mac_vdev_delete(struct ath11k *ar, struct ath11k_vif *arvif) +{ + unsigned long time_left; + struct ieee80211_vif *vif = arvif->vif; + int ret = 0; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->vdev_delete_done); + + ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id); + if (ret) { + ath11k_warn(ar->ab, "failed to delete WMI vdev %d: %d\n", + arvif->vdev_id, ret); + return ret; + } + + time_left = wait_for_completion_timeout(&ar->vdev_delete_done, + ATH11K_VDEV_DELETE_TIMEOUT_HZ); + if (time_left == 0) { + ath11k_warn(ar->ab, "Timeout in receiving vdev delete response\n"); + return -ETIMEDOUT; + } + + ar->ab->free_vdev_map |= 1LL << (arvif->vdev_id); + ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); + ar->num_created_vdevs--; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", + vif->addr, arvif->vdev_id); + + return ret; +} + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -6373,18 +6477,16 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, ath11k_dp_vdev_tx_attach(ar, arvif); + ath11k_debugfs_add_interface(arvif); + if (vif->type != NL80211_IFTYPE_MONITOR && test_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags)) { ret = ath11k_mac_monitor_vdev_create(ar); - if (ret) { + if (ret) ath11k_warn(ar->ab, "failed to create monitor vdev during add interface: %d", ret); - goto err_peer_del; - } } - ath11k_debugfs_add_interface(arvif); - mutex_unlock(&ar->conf_mutex); return 0; @@ -6400,16 +6502,12 @@ 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; + ath11k_mac_vdev_delete(ar, arvif); spin_lock_bh(&ar->data_lock); list_del(&arvif->list); spin_unlock_bh(&ar->data_lock); err: - ath11k_debugfs_remove_interface(arvif); mutex_unlock(&ar->conf_mutex); return ret; @@ -6432,7 +6530,6 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_base *ab = ar->ab; - unsigned long time_left; int ret; int i; @@ -6453,29 +6550,13 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); } - reinit_completion(&ar->vdev_delete_done); - - ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id); + ret = ath11k_mac_vdev_delete(ar, arvif); if (ret) { - ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n", + ath11k_warn(ab, "failed to delete vdev %d: %d\n", arvif->vdev_id, ret); goto err_vdev_del; } - time_left = wait_for_completion_timeout(&ar->vdev_delete_done, - ATH11K_VDEV_DELETE_TIMEOUT_HZ); - if (time_left == 0) { - ath11k_warn(ab, "Timeout in receiving vdev delete response\n"); - goto err_vdev_del; - } - - ab->free_vdev_map |= 1LL << (arvif->vdev_id); - ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); - ar->num_created_vdevs--; - - ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", - vif->addr, arvif->vdev_id); - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); ar->monitor_vdev_id = -1; @@ -7929,6 +8010,7 @@ ath11k_mac_op_reconfig_complete(struct ieee80211_hw *hw, struct ath11k *ar = hw->priv; struct ath11k_base *ab = ar->ab; int recovery_count; + struct ath11k_vif *arvif; if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; @@ -7964,6 +8046,12 @@ ath11k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset success\n"); } } + if (ar->ab->hw_params.support_fw_mac_sequence) { + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_STA) + ieee80211_hw_restart_disconnect(arvif->vif); + } + } } mutex_unlock(&ar->conf_mutex); @@ -8539,6 +8627,7 @@ err_fallback: static const struct ieee80211_ops ath11k_ops = { .tx = ath11k_mac_op_tx, + .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = ath11k_mac_op_start, .stop = ath11k_mac_op_stop, .reconfig_complete = ath11k_mac_op_reconfig_complete, @@ -9014,6 +9103,9 @@ static int __ath11k_mac_register(struct ath11k *ar) NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); } + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_SET_SCAN_DWELL); + ath11k_reg_init(ar); if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) { |