|
@@ -1056,6 +1056,10 @@ static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif)
|
|
|
if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
|
|
|
return 0;
|
|
|
|
|
|
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
|
|
|
+ arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
|
|
|
+ return 0;
|
|
|
+
|
|
|
bcn = ieee80211_beacon_get_template(hw, vif, &offs);
|
|
|
if (!bcn) {
|
|
|
ath10k_warn(ar, "failed to get beacon template from mac80211\n");
|
|
@@ -1101,6 +1105,9 @@ static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
|
|
|
if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
|
|
|
return 0;
|
|
|
|
|
|
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
|
|
|
+ return 0;
|
|
|
+
|
|
|
prb = ieee80211_proberesp_get(hw, vif);
|
|
|
if (!prb) {
|
|
|
ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
|
|
@@ -1130,10 +1137,9 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
|
|
|
if (!info->enable_beacon) {
|
|
|
ath10k_vdev_stop(arvif);
|
|
|
|
|
|
+ spin_lock_bh(&arvif->ar->data_lock);
|
|
|
arvif->is_started = false;
|
|
|
arvif->is_up = false;
|
|
|
-
|
|
|
- spin_lock_bh(&arvif->ar->data_lock);
|
|
|
ath10k_mac_vif_beacon_free(arvif);
|
|
|
spin_unlock_bh(&arvif->ar->data_lock);
|
|
|
|
|
@@ -1361,6 +1367,49 @@ static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif)
|
|
|
+{
|
|
|
+ struct ath10k *ar = arvif->ar;
|
|
|
+ struct ieee80211_vif *vif = arvif->vif;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!vif->csa_active)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!arvif->is_up)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!ieee80211_csa_is_complete(vif)) {
|
|
|
+ ieee80211_csa_update_counter(vif);
|
|
|
+
|
|
|
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
|
|
|
+ if (ret)
|
|
|
+ ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
|
|
|
+ ret);
|
|
|
+
|
|
|
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
|
|
|
+ if (ret)
|
|
|
+ ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
|
|
|
+ ret);
|
|
|
+ } else {
|
|
|
+ ieee80211_csa_finish(vif);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void ath10k_mac_vif_ap_csa_work(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
|
|
|
+ ap_csa_work);
|
|
|
+ struct ath10k *ar = arvif->ar;
|
|
|
+
|
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
|
+ ath10k_mac_vif_ap_csa_count_down(arvif);
|
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
|
+}
|
|
|
+
|
|
|
/**********************/
|
|
|
/* Station management */
|
|
|
/**********************/
|
|
@@ -1949,7 +1998,9 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ spin_lock_bh(&arvif->ar->data_lock);
|
|
|
arvif->is_up = true;
|
|
|
+ spin_unlock_bh(&arvif->ar->data_lock);
|
|
|
|
|
|
/* Workaround: Some firmware revisions (tested with qca6174
|
|
|
* WLAN.RM.2.0-00073) have buggy powersave state machine and must be
|
|
@@ -1991,7 +2042,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ spin_lock_bh(&arvif->ar->data_lock);
|
|
|
arvif->is_up = false;
|
|
|
+ spin_unlock_bh(&arvif->ar->data_lock);
|
|
|
}
|
|
|
|
|
|
static int ath10k_station_assoc(struct ath10k *ar,
|
|
@@ -3059,6 +3112,16 @@ static void ath10k_config_chan(struct ath10k *ar)
|
|
|
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
|
|
continue;
|
|
|
|
|
|
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
|
|
|
+ if (ret)
|
|
|
+ ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n",
|
|
|
+ ret);
|
|
|
+
|
|
|
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
|
|
|
+ if (ret)
|
|
|
+ ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n",
|
|
|
+ ret);
|
|
|
+
|
|
|
ret = ath10k_vdev_restart(arvif);
|
|
|
if (ret) {
|
|
|
ath10k_warn(ar, "failed to restart vdev %d: %d\n",
|
|
@@ -3219,6 +3282,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
arvif->vif = vif;
|
|
|
|
|
|
INIT_LIST_HEAD(&arvif->list);
|
|
|
+ INIT_WORK(&arvif->ap_csa_work, ath10k_mac_vif_ap_csa_work);
|
|
|
|
|
|
if (ar->free_vdev_map == 0) {
|
|
|
ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
|
|
@@ -3436,6 +3500,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
|
|
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
|
|
int ret;
|
|
|
|
|
|
+ cancel_work_sync(&arvif->ap_csa_work);
|
|
|
+
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
|
|
|
spin_lock_bh(&ar->data_lock);
|