|
@@ -1070,6 +1070,7 @@ static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar)
|
|
|
return false;
|
|
|
|
|
|
return ar->monitor ||
|
|
|
+ ar->filter_flags & FIF_OTHER_BSS ||
|
|
|
test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
|
|
|
}
|
|
|
|
|
@@ -3617,9 +3618,6 @@ static int ath10k_start_scan(struct ath10k *ar,
|
|
|
}
|
|
|
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+200));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -4064,21 +4062,56 @@ static u32 get_nss_from_chainmask(u16 chain_mask)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+static int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar)
|
|
|
+{
|
|
|
+ int nsts = ar->vht_cap_info;
|
|
|
+ nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
|
|
+ nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
|
|
|
+
|
|
|
+ /* If firmware does not deliver to host number of space-time
|
|
|
+ * streams supported, assume it support up to 4 BF STS and return
|
|
|
+ * the value for VHT CAP: nsts-1)
|
|
|
+ * */
|
|
|
+ if (nsts == 0)
|
|
|
+ return 3;
|
|
|
+
|
|
|
+ return nsts;
|
|
|
+}
|
|
|
+
|
|
|
+static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar)
|
|
|
+{
|
|
|
+ int sound_dim = ar->vht_cap_info;
|
|
|
+ sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
|
|
|
+ sound_dim >>=IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
|
|
|
+
|
|
|
+ /* If the sounding dimension is not advertised by the firmware,
|
|
|
+ * let's use a default value of 1
|
|
|
+ */
|
|
|
+ if (sound_dim == 0)
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ return sound_dim;
|
|
|
+}
|
|
|
+
|
|
|
static int ath10k_mac_set_txbf_conf(struct ath10k_vif *arvif)
|
|
|
{
|
|
|
u32 value = 0;
|
|
|
struct ath10k *ar = arvif->ar;
|
|
|
+ int nsts;
|
|
|
+ int sound_dim;
|
|
|
|
|
|
if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_BEFORE_ASSOC)
|
|
|
return 0;
|
|
|
|
|
|
+ nsts = ath10k_mac_get_vht_cap_bf_sts(ar);
|
|
|
if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
|
|
|
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE))
|
|
|
- value |= SM((ar->num_rf_chains - 1), WMI_TXBF_STS_CAP_OFFSET);
|
|
|
+ value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET);
|
|
|
|
|
|
+ sound_dim = ath10k_mac_get_vht_cap_bf_sound_dim(ar);
|
|
|
if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
|
|
|
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE))
|
|
|
- value |= SM((ar->num_rf_chains - 1), WMI_BF_SOUND_DIM_OFFSET);
|
|
|
+ value |= SM(sound_dim, WMI_BF_SOUND_DIM_OFFSET);
|
|
|
|
|
|
if (!value)
|
|
|
return 0;
|
|
@@ -4175,6 +4208,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
case NL80211_IFTYPE_ADHOC:
|
|
|
arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
|
|
|
break;
|
|
|
+ case NL80211_IFTYPE_MESH_POINT:
|
|
|
+ if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ arvif->vdev_type = WMI_VDEV_TYPE_AP;
|
|
|
+ break;
|
|
|
case NL80211_IFTYPE_AP:
|
|
|
arvif->vdev_type = WMI_VDEV_TYPE_AP;
|
|
|
|
|
@@ -4215,6 +4256,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
* become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
|
|
|
*/
|
|
|
if (vif->type == NL80211_IFTYPE_ADHOC ||
|
|
|
+ vif->type == NL80211_IFTYPE_MESH_POINT ||
|
|
|
vif->type == NL80211_IFTYPE_AP) {
|
|
|
arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
|
|
|
IEEE80211_MAX_FRAME_LEN,
|
|
@@ -4554,6 +4596,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
if (ret)
|
|
|
ath10k_warn(ar, "failed to update beacon template: %d\n",
|
|
|
ret);
|
|
|
+
|
|
|
+ if (ieee80211_vif_is_mesh(vif)) {
|
|
|
+ /* mesh doesn't use SSID but firmware needs it */
|
|
|
+ strncpy(arvif->u.ap.ssid, "mesh",
|
|
|
+ sizeof(arvif->u.ap.ssid));
|
|
|
+ arvif->u.ap.ssid_len = 4;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (changed & BSS_CHANGED_AP_PROBE_RESP) {
|
|
@@ -4751,6 +4800,11 @@ static int ath10k_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 +
|
|
|
+ 200));
|
|
|
+
|
|
|
exit:
|
|
|
mutex_unlock(&ar->conf_mutex);
|
|
|
return ret;
|
|
@@ -5293,6 +5347,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
|
|
} else if (old_state == IEEE80211_STA_AUTH &&
|
|
|
new_state == IEEE80211_STA_ASSOC &&
|
|
|
(vif->type == NL80211_IFTYPE_AP ||
|
|
|
+ vif->type == NL80211_IFTYPE_MESH_POINT ||
|
|
|
vif->type == NL80211_IFTYPE_ADHOC)) {
|
|
|
/*
|
|
|
* New association.
|
|
@@ -5328,6 +5383,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
|
|
|
} else if (old_state == IEEE80211_STA_ASSOC &&
|
|
|
new_state == IEEE80211_STA_AUTH &&
|
|
|
(vif->type == NL80211_IFTYPE_AP ||
|
|
|
+ vif->type == NL80211_IFTYPE_MESH_POINT ||
|
|
|
vif->type == NL80211_IFTYPE_ADHOC)) {
|
|
|
/*
|
|
|
* Disassociation.
|
|
@@ -5901,7 +5957,7 @@ ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
|
|
|
}
|
|
|
|
|
|
static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
|
|
|
- u8 rate, u8 nss, u8 sgi)
|
|
|
+ u8 rate, u8 nss, u8 sgi, u8 ldpc)
|
|
|
{
|
|
|
struct ath10k *ar = arvif->ar;
|
|
|
u32 vdev_param;
|
|
@@ -5934,6 +5990,13 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+ vdev_param = ar->wmi.vdev_param->ldpc;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ldpc);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn(ar, "failed to set ldpc param %d: %d\n", ldpc, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -5997,6 +6060,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
|
|
|
u8 rate;
|
|
|
u8 nss;
|
|
|
u8 sgi;
|
|
|
+ u8 ldpc;
|
|
|
int single_nss;
|
|
|
int ret;
|
|
|
|
|
@@ -6006,6 +6070,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
|
|
|
band = def.chan->band;
|
|
|
ht_mcs_mask = mask->control[band].ht_mcs;
|
|
|
vht_mcs_mask = mask->control[band].vht_mcs;
|
|
|
+ ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC);
|
|
|
|
|
|
sgi = mask->control[band].gi;
|
|
|
if (sgi == NL80211_TXRATE_FORCE_LGI)
|
|
@@ -6044,7 +6109,7 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
|
|
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
|
|
|
- ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi);
|
|
|
+ ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc);
|
|
|
if (ret) {
|
|
|
ath10k_warn(ar, "failed to set fixed rate params on vdev %i: %d\n",
|
|
|
arvif->vdev_id, ret);
|
|
@@ -6218,6 +6283,94 @@ ath10k_mac_update_rx_channel(struct ath10k *ar,
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+ath10k_mac_update_vif_chan(struct ath10k *ar,
|
|
|
+ struct ieee80211_vif_chanctx_switch *vifs,
|
|
|
+ int n_vifs)
|
|
|
+{
|
|
|
+ struct ath10k_vif *arvif;
|
|
|
+ int ret;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ lockdep_assert_held(&ar->conf_mutex);
|
|
|
+
|
|
|
+ /* First stop monitor interface. Some FW versions crash if there's a
|
|
|
+ * lone monitor interface.
|
|
|
+ */
|
|
|
+ if (ar->monitor_started)
|
|
|
+ ath10k_monitor_stop(ar);
|
|
|
+
|
|
|
+ for (i = 0; i < n_vifs; i++) {
|
|
|
+ arvif = ath10k_vif_to_arvif(vifs[i].vif);
|
|
|
+
|
|
|
+ ath10k_dbg(ar, ATH10K_DBG_MAC,
|
|
|
+ "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
|
|
|
+ arvif->vdev_id,
|
|
|
+ vifs[i].old_ctx->def.chan->center_freq,
|
|
|
+ vifs[i].new_ctx->def.chan->center_freq,
|
|
|
+ vifs[i].old_ctx->def.width,
|
|
|
+ vifs[i].new_ctx->def.width);
|
|
|
+
|
|
|
+ if (WARN_ON(!arvif->is_started))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (WARN_ON(!arvif->is_up))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn(ar, "failed to down vdev %d: %d\n",
|
|
|
+ arvif->vdev_id, ret);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* All relevant vdevs are downed and associated channel resources
|
|
|
+ * should be available for the channel switch now.
|
|
|
+ */
|
|
|
+
|
|
|
+ spin_lock_bh(&ar->data_lock);
|
|
|
+ ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
|
|
|
+ spin_unlock_bh(&ar->data_lock);
|
|
|
+
|
|
|
+ for (i = 0; i < n_vifs; i++) {
|
|
|
+ arvif = ath10k_vif_to_arvif(vifs[i].vif);
|
|
|
+
|
|
|
+ if (WARN_ON(!arvif->is_started))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (WARN_ON(!arvif->is_up))
|
|
|
+ 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, &vifs[i].new_ctx->def);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn(ar, "failed to restart vdev %d: %d\n",
|
|
|
+ arvif->vdev_id, ret);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
|
|
+ arvif->bssid);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
|
|
|
+ arvif->vdev_id, ret);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ath10k_monitor_recalc(ar);
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
ath10k_mac_op_add_chanctx(struct ieee80211_hw *hw,
|
|
|
struct ieee80211_chanctx_conf *ctx)
|
|
@@ -6264,12 +6417,52 @@ ath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
|
|
|
mutex_unlock(&ar->conf_mutex);
|
|
|
}
|
|
|
|
|
|
+struct ath10k_mac_change_chanctx_arg {
|
|
|
+ struct ieee80211_chanctx_conf *ctx;
|
|
|
+ struct ieee80211_vif_chanctx_switch *vifs;
|
|
|
+ int n_vifs;
|
|
|
+ int next_vif;
|
|
|
+};
|
|
|
+
|
|
|
+static void
|
|
|
+ath10k_mac_change_chanctx_cnt_iter(void *data, u8 *mac,
|
|
|
+ struct ieee80211_vif *vif)
|
|
|
+{
|
|
|
+ struct ath10k_mac_change_chanctx_arg *arg = data;
|
|
|
+
|
|
|
+ if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx)
|
|
|
+ return;
|
|
|
+
|
|
|
+ arg->n_vifs++;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+ath10k_mac_change_chanctx_fill_iter(void *data, u8 *mac,
|
|
|
+ struct ieee80211_vif *vif)
|
|
|
+{
|
|
|
+ struct ath10k_mac_change_chanctx_arg *arg = data;
|
|
|
+ struct ieee80211_chanctx_conf *ctx;
|
|
|
+
|
|
|
+ ctx = rcu_access_pointer(vif->chanctx_conf);
|
|
|
+ if (ctx != arg->ctx)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (WARN_ON(arg->next_vif == arg->n_vifs))
|
|
|
+ return;
|
|
|
+
|
|
|
+ arg->vifs[arg->next_vif].vif = vif;
|
|
|
+ arg->vifs[arg->next_vif].old_ctx = ctx;
|
|
|
+ arg->vifs[arg->next_vif].new_ctx = ctx;
|
|
|
+ arg->next_vif++;
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
|
|
|
struct ieee80211_chanctx_conf *ctx,
|
|
|
u32 changed)
|
|
|
{
|
|
|
struct ath10k *ar = hw->priv;
|
|
|
+ struct ath10k_mac_change_chanctx_arg arg = { .ctx = ctx };
|
|
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
|
|
@@ -6283,6 +6476,30 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw,
|
|
|
if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
|
|
|
goto unlock;
|
|
|
|
|
|
+ if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
|
|
|
+ ieee80211_iterate_active_interfaces_atomic(
|
|
|
+ hw,
|
|
|
+ IEEE80211_IFACE_ITER_NORMAL,
|
|
|
+ ath10k_mac_change_chanctx_cnt_iter,
|
|
|
+ &arg);
|
|
|
+ if (arg.n_vifs == 0)
|
|
|
+ goto radar;
|
|
|
+
|
|
|
+ arg.vifs = kcalloc(arg.n_vifs, sizeof(arg.vifs[0]),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!arg.vifs)
|
|
|
+ goto radar;
|
|
|
+
|
|
|
+ ieee80211_iterate_active_interfaces_atomic(
|
|
|
+ hw,
|
|
|
+ IEEE80211_IFACE_ITER_NORMAL,
|
|
|
+ ath10k_mac_change_chanctx_fill_iter,
|
|
|
+ &arg);
|
|
|
+ ath10k_mac_update_vif_chan(ar, arg.vifs, arg.n_vifs);
|
|
|
+ kfree(arg.vifs);
|
|
|
+ }
|
|
|
+
|
|
|
+radar:
|
|
|
ath10k_recalc_radar_detection(ar);
|
|
|
|
|
|
/* FIXME: How to configure Rx chains properly? */
|
|
@@ -6402,91 +6619,13 @@ ath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
|
|
|
enum ieee80211_chanctx_switch_mode mode)
|
|
|
{
|
|
|
struct ath10k *ar = hw->priv;
|
|
|
- struct ath10k_vif *arvif;
|
|
|
- int ret;
|
|
|
- int i;
|
|
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
|
|
|
ath10k_dbg(ar, ATH10K_DBG_MAC,
|
|
|
"mac chanctx switch n_vifs %d mode %d\n",
|
|
|
n_vifs, mode);
|
|
|
-
|
|
|
- /* First stop monitor interface. Some FW versions crash if there's a
|
|
|
- * lone monitor interface.
|
|
|
- */
|
|
|
- if (ar->monitor_started)
|
|
|
- ath10k_monitor_stop(ar);
|
|
|
-
|
|
|
- for (i = 0; i < n_vifs; i++) {
|
|
|
- arvif = ath10k_vif_to_arvif(vifs[i].vif);
|
|
|
-
|
|
|
- ath10k_dbg(ar, ATH10K_DBG_MAC,
|
|
|
- "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
|
|
|
- arvif->vdev_id,
|
|
|
- vifs[i].old_ctx->def.chan->center_freq,
|
|
|
- vifs[i].new_ctx->def.chan->center_freq,
|
|
|
- vifs[i].old_ctx->def.width,
|
|
|
- vifs[i].new_ctx->def.width);
|
|
|
-
|
|
|
- if (WARN_ON(!arvif->is_started))
|
|
|
- continue;
|
|
|
-
|
|
|
- if (WARN_ON(!arvif->is_up))
|
|
|
- continue;
|
|
|
-
|
|
|
- ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
|
|
- if (ret) {
|
|
|
- ath10k_warn(ar, "failed to down vdev %d: %d\n",
|
|
|
- arvif->vdev_id, ret);
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* All relevant vdevs are downed and associated channel resources
|
|
|
- * should be available for the channel switch now.
|
|
|
- */
|
|
|
-
|
|
|
- spin_lock_bh(&ar->data_lock);
|
|
|
- ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs);
|
|
|
- spin_unlock_bh(&ar->data_lock);
|
|
|
-
|
|
|
- for (i = 0; i < n_vifs; i++) {
|
|
|
- arvif = ath10k_vif_to_arvif(vifs[i].vif);
|
|
|
-
|
|
|
- if (WARN_ON(!arvif->is_started))
|
|
|
- continue;
|
|
|
-
|
|
|
- if (WARN_ON(!arvif->is_up))
|
|
|
- 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, &vifs[i].new_ctx->def);
|
|
|
- if (ret) {
|
|
|
- ath10k_warn(ar, "failed to restart vdev %d: %d\n",
|
|
|
- arvif->vdev_id, ret);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
|
|
- arvif->bssid);
|
|
|
- if (ret) {
|
|
|
- ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
|
|
|
- arvif->vdev_id, ret);
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- ath10k_monitor_recalc(ar);
|
|
|
+ ath10k_mac_update_vif_chan(ar, vifs, n_vifs);
|
|
|
|
|
|
mutex_unlock(&ar->conf_mutex);
|
|
|
return 0;
|
|
@@ -6642,6 +6781,9 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
|
|
|
{
|
|
|
.max = 7,
|
|
|
.types = BIT(NL80211_IFTYPE_AP)
|
|
|
+#ifdef CONFIG_MAC80211_MESH
|
|
|
+ | BIT(NL80211_IFTYPE_MESH_POINT)
|
|
|
+#endif
|
|
|
},
|
|
|
};
|
|
|
|
|
@@ -6649,6 +6791,9 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
|
|
|
{
|
|
|
.max = 8,
|
|
|
.types = BIT(NL80211_IFTYPE_AP)
|
|
|
+#ifdef CONFIG_MAC80211_MESH
|
|
|
+ | BIT(NL80211_IFTYPE_MESH_POINT)
|
|
|
+#endif
|
|
|
},
|
|
|
};
|
|
|
|
|
@@ -6686,6 +6831,9 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = {
|
|
|
{
|
|
|
.max = 2,
|
|
|
.types = BIT(NL80211_IFTYPE_AP) |
|
|
|
+#ifdef CONFIG_MAC80211_MESH
|
|
|
+ BIT(NL80211_IFTYPE_MESH_POINT) |
|
|
|
+#endif
|
|
|
BIT(NL80211_IFTYPE_P2P_CLIENT) |
|
|
|
BIT(NL80211_IFTYPE_P2P_GO),
|
|
|
},
|
|
@@ -6707,6 +6855,9 @@ static const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = {
|
|
|
{
|
|
|
.max = 1,
|
|
|
.types = BIT(NL80211_IFTYPE_AP) |
|
|
|
+#ifdef CONFIG_MAC80211_MESH
|
|
|
+ BIT(NL80211_IFTYPE_MESH_POINT) |
|
|
|
+#endif
|
|
|
BIT(NL80211_IFTYPE_P2P_GO),
|
|
|
},
|
|
|
{
|
|
@@ -6773,6 +6924,9 @@ static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = {
|
|
|
{
|
|
|
.max = 16,
|
|
|
.types = BIT(NL80211_IFTYPE_AP)
|
|
|
+#ifdef CONFIG_MAC80211_MESH
|
|
|
+ | BIT(NL80211_IFTYPE_MESH_POINT)
|
|
|
+#endif
|
|
|
},
|
|
|
};
|
|
|
|
|
@@ -6804,7 +6958,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
|
|
|
|
|
|
if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
|
|
|
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
|
|
|
- val = ar->num_rf_chains - 1;
|
|
|
+ val = ath10k_mac_get_vht_cap_bf_sts(ar);
|
|
|
val <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
|
|
|
val &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
|
|
|
|
@@ -6813,7 +6967,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
|
|
|
|
|
|
if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
|
|
|
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
|
|
|
- val = ar->num_rf_chains - 1;
|
|
|
+ val = ath10k_mac_get_vht_cap_bf_sound_dim(ar);
|
|
|
val <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
|
|
|
val &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
|
|
|
|
|
@@ -6997,7 +7151,8 @@ int ath10k_mac_register(struct ath10k *ar)
|
|
|
|
|
|
ar->hw->wiphy->interface_modes =
|
|
|
BIT(NL80211_IFTYPE_STATION) |
|
|
|
- BIT(NL80211_IFTYPE_AP);
|
|
|
+ BIT(NL80211_IFTYPE_AP) |
|
|
|
+ BIT(NL80211_IFTYPE_MESH_POINT);
|
|
|
|
|
|
ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
|
|
|
ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;
|