|
@@ -334,25 +334,29 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
|
|
|
|
|
static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
|
|
|
{
|
|
|
+ struct ath10k *ar = arvif->ar;
|
|
|
+ u32 vdev_param;
|
|
|
+
|
|
|
if (value != 0xFFFFFFFF)
|
|
|
value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold,
|
|
|
ATH10K_RTS_MAX);
|
|
|
|
|
|
- return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_RTS_THRESHOLD,
|
|
|
- value);
|
|
|
+ vdev_param = ar->wmi.vdev_param->rts_threshold;
|
|
|
+ return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
|
|
|
}
|
|
|
|
|
|
static int ath10k_mac_set_frag(struct ath10k_vif *arvif, u32 value)
|
|
|
{
|
|
|
+ struct ath10k *ar = arvif->ar;
|
|
|
+ u32 vdev_param;
|
|
|
+
|
|
|
if (value != 0xFFFFFFFF)
|
|
|
value = clamp_t(u32, arvif->ar->hw->wiphy->frag_threshold,
|
|
|
ATH10K_FRAGMT_THRESHOLD_MIN,
|
|
|
ATH10K_FRAGMT_THRESHOLD_MAX);
|
|
|
|
|
|
- return ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
|
|
|
- value);
|
|
|
+ vdev_param = ar->wmi.vdev_param->fragmentation_threshold;
|
|
|
+ return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
|
|
|
}
|
|
|
|
|
|
static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
|
|
@@ -562,12 +566,9 @@ static int ath10k_monitor_stop(struct ath10k *ar)
|
|
|
|
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
|
|
- /* For some reasons, ath10k_wmi_vdev_down() here couse
|
|
|
- * often ath10k_wmi_vdev_stop() to fail. Next we could
|
|
|
- * not run monitor vdev and driver reload
|
|
|
- * required. Don't see such problems we skip
|
|
|
- * ath10k_wmi_vdev_down() here.
|
|
|
- */
|
|
|
+ ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
|
|
|
+ if (ret)
|
|
|
+ ath10k_warn("Monitor vdev down failed: %d\n", ret);
|
|
|
|
|
|
ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
|
|
|
if (ret)
|
|
@@ -677,6 +678,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
|
|
|
struct ieee80211_bss_conf *info,
|
|
|
const u8 self_peer[ETH_ALEN])
|
|
|
{
|
|
|
+ u32 vdev_param;
|
|
|
int ret = 0;
|
|
|
|
|
|
lockdep_assert_held(&arvif->ar->conf_mutex);
|
|
@@ -710,8 +712,8 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_ATIM_WINDOW,
|
|
|
+ vdev_param = arvif->ar->wmi.vdev_param->atim_window;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
|
|
|
ATH10K_DEFAULT_ATIM);
|
|
|
if (ret)
|
|
|
ath10k_warn("Failed to set IBSS ATIM for VDEV:%d ret:%d\n",
|
|
@@ -721,35 +723,30 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
|
|
|
/*
|
|
|
* Review this when mac80211 gains per-interface powersave support.
|
|
|
*/
|
|
|
-static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|
|
+static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
|
|
|
{
|
|
|
- struct ath10k_generic_iter *ar_iter = data;
|
|
|
- struct ieee80211_conf *conf = &ar_iter->ar->hw->conf;
|
|
|
- struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
|
|
+ struct ath10k *ar = arvif->ar;
|
|
|
+ struct ieee80211_conf *conf = &ar->hw->conf;
|
|
|
enum wmi_sta_powersave_param param;
|
|
|
enum wmi_sta_ps_mode psmode;
|
|
|
int ret;
|
|
|
|
|
|
lockdep_assert_held(&arvif->ar->conf_mutex);
|
|
|
|
|
|
- if (vif->type != NL80211_IFTYPE_STATION)
|
|
|
- return;
|
|
|
+ if (arvif->vif->type != NL80211_IFTYPE_STATION)
|
|
|
+ return 0;
|
|
|
|
|
|
if (conf->flags & IEEE80211_CONF_PS) {
|
|
|
psmode = WMI_STA_PS_MODE_ENABLED;
|
|
|
param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
|
|
|
|
|
|
- ret = ath10k_wmi_set_sta_ps_param(ar_iter->ar,
|
|
|
- arvif->vdev_id,
|
|
|
- param,
|
|
|
+ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
|
|
|
conf->dynamic_ps_timeout);
|
|
|
if (ret) {
|
|
|
ath10k_warn("Failed to set inactivity time for VDEV: %d\n",
|
|
|
arvif->vdev_id);
|
|
|
- return;
|
|
|
+ return ret;
|
|
|
}
|
|
|
-
|
|
|
- ar_iter->ret = ret;
|
|
|
} else {
|
|
|
psmode = WMI_STA_PS_MODE_DISABLED;
|
|
|
}
|
|
@@ -757,11 +754,14 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|
|
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
|
|
|
arvif->vdev_id, psmode ? "enable" : "disable");
|
|
|
|
|
|
- ar_iter->ret = ath10k_wmi_set_psmode(ar_iter->ar, arvif->vdev_id,
|
|
|
- psmode);
|
|
|
- if (ar_iter->ret)
|
|
|
+ ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
|
|
|
+ if (ret) {
|
|
|
ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n",
|
|
|
psmode, arvif->vdev_id);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/**********************/
|
|
@@ -1031,14 +1031,27 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
|
|
|
struct wmi_peer_assoc_complete_arg *arg)
|
|
|
{
|
|
|
const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
|
|
|
+ u8 ampdu_factor;
|
|
|
|
|
|
if (!vht_cap->vht_supported)
|
|
|
return;
|
|
|
|
|
|
arg->peer_flags |= WMI_PEER_VHT;
|
|
|
-
|
|
|
arg->peer_vht_caps = vht_cap->cap;
|
|
|
|
|
|
+
|
|
|
+ ampdu_factor = (vht_cap->cap &
|
|
|
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
|
|
|
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
|
|
|
+
|
|
|
+ /* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to
|
|
|
+ * zero in VHT IE. Using it would result in degraded throughput.
|
|
|
+ * arg->peer_max_mpdu at this point contains HT max_mpdu so keep
|
|
|
+ * it if VHT max_mpdu is smaller. */
|
|
|
+ arg->peer_max_mpdu = max(arg->peer_max_mpdu,
|
|
|
+ (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR +
|
|
|
+ ampdu_factor)) - 1);
|
|
|
+
|
|
|
if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
|
|
|
arg->peer_flags |= WMI_PEER_80MHZ;
|
|
|
|
|
@@ -1124,26 +1137,25 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
|
|
|
WARN_ON(phymode == MODE_UNKNOWN);
|
|
|
}
|
|
|
|
|
|
-static int ath10k_peer_assoc(struct ath10k *ar,
|
|
|
- struct ath10k_vif *arvif,
|
|
|
- struct ieee80211_sta *sta,
|
|
|
- struct ieee80211_bss_conf *bss_conf)
|
|
|
+static int ath10k_peer_assoc_prepare(struct ath10k *ar,
|
|
|
+ struct ath10k_vif *arvif,
|
|
|
+ struct ieee80211_sta *sta,
|
|
|
+ struct ieee80211_bss_conf *bss_conf,
|
|
|
+ struct wmi_peer_assoc_complete_arg *arg)
|
|
|
{
|
|
|
- struct wmi_peer_assoc_complete_arg arg;
|
|
|
-
|
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
|
|
- memset(&arg, 0, sizeof(struct wmi_peer_assoc_complete_arg));
|
|
|
+ memset(arg, 0, sizeof(*arg));
|
|
|
|
|
|
- ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, &arg);
|
|
|
- ath10k_peer_assoc_h_crypto(ar, arvif, &arg);
|
|
|
- ath10k_peer_assoc_h_rates(ar, sta, &arg);
|
|
|
- ath10k_peer_assoc_h_ht(ar, sta, &arg);
|
|
|
- ath10k_peer_assoc_h_vht(ar, sta, &arg);
|
|
|
- ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, &arg);
|
|
|
- ath10k_peer_assoc_h_phymode(ar, arvif, sta, &arg);
|
|
|
+ ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg);
|
|
|
+ ath10k_peer_assoc_h_crypto(ar, arvif, arg);
|
|
|
+ ath10k_peer_assoc_h_rates(ar, sta, arg);
|
|
|
+ ath10k_peer_assoc_h_ht(ar, sta, arg);
|
|
|
+ ath10k_peer_assoc_h_vht(ar, sta, arg);
|
|
|
+ ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg);
|
|
|
+ ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg);
|
|
|
|
|
|
- return ath10k_wmi_peer_assoc(ar, &arg);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/* can be called only in mac80211 callbacks due to `key_count` usage */
|
|
@@ -1153,6 +1165,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
|
|
{
|
|
|
struct ath10k *ar = hw->priv;
|
|
|
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
|
|
+ struct wmi_peer_assoc_complete_arg peer_arg;
|
|
|
struct ieee80211_sta *ap_sta;
|
|
|
int ret;
|
|
|
|
|
@@ -1168,15 +1181,24 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- ret = ath10k_peer_assoc(ar, arvif, ap_sta, bss_conf);
|
|
|
+ ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
|
|
|
+ bss_conf, &peer_arg);
|
|
|
if (ret) {
|
|
|
- ath10k_warn("Peer assoc failed for %pM\n", bss_conf->bssid);
|
|
|
+ ath10k_warn("Peer assoc prepare failed for %pM\n: %d",
|
|
|
+ bss_conf->bssid, ret);
|
|
|
rcu_read_unlock();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
+ ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("Peer assoc failed for %pM\n: %d",
|
|
|
+ bss_conf->bssid, ret);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
ath10k_dbg(ATH10K_DBG_MAC,
|
|
|
"mac vdev %d up (associated) bssid %pM aid %d\n",
|
|
|
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
|
|
@@ -1224,19 +1246,28 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
|
|
|
/* FIXME: why don't we print error if wmi call fails? */
|
|
|
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
|
|
|
|
|
- arvif->def_wep_key_index = 0;
|
|
|
+ arvif->def_wep_key_idx = 0;
|
|
|
}
|
|
|
|
|
|
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
|
|
|
struct ieee80211_sta *sta)
|
|
|
{
|
|
|
+ struct wmi_peer_assoc_complete_arg peer_arg;
|
|
|
int ret = 0;
|
|
|
|
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
|
|
- ret = ath10k_peer_assoc(ar, arvif, sta, NULL);
|
|
|
+ ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
|
|
|
if (ret) {
|
|
|
- ath10k_warn("WMI peer assoc failed for %pM\n", sta->addr);
|
|
|
+ ath10k_warn("WMI peer assoc prepare failed for %pM\n",
|
|
|
+ sta->addr);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("Peer assoc failed for STA %pM\n: %d",
|
|
|
+ sta->addr, ret);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1405,6 +1436,33 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
|
|
|
/* TX handlers */
|
|
|
/***************/
|
|
|
|
|
|
+static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
|
|
|
+{
|
|
|
+ if (ieee80211_is_mgmt(hdr->frame_control))
|
|
|
+ return HTT_DATA_TX_EXT_TID_MGMT;
|
|
|
+
|
|
|
+ if (!ieee80211_is_data_qos(hdr->frame_control))
|
|
|
+ return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
|
|
+
|
|
|
+ if (!is_unicast_ether_addr(ieee80211_get_DA(hdr)))
|
|
|
+ return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
|
|
+
|
|
|
+ return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
+}
|
|
|
+
|
|
|
+static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
|
|
|
+ struct ieee80211_tx_info *info)
|
|
|
+{
|
|
|
+ if (info->control.vif)
|
|
|
+ return ath10k_vif_to_arvif(info->control.vif)->vdev_id;
|
|
|
+
|
|
|
+ if (ar->monitor_enabled)
|
|
|
+ return ar->monitor_vdev_id;
|
|
|
+
|
|
|
+ ath10k_warn("could not resolve vdev id\n");
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Frames sent to the FW have to be in "Native Wifi" format.
|
|
|
* Strip the QoS field from the 802.11 header.
|
|
@@ -1425,6 +1483,30 @@ static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw,
|
|
|
skb_pull(skb, IEEE80211_QOS_CTL_LEN);
|
|
|
}
|
|
|
|
|
|
+static void ath10k_tx_wep_key_work(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
|
|
|
+ wep_key_work);
|
|
|
+ int ret, keyidx = arvif->def_wep_key_newidx;
|
|
|
+
|
|
|
+ if (arvif->def_wep_key_idx == keyidx)
|
|
|
+ return;
|
|
|
+
|
|
|
+ ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
|
|
|
+ arvif->vdev_id, keyidx);
|
|
|
+
|
|
|
+ ret = ath10k_wmi_vdev_set_param(arvif->ar,
|
|
|
+ arvif->vdev_id,
|
|
|
+ arvif->ar->wmi.vdev_param->def_keyid,
|
|
|
+ keyidx);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("could not update wep keyidx (%d)\n", ret);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ arvif->def_wep_key_idx = keyidx;
|
|
|
+}
|
|
|
+
|
|
|
static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
|
|
{
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
@@ -1433,7 +1515,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
|
|
struct ath10k *ar = arvif->ar;
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
struct ieee80211_key_conf *key = info->control.hw_key;
|
|
|
- int ret;
|
|
|
|
|
|
if (!ieee80211_has_protected(hdr->frame_control))
|
|
|
return;
|
|
@@ -1445,21 +1526,14 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
|
|
|
key->cipher != WLAN_CIPHER_SUITE_WEP104)
|
|
|
return;
|
|
|
|
|
|
- if (key->keyidx == arvif->def_wep_key_index)
|
|
|
- return;
|
|
|
-
|
|
|
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d keyidx %d\n",
|
|
|
- arvif->vdev_id, key->keyidx);
|
|
|
-
|
|
|
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_DEF_KEYID,
|
|
|
- key->keyidx);
|
|
|
- if (ret) {
|
|
|
- ath10k_warn("could not update wep keyidx (%d)\n", ret);
|
|
|
+ if (key->keyidx == arvif->def_wep_key_idx)
|
|
|
return;
|
|
|
- }
|
|
|
|
|
|
- arvif->def_wep_key_index = key->keyidx;
|
|
|
+ /* FIXME: Most likely a few frames will be TXed with an old key. Simply
|
|
|
+ * queueing frames until key index is updated is not an option because
|
|
|
+ * sk_buff may need more processing to be done, e.g. offchannel */
|
|
|
+ arvif->def_wep_key_newidx = key->keyidx;
|
|
|
+ ieee80211_queue_work(ar->hw, &arvif->wep_key_work);
|
|
|
}
|
|
|
|
|
|
static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb)
|
|
@@ -1489,7 +1563,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb)
|
|
|
static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
|
|
|
{
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
- int ret;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (ar->htt.target_version_major >= 3) {
|
|
|
/* Since HTT 3.0 there is no separate mgmt tx command */
|
|
@@ -1497,16 +1571,32 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
|
|
|
goto exit;
|
|
|
}
|
|
|
|
|
|
- if (ieee80211_is_mgmt(hdr->frame_control))
|
|
|
- ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
|
|
|
- else if (ieee80211_is_nullfunc(hdr->frame_control))
|
|
|
+ if (ieee80211_is_mgmt(hdr->frame_control)) {
|
|
|
+ if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
|
|
+ ar->fw_features)) {
|
|
|
+ if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
|
|
|
+ ATH10K_MAX_NUM_MGMT_PENDING) {
|
|
|
+ ath10k_warn("wmi mgmt_tx queue limit reached\n");
|
|
|
+ ret = -EBUSY;
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ skb_queue_tail(&ar->wmi_mgmt_tx_queue, skb);
|
|
|
+ ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
|
|
|
+ } else {
|
|
|
+ ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
|
|
|
+ }
|
|
|
+ } else if (!test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
|
|
|
+ ar->fw_features) &&
|
|
|
+ ieee80211_is_nullfunc(hdr->frame_control)) {
|
|
|
/* FW does not report tx status properly for NullFunc frames
|
|
|
* unless they are sent through mgmt tx path. mac80211 sends
|
|
|
- * those frames when it detects link/beacon loss and depends on
|
|
|
- * the tx status to be correct. */
|
|
|
+ * those frames when it detects link/beacon loss and depends
|
|
|
+ * on the tx status to be correct. */
|
|
|
ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
|
|
|
- else
|
|
|
+ } else {
|
|
|
ret = ath10k_htt_tx(&ar->htt, skb);
|
|
|
+ }
|
|
|
|
|
|
exit:
|
|
|
if (ret) {
|
|
@@ -1557,7 +1647,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
|
|
|
|
|
hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
peer_addr = ieee80211_get_DA(hdr);
|
|
|
- vdev_id = ATH10K_SKB_CB(skb)->htt.vdev_id;
|
|
|
+ vdev_id = ATH10K_SKB_CB(skb)->vdev_id;
|
|
|
|
|
|
spin_lock_bh(&ar->data_lock);
|
|
|
peer = ath10k_peer_find(ar, vdev_id, peer_addr);
|
|
@@ -1599,6 +1689,36 @@ void ath10k_offchan_tx_work(struct work_struct *work)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar)
|
|
|
+{
|
|
|
+ struct sk_buff *skb;
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ skb = skb_dequeue(&ar->wmi_mgmt_tx_queue);
|
|
|
+ if (!skb)
|
|
|
+ break;
|
|
|
+
|
|
|
+ ieee80211_free_txskb(ar->hw, skb);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work);
|
|
|
+ struct sk_buff *skb;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ skb = skb_dequeue(&ar->wmi_mgmt_tx_queue);
|
|
|
+ if (!skb)
|
|
|
+ break;
|
|
|
+
|
|
|
+ ret = ath10k_wmi_mgmt_tx(ar, skb);
|
|
|
+ if (ret)
|
|
|
+ ath10k_warn("wmi mgmt_tx failed (%d)\n", ret);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/************/
|
|
|
/* Scanning */
|
|
|
/************/
|
|
@@ -1722,16 +1842,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
|
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
struct ath10k *ar = hw->priv;
|
|
|
- struct ath10k_vif *arvif = NULL;
|
|
|
- u32 vdev_id = 0;
|
|
|
- u8 tid;
|
|
|
-
|
|
|
- if (info->control.vif) {
|
|
|
- arvif = ath10k_vif_to_arvif(info->control.vif);
|
|
|
- vdev_id = arvif->vdev_id;
|
|
|
- } else if (ar->monitor_enabled) {
|
|
|
- vdev_id = ar->monitor_vdev_id;
|
|
|
- }
|
|
|
+ u8 tid, vdev_id;
|
|
|
|
|
|
/* We should disable CCK RATE due to P2P */
|
|
|
if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
|
|
@@ -1739,14 +1850,8 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
|
|
|
|
|
/* we must calculate tid before we apply qos workaround
|
|
|
* as we'd lose the qos control field */
|
|
|
- tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
|
|
|
- if (ieee80211_is_mgmt(hdr->frame_control)) {
|
|
|
- tid = HTT_DATA_TX_EXT_TID_MGMT;
|
|
|
- } else if (ieee80211_is_data_qos(hdr->frame_control) &&
|
|
|
- is_unicast_ether_addr(ieee80211_get_DA(hdr))) {
|
|
|
- u8 *qc = ieee80211_get_qos_ctl(hdr);
|
|
|
- tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
|
|
|
- }
|
|
|
+ tid = ath10k_tx_h_get_tid(hdr);
|
|
|
+ vdev_id = ath10k_tx_h_get_vdev_id(ar, info);
|
|
|
|
|
|
/* it makes no sense to process injected frames like that */
|
|
|
if (info->control.vif &&
|
|
@@ -1757,14 +1862,14 @@ static void ath10k_tx(struct ieee80211_hw *hw,
|
|
|
ath10k_tx_h_seq_no(skb);
|
|
|
}
|
|
|
|
|
|
+ ATH10K_SKB_CB(skb)->vdev_id = vdev_id;
|
|
|
ATH10K_SKB_CB(skb)->htt.is_offchan = false;
|
|
|
- ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id;
|
|
|
ATH10K_SKB_CB(skb)->htt.tid = tid;
|
|
|
|
|
|
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
|
|
|
spin_lock_bh(&ar->data_lock);
|
|
|
ATH10K_SKB_CB(skb)->htt.is_offchan = true;
|
|
|
- ATH10K_SKB_CB(skb)->htt.vdev_id = ar->scan.vdev_id;
|
|
|
+ ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
|
|
|
spin_unlock_bh(&ar->data_lock);
|
|
|
|
|
|
ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb);
|
|
@@ -1786,6 +1891,7 @@ void ath10k_halt(struct ath10k *ar)
|
|
|
|
|
|
del_timer_sync(&ar->scan.timeout);
|
|
|
ath10k_offchan_tx_purge(ar);
|
|
|
+ ath10k_mgmt_over_wmi_tx_purge(ar);
|
|
|
ath10k_peer_cleanup_all(ar);
|
|
|
ath10k_core_stop(ar);
|
|
|
ath10k_hif_power_down(ar);
|
|
@@ -1832,12 +1938,12 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
|
|
else if (ar->state == ATH10K_STATE_RESTARTING)
|
|
|
ar->state = ATH10K_STATE_RESTARTED;
|
|
|
|
|
|
- ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1);
|
|
|
+ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
|
|
|
if (ret)
|
|
|
ath10k_warn("could not enable WMI_PDEV_PARAM_PMF_QOS (%d)\n",
|
|
|
ret);
|
|
|
|
|
|
- ret = ath10k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 0);
|
|
|
+ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 0);
|
|
|
if (ret)
|
|
|
ath10k_warn("could not init WMI_PDEV_PARAM_DYNAMIC_BW (%d)\n",
|
|
|
ret);
|
|
@@ -1862,32 +1968,29 @@ static void ath10k_stop(struct ieee80211_hw *hw)
|
|
|
ar->state = ATH10K_STATE_OFF;
|
|
|
mutex_unlock(&ar->conf_mutex);
|
|
|
|
|
|
+ ath10k_mgmt_over_wmi_tx_purge(ar);
|
|
|
+
|
|
|
cancel_work_sync(&ar->offchan_tx_work);
|
|
|
+ cancel_work_sync(&ar->wmi_mgmt_tx_work);
|
|
|
cancel_work_sync(&ar->restart_work);
|
|
|
}
|
|
|
|
|
|
-static void ath10k_config_ps(struct ath10k *ar)
|
|
|
+static int ath10k_config_ps(struct ath10k *ar)
|
|
|
{
|
|
|
- struct ath10k_generic_iter ar_iter;
|
|
|
+ struct ath10k_vif *arvif;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
lockdep_assert_held(&ar->conf_mutex);
|
|
|
|
|
|
- /* During HW reconfiguration mac80211 reports all interfaces that were
|
|
|
- * running until reconfiguration was started. Since FW doesn't have any
|
|
|
- * vdevs at this point we must not iterate over this interface list.
|
|
|
- * This setting will be updated upon add_interface(). */
|
|
|
- if (ar->state == ATH10K_STATE_RESTARTED)
|
|
|
- return;
|
|
|
-
|
|
|
- memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
|
|
|
- ar_iter.ar = ar;
|
|
|
-
|
|
|
- ieee80211_iterate_active_interfaces_atomic(
|
|
|
- ar->hw, IEEE80211_IFACE_ITER_NORMAL,
|
|
|
- ath10k_ps_iter, &ar_iter);
|
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
|
+ ret = ath10k_mac_vif_setup_ps(arvif);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("could not setup powersave (%d)\n", ret);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (ar_iter.ret)
|
|
|
- ath10k_warn("failed to set ps config (%d)\n", ar_iter.ret);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
|
|
@@ -1936,6 +2039,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
int ret = 0;
|
|
|
u32 value;
|
|
|
int bit;
|
|
|
+ u32 vdev_param;
|
|
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
|
|
@@ -1944,21 +2048,22 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
arvif->ar = ar;
|
|
|
arvif->vif = vif;
|
|
|
|
|
|
+ INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
|
|
|
+
|
|
|
if ((vif->type == NL80211_IFTYPE_MONITOR) && ar->monitor_present) {
|
|
|
ath10k_warn("Only one monitor interface allowed\n");
|
|
|
ret = -EBUSY;
|
|
|
- goto exit;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
bit = ffs(ar->free_vdev_map);
|
|
|
if (bit == 0) {
|
|
|
ret = -EBUSY;
|
|
|
- goto exit;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
arvif->vdev_id = bit - 1;
|
|
|
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
|
|
|
- ar->free_vdev_map &= ~(1 << arvif->vdev_id);
|
|
|
|
|
|
if (ar->p2p)
|
|
|
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
|
|
@@ -1994,25 +2099,34 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
arvif->vdev_subtype, vif->addr);
|
|
|
if (ret) {
|
|
|
ath10k_warn("WMI vdev create failed: ret %d\n", ret);
|
|
|
- goto exit;
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_set_param(ar, 0, WMI_VDEV_PARAM_DEF_KEYID,
|
|
|
- arvif->def_wep_key_index);
|
|
|
- if (ret)
|
|
|
+ ar->free_vdev_map &= ~BIT(arvif->vdev_id);
|
|
|
+ list_add(&arvif->list, &ar->arvifs);
|
|
|
+
|
|
|
+ vdev_param = ar->wmi.vdev_param->def_keyid;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
|
|
|
+ arvif->def_wep_key_idx);
|
|
|
+ if (ret) {
|
|
|
ath10k_warn("Failed to set default keyid: %d\n", ret);
|
|
|
+ goto err_vdev_delete;
|
|
|
+ }
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_TX_ENCAP_TYPE,
|
|
|
+ vdev_param = ar->wmi.vdev_param->tx_encap_type;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
|
|
ATH10K_HW_TXRX_NATIVE_WIFI);
|
|
|
- if (ret)
|
|
|
+ /* 10.X firmware does not support this VDEV parameter. Do not warn */
|
|
|
+ if (ret && ret != -EOPNOTSUPP) {
|
|
|
ath10k_warn("Failed to set TX encap: %d\n", ret);
|
|
|
+ goto err_vdev_delete;
|
|
|
+ }
|
|
|
|
|
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
|
|
ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
|
|
|
if (ret) {
|
|
|
ath10k_warn("Failed to create peer for AP: %d\n", ret);
|
|
|
- goto exit;
|
|
|
+ goto err_vdev_delete;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2021,39 +2135,62 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
|
|
value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
|
|
|
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
|
|
param, value);
|
|
|
- if (ret)
|
|
|
+ if (ret) {
|
|
|
ath10k_warn("Failed to set RX wake policy: %d\n", ret);
|
|
|
+ goto err_peer_delete;
|
|
|
+ }
|
|
|
|
|
|
param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
|
|
|
value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
|
|
|
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
|
|
param, value);
|
|
|
- if (ret)
|
|
|
+ if (ret) {
|
|
|
ath10k_warn("Failed to set TX wake thresh: %d\n", ret);
|
|
|
+ goto err_peer_delete;
|
|
|
+ }
|
|
|
|
|
|
param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
|
|
|
value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
|
|
|
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
|
|
|
param, value);
|
|
|
- if (ret)
|
|
|
+ if (ret) {
|
|
|
ath10k_warn("Failed to set PSPOLL count: %d\n", ret);
|
|
|
+ goto err_peer_delete;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
|
|
|
- if (ret)
|
|
|
+ if (ret) {
|
|
|
ath10k_warn("failed to set rts threshold for vdev %d (%d)\n",
|
|
|
arvif->vdev_id, ret);
|
|
|
+ goto err_peer_delete;
|
|
|
+ }
|
|
|
|
|
|
ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
|
|
|
- if (ret)
|
|
|
+ if (ret) {
|
|
|
ath10k_warn("failed to set frag threshold for vdev %d (%d)\n",
|
|
|
arvif->vdev_id, ret);
|
|
|
+ goto err_peer_delete;
|
|
|
+ }
|
|
|
|
|
|
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
|
|
ar->monitor_present = true;
|
|
|
|
|
|
-exit:
|
|
|
mutex_unlock(&ar->conf_mutex);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err_peer_delete:
|
|
|
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP)
|
|
|
+ ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr);
|
|
|
+
|
|
|
+err_vdev_delete:
|
|
|
+ ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
|
|
|
+ ar->free_vdev_map &= ~BIT(arvif->vdev_id);
|
|
|
+ list_del(&arvif->list);
|
|
|
+
|
|
|
+err:
|
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -2066,6 +2203,8 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
|
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
|
|
|
+ cancel_work_sync(&arvif->wep_key_work);
|
|
|
+
|
|
|
spin_lock_bh(&ar->data_lock);
|
|
|
if (arvif->beacon) {
|
|
|
dev_kfree_skb_any(arvif->beacon);
|
|
@@ -2074,6 +2213,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
|
|
|
spin_unlock_bh(&ar->data_lock);
|
|
|
|
|
|
ar->free_vdev_map |= 1 << (arvif->vdev_id);
|
|
|
+ list_del(&arvif->list);
|
|
|
|
|
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
|
|
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
|
|
@@ -2154,6 +2294,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
struct ath10k *ar = hw->priv;
|
|
|
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
|
|
int ret = 0;
|
|
|
+ u32 vdev_param, pdev_param;
|
|
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
|
|
@@ -2162,8 +2303,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
|
|
|
if (changed & BSS_CHANGED_BEACON_INT) {
|
|
|
arvif->beacon_interval = info->beacon_int;
|
|
|
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_BEACON_INTERVAL,
|
|
|
+ vdev_param = ar->wmi.vdev_param->beacon_interval;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
|
|
arvif->beacon_interval);
|
|
|
ath10k_dbg(ATH10K_DBG_MAC,
|
|
|
"mac vdev %d beacon_interval %d\n",
|
|
@@ -2179,8 +2320,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
"vdev %d set beacon tx mode to staggered\n",
|
|
|
arvif->vdev_id);
|
|
|
|
|
|
- ret = ath10k_wmi_pdev_set_param(ar,
|
|
|
- WMI_PDEV_PARAM_BEACON_TX_MODE,
|
|
|
+ pdev_param = ar->wmi.pdev_param->beacon_tx_mode;
|
|
|
+ ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
|
|
|
WMI_BEACON_STAGGERED_MODE);
|
|
|
if (ret)
|
|
|
ath10k_warn("Failed to set beacon mode for VDEV: %d\n",
|
|
@@ -2194,8 +2335,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
"mac vdev %d dtim_period %d\n",
|
|
|
arvif->vdev_id, arvif->dtim_period);
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_DTIM_PERIOD,
|
|
|
+ vdev_param = ar->wmi.vdev_param->dtim_period;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
|
|
arvif->dtim_period);
|
|
|
if (ret)
|
|
|
ath10k_warn("Failed to set dtim period for VDEV: %d\n",
|
|
@@ -2262,8 +2403,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
|
|
|
arvif->vdev_id, cts_prot);
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_ENABLE_RTSCTS,
|
|
|
+ vdev_param = ar->wmi.vdev_param->enable_rtscts;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
|
|
cts_prot);
|
|
|
if (ret)
|
|
|
ath10k_warn("Failed to set CTS prot for VDEV: %d\n",
|
|
@@ -2281,8 +2422,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
|
|
|
arvif->vdev_id, slottime);
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_SLOT_TIME,
|
|
|
+ vdev_param = ar->wmi.vdev_param->slot_time;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
|
|
slottime);
|
|
|
if (ret)
|
|
|
ath10k_warn("Failed to set erp slot for VDEV: %d\n",
|
|
@@ -2300,8 +2441,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
"mac vdev %d preamble %dn",
|
|
|
arvif->vdev_id, preamble);
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
|
|
|
- WMI_VDEV_PARAM_PREAMBLE,
|
|
|
+ vdev_param = ar->wmi.vdev_param->preamble;
|
|
|
+ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
|
|
|
preamble);
|
|
|
if (ret)
|
|
|
ath10k_warn("Failed to set preamble for VDEV: %d\n",
|
|
@@ -2751,86 +2892,51 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw)
|
|
|
* Both RTS and Fragmentation threshold are interface-specific
|
|
|
* in ath10k, but device-specific in mac80211.
|
|
|
*/
|
|
|
-static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|
|
-{
|
|
|
- struct ath10k_generic_iter *ar_iter = data;
|
|
|
- struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
|
|
- u32 rts = ar_iter->ar->hw->wiphy->rts_threshold;
|
|
|
-
|
|
|
- lockdep_assert_held(&arvif->ar->conf_mutex);
|
|
|
-
|
|
|
- /* During HW reconfiguration mac80211 reports all interfaces that were
|
|
|
- * running until reconfiguration was started. Since FW doesn't have any
|
|
|
- * vdevs at this point we must not iterate over this interface list.
|
|
|
- * This setting will be updated upon add_interface(). */
|
|
|
- if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
|
|
|
- return;
|
|
|
-
|
|
|
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts_threshold %d\n",
|
|
|
- arvif->vdev_id, rts);
|
|
|
-
|
|
|
- ar_iter->ret = ath10k_mac_set_rts(arvif, rts);
|
|
|
- if (ar_iter->ret)
|
|
|
- ath10k_warn("Failed to set RTS threshold for VDEV: %d\n",
|
|
|
- arvif->vdev_id);
|
|
|
-}
|
|
|
|
|
|
static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
|
|
{
|
|
|
- struct ath10k_generic_iter ar_iter;
|
|
|
struct ath10k *ar = hw->priv;
|
|
|
-
|
|
|
- memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
|
|
|
- ar_iter.ar = ar;
|
|
|
+ struct ath10k_vif *arvif;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
- ieee80211_iterate_active_interfaces_atomic(
|
|
|
- hw, IEEE80211_IFACE_ITER_NORMAL,
|
|
|
- ath10k_set_rts_iter, &ar_iter);
|
|
|
- mutex_unlock(&ar->conf_mutex);
|
|
|
-
|
|
|
- return ar_iter.ret;
|
|
|
-}
|
|
|
-
|
|
|
-static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
|
|
-{
|
|
|
- struct ath10k_generic_iter *ar_iter = data;
|
|
|
- struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
|
|
- u32 frag = ar_iter->ar->hw->wiphy->frag_threshold;
|
|
|
-
|
|
|
- lockdep_assert_held(&arvif->ar->conf_mutex);
|
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
|
+ ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
|
|
|
+ arvif->vdev_id, value);
|
|
|
|
|
|
- /* During HW reconfiguration mac80211 reports all interfaces that were
|
|
|
- * running until reconfiguration was started. Since FW doesn't have any
|
|
|
- * vdevs at this point we must not iterate over this interface list.
|
|
|
- * This setting will be updated upon add_interface(). */
|
|
|
- if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
|
|
|
- return;
|
|
|
-
|
|
|
- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation_threshold %d\n",
|
|
|
- arvif->vdev_id, frag);
|
|
|
+ ret = ath10k_mac_set_rts(arvif, value);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("could not set rts threshold for vdev %d (%d)\n",
|
|
|
+ arvif->vdev_id, ret);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
|
|
|
|
- ar_iter->ret = ath10k_mac_set_frag(arvif, frag);
|
|
|
- if (ar_iter->ret)
|
|
|
- ath10k_warn("Failed to set frag threshold for VDEV: %d\n",
|
|
|
- arvif->vdev_id);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
|
|
|
{
|
|
|
- struct ath10k_generic_iter ar_iter;
|
|
|
struct ath10k *ar = hw->priv;
|
|
|
-
|
|
|
- memset(&ar_iter, 0, sizeof(struct ath10k_generic_iter));
|
|
|
- ar_iter.ar = ar;
|
|
|
+ struct ath10k_vif *arvif;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
- ieee80211_iterate_active_interfaces_atomic(
|
|
|
- hw, IEEE80211_IFACE_ITER_NORMAL,
|
|
|
- ath10k_set_frag_iter, &ar_iter);
|
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
|
+ ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
|
|
|
+ arvif->vdev_id, value);
|
|
|
+
|
|
|
+ ret = ath10k_mac_set_rts(arvif, value);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("could not set fragmentation threshold for vdev %d (%d)\n",
|
|
|
+ arvif->vdev_id, ret);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
mutex_unlock(&ar->conf_mutex);
|
|
|
|
|
|
- return ar_iter.ret;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|