aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath11k/mac.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath11k/mac.c')
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c242
1 files changed, 158 insertions, 84 deletions
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 7f8dd47d2333..5c175e3e09b2 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -537,31 +537,6 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id)
return NULL;
}
-struct ath11k *ath11k_mac_get_ar_vdev_stop_status(struct ath11k_base *ab,
- u32 vdev_id)
-{
- int i;
- struct ath11k_pdev *pdev;
- struct ath11k *ar;
-
- for (i = 0; i < ab->num_radios; i++) {
- pdev = rcu_dereference(ab->pdevs_active[i]);
- if (pdev && pdev->ar) {
- ar = pdev->ar;
-
- spin_lock_bh(&ar->data_lock);
- if (ar->vdev_stop_status.stop_in_progress &&
- ar->vdev_stop_status.vdev_id == vdev_id) {
- ar->vdev_stop_status.stop_in_progress = false;
- spin_unlock_bh(&ar->data_lock);
- return ar;
- }
- spin_unlock_bh(&ar->data_lock);
- }
- }
- return NULL;
-}
-
static void ath11k_pdev_caps_update(struct ath11k *ar)
{
struct ath11k_base *ab = ar->ab;
@@ -1850,6 +1825,52 @@ static void ath11k_recalculate_mgmt_rate(struct ath11k *ar,
ath11k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret);
}
+static int ath11k_mac_fils_discovery(struct ath11k_vif *arvif,
+ struct ieee80211_bss_conf *info)
+{
+ struct ath11k *ar = arvif->ar;
+ struct sk_buff *tmpl;
+ int ret;
+ u32 interval;
+ bool unsol_bcast_probe_resp_enabled = false;
+
+ if (info->fils_discovery.max_interval) {
+ interval = info->fils_discovery.max_interval;
+
+ tmpl = ieee80211_get_fils_discovery_tmpl(ar->hw, arvif->vif);
+ if (tmpl)
+ ret = ath11k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id,
+ tmpl);
+ } else if (info->unsol_bcast_probe_resp_interval) {
+ unsol_bcast_probe_resp_enabled = 1;
+ interval = info->unsol_bcast_probe_resp_interval;
+
+ tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(ar->hw,
+ arvif->vif);
+ if (tmpl)
+ ret = ath11k_wmi_probe_resp_tmpl(ar, arvif->vdev_id,
+ tmpl);
+ } else { /* Disable */
+ return ath11k_wmi_fils_discovery(ar, arvif->vdev_id, 0, false);
+ }
+
+ if (!tmpl) {
+ ath11k_warn(ar->ab,
+ "mac vdev %i failed to retrieve %s template\n",
+ arvif->vdev_id, (unsol_bcast_probe_resp_enabled ?
+ "unsolicited broadcast probe response" :
+ "FILS discovery"));
+ return -EPERM;
+ }
+ kfree_skb(tmpl);
+
+ if (!ret)
+ ret = ath11k_wmi_fils_discovery(ar, arvif->vdev_id, interval,
+ unsol_bcast_probe_resp_enabled);
+
+ return ret;
+}
+
static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
@@ -1904,20 +1925,6 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret)
ath11k_warn(ar->ab, "failed to update bcn template: %d\n",
ret);
-
- if (vif->bss_conf.he_support) {
- ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
- WMI_VDEV_PARAM_BA_MODE,
- WMI_BA_MODE_BUFFER_SIZE_256);
- if (ret)
- ath11k_warn(ar->ab,
- "failed to set BA BUFFER SIZE 256 for vdev: %d\n",
- arvif->vdev_id);
- else
- ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
- "Set BA BUFFER SIZE 256 for VDEV: %d\n",
- arvif->vdev_id);
- }
}
if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) {
@@ -1948,9 +1955,33 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
ether_addr_copy(arvif->bssid, info->bssid);
- if (changed & BSS_CHANGED_BEACON_ENABLED)
+ if (changed & BSS_CHANGED_BEACON_ENABLED) {
ath11k_control_beaconing(arvif, info);
+ if (arvif->is_up && vif->bss_conf.he_support &&
+ vif->bss_conf.he_oper.params) {
+ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+ WMI_VDEV_PARAM_BA_MODE,
+ WMI_BA_MODE_BUFFER_SIZE_256);
+ if (ret)
+ ath11k_warn(ar->ab,
+ "failed to set BA BUFFER SIZE 256 for vdev: %d\n",
+ arvif->vdev_id);
+
+ param_id = WMI_VDEV_PARAM_HEOPS_0_31;
+ param_value = vif->bss_conf.he_oper.params;
+ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+ param_id, param_value);
+ ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+ "he oper param: %x set for VDEV: %d\n",
+ param_value, arvif->vdev_id);
+
+ if (ret)
+ ath11k_warn(ar->ab, "Failed to set he oper params %x for VDEV %d: %i\n",
+ param_value, arvif->vdev_id, ret);
+ }
+ }
+
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
u32 cts_prot;
@@ -2111,6 +2142,10 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
+ if (changed & BSS_CHANGED_FILS_DISCOVERY ||
+ changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP)
+ ath11k_mac_fils_discovery(arvif, info);
+
mutex_unlock(&ar->conf_mutex);
}
@@ -3729,11 +3764,6 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar,
he_cap_elem->mac_cap_info[1] &=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
- he_cap_elem->phy_cap_info[4] &=
- ~IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK;
- he_cap_elem->phy_cap_info[4] &=
- ~IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK;
- he_cap_elem->phy_cap_info[4] |= (ar->num_tx_chains - 1) << 2;
he_cap_elem->phy_cap_info[5] &=
~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
@@ -3977,21 +4007,20 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar)
static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
{
struct ath11k *ar = container_of(work, struct ath11k, wmi_mgmt_tx_work);
- struct ieee80211_tx_info *info;
+ struct ath11k_skb_cb *skb_cb;
struct ath11k_vif *arvif;
struct sk_buff *skb;
int ret;
while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) {
- info = IEEE80211_SKB_CB(skb);
- if (!info->control.vif) {
- ath11k_warn(ar->ab, "no vif found for mgmt frame, flags 0x%x\n",
- info->control.flags);
+ skb_cb = ATH11K_SKB_CB(skb);
+ if (!skb_cb->vif) {
+ ath11k_warn(ar->ab, "no vif found for mgmt frame\n");
ieee80211_free_txskb(ar->hw, skb);
continue;
}
- arvif = ath11k_vif_to_arvif(info->control.vif);
+ arvif = ath11k_vif_to_arvif(skb_cb->vif);
if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) &&
arvif->is_started) {
ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
@@ -4004,8 +4033,8 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
}
} else {
ath11k_warn(ar->ab,
- "dropping mgmt frame for vdev %d, flags 0x%x is_started %d\n",
- arvif->vdev_id, info->control.flags,
+ "dropping mgmt frame for vdev %d, is_started %d\n",
+ arvif->vdev_id,
arvif->is_started);
ieee80211_free_txskb(ar->hw, skb);
}
@@ -4053,10 +4082,20 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif = info->control.vif;
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_key_conf *key = info->control.hw_key;
+ u32 info_flags = info->flags;
bool is_prb_rsp;
int ret;
- if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
+ memset(skb_cb, 0, sizeof(*skb_cb));
+ skb_cb->vif = vif;
+
+ if (key) {
+ skb_cb->cipher = key->cipher;
+ skb_cb->flags |= ATH11K_SKB_CIPHER_SET;
+ }
+
+ if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP;
} else if (ieee80211_is_mgmt(hdr->frame_control)) {
is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
@@ -4094,7 +4133,8 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable)
if (enable) {
tlv_filter = ath11k_mac_mon_status_filter_default;
- tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar);
+ if (ath11k_debugfs_rx_filter(ar))
+ tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar);
}
for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
@@ -4106,6 +4146,10 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable)
&tlv_filter);
}
+ if (enable && !ar->ab->hw_params.rxdma1_enable)
+ mod_timer(&ar->ab->mon_reap_timer, jiffies +
+ msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));
+
return ret;
}
@@ -4578,8 +4622,22 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
err_peer_del:
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ reinit_completion(&ar->peer_delete_done);
+
+ ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr,
+ arvif->vdev_id);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
+ arvif->vdev_id, vif->addr);
+ goto err;
+ }
+
+ ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id,
+ vif->addr);
+ if (ret)
+ goto err;
+
ar->num_peers--;
- ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, arvif->vdev_id);
}
err_vdev_del:
@@ -4614,6 +4672,7 @@ 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;
@@ -4622,10 +4681,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);
- spin_lock_bh(&ar->data_lock);
- list_del(&arvif->list);
- spin_unlock_bh(&ar->data_lock);
-
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
if (ret)
@@ -4633,16 +4688,33 @@ 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);
- if (ret)
+ if (ret) {
ath11k_warn(ab, "failed to delete WMI 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);
- ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
- ab->free_vdev_map |= 1LL << (arvif->vdev_id);
+
+err_vdev_del:
+ spin_lock_bh(&ar->data_lock);
+ list_del(&arvif->list);
+ spin_unlock_bh(&ar->data_lock);
ath11k_peer_cleanup(ar, arvif->vdev_id);
@@ -4946,13 +5018,6 @@ static int ath11k_mac_vdev_stop(struct ath11k_vif *arvif)
reinit_completion(&ar->vdev_setup_done);
- spin_lock_bh(&ar->data_lock);
-
- ar->vdev_stop_status.stop_in_progress = true;
- ar->vdev_stop_status.vdev_id = arvif->vdev_id;
-
- spin_unlock_bh(&ar->data_lock);
-
ret = ath11k_wmi_vdev_stop(ar, arvif->vdev_id);
if (ret) {
ath11k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n",
@@ -4981,10 +5046,6 @@ static int ath11k_mac_vdev_stop(struct ath11k_vif *arvif)
return 0;
err:
- spin_lock_bh(&ar->data_lock);
- ar->vdev_stop_status.stop_in_progress = false;
- spin_unlock_bh(&ar->data_lock);
-
return ret;
}
@@ -5225,20 +5286,26 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
arvif->vdev_type != WMI_VDEV_TYPE_AP &&
arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
memcpy(&arvif->chanctx, ctx, sizeof(*ctx));
- mutex_unlock(&ar->conf_mutex);
- return 0;
+ ret = 0;
+ goto out;
}
if (WARN_ON(arvif->is_started)) {
- mutex_unlock(&ar->conf_mutex);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out;
}
if (ab->hw_params.vdev_start_delay) {
param.vdev_id = arvif->vdev_id;
param.peer_type = WMI_PEER_TYPE_DEFAULT;
param.peer_addr = ar->mac_addr;
+
ret = ath11k_peer_create(ar, arvif, NULL, &param);
+ if (ret) {
+ ath11k_warn(ab, "failed to create peer after vdev start delay: %d",
+ ret);
+ goto out;
+ }
}
ret = ath11k_mac_vdev_start(arvif, &ctx->def);
@@ -5246,23 +5313,21 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n",
arvif->vdev_id, vif->addr,
ctx->def.chan->center_freq, ret);
- goto err;
+ goto out;
}
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id);
if (ret)
- goto err;
+ goto out;
}
arvif->is_started = true;
/* TODO: Setup ps and cts/rts protection */
- mutex_unlock(&ar->conf_mutex);
-
- return 0;
+ ret = 0;
-err:
+out:
mutex_unlock(&ar->conf_mutex);
return ret;
@@ -6258,6 +6323,13 @@ static int __ath11k_mac_register(struct ath11k *ar)
ar->hw->wiphy->num_iftype_ext_capab =
ARRAY_SIZE(ath11k_iftypes_ext_capa);
+ if (ar->supports_6ghz) {
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_FILS_DISCOVERY);
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
+ }
+
ath11k_reg_init(ar);
if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) {
@@ -6397,7 +6469,9 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
INIT_LIST_HEAD(&ar->ppdu_stats_info);
mutex_init(&ar->conf_mutex);
init_completion(&ar->vdev_setup_done);
+ init_completion(&ar->vdev_delete_done);
init_completion(&ar->peer_assoc_done);
+ init_completion(&ar->peer_delete_done);
init_completion(&ar->install_key_done);
init_completion(&ar->bss_survey_done);
init_completion(&ar->scan.started);