aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/intel/iwlwifi/mvm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c367
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c19
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c106
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c44
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c269
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/nvm.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c194
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/power.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.c182
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.h17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rx.c39
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c119
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c117
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c54
20 files changed, 1037 insertions, 599 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 0e97d5e6c644..a19f646a324f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -160,6 +160,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
mvm->ptk_icvlen = key->icv_len;
mvm->gtk_ivlen = key->iv_len;
mvm->gtk_icvlen = key->icv_len;
+ mutex_unlock(&mvm->mutex);
/* don't upload key again */
return;
@@ -360,11 +361,11 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw,
if (sta) {
rsc = data->rsc->ucast_rsc;
} else {
- if (WARN_ON(data->gtks > ARRAY_SIZE(data->gtk_ids)))
+ if (WARN_ON(data->gtks >= ARRAY_SIZE(data->gtk_ids)))
return;
data->gtk_ids[data->gtks] = key->keyidx;
rsc = data->rsc->mcast_rsc[data->gtks % 2];
- if (WARN_ON(key->keyidx >
+ if (WARN_ON(key->keyidx >=
ARRAY_SIZE(data->rsc->mcast_key_id_map)))
return;
data->rsc->mcast_key_id_map[key->keyidx] = data->gtks % 2;
@@ -1378,12 +1379,49 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
/* converted data from the different status responses */
struct iwl_wowlan_status_data {
- u16 pattern_number;
- u16 qos_seq_ctr[8];
+ u64 replay_ctr;
+ u32 num_of_gtk_rekeys;
+ u32 received_beacons;
u32 wakeup_reasons;
u32 wake_packet_length;
u32 wake_packet_bufsize;
- const u8 *wake_packet;
+ u16 pattern_number;
+ u16 non_qos_seq_ctr;
+ u16 qos_seq_ctr[8];
+ u8 tid_tear_down;
+
+ struct {
+ /*
+ * We store both the TKIP and AES representations
+ * coming from the firmware because we decode the
+ * data from there before we iterate the keys and
+ * know which one we need.
+ */
+ struct {
+ struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT];
+ } tkip, aes;
+ /* including RX MIC key for TKIP */
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ u8 len;
+ u8 flags;
+ } gtk;
+
+ struct {
+ /* Same as above */
+ struct {
+ struct ieee80211_key_seq seq[IWL_MAX_TID_COUNT];
+ u64 tx_pn;
+ } tkip, aes;
+ } ptk;
+
+ struct {
+ u64 ipn;
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ u8 len;
+ u8 flags;
+ } igtk;
+
+ u8 wake_packet[];
};
static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm,
@@ -1539,77 +1577,90 @@ static void iwl_mvm_tkip_sc_to_seq(struct tkip_sc *sc,
seq->tkip.iv16 = le16_to_cpu(sc->iv16);
}
-static void iwl_mvm_set_aes_rx_seq(struct iwl_mvm *mvm, struct aes_sc *scs,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
+static void iwl_mvm_set_key_rx_seq_tids(struct ieee80211_key_conf *key,
+ struct ieee80211_key_seq *seq)
{
int tid;
- BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
+ for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
+ ieee80211_set_key_rx_seq(key, tid, &seq[tid]);
+}
- if (sta && iwl_mvm_has_new_rx_api(mvm)) {
- struct iwl_mvm_sta *mvmsta;
- struct iwl_mvm_key_pn *ptk_pn;
+static void iwl_mvm_set_aes_ptk_rx_seq(struct iwl_mvm *mvm,
+ struct iwl_wowlan_status_data *status,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_mvm_key_pn *ptk_pn;
+ int tid;
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ iwl_mvm_set_key_rx_seq_tids(key, status->ptk.aes.seq);
- rcu_read_lock();
- ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]);
- if (WARN_ON(!ptk_pn)) {
- rcu_read_unlock();
- return;
- }
+ if (!iwl_mvm_has_new_rx_api(mvm))
+ return;
- for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
- struct ieee80211_key_seq seq = {};
- int i;
- iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
- ieee80211_set_key_rx_seq(key, tid, &seq);
- for (i = 1; i < mvm->trans->num_rx_queues; i++)
- memcpy(ptk_pn->q[i].pn[tid],
- seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
- }
+ rcu_read_lock();
+ ptk_pn = rcu_dereference(mvmsta->ptk_pn[key->keyidx]);
+ if (WARN_ON(!ptk_pn)) {
rcu_read_unlock();
- } else {
- for (tid = 0; tid < IWL_NUM_RSC; tid++) {
- struct ieee80211_key_seq seq = {};
+ return;
+ }
- iwl_mvm_aes_sc_to_seq(&scs[tid], &seq);
- ieee80211_set_key_rx_seq(key, tid, &seq);
- }
+ for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+ int i;
+
+ for (i = 1; i < mvm->trans->num_rx_queues; i++)
+ memcpy(ptk_pn->q[i].pn[tid],
+ status->ptk.aes.seq[tid].ccmp.pn,
+ IEEE80211_CCMP_PN_LEN);
}
+ rcu_read_unlock();
}
-static void iwl_mvm_set_tkip_rx_seq(struct tkip_sc *scs,
- struct ieee80211_key_conf *key)
+static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status,
+ union iwl_all_tsc_rsc *sc)
{
- int tid;
+ int i;
+
+ BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_MAX_TID_COUNT);
+ BUILD_BUG_ON(IWL_MAX_TID_COUNT > IWL_NUM_RSC);
- BUILD_BUG_ON(IWL_NUM_RSC != IEEE80211_NUM_TIDS);
+ /* GTK RX counters */
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ iwl_mvm_tkip_sc_to_seq(&sc->tkip.multicast_rsc[i],
+ &status->gtk.tkip.seq[i]);
+ iwl_mvm_aes_sc_to_seq(&sc->aes.multicast_rsc[i],
+ &status->gtk.aes.seq[i]);
+ }
- for (tid = 0; tid < IWL_NUM_RSC; tid++) {
- struct ieee80211_key_seq seq = {};
+ /* PTK TX counter */
+ status->ptk.tkip.tx_pn = (u64)le16_to_cpu(sc->tkip.tsc.iv16) |
+ ((u64)le32_to_cpu(sc->tkip.tsc.iv32) << 16);
+ status->ptk.aes.tx_pn = le64_to_cpu(sc->aes.tsc.pn);
- iwl_mvm_tkip_sc_to_seq(&scs[tid], &seq);
- ieee80211_set_key_rx_seq(key, tid, &seq);
+ /* PTK RX counters */
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ iwl_mvm_tkip_sc_to_seq(&sc->tkip.unicast_rsc[i],
+ &status->ptk.tkip.seq[i]);
+ iwl_mvm_aes_sc_to_seq(&sc->aes.unicast_rsc[i],
+ &status->ptk.aes.seq[i]);
}
}
static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm,
struct ieee80211_key_conf *key,
- struct iwl_wowlan_status *status)
+ struct iwl_wowlan_status_data *status)
{
- union iwl_all_tsc_rsc *rsc = &status->gtk[0].rsc.all_tsc_rsc;
-
switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
- iwl_mvm_set_aes_rx_seq(mvm, rsc->aes.multicast_rsc, NULL, key);
+ iwl_mvm_set_key_rx_seq_tids(key, status->gtk.aes.seq);
break;
case WLAN_CIPHER_SUITE_TKIP:
- iwl_mvm_set_tkip_rx_seq(rsc->tkip.multicast_rsc, key);
+ iwl_mvm_set_key_rx_seq_tids(key, status->gtk.tkip.seq);
break;
default:
WARN_ON(1);
@@ -1618,7 +1669,7 @@ static void iwl_mvm_set_key_rx_seq(struct iwl_mvm *mvm,
struct iwl_mvm_d3_gtk_iter_data {
struct iwl_mvm *mvm;
- struct iwl_wowlan_status *status;
+ struct iwl_wowlan_status_data *status;
void *last_gtk;
u32 cipher;
bool find_phase, unhandled_cipher;
@@ -1632,6 +1683,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
void *_data)
{
struct iwl_mvm_d3_gtk_iter_data *data = _data;
+ struct iwl_wowlan_status_data *status = data->status;
if (data->unhandled_cipher)
return;
@@ -1660,10 +1712,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
* note that this assumes no TDLS sessions are active
*/
if (sta) {
- struct ieee80211_key_seq seq = {};
- union iwl_all_tsc_rsc *sc =
- &data->status->gtk[0].rsc.all_tsc_rsc;
-
if (data->find_phase)
return;
@@ -1671,16 +1719,12 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
- iwl_mvm_set_aes_rx_seq(data->mvm, sc->aes.unicast_rsc,
- sta, key);
- atomic64_set(&key->tx_pn, le64_to_cpu(sc->aes.tsc.pn));
+ atomic64_set(&key->tx_pn, status->ptk.aes.tx_pn);
+ iwl_mvm_set_aes_ptk_rx_seq(data->mvm, status, sta, key);
break;
case WLAN_CIPHER_SUITE_TKIP:
- iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq);
- iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key);
- atomic64_set(&key->tx_pn,
- (u64)seq.tkip.iv16 |
- ((u64)seq.tkip.iv32 << 16));
+ atomic64_set(&key->tx_pn, status->ptk.tkip.tx_pn);
+ iwl_mvm_set_key_rx_seq_tids(key, status->ptk.tkip.seq);
break;
}
@@ -1702,7 +1746,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- struct iwl_wowlan_status *status)
+ struct iwl_wowlan_status_data *status)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_d3_gtk_iter_data gtkdata = {
@@ -1716,7 +1760,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
if (!status || !vif->bss_conf.bssid)
return false;
- if (le32_to_cpu(status->wakeup_reasons) & disconnection_reasons)
+ if (status->wakeup_reasons & disconnection_reasons)
return false;
/* find last GTK that we used initially, if any */
@@ -1740,7 +1784,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
iwl_mvm_d3_update_keys, &gtkdata);
IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n",
- le32_to_cpu(status->num_of_gtk_rekeys));
+ status->num_of_gtk_rekeys);
if (status->num_of_gtk_rekeys) {
struct ieee80211_key_conf *key;
struct {
@@ -1749,36 +1793,32 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
} conf = {
.conf.cipher = gtkdata.cipher,
.conf.keyidx =
- iwlmvm_wowlan_gtk_idx(&status->gtk[0]),
+ status->gtk.flags & IWL_WOWLAN_GTK_IDX_MASK,
};
__be64 replay_ctr;
IWL_DEBUG_WOWLAN(mvm,
"Received from FW GTK cipher %d, key index %d\n",
conf.conf.cipher, conf.conf.keyidx);
+
+ BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);
+ BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk.key));
+
+ memcpy(conf.conf.key, status->gtk.key, sizeof(status->gtk.key));
+
switch (gtkdata.cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_GCMP:
- BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);
conf.conf.keylen = WLAN_KEY_LEN_CCMP;
- memcpy(conf.conf.key, status->gtk[0].key,
- WLAN_KEY_LEN_CCMP);
break;
case WLAN_CIPHER_SUITE_GCMP_256:
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);
conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;
- memcpy(conf.conf.key, status->gtk[0].key,
- WLAN_KEY_LEN_GCMP_256);
break;
case WLAN_CIPHER_SUITE_TKIP:
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);
conf.conf.keylen = WLAN_KEY_LEN_TKIP;
- memcpy(conf.conf.key, status->gtk[0].key, 16);
- /* leave TX MIC key zeroed, we don't use it anyway */
- memcpy(conf.conf.key +
- NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
- status->gtk[0].tkip_mic_key, 8);
break;
}
@@ -1787,8 +1827,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
return false;
iwl_mvm_set_key_rx_seq(mvm, key, status);
- replay_ctr =
- cpu_to_be64(le64_to_cpu(status->replay_ctr));
+ replay_ctr = cpu_to_be64(status->replay_ctr);
ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
(void *)&replay_ctr, GFP_KERNEL);
@@ -1799,7 +1838,7 @@ out:
WOWLAN_GET_STATUSES, 0) < 10) {
mvmvif->seqno_valid = true;
/* +0x10 because the set API expects next-to-use, not last-used */
- mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10;
+ mvmvif->seqno = status->non_qos_seq_ctr + 0x10;
}
return true;
@@ -1807,13 +1846,13 @@ out:
/* Occasionally, templates would be nice. This is one of those times ... */
#define iwl_mvm_parse_wowlan_status_common(_ver) \
-static struct iwl_wowlan_status * \
+static struct iwl_wowlan_status_data * \
iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \
- void *_data, int len) \
+ struct iwl_wowlan_status_ ##_ver *data,\
+ int len) \
{ \
- struct iwl_wowlan_status *status; \
- struct iwl_wowlan_status_ ##_ver *data = _data; \
- int data_size; \
+ struct iwl_wowlan_status_data *status; \
+ int data_size, i; \
\
if (len < sizeof(*data)) { \
IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); \
@@ -1831,18 +1870,22 @@ iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \
return ERR_PTR(-ENOMEM); \
\
/* copy all the common fields */ \
- status->replay_ctr = data->replay_ctr; \
- status->pattern_number = data->pattern_number; \
- status->non_qos_seq_ctr = data->non_qos_seq_ctr; \
- memcpy(status->qos_seq_ctr, data->qos_seq_ctr, \
- sizeof(status->qos_seq_ctr)); \
- status->wakeup_reasons = data->wakeup_reasons; \
- status->num_of_gtk_rekeys = data->num_of_gtk_rekeys; \
- status->received_beacons = data->received_beacons; \
- status->wake_packet_length = data->wake_packet_length; \
- status->wake_packet_bufsize = data->wake_packet_bufsize; \
+ status->replay_ctr = le64_to_cpu(data->replay_ctr); \
+ status->pattern_number = le16_to_cpu(data->pattern_number); \
+ status->non_qos_seq_ctr = le16_to_cpu(data->non_qos_seq_ctr); \
+ for (i = 0; i < 8; i++) \
+ status->qos_seq_ctr[i] = \
+ le16_to_cpu(data->qos_seq_ctr[i]); \
+ status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons); \
+ status->num_of_gtk_rekeys = \
+ le32_to_cpu(data->num_of_gtk_rekeys); \
+ status->received_beacons = le32_to_cpu(data->received_beacons); \
+ status->wake_packet_length = \
+ le32_to_cpu(data->wake_packet_length); \
+ status->wake_packet_bufsize = \
+ le32_to_cpu(data->wake_packet_bufsize); \
memcpy(status->wake_packet, data->wake_packet, \
- le32_to_cpu(status->wake_packet_bufsize)); \
+ status->wake_packet_bufsize); \
\
return status; \
}
@@ -1851,10 +1894,49 @@ iwl_mvm_parse_wowlan_status_common(v6)
iwl_mvm_parse_wowlan_status_common(v7)
iwl_mvm_parse_wowlan_status_common(v9)
-static struct iwl_wowlan_status *
+static void iwl_mvm_convert_gtk(struct iwl_wowlan_status_data *status,
+ struct iwl_wowlan_gtk_status *data)
+{
+ BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key));
+ BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
+ sizeof(data->tkip_mic_key) >
+ sizeof(status->gtk.key));
+
+ status->gtk.len = data->key_len;
+ status->gtk.flags = data->key_flags;
+
+ memcpy(status->gtk.key, data->key, sizeof(data->key));
+
+ /* if it's as long as the TKIP encryption key, copy MIC key */
+ if (status->gtk.len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
+ memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
+ data->tkip_mic_key, sizeof(data->tkip_mic_key));
+}
+
+static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
+ struct iwl_wowlan_igtk_status *data)
+{
+ const u8 *ipn = data->ipn;
+
+ BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key));
+
+ status->igtk.len = data->key_len;
+ status->igtk.flags = data->key_flags;
+
+ memcpy(status->igtk.key, data->key, sizeof(data->key));
+
+ status->igtk.ipn = ((u64)ipn[5] << 0) |
+ ((u64)ipn[4] << 8) |
+ ((u64)ipn[3] << 16) |
+ ((u64)ipn[2] << 24) |
+ ((u64)ipn[1] << 32) |
+ ((u64)ipn[0] << 40);
+}
+
+static struct iwl_wowlan_status_data *
iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
{
- struct iwl_wowlan_status *status;
+ struct iwl_wowlan_status_data *status;
struct iwl_wowlan_get_status_cmd get_status_cmd = {
.sta_id = cpu_to_le32(sta_id),
};
@@ -1894,59 +1976,57 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) {
struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data;
- status = iwl_mvm_parse_wowlan_status_common_v6(mvm,
- cmd.resp_pkt->data,
- len);
+ status = iwl_mvm_parse_wowlan_status_common_v6(mvm, v6, len);
if (IS_ERR(status))
goto out_free_resp;
BUILD_BUG_ON(sizeof(v6->gtk.decrypt_key) >
- sizeof(status->gtk[0].key));
- BUILD_BUG_ON(sizeof(v6->gtk.tkip_mic_key) >
- sizeof(status->gtk[0].tkip_mic_key));
+ sizeof(status->gtk.key));
+ BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
+ sizeof(v6->gtk.tkip_mic_key) >
+ sizeof(status->gtk.key));
/* copy GTK info to the right place */
- memcpy(status->gtk[0].key, v6->gtk.decrypt_key,
+ memcpy(status->gtk.key, v6->gtk.decrypt_key,
sizeof(v6->gtk.decrypt_key));
- memcpy(status->gtk[0].tkip_mic_key, v6->gtk.tkip_mic_key,
+ memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
+ v6->gtk.tkip_mic_key,
sizeof(v6->gtk.tkip_mic_key));
- memcpy(&status->gtk[0].rsc, &v6->gtk.rsc,
- sizeof(status->gtk[0].rsc));
+
+ iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc);
/* hardcode the key length to 16 since v6 only supports 16 */
- status->gtk[0].key_len = 16;
+ status->gtk.len = 16;
/*
* The key index only uses 2 bits (values 0 to 3) and
* we always set bit 7 which means this is the
* currently used key.
*/
- status->gtk[0].key_flags = v6->gtk.key_index | BIT(7);
+ status->gtk.flags = v6->gtk.key_index | BIT(7);
} else if (notif_ver == 7) {
struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data;
- status = iwl_mvm_parse_wowlan_status_common_v7(mvm,
- cmd.resp_pkt->data,
- len);
+ status = iwl_mvm_parse_wowlan_status_common_v7(mvm, v7, len);
if (IS_ERR(status))
goto out_free_resp;
- status->gtk[0] = v7->gtk[0];
- status->igtk[0] = v7->igtk[0];
+ iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc);
+ iwl_mvm_convert_gtk(status, &v7->gtk[0]);
+ iwl_mvm_convert_igtk(status, &v7->igtk[0]);
} else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) {
struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data;
/* these three command versions have same layout and size, the
* difference is only in a few not used (reserved) fields.
*/
- status = iwl_mvm_parse_wowlan_status_common_v9(mvm,
- cmd.resp_pkt->data,
- len);
+ status = iwl_mvm_parse_wowlan_status_common_v9(mvm, v9, len);
if (IS_ERR(status))
goto out_free_resp;
- status->gtk[0] = v9->gtk[0];
- status->igtk[0] = v9->igtk[0];
+ iwl_mvm_convert_key_counters(status, &v9->gtk[0].rsc.all_tsc_rsc);
+ iwl_mvm_convert_gtk(status, &v9->gtk[0]);
+ iwl_mvm_convert_igtk(status, &v9->igtk[0]);
status->tid_tear_down = v9->tid_tear_down;
} else {
@@ -1961,7 +2041,7 @@ out_free_resp:
return status;
}
-static struct iwl_wowlan_status *
+static struct iwl_wowlan_status_data *
iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, u8 sta_id)
{
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
@@ -1986,29 +2066,17 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_wowlan_status_data status;
- struct iwl_wowlan_status *fw_status;
+ struct iwl_wowlan_status_data *status;
int i;
bool keep;
struct iwl_mvm_sta *mvm_ap_sta;
- fw_status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id);
- if (IS_ERR_OR_NULL(fw_status))
+ status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id);
+ if (IS_ERR(status))
goto out_unlock;
IWL_DEBUG_WOWLAN(mvm, "wakeup reason 0x%x\n",
- le32_to_cpu(fw_status->wakeup_reasons));
-
- status.pattern_number = le16_to_cpu(fw_status->pattern_number);
- for (i = 0; i < 8; i++)
- status.qos_seq_ctr[i] =
- le16_to_cpu(fw_status->qos_seq_ctr[i]);
- status.wakeup_reasons = le32_to_cpu(fw_status->wakeup_reasons);
- status.wake_packet_length =
- le32_to_cpu(fw_status->wake_packet_length);
- status.wake_packet_bufsize =
- le32_to_cpu(fw_status->wake_packet_bufsize);
- status.wake_packet = fw_status->wake_packet;
+ status->wakeup_reasons);
/* still at hard-coded place 0 for D3 image */
mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, 0);
@@ -2016,7 +2084,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
goto out_free;
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
- u16 seq = status.qos_seq_ctr[i];
+ u16 seq = status->qos_seq_ctr[i];
/* firmware stores last-used value, we store next value */
seq += 0x10;
mvm_ap_sta->tid_data[i].seq_number = seq;
@@ -2032,15 +2100,15 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
/* now we have all the data we need, unlock to avoid mac80211 issues */
mutex_unlock(&mvm->mutex);
- iwl_mvm_report_wakeup_reasons(mvm, vif, &status);
+ iwl_mvm_report_wakeup_reasons(mvm, vif, status);
- keep = iwl_mvm_setup_connection_keep(mvm, vif, fw_status);
+ keep = iwl_mvm_setup_connection_keep(mvm, vif, status);
- kfree(fw_status);
+ kfree(status);
return keep;
out_free:
- kfree(fw_status);
+ kfree(status);
out_unlock:
mutex_unlock(&mvm->mutex);
return false;
@@ -2164,16 +2232,16 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
.pattern_idx = -1,
};
struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup;
+ struct iwl_wowlan_status_data *status;
struct iwl_mvm_nd_query_results query;
- struct iwl_wowlan_status *fw_status;
unsigned long matched_profiles;
u32 reasons = 0;
int i, n_matches, ret;
- fw_status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA);
- if (!IS_ERR_OR_NULL(fw_status)) {
- reasons = le32_to_cpu(fw_status->wakeup_reasons);
- kfree(fw_status);
+ status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA);
+ if (!IS_ERR(status)) {
+ reasons = status->wakeup_reasons;
+ kfree(status);
}
if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
@@ -2335,7 +2403,6 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
false, 0);
ret = 1;
- mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
goto err;
}
@@ -2384,6 +2451,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
}
}
+ /* after the successful handshake, we're out of D3 */
mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
/*
@@ -2454,6 +2522,9 @@ out:
*/
set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);
+ /* regardless of what happened, we're now out of D3 */
+ mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+
return 1;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 5dc39fbb74d6..ff66001d507e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -395,10 +395,9 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf,
"A-MPDU size limit %d\n",
lq_sta->pers.dbg_agg_frame_count_lim);
desc += scnprintf(buff + desc, bufsz - desc,
- "valid_tx_ant %s%s%s\n",
+ "valid_tx_ant %s%s\n",
(iwl_mvm_get_valid_tx_ant(mvm) & ANT_A) ? "ANT_A," : "",
- (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : "",
- (iwl_mvm_get_valid_tx_ant(mvm) & ANT_C) ? "ANT_C" : "");
+ (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : "");
desc += scnprintf(buff + desc, bufsz - desc,
"last tx rate=0x%X ",
lq_sta->last_rate_n_flags);
@@ -986,8 +985,8 @@ static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm,
continue;
pos += scnprintf(pos, endpos - pos, "Rate[%d]: ",
(int)(ARRAY_SIZE(stats->last_rates) - i));
- pos += rs_pretty_print_rate(pos, endpos - pos,
- stats->last_rates[idx]);
+ pos += rs_pretty_print_rate_v1(pos, endpos - pos,
+ stats->last_rates[idx]);
if (pos < endpos - 1)
*pos++ = '\n';
}
@@ -1060,8 +1059,6 @@ iwl_dbgfs_scan_ant_rxchain_read(struct file *file,
pos += scnprintf(buf + pos, bufsz - pos, "A");
if (mvm->scan_rx_ant & ANT_B)
pos += scnprintf(buf + pos, bufsz - pos, "B");
- if (mvm->scan_rx_ant & ANT_C)
- pos += scnprintf(buf + pos, bufsz - pos, "C");
pos += scnprintf(buf + pos, bufsz - pos, " (%hhx)\n", mvm->scan_rx_ant);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
@@ -1196,7 +1193,6 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)
struct ieee80211_tx_info *info;
struct iwl_mac_beacon_cmd beacon_cmd = {};
u8 rate;
- u16 flags;
int i;
len /= 2;
@@ -1243,12 +1239,9 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)
mvmvif = iwl_mvm_vif_from_mac80211(vif);
info = IEEE80211_SKB_CB(beacon);
rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif);
- flags = iwl_mvm_mac80211_idx_to_hwrate(rate);
- if (rate == IWL_FIRST_CCK_RATE)
- flags |= IWL_MAC_BEACON_CCK;
-
- beacon_cmd.flags = cpu_to_le16(flags);
+ beacon_cmd.flags =
+ cpu_to_le16(iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw, rate));
beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
index 03e5bf5cb909..949fb790f8fb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
@@ -324,6 +324,7 @@ iwl_mvm_ftm_target_chandef_v2(struct iwl_mvm *mvm,
u8 *ctrl_ch_position)
{
u32 freq = peer->chandef.chan->center_freq;
+ u8 cmd_ver;
*channel = ieee80211_frequency_to_channel(freq);
@@ -344,6 +345,17 @@ iwl_mvm_ftm_target_chandef_v2(struct iwl_mvm *mvm,
*format_bw = IWL_LOCATION_FRAME_FORMAT_VHT;
*format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS;
break;
+ case NL80211_CHAN_WIDTH_160:
+ cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LOCATION_GROUP,
+ TOF_RANGE_REQ_CMD,
+ IWL_FW_CMD_VER_UNKNOWN);
+
+ if (cmd_ver >= 13) {
+ *format_bw = IWL_LOCATION_FRAME_FORMAT_HE;
+ *format_bw |= IWL_LOCATION_BW_160MHZ << LOCATION_BW_POS;
+ break;
+ }
+ fallthrough;
default:
IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n",
peer->chandef.width);
@@ -1142,6 +1154,7 @@ static u8 iwl_mvm_ftm_get_range_resp_ver(struct iwl_mvm *mvm)
static bool iwl_mvm_ftm_resp_size_validation(u8 ver, unsigned int pkt_len)
{
switch (ver) {
+ case 9:
case 8:
return pkt_len == sizeof(struct iwl_tof_range_rsp_ntfy_v8);
case 7:
@@ -1205,7 +1218,7 @@ void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
int peer_idx;
if (new_api) {
- if (notif_ver == 8) {
+ if (notif_ver >= 8) {
fw_ap = &fw_resp_v8->ap[i];
iwl_mvm_ftm_pasn_update_pn(mvm, fw_ap);
} else if (notif_ver == 7) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
index eba5433c2626..bda6da7d988e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
@@ -46,8 +46,8 @@ static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef,
}
static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef,
- u8 *format_bw,
- u8 *ctrl_ch_position)
+ u8 *format_bw, u8 *ctrl_ch_position,
+ u8 cmd_ver)
{
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
@@ -68,6 +68,14 @@ static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef,
*format_bw |= IWL_LOCATION_BW_80MHZ << LOCATION_BW_POS;
*ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
break;
+ case NL80211_CHAN_WIDTH_160:
+ if (cmd_ver >= 9) {
+ *format_bw = IWL_LOCATION_FRAME_FORMAT_HE;
+ *format_bw |= IWL_LOCATION_BW_160MHZ << LOCATION_BW_POS;
+ *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
+ break;
+ }
+ fallthrough;
default:
return -ENOTSUPP;
}
@@ -140,7 +148,8 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
if (cmd_ver >= 7)
err = iwl_mvm_ftm_responder_set_bw_v2(chandef, &cmd.format_bw,
- &cmd.ctrl_ch_position);
+ &cmd.ctrl_ch_position,
+ cmd_ver);
else
err = iwl_mvm_ftm_responder_set_bw_v1(chandef, &cmd.format_bw,
&cmd.ctrl_ch_position);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 74404c96063b..863fec150e53 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -295,6 +295,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
if (ret) {
struct iwl_trans *trans = mvm->trans;
+ /* SecBoot info */
if (trans->trans_cfg->device_family >=
IWL_DEVICE_FAMILY_22000) {
IWL_ERR(mvm,
@@ -302,6 +303,17 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS),
iwl_read_umac_prph(trans,
UMAG_SB_CPU_2_STATUS));
+ } else if (trans->trans_cfg->device_family >=
+ IWL_DEVICE_FAMILY_8000) {
+ IWL_ERR(mvm,
+ "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n",
+ iwl_read_prph(trans, SB_CPU_1_STATUS),
+ iwl_read_prph(trans, SB_CPU_2_STATUS));
+ }
+
+ /* LMAC/UMAC PC info */
+ if (trans->trans_cfg->device_family >=
+ IWL_DEVICE_FAMILY_9000) {
IWL_ERR(mvm, "UMAC PC: 0x%x\n",
iwl_read_umac_prph(trans,
UREG_UMAC_CURRENT_PC));
@@ -312,12 +324,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
IWL_ERR(mvm, "LMAC2 PC: 0x%x\n",
iwl_read_umac_prph(trans,
UREG_LMAC2_CURRENT_PC));
- } else if (trans->trans_cfg->device_family >=
- IWL_DEVICE_FAMILY_8000) {
- IWL_ERR(mvm,
- "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n",
- iwl_read_prph(trans, SB_CPU_1_STATUS),
- iwl_read_prph(trans, SB_CPU_2_STATUS));
}
if (ret == -ETIMEDOUT)
@@ -763,14 +769,18 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
int ret;
struct iwl_host_cmd cmd;
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_OPS_GROUP,
- GEO_TX_POWER_LIMIT,
+ PER_CHAIN_LIMIT_OFFSET_CMD,
IWL_FW_CMD_VER_UNKNOWN);
/* the ops field is at the same spot for all versions, so set in v1 */
geo_tx_cmd.v1.ops =
cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE);
- if (cmd_ver == 3)
+ if (cmd_ver == 5)
+ len = sizeof(geo_tx_cmd.v5);
+ else if (cmd_ver == 4)
+ len = sizeof(geo_tx_cmd.v4);
+ else if (cmd_ver == 3)
len = sizeof(geo_tx_cmd.v3);
else if (fw_has_api(&mvm->fwrt.fw->ucode_capa,
IWL_UCODE_TLV_API_SAR_TABLE_VER))
@@ -782,7 +792,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
return -EOPNOTSUPP;
cmd = (struct iwl_host_cmd){
- .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT),
+ .id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD),
.len = { len, },
.flags = CMD_WANT_SKB,
.data = { &geo_tx_cmd },
@@ -797,7 +807,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
resp = (void *)cmd.resp_pkt->data;
ret = le32_to_cpu(resp->profile_idx);
- if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES))
+ if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES_REV3))
ret = -EIO;
iwl_free_resp(&cmd);
@@ -809,36 +819,58 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
union iwl_geo_tx_power_profiles_cmd cmd;
u16 len;
u32 n_bands;
+ u32 n_profiles;
int ret;
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, PHY_OPS_GROUP,
- GEO_TX_POWER_LIMIT,
+ PER_CHAIN_LIMIT_OFFSET_CMD,
IWL_FW_CMD_VER_UNKNOWN);
BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, ops) !=
offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, ops) ||
offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, ops) !=
- offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops));
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops) ||
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, ops) !=
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, ops) ||
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, ops) !=
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, ops));
+
/* the ops field is at the same spot for all versions, so set in v1 */
cmd.v1.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES);
- if (cmd_ver == 3) {
+ if (cmd_ver == 5) {
+ len = sizeof(cmd.v5);
+ n_bands = ARRAY_SIZE(cmd.v5.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES_REV3;
+ } else if (cmd_ver == 4) {
+ len = sizeof(cmd.v4);
+ n_bands = ARRAY_SIZE(cmd.v4.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES_REV3;
+ } else if (cmd_ver == 3) {
len = sizeof(cmd.v3);
n_bands = ARRAY_SIZE(cmd.v3.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES;
} else if (fw_has_api(&mvm->fwrt.fw->ucode_capa,
IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
len = sizeof(cmd.v2);
n_bands = ARRAY_SIZE(cmd.v2.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES;
} else {
len = sizeof(cmd.v1);
n_bands = ARRAY_SIZE(cmd.v1.table[0]);
+ n_profiles = ACPI_NUM_GEO_PROFILES;
}
BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, table) !=
offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, table) ||
offsetof(struct iwl_geo_tx_power_profiles_cmd_v2, table) !=
- offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table));
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table) ||
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v3, table) !=
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) ||
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) !=
+ offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, table));
/* the table is at the same position for all versions, so set use v1 */
- ret = iwl_sar_geo_init(&mvm->fwrt, &cmd.v1.table[0][0], n_bands);
+ ret = iwl_sar_geo_init(&mvm->fwrt, &cmd.v1.table[0][0],
+ n_bands, n_profiles);
/*
* It is a valid scenario to not support SAR, or miss wgds table,
@@ -851,14 +883,19 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
* Set the revision on versions that contain it.
* This must be done after calling iwl_sar_geo_init().
*/
- if (cmd_ver == 3)
+ if (cmd_ver == 5)
+ cmd.v5.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
+ else if (cmd_ver == 4)
+ cmd.v4.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
+ else if (cmd_ver == 3)
cmd.v3.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
else if (fw_has_api(&mvm->fwrt.fw->ucode_capa,
IWL_UCODE_TLV_API_SAR_TABLE_VER))
cmd.v2.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
return iwl_mvm_send_cmd_pdu(mvm,
- WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT),
+ WIDE_ID(PHY_OPS_GROUP,
+ PER_CHAIN_LIMIT_OFFSET_CMD),
0, len, &cmd);
}
@@ -1108,7 +1145,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
{
u8 value;
- int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0, DSM_RFI_FUNC_ENABLE,
+ int ret = iwl_acpi_get_dsm_u8(mvm->fwrt.dev, 0, DSM_RFI_FUNC_ENABLE,
&iwl_rfi_guid, &value);
if (ret < 0) {
@@ -1133,30 +1170,45 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
{
int ret;
u32 value;
- struct iwl_lari_config_change_cmd_v4 cmd = {};
+ struct iwl_lari_config_change_cmd_v5 cmd = {};
cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt);
- ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, DSM_FUNC_11AX_ENABLEMENT,
+ ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, DSM_FUNC_11AX_ENABLEMENT,
&iwl_guid, &value);
if (!ret)
cmd.oem_11ax_allow_bitmap = cpu_to_le32(value);
- /* apply more config masks here */
- ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0,
+ ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0,
DSM_FUNC_ENABLE_UNII4_CHAN,
&iwl_guid, &value);
if (!ret)
cmd.oem_unii4_allow_bitmap = cpu_to_le32(value);
+ ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0,
+ DSM_FUNC_ACTIVATE_CHANNEL,
+ &iwl_guid, &value);
+ if (!ret)
+ cmd.chan_state_active_bitmap = cpu_to_le32(value);
+
+ ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0,
+ DSM_FUNC_ENABLE_6E,
+ &iwl_guid, &value);
+ if (!ret)
+ cmd.oem_uhb_allow_bitmap = cpu_to_le32(value);
+
if (cmd.config_bitmap ||
+ cmd.oem_uhb_allow_bitmap ||
cmd.oem_11ax_allow_bitmap ||
- cmd.oem_unii4_allow_bitmap) {
+ cmd.oem_unii4_allow_bitmap ||
+ cmd.chan_state_active_bitmap) {
size_t cmd_size;
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
REGULATORY_AND_NVM_GROUP,
LARI_CONFIG_CHANGE, 1);
- if (cmd_ver == 4)
+ if (cmd_ver == 5)
+ cmd_size = sizeof(struct iwl_lari_config_change_cmd_v5);
+ else if (cmd_ver == 4)
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4);
else if (cmd_ver == 3)
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3);
@@ -1170,9 +1222,13 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
le32_to_cpu(cmd.config_bitmap),
le32_to_cpu(cmd.oem_11ax_allow_bitmap));
IWL_DEBUG_RADIO(mvm,
- "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, cmd_ver=%d\n",
+ "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n",
le32_to_cpu(cmd.oem_unii4_allow_bitmap),
+ le32_to_cpu(cmd.chan_state_active_bitmap),
cmd_ver);
+ IWL_DEBUG_RADIO(mvm,
+ "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x\n",
+ le32_to_cpu(cmd.oem_uhb_allow_bitmap));
ret = iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(REGULATORY_AND_NVM_GROUP,
LARI_CONFIG_CHANGE),
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index fd352b2624a6..fd7d4abfb454 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -604,6 +604,12 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
ctxt_sta->is_assoc = cpu_to_le32(1);
+ if (!mvmvif->authorized &&
+ fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO))
+ ctxt_sta->data_policy |=
+ cpu_to_le32(COEX_HIGH_PRIORITY_ENABLE);
+
/*
* allow multicast data frames only as long as the station is
* authorized, i.e., GTK keys are already installed (if needed)
@@ -812,6 +818,21 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
return rate;
}
+u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx)
+{
+ u16 flags = iwl_mvm_mac80211_idx_to_hwrate(fw, rate_idx);
+ bool is_new_rate = iwl_fw_lookup_cmd_ver(fw,
+ LONG_GROUP,
+ BEACON_TEMPLATE_CMD,
+ 0) > 10;
+
+ if (rate_idx <= IWL_FIRST_CCK_RATE)
+ flags |= is_new_rate ? IWL_MAC_BEACON_CCK
+ : IWL_MAC_BEACON_CCK_V1;
+
+ return flags;
+}
+
static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct sk_buff *beacon,
@@ -844,9 +865,10 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif);
- tx->rate_n_flags |= cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate));
+ tx->rate_n_flags |=
+ cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate));
if (rate == IWL_FIRST_CCK_RATE)
- tx->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK);
+ tx->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1);
}
@@ -929,11 +951,7 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
u16 flags;
struct ieee80211_chanctx_conf *ctx;
int channel;
-
- flags = iwl_mvm_mac80211_idx_to_hwrate(rate);
-
- if (rate == IWL_FIRST_CCK_RATE)
- flags |= IWL_MAC_BEACON_CCK;
+ flags = iwl_mvm_mac_ctxt_get_beacon_flags(mvm->fw, rate);
/* Enable FILS on PSC channels only */
rcu_read_lock();
@@ -942,7 +960,11 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
WARN_ON(channel == 0);
if (cfg80211_channel_is_psc(ctx->def.chan) &&
!IWL_MVM_DISABLE_AP_FILS) {
- flags |= IWL_MAC_BEACON_FILS;
+ flags |= iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ BEACON_TEMPLATE_CMD,
+ 0) > 10 ?
+ IWL_MAC_BEACON_FILS :
+ IWL_MAC_BEACON_FILS_V1;
beacon_cmd.short_ssid =
cpu_to_le32(~crc32_le(~0, vif->bss_conf.ssid,
vif->bss_conf.ssid_len));
@@ -1535,11 +1557,11 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
ieee80211_beacon_set_cntdwn(vif, notif->csa_counter);
}
-void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb)
+void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data;
+ struct iwl_channel_switch_start_notif *notif = (void *)pkt->data;
struct ieee80211_vif *csa_vif, *vif;
struct iwl_mvm_vif *mvmvif;
u32 id_n_color, csa_id, mac_id;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 3a4585222d6d..9fb9c7dad314 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -145,7 +145,8 @@ static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {
.bandwidths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
- BIT(NL80211_CHAN_WIDTH_80),
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
.preambles = BIT(NL80211_PREAMBLE_LEGACY) |
BIT(NL80211_PREAMBLE_HT) |
BIT(NL80211_PREAMBLE_VHT) |
@@ -2022,7 +2023,8 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
}
sband = mvm->hw->wiphy->bands[chanctx_conf->def.chan->band];
- own_he_cap = ieee80211_get_he_iftype_cap(sband, vif->type);
+ own_he_cap = ieee80211_get_he_iftype_cap(sband,
+ ieee80211_vif_type_p2p(vif));
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_ctxt_cmd.sta_id]);
if (IS_ERR_OR_NULL(sta)) {
@@ -2234,6 +2236,34 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
IWL_ERR(mvm, "Failed to config FW to work HE!\n");
}
+static void iwl_mvm_protect_assoc(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ u32 duration_override)
+{
+ u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
+ u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
+
+ if (duration_override > duration)
+ duration = duration_override;
+
+ /* Try really hard to protect the session and hear a beacon
+ * The new session protection command allows us to protect the
+ * session for a much longer time since the firmware will internally
+ * create two events: a 300TU one with a very high priority that
+ * won't be fragmented which should be enough for 99% of the cases,
+ * and another one (which we configure here to be 900TU long) which
+ * will have a slightly lower priority, but more importantly, can be
+ * fragmented so that it'll allow other activities to run.
+ */
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))
+ iwl_mvm_schedule_session_protection(mvm, vif, 900,
+ min_duration, false);
+ else
+ iwl_mvm_protect_session(mvm, vif, duration,
+ min_duration, 500, false);
+}
+
static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -2317,6 +2347,20 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
iwl_mvm_protect_session(mvm, vif, dur, dur,
5 * dur, false);
+ } else if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+ &mvm->status) &&
+ !vif->bss_conf.dtim_period) {
+ /*
+ * If we're not restarting and still haven't
+ * heard a beacon (dtim period unknown) then
+ * make sure we still have enough minimum time
+ * remaining in the time event, since the auth
+ * might actually have taken quite a while
+ * (especially for SAE) and so the remaining
+ * time could be small without us having heard
+ * a beacon yet.
+ */
+ iwl_mvm_protect_assoc(mvm, vif, 0);
}
iwl_mvm_sf_update(mvm, vif, false);
@@ -3192,38 +3236,52 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
if (iwl_mvm_phy_ctx_count(mvm) > 1)
iwl_mvm_teardown_tdls_peers(mvm);
- if (sta->tdls)
+ if (sta->tdls) {
iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,
NL80211_TDLS_ENABLE_LINK);
+ } else {
+ /* enable beacon filtering */
+ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
- /* enable beacon filtering */
- WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
+ mvmvif->authorized = 1;
- /*
- * Now that the station is authorized, i.e., keys were already
- * installed, need to indicate to the FW that
- * multicast data frames can be forwarded to the driver
- */
- iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+ /*
+ * Now that the station is authorized, i.e., keys were already
+ * installed, need to indicate to the FW that
+ * multicast data frames can be forwarded to the driver
+ */
+ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+ }
iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
true);
} else if (old_state == IEEE80211_STA_AUTHORIZED &&
new_state == IEEE80211_STA_ASSOC) {
- /* Multicast data frames are no longer allowed */
- iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+ if (!sta->tdls) {
+ /* Multicast data frames are no longer allowed */
+ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+
+ /*
+ * Set this after the above iwl_mvm_mac_ctxt_changed()
+ * to avoid sending high prio again for a little time.
+ */
+ mvmvif->authorized = 0;
- /* disable beacon filtering */
- ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
- WARN_ON(ret &&
- !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
- &mvm->status));
+ /* disable beacon filtering */
+ ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
+ WARN_ON(ret &&
+ !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
+ &mvm->status));
+ }
ret = 0;
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTH) {
if (vif->type == NL80211_IFTYPE_AP) {
mvmvif->ap_assoc_sta_count--;
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+ } else if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
+ /* remove session protection if still running */
+ iwl_mvm_stop_session_protection(mvm, vif);
}
ret = 0;
} else if (old_state == IEEE80211_STA_AUTH &&
@@ -3316,29 +3374,24 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
struct ieee80211_prep_tx_info *info)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
- u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
- if (info->duration > duration)
- duration = info->duration;
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_protect_assoc(mvm, vif, info->duration);
+ mutex_unlock(&mvm->mutex);
+}
+
+static void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_prep_tx_info *info)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ /* for successful cases (auth/assoc), don't cancel session protection */
+ if (info->success)
+ return;
mutex_lock(&mvm->mutex);
- /* Try really hard to protect the session and hear a beacon
- * The new session protection command allows us to protect the
- * session for a much longer time since the firmware will internally
- * create two events: a 300TU one with a very high priority that
- * won't be fragmented which should be enough for 99% of the cases,
- * and another one (which we configure here to be 900TU long) which
- * will have a slightly lower priority, but more importantly, can be
- * fragmented so that it'll allow other activities to run.
- */
- if (fw_has_capa(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))
- iwl_mvm_schedule_session_protection(mvm, vif, 900,
- min_duration, false);
- else
- iwl_mvm_protect_session(mvm, vif, duration,
- min_duration, 500, false);
+ iwl_mvm_stop_session_protection(mvm, vif);
mutex_unlock(&mvm->mutex);
}
@@ -4704,6 +4757,9 @@ static void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw,
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CS_MODIFY))
return;
+ IWL_DEBUG_MAC80211(mvm, "Modify CSA on mac %d count = %d (old %d) mode = %d\n",
+ mvmvif->id, chsw->count, mvmvif->csa_count, chsw->block_tx);
+
if (chsw->count >= mvmvif->csa_count && chsw->block_tx) {
if (mvmvif->csa_misbehave) {
/* Second time, give up on this AP*/
@@ -4720,8 +4776,6 @@ static void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw,
if (mvmvif->csa_failed)
goto out_unlock;
- IWL_DEBUG_MAC80211(mvm, "Modify CSA on mac %d count = %d mode = %d\n",
- mvmvif->id, chsw->count, chsw->block_tx);
WARN_ON(iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(MAC_CONF_GROUP,
CHANNEL_SWITCH_TIME_EVENT_CMD),
@@ -4873,6 +4927,8 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)
{
+ u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
+
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
case RATE_MCS_CHAN_WIDTH_20:
rinfo->bw = RATE_INFO_BW_20;
@@ -4888,30 +4944,65 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)
break;
}
- if (rate_n_flags & RATE_MCS_HT_MSK) {
- rinfo->flags |= RATE_INFO_FLAGS_MCS;
- rinfo->mcs = u32_get_bits(rate_n_flags, RATE_HT_MCS_INDEX_MSK);
- rinfo->nss = u32_get_bits(rate_n_flags,
- RATE_HT_MCS_NSS_MSK) + 1;
- if (rate_n_flags & RATE_MCS_SGI_MSK)
- rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
- } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
- rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
- rinfo->mcs = u32_get_bits(rate_n_flags,
- RATE_VHT_MCS_RATE_CODE_MSK);
- rinfo->nss = u32_get_bits(rate_n_flags,
- RATE_VHT_MCS_NSS_MSK) + 1;
- if (rate_n_flags & RATE_MCS_SGI_MSK)
- rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
- } else if (rate_n_flags & RATE_MCS_HE_MSK) {
+ if (format == RATE_MCS_CCK_MSK ||
+ format == RATE_MCS_LEGACY_OFDM_MSK) {
+ int rate = u32_get_bits(rate_n_flags, RATE_LEGACY_RATE_MSK);
+
+ /* add the offset needed to get to the legacy ofdm indices */
+ if (format == RATE_MCS_LEGACY_OFDM_MSK)
+ rate += IWL_FIRST_OFDM_RATE;
+
+ switch (rate) {
+ case IWL_RATE_1M_INDEX:
+ rinfo->legacy = 10;
+ break;
+ case IWL_RATE_2M_INDEX:
+ rinfo->legacy = 20;
+ break;
+ case IWL_RATE_5M_INDEX:
+ rinfo->legacy = 55;
+ break;
+ case IWL_RATE_11M_INDEX:
+ rinfo->legacy = 110;
+ break;
+ case IWL_RATE_6M_INDEX:
+ rinfo->legacy = 60;
+ break;
+ case IWL_RATE_9M_INDEX:
+ rinfo->legacy = 90;
+ break;
+ case IWL_RATE_12M_INDEX:
+ rinfo->legacy = 120;
+ break;
+ case IWL_RATE_18M_INDEX:
+ rinfo->legacy = 180;
+ break;
+ case IWL_RATE_24M_INDEX:
+ rinfo->legacy = 240;
+ break;
+ case IWL_RATE_36M_INDEX:
+ rinfo->legacy = 360;
+ break;
+ case IWL_RATE_48M_INDEX:
+ rinfo->legacy = 480;
+ break;
+ case IWL_RATE_54M_INDEX:
+ rinfo->legacy = 540;
+ }
+ return;
+ }
+
+ rinfo->nss = u32_get_bits(rate_n_flags,
+ RATE_MCS_NSS_MSK) + 1;
+ rinfo->mcs = format == RATE_MCS_HT_MSK ?
+ RATE_HT_MCS_INDEX(rate_n_flags) :
+ u32_get_bits(rate_n_flags, RATE_MCS_CODE_MSK);
+
+ if (format == RATE_MCS_HE_MSK) {
u32 gi_ltf = u32_get_bits(rate_n_flags,
RATE_MCS_HE_GI_LTF_MSK);
rinfo->flags |= RATE_INFO_FLAGS_HE_MCS;
- rinfo->mcs = u32_get_bits(rate_n_flags,
- RATE_VHT_MCS_RATE_CODE_MSK);
- rinfo->nss = u32_get_bits(rate_n_flags,
- RATE_VHT_MCS_NSS_MSK) + 1;
if (rate_n_flags & RATE_MCS_HE_106T_MSK) {
rinfo->bw = RATE_INFO_BW_HE_RU;
@@ -4925,10 +5016,10 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)
rinfo->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
else if (gi_ltf == 2)
rinfo->he_gi = NL80211_RATE_INFO_HE_GI_1_6;
- else if (rate_n_flags & RATE_MCS_SGI_MSK)
- rinfo->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
- else
+ else if (gi_ltf == 3)
rinfo->he_gi = NL80211_RATE_INFO_HE_GI_3_2;
+ else
+ rinfo->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
break;
case RATE_MCS_HE_TYPE_MU:
if (gi_ltf == 0 || gi_ltf == 1)
@@ -4948,46 +5039,19 @@ static void iwl_mvm_set_sta_rate(u32 rate_n_flags, struct rate_info *rinfo)
if (rate_n_flags & RATE_HE_DUAL_CARRIER_MODE_MSK)
rinfo->he_dcm = 1;
- } else {
- switch (u32_get_bits(rate_n_flags, RATE_LEGACY_RATE_MSK)) {
- case IWL_RATE_1M_PLCP:
- rinfo->legacy = 10;
- break;
- case IWL_RATE_2M_PLCP:
- rinfo->legacy = 20;
- break;
- case IWL_RATE_5M_PLCP:
- rinfo->legacy = 55;
- break;
- case IWL_RATE_11M_PLCP:
- rinfo->legacy = 110;
- break;
- case IWL_RATE_6M_PLCP:
- rinfo->legacy = 60;
- break;
- case IWL_RATE_9M_PLCP:
- rinfo->legacy = 90;
- break;
- case IWL_RATE_12M_PLCP:
- rinfo->legacy = 120;
- break;
- case IWL_RATE_18M_PLCP:
- rinfo->legacy = 180;
- break;
- case IWL_RATE_24M_PLCP:
- rinfo->legacy = 240;
- break;
- case IWL_RATE_36M_PLCP:
- rinfo->legacy = 360;
- break;
- case IWL_RATE_48M_PLCP:
- rinfo->legacy = 480;
- break;
- case IWL_RATE_54M_PLCP:
- rinfo->legacy = 540;
- break;
- }
+ return;
+ }
+
+ if (rate_n_flags & RATE_MCS_SGI_MSK)
+ rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
+
+ if (format == RATE_MCS_HT_MSK) {
+ rinfo->flags |= RATE_INFO_FLAGS_MCS;
+
+ } else if (format == RATE_MCS_VHT_MSK) {
+ rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
}
+
}
static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
@@ -5332,6 +5396,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.sta_rc_update = iwl_mvm_sta_rc_update,
.conf_tx = iwl_mvm_mac_conf_tx,
.mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
+ .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,
.mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,
.flush = iwl_mvm_mac_flush,
.sched_scan_start = iwl_mvm_mac_sched_scan_start,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index f877d86b038e..2b1dcd60e00f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -297,6 +297,7 @@ struct iwl_probe_resp_data {
* see enum &iwl_mvm_low_latency_cause for causes.
* @low_latency_actual: boolean, indicates low latency is set,
* as a result from low_latency bit flags and takes force into account.
+ * @authorized: indicates the AP station was set to authorized
* @ps_disabled: indicates that this interface requires PS to be disabled
* @queue_params: QoS params for this MAC
* @bcast_sta: station used for broadcast packets. Used by the following
@@ -330,6 +331,7 @@ struct iwl_mvm_vif {
bool monitor_active;
u8 low_latency: 6;
u8 low_latency_actual: 1;
+ u8 authorized:1;
bool ps_disabled;
struct iwl_mvm_vif_bf_data bf_data;
@@ -1443,12 +1445,17 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm);
int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm);
/* Utils */
+int iwl_mvm_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,
+ enum nl80211_band band);
int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
enum nl80211_band band);
void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
enum nl80211_band band,
struct ieee80211_tx_rate *r);
-u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
+void iwl_mvm_hwrate_to_tx_rate_v1(u32 rate_n_flags,
+ enum nl80211_band band,
+ struct ieee80211_tx_rate *r);
+u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx);
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);
static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
@@ -1629,6 +1636,8 @@ int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
void *data, int len);
u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
struct ieee80211_vif *vif);
+u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw,
+ u8 rate_idx);
void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
__le32 *tim_index, __le32 *tim_size,
u8 *beacon, u32 frame_size);
@@ -1649,8 +1658,8 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
-void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb);
+void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb);
/* Bindings */
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@@ -1732,7 +1741,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
/* rate scaling */
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq);
void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg);
-int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate);
+int rs_pretty_print_rate_v1(char *buf, int bufsz, const u32 rate);
void rs_update_last_rssi(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvmsta,
struct ieee80211_rx_status *rx_status);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index da705fcaf0fc..6d18a1fd649b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -583,8 +583,9 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
return;
wgds_tbl_idx = iwl_mvm_get_sar_geo_profile(mvm);
- if (wgds_tbl_idx < 0)
- IWL_DEBUG_INFO(mvm, "SAR WGDS is disabled (%d)\n",
+ if (wgds_tbl_idx < 1)
+ IWL_DEBUG_INFO(mvm,
+ "SAR WGDS is disabled or error received (%d)\n",
wgds_tbl_idx);
else
IWL_DEBUG_INFO(mvm, "SAR WGDS: geo profile %d is configured\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 77ea2d0a3091..232ad531d612 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -29,7 +29,6 @@
#define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux"
MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_AUTHOR(DRV_AUTHOR);
MODULE_LICENSE("GPL");
static const struct iwl_op_mode_ops iwl_mvm_ops;
@@ -384,9 +383,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
iwl_mvm_probe_resp_data_notif,
RX_HANDLER_ASYNC_LOCKED,
struct iwl_probe_resp_data_notif),
- RX_HANDLER_GRP(MAC_CONF_GROUP, CHANNEL_SWITCH_NOA_NOTIF,
- iwl_mvm_channel_switch_noa_notif,
- RX_HANDLER_SYNC, struct iwl_channel_switch_noa_notif),
+ RX_HANDLER_GRP(MAC_CONF_GROUP, CHANNEL_SWITCH_START_NOTIF,
+ iwl_mvm_channel_switch_start_notif,
+ RX_HANDLER_SYNC, struct iwl_channel_switch_start_notif),
RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF,
iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED,
struct iwl_datapath_monitor_notif),
@@ -512,7 +511,7 @@ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD),
HCMD_NAME(SESSION_PROTECTION_CMD),
HCMD_NAME(SESSION_PROTECTION_NOTIF),
- HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF),
+ HCMD_NAME(CHANNEL_SWITCH_START_NOTIF),
};
/* Please keep this array *SORTED* by hex value.
@@ -522,7 +521,7 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = {
HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE),
HCMD_NAME(CTDP_CONFIG_CMD),
HCMD_NAME(TEMP_REPORTING_THRESHOLDS_CMD),
- HCMD_NAME(GEO_TX_POWER_LIMIT),
+ HCMD_NAME(PER_CHAIN_LIMIT_OFFSET_CMD),
HCMD_NAME(CT_KILL_NOTIFICATION),
HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE),
};
@@ -726,6 +725,183 @@ static int iwl_mvm_start_post_nvm(struct iwl_mvm *mvm)
return 0;
}
+struct iwl_mvm_frob_txf_data {
+ u8 *buf;
+ size_t buflen;
+};
+
+static void iwl_mvm_frob_txf_key_iter(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ void *data)
+{
+ struct iwl_mvm_frob_txf_data *txf = data;
+ u8 keylen, match, matchend;
+ u8 *keydata;
+ size_t i;
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ keydata = key->key;
+ keylen = key->keylen;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ /*
+ * WEP has short keys which might show up in the payload,
+ * and then you can deduce the key, so in this case just
+ * remove all FIFO data.
+ * For TKIP, we don't know the phase 2 keys here, so same.
+ */
+ memset(txf->buf, 0xBB, txf->buflen);
+ return;
+ default:
+ return;
+ }
+
+ /* scan for key material and clear it out */
+ match = 0;
+ for (i = 0; i < txf->buflen; i++) {
+ if (txf->buf[i] != keydata[match]) {
+ match = 0;
+ continue;
+ }
+ match++;
+ if (match == keylen) {
+ memset(txf->buf + i - keylen, 0xAA, keylen);
+ match = 0;
+ }
+ }
+
+ /* we're dealing with a FIFO, so check wrapped around data */
+ matchend = match;
+ for (i = 0; match && i < keylen - match; i++) {
+ if (txf->buf[i] != keydata[match])
+ break;
+ match++;
+ if (match == keylen) {
+ memset(txf->buf, 0xAA, i + 1);
+ memset(txf->buf + txf->buflen - matchend, 0xAA,
+ matchend);
+ break;
+ }
+ }
+}
+
+static void iwl_mvm_frob_txf(void *ctx, void *buf, size_t buflen)
+{
+ struct iwl_mvm_frob_txf_data txf = {
+ .buf = buf,
+ .buflen = buflen,
+ };
+ struct iwl_mvm *mvm = ctx;
+
+ /* embedded key material exists only on old API */
+ if (iwl_mvm_has_new_tx_api(mvm))
+ return;
+
+ rcu_read_lock();
+ ieee80211_iter_keys_rcu(mvm->hw, NULL, iwl_mvm_frob_txf_key_iter, &txf);
+ rcu_read_unlock();
+}
+
+static void iwl_mvm_frob_hcmd(void *ctx, void *hcmd, size_t len)
+{
+ /* we only use wide headers for commands */
+ struct iwl_cmd_header_wide *hdr = hcmd;
+ unsigned int frob_start = sizeof(*hdr), frob_end = 0;
+
+ if (len < sizeof(hdr))
+ return;
+
+ /* all the commands we care about are in LONG_GROUP */
+ if (hdr->group_id != LONG_GROUP)
+ return;
+
+ switch (hdr->cmd) {
+ case WEP_KEY:
+ case WOWLAN_TKIP_PARAM:
+ case WOWLAN_KEK_KCK_MATERIAL:
+ case ADD_STA_KEY:
+ /*
+ * blank out everything here, easier than dealing
+ * with the various versions of the command
+ */
+ frob_end = INT_MAX;
+ break;
+ case MGMT_MCAST_KEY:
+ frob_start = offsetof(struct iwl_mvm_mgmt_mcast_key_cmd, igtk);
+ BUILD_BUG_ON(offsetof(struct iwl_mvm_mgmt_mcast_key_cmd, igtk) !=
+ offsetof(struct iwl_mvm_mgmt_mcast_key_cmd_v1, igtk));
+
+ frob_end = offsetofend(struct iwl_mvm_mgmt_mcast_key_cmd, igtk);
+ BUILD_BUG_ON(offsetof(struct iwl_mvm_mgmt_mcast_key_cmd, igtk) <
+ offsetof(struct iwl_mvm_mgmt_mcast_key_cmd_v1, igtk));
+ break;
+ }
+
+ if (frob_start >= frob_end)
+ return;
+
+ if (frob_end > len)
+ frob_end = len;
+
+ memset((u8 *)hcmd + frob_start, 0xAA, frob_end - frob_start);
+}
+
+static void iwl_mvm_frob_mem(void *ctx, u32 mem_addr, void *mem, size_t buflen)
+{
+ const struct iwl_dump_exclude *excl;
+ struct iwl_mvm *mvm = ctx;
+ int i;
+
+ switch (mvm->fwrt.cur_fw_img) {
+ case IWL_UCODE_INIT:
+ default:
+ /* not relevant */
+ return;
+ case IWL_UCODE_REGULAR:
+ case IWL_UCODE_REGULAR_USNIFFER:
+ excl = mvm->fw->dump_excl;
+ break;
+ case IWL_UCODE_WOWLAN:
+ excl = mvm->fw->dump_excl_wowlan;
+ break;
+ }
+
+ BUILD_BUG_ON(sizeof(mvm->fw->dump_excl) !=
+ sizeof(mvm->fw->dump_excl_wowlan));
+
+ for (i = 0; i < ARRAY_SIZE(mvm->fw->dump_excl); i++) {
+ u32 start, end;
+
+ if (!excl[i].addr || !excl[i].size)
+ continue;
+
+ start = excl[i].addr;
+ end = start + excl[i].size;
+
+ if (end <= mem_addr || start >= mem_addr + buflen)
+ continue;
+
+ if (start < mem_addr)
+ start = mem_addr;
+
+ if (end > mem_addr + buflen)
+ end = mem_addr + buflen;
+
+ memset((u8 *)mem + start - mem_addr, 0xAA, end - start);
+ }
+}
+
+static const struct iwl_dump_sanitize_ops iwl_mvm_sanitize_ops = {
+ .frob_txf = iwl_mvm_frob_txf,
+ .frob_hcmd = iwl_mvm_frob_hcmd,
+ .frob_mem = iwl_mvm_frob_mem,
+};
+
static struct iwl_op_mode *
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
const struct iwl_fw *fw, struct dentry *dbgfs_dir)
@@ -775,7 +951,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->hw = hw;
iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm,
- dbgfs_dir);
+ &iwl_mvm_sanitize_ops, mvm, dbgfs_dir);
iwl_mvm_get_acpi_tables(mvm);
@@ -868,8 +1044,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->cmd_ver.range_resp =
iwl_fw_lookup_notif_ver(mvm->fw, LOCATION_GROUP,
TOF_RANGE_RESPONSE_NOTIF, 5);
- /* we only support up to version 8 */
- if (WARN_ON_ONCE(mvm->cmd_ver.range_resp > 8))
+ /* we only support up to version 9 */
+ if (WARN_ON_ONCE(mvm->cmd_ver.range_resp > 9))
goto out_free;
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
index f2b090be3898..b2ea2fca5376 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2019 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -128,6 +128,19 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
enum ieee80211_ac_numbers ac;
bool tid_found = false;
+ if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ||
+ cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
+ cmd->rx_data_timeout_uapsd =
+ cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
+ cmd->tx_data_timeout_uapsd =
+ cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
+ } else {
+ cmd->rx_data_timeout_uapsd =
+ cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
+ cmd->tx_data_timeout_uapsd =
+ cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
+ }
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* set advanced pm flag with no uapsd ACs to enable ps-poll */
if (mvmvif->dbgfs_pm.use_ps_poll) {
@@ -182,19 +195,6 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
cmd->uapsd_max_sp = mvm->hw->uapsd_max_sp_len;
- if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status) ||
- cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
- cmd->rx_data_timeout_uapsd =
- cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT);
- cmd->tx_data_timeout_uapsd =
- cpu_to_le32(IWL_MVM_WOWLAN_PS_TX_DATA_TIMEOUT);
- } else {
- cmd->rx_data_timeout_uapsd =
- cpu_to_le32(IWL_MVM_UAPSD_RX_DATA_TIMEOUT);
- cmd->tx_data_timeout_uapsd =
- cpu_to_le32(IWL_MVM_UAPSD_TX_DATA_TIMEOUT);
- }
-
if (cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) {
cmd->heavy_tx_thld_packets =
IWL_MVM_PS_SNOOZE_HEAVY_TX_THLD_PACKETS;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index 2d58cb969918..958702403a45 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -32,10 +32,6 @@ static u8 rs_fw_set_active_chains(u8 chains)
fw_chains |= IWL_TLC_MNG_CHAIN_A_MSK;
if (chains & ANT_B)
fw_chains |= IWL_TLC_MNG_CHAIN_B_MSK;
- if (chains & ANT_C)
- WARN(false,
- "tlc offload doesn't support antenna C. chains: 0x%x\n",
- chains);
return fw_chains;
}
@@ -314,7 +310,19 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
if (flags & IWL_TLC_NOTIF_FLAG_RATE) {
char pretty_rate[100];
+
+ if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
+ TLC_MNG_UPDATE_NOTIF, 0) < 3) {
+ rs_pretty_print_rate_v1(pretty_rate, sizeof(pretty_rate),
+ le32_to_cpu(notif->rate));
+ IWL_DEBUG_RATE(mvm,
+ "Got rate in old format. Rate: %s. Converting.\n",
+ pretty_rate);
+ lq_sta->last_rate_n_flags =
+ iwl_new_rate_from_v1(le32_to_cpu(notif->rate));
+ } else {
lq_sta->last_rate_n_flags = le32_to_cpu(notif->rate);
+ }
rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate),
lq_sta->last_rate_n_flags);
IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index b97708cb869d..f4d02f9fe16d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -4,11 +4,6 @@
* Copyright(c) 2005 - 2014, 2018 - 2021 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- *
- * Contact Information:
- * Intel Linux Wireless <[email protected]>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
*****************************************************************************/
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -335,15 +330,15 @@ static const struct rs_tx_column rs_tx_columns[] = {
static inline u8 rs_extract_rate(u32 rate_n_flags)
{
/* also works for HT because bits 7:6 are zero there */
- return (u8)(rate_n_flags & RATE_LEGACY_RATE_MSK);
+ return (u8)(rate_n_flags & RATE_LEGACY_RATE_MSK_V1);
}
static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
{
int idx = 0;
- if (rate_n_flags & RATE_MCS_HT_MSK) {
- idx = rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK;
+ if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
+ idx = rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK_V1;
idx += IWL_RATE_MCS_0_INDEX;
/* skip 9M not supported in HT*/
@@ -351,8 +346,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
idx += 1;
if ((idx >= IWL_FIRST_HT_RATE) && (idx <= IWL_LAST_HT_RATE))
return idx;
- } else if (rate_n_flags & RATE_MCS_VHT_MSK ||
- rate_n_flags & RATE_MCS_HE_MSK) {
+ } else if (rate_n_flags & RATE_MCS_VHT_MSK_V1 ||
+ rate_n_flags & RATE_MCS_HE_MSK_V1) {
idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
idx += IWL_RATE_MCS_0_INDEX;
@@ -361,8 +356,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
idx++;
if ((idx >= IWL_FIRST_VHT_RATE) && (idx <= IWL_LAST_VHT_RATE))
return idx;
- if ((rate_n_flags & RATE_MCS_HE_MSK) &&
- (idx <= IWL_LAST_HE_RATE))
+ if ((rate_n_flags & RATE_MCS_HE_MSK_V1) &&
+ idx <= IWL_LAST_HE_RATE)
return idx;
} else {
/* legacy rate format, search for match in table */
@@ -459,44 +454,8 @@ static const u16 expected_tpt_mimo2_160MHz[4][IWL_RATE_COUNT] = {
{0, 0, 0, 0, 971, 0, 1925, 2861, 3779, 5574, 7304, 8147, 8976, 10592, 11640},
};
-/* mbps, mcs */
-static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
- { "1", "BPSK DSSS"},
- { "2", "QPSK DSSS"},
- {"5.5", "BPSK CCK"},
- { "11", "QPSK CCK"},
- { "6", "BPSK 1/2"},
- { "9", "BPSK 1/2"},
- { "12", "QPSK 1/2"},
- { "18", "QPSK 3/4"},
- { "24", "16QAM 1/2"},
- { "36", "16QAM 3/4"},
- { "48", "64QAM 2/3"},
- { "54", "64QAM 3/4"},
- { "60", "64QAM 5/6"},
-};
-
#define MCS_INDEX_PER_STREAM (8)
-static const char *rs_pretty_ant(u8 ant)
-{
- static const char * const ant_name[] = {
- [ANT_NONE] = "None",
- [ANT_A] = "A",
- [ANT_B] = "B",
- [ANT_AB] = "AB",
- [ANT_C] = "C",
- [ANT_AC] = "AC",
- [ANT_BC] = "BC",
- [ANT_ABC] = "ABC",
- };
-
- if (ant > ANT_ABC)
- return "UNKNOWN";
-
- return ant_name[ant];
-}
-
static const char *rs_pretty_lq_type(enum iwl_table_type type)
{
static const char * const lq_types[] = {
@@ -558,7 +517,7 @@ static char *rs_pretty_rate(const struct rs_rate *rate)
rate_str = "BAD_RATE";
sprintf(buf, "(%s|%s|%s)", rs_pretty_lq_type(rate->type),
- rs_pretty_ant(rate->ant), rate_str);
+ iwl_rs_pretty_ant(rate->ant), rate_str);
return buf;
}
@@ -654,8 +613,7 @@ static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
{
return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
- !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
- !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
+ !!(rate_n_flags & RATE_MCS_ANT_B_MSK);
}
/*
@@ -820,12 +778,12 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
int index = rate->index;
ucode_rate |= ((rate->ant << RATE_MCS_ANT_POS) &
- RATE_MCS_ANT_ABC_MSK);
+ RATE_MCS_ANT_AB_MSK);
if (is_legacy(rate)) {
ucode_rate |= iwl_rates[index].plcp;
if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
- ucode_rate |= RATE_MCS_CCK_MSK;
+ ucode_rate |= RATE_MCS_CCK_MSK_V1;
return ucode_rate;
}
@@ -840,7 +798,7 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
IWL_ERR(mvm, "Invalid HT rate index %d\n", index);
index = IWL_LAST_HT_RATE;
}
- ucode_rate |= RATE_MCS_HT_MSK;
+ ucode_rate |= RATE_MCS_HT_MSK_V1;
if (is_ht_siso(rate))
ucode_rate |= iwl_rates[index].plcp_ht_siso;
@@ -853,7 +811,7 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
IWL_ERR(mvm, "Invalid VHT rate index %d\n", index);
index = IWL_LAST_VHT_RATE;
}
- ucode_rate |= RATE_MCS_VHT_MSK;
+ ucode_rate |= RATE_MCS_VHT_MSK_V1;
if (is_vht_siso(rate))
ucode_rate |= iwl_rates[index].plcp_vht_siso;
else if (is_vht_mimo2(rate))
@@ -873,9 +831,9 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
ucode_rate |= rate->bw;
if (rate->sgi)
- ucode_rate |= RATE_MCS_SGI_MSK;
+ ucode_rate |= RATE_MCS_SGI_MSK_V1;
if (rate->ldpc)
- ucode_rate |= RATE_MCS_LDPC_MSK;
+ ucode_rate |= RATE_MCS_LDPC_MSK_V1;
return ucode_rate;
}
@@ -885,7 +843,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
enum nl80211_band band,
struct rs_rate *rate)
{
- u32 ant_msk = ucode_rate & RATE_MCS_ANT_ABC_MSK;
+ u32 ant_msk = ucode_rate & RATE_MCS_ANT_AB_MSK;
u8 num_of_ant = get_num_of_ant_from_rate(ucode_rate);
u8 nss;
@@ -898,9 +856,9 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
rate->ant = (ant_msk >> RATE_MCS_ANT_POS);
/* Legacy */
- if (!(ucode_rate & RATE_MCS_HT_MSK) &&
- !(ucode_rate & RATE_MCS_VHT_MSK) &&
- !(ucode_rate & RATE_MCS_HE_MSK)) {
+ if (!(ucode_rate & RATE_MCS_HT_MSK_V1) &&
+ !(ucode_rate & RATE_MCS_VHT_MSK_V1) &&
+ !(ucode_rate & RATE_MCS_HE_MSK_V1)) {
if (num_of_ant == 1) {
if (band == NL80211_BAND_5GHZ)
rate->type = LQ_LEGACY_A;
@@ -912,20 +870,20 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
}
/* HT, VHT or HE */
- if (ucode_rate & RATE_MCS_SGI_MSK)
+ if (ucode_rate & RATE_MCS_SGI_MSK_V1)
rate->sgi = true;
- if (ucode_rate & RATE_MCS_LDPC_MSK)
+ if (ucode_rate & RATE_MCS_LDPC_MSK_V1)
rate->ldpc = true;
if (ucode_rate & RATE_MCS_STBC_MSK)
rate->stbc = true;
if (ucode_rate & RATE_MCS_BF_MSK)
rate->bfer = true;
- rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
+ rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK_V1;
- if (ucode_rate & RATE_MCS_HT_MSK) {
- nss = ((ucode_rate & RATE_HT_MCS_NSS_MSK) >>
- RATE_HT_MCS_NSS_POS) + 1;
+ if (ucode_rate & RATE_MCS_HT_MSK_V1) {
+ nss = ((ucode_rate & RATE_HT_MCS_NSS_MSK_V1) >>
+ RATE_HT_MCS_NSS_POS_V1) + 1;
if (nss == 1) {
rate->type = LQ_HT_SISO;
@@ -938,7 +896,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
} else {
WARN_ON_ONCE(1);
}
- } else if (ucode_rate & RATE_MCS_VHT_MSK) {
+ } else if (ucode_rate & RATE_MCS_VHT_MSK_V1) {
nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
@@ -953,7 +911,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
} else {
WARN_ON_ONCE(1);
}
- } else if (ucode_rate & RATE_MCS_HE_MSK) {
+ } else if (ucode_rate & RATE_MCS_HE_MSK_V1) {
nss = ((ucode_rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
@@ -981,9 +939,6 @@ static int rs_toggle_antenna(u32 valid_ant, struct rs_rate *rate)
{
u8 new_ant_type;
- if (!rate->ant || WARN_ON_ONCE(rate->ant & ANT_C))
- return 0;
-
if (!rs_is_valid_ant(valid_ant, rate->ant))
return 0;
@@ -2552,7 +2507,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
}
IWL_DEBUG_RATE(mvm, "Best ANT: %s Best RSSI: %d\n",
- rs_pretty_ant(best_ant), best_rssi);
+ iwl_rs_pretty_ant(best_ant), best_rssi);
if (best_ant != ANT_A && best_ant != ANT_B)
rate->ant = first_antenna(valid_tx_ant);
@@ -2652,7 +2607,6 @@ void rs_update_last_rssi(struct iwl_mvm *mvm,
lq_sta->pers.chains = rx_status->chains;
lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0];
lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1];
- lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2];
lq_sta->pers.last_rssi = S8_MIN;
for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) {
@@ -2738,8 +2692,8 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
return;
lq_sta = mvm_sta;
- iwl_mvm_hwrate_to_tx_rate(lq_sta->last_rate_n_flags,
- info->band, &info->control.rates[0]);
+ iwl_mvm_hwrate_to_tx_rate_v1(lq_sta->last_rate_n_flags,
+ info->band, &info->control.rates[0]);
info->control.rates[0].count = 1;
/* Report the optimal rate based on rssi and STA caps if we haven't
@@ -2749,8 +2703,8 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
optimal_rate = rs_get_optimal_rate(mvm, lq_sta);
last_ucode_rate = ucode_rate_from_rs_rate(mvm,
optimal_rate);
- iwl_mvm_hwrate_to_tx_rate(last_ucode_rate, info->band,
- &txrc->reported_rate);
+ iwl_mvm_hwrate_to_tx_rate_v1(last_ucode_rate, info->band,
+ &txrc->reported_rate);
}
}
@@ -2909,7 +2863,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
mvm->drv_rx_stats.success_frames++;
- switch (rate & RATE_MCS_CHAN_WIDTH_MSK) {
+ switch (rate & RATE_MCS_CHAN_WIDTH_MSK_V1) {
case RATE_MCS_CHAN_WIDTH_20:
mvm->drv_rx_stats.bw_20_frames++;
break;
@@ -2926,10 +2880,10 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
WARN_ONCE(1, "bad BW. rate 0x%x", rate);
}
- if (rate & RATE_MCS_HT_MSK) {
+ if (rate & RATE_MCS_HT_MSK_V1) {
mvm->drv_rx_stats.ht_frames++;
- nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1;
- } else if (rate & RATE_MCS_VHT_MSK) {
+ nss = ((rate & RATE_HT_MCS_NSS_MSK_V1) >> RATE_HT_MCS_NSS_POS_V1) + 1;
+ } else if (rate & RATE_MCS_VHT_MSK_V1) {
mvm->drv_rx_stats.vht_frames++;
nss = ((rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
@@ -2942,7 +2896,7 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
else if (nss == 2)
mvm->drv_rx_stats.mimo2_frames++;
- if (rate & RATE_MCS_SGI_MSK)
+ if (rate & RATE_MCS_SGI_MSK_V1)
mvm->drv_rx_stats.sgi_frames++;
else
mvm->drv_rx_stats.ngi_frames++;
@@ -3323,7 +3277,7 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
int i;
int num_rates = ARRAY_SIZE(lq_cmd->rs_table);
__le32 ucode_rate_le32 = cpu_to_le32(ucode_rate);
- u8 ant = (ucode_rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS;
+ u8 ant = (ucode_rate & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS;
for (i = 0; i < num_rates; i++)
lq_cmd->rs_table[i] = ucode_rate_le32;
@@ -3688,35 +3642,37 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta)
IWL_DEBUG_RATE(mvm, "leave\n");
}
-int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate)
+int rs_pretty_print_rate_v1(char *buf, int bufsz, const u32 rate)
{
- char *type, *bw;
+ char *type;
u8 mcs = 0, nss = 0;
- u8 ant = (rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS;
+ u8 ant = (rate & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS;
+ u32 bw = (rate & RATE_MCS_CHAN_WIDTH_MSK_V1) >>
+ RATE_MCS_CHAN_WIDTH_POS;
- if (!(rate & RATE_MCS_HT_MSK) &&
- !(rate & RATE_MCS_VHT_MSK) &&
- !(rate & RATE_MCS_HE_MSK)) {
+ if (!(rate & RATE_MCS_HT_MSK_V1) &&
+ !(rate & RATE_MCS_VHT_MSK_V1) &&
+ !(rate & RATE_MCS_HE_MSK_V1)) {
int index = iwl_hwrate_to_plcp_idx(rate);
return scnprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps",
- rs_pretty_ant(ant),
+ iwl_rs_pretty_ant(ant),
index == IWL_RATE_INVALID ? "BAD" :
- iwl_rate_mcs[index].mbps);
+ iwl_rate_mcs(index)->mbps);
}
- if (rate & RATE_MCS_VHT_MSK) {
+ if (rate & RATE_MCS_VHT_MSK_V1) {
type = "VHT";
mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK;
nss = ((rate & RATE_VHT_MCS_NSS_MSK)
>> RATE_VHT_MCS_NSS_POS) + 1;
- } else if (rate & RATE_MCS_HT_MSK) {
+ } else if (rate & RATE_MCS_HT_MSK_V1) {
type = "HT";
- mcs = rate & RATE_HT_MCS_INDEX_MSK;
- nss = ((rate & RATE_HT_MCS_NSS_MSK)
- >> RATE_HT_MCS_NSS_POS) + 1;
- } else if (rate & RATE_MCS_HE_MSK) {
+ mcs = rate & RATE_HT_MCS_INDEX_MSK_V1;
+ nss = ((rate & RATE_HT_MCS_NSS_MSK_V1)
+ >> RATE_HT_MCS_NSS_POS_V1) + 1;
+ } else if (rate & RATE_MCS_HE_MSK_V1) {
type = "HE";
mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK;
nss = ((rate & RATE_VHT_MCS_NSS_MSK)
@@ -3725,29 +3681,12 @@ int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate)
type = "Unknown"; /* shouldn't happen */
}
- switch (rate & RATE_MCS_CHAN_WIDTH_MSK) {
- case RATE_MCS_CHAN_WIDTH_20:
- bw = "20Mhz";
- break;
- case RATE_MCS_CHAN_WIDTH_40:
- bw = "40Mhz";
- break;
- case RATE_MCS_CHAN_WIDTH_80:
- bw = "80Mhz";
- break;
- case RATE_MCS_CHAN_WIDTH_160:
- bw = "160Mhz";
- break;
- default:
- bw = "BAD BW";
- }
-
return scnprintf(buf, bufsz,
"0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s%s",
- rate, type, rs_pretty_ant(ant), bw, mcs, nss,
- (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ",
+ rate, type, iwl_rs_pretty_ant(ant), iwl_rs_pretty_bw(bw), mcs, nss,
+ (rate & RATE_MCS_SGI_MSK_V1) ? "SGI " : "NGI ",
(rate & RATE_MCS_STBC_MSK) ? "STBC " : "",
- (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "",
+ (rate & RATE_MCS_LDPC_MSK_V1) ? "LDPC " : "",
(rate & RATE_HE_DUAL_CARRIER_MODE_MSK) ? "DCM " : "",
(rate & RATE_MCS_BF_MSK) ? "BF " : "");
}
@@ -3830,10 +3769,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
lq_sta->active_legacy_rate);
desc += scnprintf(buff + desc, bufsz - desc, "fixed rate 0x%X\n",
lq_sta->pers.dbg_fixed_rate);
- desc += scnprintf(buff + desc, bufsz - desc, "valid_tx_ant %s%s%s\n",
+ desc += scnprintf(buff + desc, bufsz - desc, "valid_tx_ant %s%s\n",
(iwl_mvm_get_valid_tx_ant(mvm) & ANT_A) ? "ANT_A," : "",
- (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : "",
- (iwl_mvm_get_valid_tx_ant(mvm) & ANT_C) ? "ANT_C" : "");
+ (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : "");
desc += scnprintf(buff + desc, bufsz - desc, "lq type %s\n",
(is_legacy(rate)) ? "legacy" :
is_vht(rate) ? "VHT" : "HT");
@@ -3891,7 +3829,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
desc += scnprintf(buff + desc, bufsz - desc,
" rate[%d] 0x%X ", i, r);
- desc += rs_pretty_print_rate(buff + desc, bufsz - desc, r);
+ desc += rs_pretty_print_rate_v1(buff + desc, bufsz - desc, r);
if (desc < bufsz - 1)
buff[desc++] = '\n';
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
index 32104c9f8f5e..b7bc8c1b2dda 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
@@ -5,11 +5,6 @@
* Copyright(c) 2015 Intel Mobile Communications GmbH
* Copyright(c) 2017 Intel Deutschland GmbH
* Copyright(c) 2018 - 2019 Intel Corporation
- *
- * Contact Information:
- * Intel Linux Wireless <[email protected]>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
*****************************************************************************/
#ifndef __rs_h__
@@ -36,11 +31,6 @@ struct iwl_rs_rate_info {
#define IWL_RATE_60M_PLCP 3
-enum {
- IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
- IWL_RATE_INVALID = IWL_RATE_COUNT,
-};
-
#define LINK_QUAL_MAX_RETRY_NUM 16
enum {
@@ -211,13 +201,6 @@ struct rs_rate {
#define is_ht80(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_80)
#define is_ht160(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_160)
-#define IWL_MAX_MCS_DISPLAY_SIZE 12
-
-struct iwl_rate_mcs_info {
- char mbps[IWL_MAX_MCS_DISPLAY_SIZE];
- char mcs[IWL_MAX_MCS_DISPLAY_SIZE];
-};
-
/**
* struct iwl_lq_sta_rs_fw - rate and related statistics for RS in FW
* @last_rate_n_flags: last rate reported by FW
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index 8ef5399ad9be..d22f40a5354d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -103,7 +103,7 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
struct iwl_rx_phy_info *phy_info,
struct ieee80211_rx_status *rx_status)
{
- int energy_a, energy_b, energy_c, max_energy;
+ int energy_a, energy_b, max_energy;
u32 val;
val =
@@ -114,14 +114,10 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >>
IWL_RX_INFO_ENERGY_ANT_B_POS;
energy_b = energy_b ? -energy_b : S8_MIN;
- energy_c = (val & IWL_RX_INFO_ENERGY_ANT_C_MSK) >>
- IWL_RX_INFO_ENERGY_ANT_C_POS;
- energy_c = energy_c ? -energy_c : S8_MIN;
max_energy = max(energy_a, energy_b);
- max_energy = max(max_energy, energy_c);
- IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n",
- energy_a, energy_b, energy_c, max_energy);
+ IWL_DEBUG_STATS(mvm, "energy In A %d B %d , and max %d\n",
+ energy_a, energy_b, max_energy);
rx_status->signal = max_energy;
rx_status->chains = (le16_to_cpu(phy_info->phy_flags) &
@@ -129,7 +125,6 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
>> RX_RES_PHY_FLAGS_ANTENNA_POS;
rx_status->chain_signal[0] = energy_a;
rx_status->chain_signal[1] = energy_b;
- rx_status->chain_signal[2] = energy_c;
}
/*
@@ -235,7 +230,7 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
mdata->rx.airtime += le16_to_cpu(phy_info->frame_time);
}
- if (!(rate_n_flags & (RATE_MCS_HT_MSK | RATE_MCS_VHT_MSK)))
+ if (!(rate_n_flags & (RATE_MCS_HT_MSK_V1 | RATE_MCS_VHT_MSK_V1)))
return;
mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
@@ -249,10 +244,10 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
mvmsta->sta_id != mvmvif->ap_sta_id)
return;
- if (rate_n_flags & RATE_MCS_HT_MSK) {
- thr = thresh_tpt[rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK];
- thr *= 1 + ((rate_n_flags & RATE_HT_MCS_NSS_MSK) >>
- RATE_HT_MCS_NSS_POS);
+ if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
+ thr = thresh_tpt[rate_n_flags & RATE_HT_MCS_RATE_CODE_MSK_V1];
+ thr *= 1 + ((rate_n_flags & RATE_HT_MCS_NSS_MSK_V1) >>
+ RATE_HT_MCS_NSS_POS_V1);
} else {
if (WARN_ON((rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK) >=
ARRAY_SIZE(thresh_tpt)))
@@ -262,7 +257,7 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
RATE_VHT_MCS_NSS_POS);
}
- thr <<= ((rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) >>
+ thr <<= ((rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK_V1) >>
RATE_MCS_CHAN_WIDTH_POS);
mdata->uapsd_nonagg_detect.rx_bytes += len;
@@ -455,7 +450,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
}
/* Set up the HT phy flags */
- switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
+ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK_V1) {
case RATE_MCS_CHAN_WIDTH_20:
break;
case RATE_MCS_CHAN_WIDTH_40:
@@ -468,20 +463,20 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_status->bw = RATE_INFO_BW_160;
break;
}
- if (!(rate_n_flags & RATE_MCS_CCK_MSK) &&
- rate_n_flags & RATE_MCS_SGI_MSK)
+ if (!(rate_n_flags & RATE_MCS_CCK_MSK_V1) &&
+ rate_n_flags & RATE_MCS_SGI_MSK_V1)
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
if (rate_n_flags & RATE_HT_MCS_GF_MSK)
rx_status->enc_flags |= RX_ENC_FLAG_HT_GF;
- if (rate_n_flags & RATE_MCS_LDPC_MSK)
+ if (rate_n_flags & RATE_MCS_LDPC_MSK_V1)
rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
- if (rate_n_flags & RATE_MCS_HT_MSK) {
+ if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
RATE_MCS_STBC_POS;
rx_status->encoding = RX_ENC_HT;
- rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+ rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK_V1;
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
- } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+ } else if (rate_n_flags & RATE_MCS_VHT_MSK_V1) {
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
RATE_MCS_STBC_POS;
rx_status->nss =
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index c12f303cf652..e0601f802628 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -240,8 +240,7 @@ static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm,
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
struct napi_struct *napi,
struct sk_buff *skb, int queue,
- struct ieee80211_sta *sta,
- bool csi)
+ struct ieee80211_sta *sta)
{
if (iwl_mvm_check_pn(mvm, skb, queue, sta))
kfree_skb(skb);
@@ -269,7 +268,6 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
(rate_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS;
rx_status->chain_signal[0] = energy_a;
rx_status->chain_signal[1] = energy_b;
- rx_status->chain_signal[2] = S8_MIN;
}
static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta,
@@ -620,7 +618,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
while ((skb = __skb_dequeue(skb_list))) {
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb,
reorder_buf->queue,
- sta, false);
+ sta);
reorder_buf->num_stored--;
}
}
@@ -1198,7 +1196,7 @@ static void iwl_mvm_decode_he_mu_ext(struct iwl_mvm *mvm,
}
if (FIELD_GET(IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CRC_OK, phy_data4) &&
- (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) != RATE_MCS_CHAN_WIDTH_20) {
+ (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK_V1) != RATE_MCS_CHAN_WIDTH_20) {
he_mu->flags1 |=
cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN |
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN);
@@ -1235,7 +1233,7 @@ iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,
* the TSF/timers are not be transmitted in HE-MU.
*/
u8 ru = le32_get_bits(phy_data->d1, IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK);
- u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK;
+ u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK_V1;
u8 offs = 0;
rx_status->bw = RATE_INFO_BW_HE_RU;
@@ -1290,13 +1288,13 @@ iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,
if (he_mu)
he_mu->flags2 |=
- le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
+ le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK_V1,
rate_n_flags),
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW);
- else if (he_type == RATE_MCS_HE_TYPE_TRIG)
+ else if (he_type == RATE_MCS_HE_TYPE_TRIG_V1)
he->data6 |=
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) |
- le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
+ le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK_V1,
rate_n_flags),
IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW);
}
@@ -1508,9 +1506,9 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >> RATE_MCS_STBC_POS;
rx_status->nss =
- ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
- RATE_VHT_MCS_NSS_POS) + 1;
- rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
+ ((rate_n_flags & RATE_MCS_NSS_MSK) >>
+ RATE_MCS_NSS_POS) + 1;
+ rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK;
rx_status->encoding = RX_ENC_HE;
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
if (rate_n_flags & RATE_MCS_BF_MSK)
@@ -1562,14 +1560,15 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
}
break;
case 3:
- if ((he_type == RATE_MCS_HE_TYPE_SU ||
- he_type == RATE_MCS_HE_TYPE_EXT_SU) &&
- rate_n_flags & RATE_MCS_SGI_MSK)
- rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
- else
- rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2;
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_3_2;
ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
break;
+ case 4:
+ rx_status->he_gi = NL80211_RATE_INFO_HE_GI_0_8;
+ ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X;
+ break;
+ default:
+ ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN;
}
he->data5 |= le16_encode_bits(ltf,
@@ -1653,7 +1652,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
struct iwl_mvm_rx_phy_data phy_data = {
.info_type = IWL_RX_PHY_INFO_TYPE_NONE,
};
- bool csi = false;
+ u32 format;
+ bool is_sgi;
if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))
return;
@@ -1691,6 +1691,13 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
phy_data.d2 = desc->v1.phy_data2;
phy_data.d3 = desc->v1.phy_data3;
}
+ if (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
+ REPLY_RX_MPDU_CMD, 0) < 4) {
+ rate_n_flags = iwl_new_rate_from_v1(rate_n_flags);
+ IWL_DEBUG_DROP(mvm, "Got old format rate, converting. New rate: 0x%x\n",
+ rate_n_flags);
+ }
+ format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
len = le16_to_cpu(desc->mpdu_len);
@@ -1744,7 +1751,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
break;
}
- if (rate_n_flags & RATE_MCS_HE_MSK)
+ if (format == RATE_MCS_HE_MSK)
iwl_mvm_rx_he(mvm, skb, &phy_data, rate_n_flags,
phy_info, queue);
@@ -1761,7 +1768,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
}
/* set the preamble flag if appropriate */
- if (rate_n_flags & RATE_MCS_CCK_MSK &&
+ if (format == RATE_MCS_CCK_MSK &&
phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)
rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
@@ -1937,33 +1944,34 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
}
}
- if (!(rate_n_flags & RATE_MCS_CCK_MSK) &&
- rate_n_flags & RATE_MCS_SGI_MSK)
+ is_sgi = format == RATE_MCS_HE_MSK ?
+ iwl_he_is_sgi(rate_n_flags) :
+ rate_n_flags & RATE_MCS_SGI_MSK;
+
+ if (!(format == RATE_MCS_CCK_MSK) && is_sgi)
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
- if (rate_n_flags & RATE_HT_MCS_GF_MSK)
- rx_status->enc_flags |= RX_ENC_FLAG_HT_GF;
if (rate_n_flags & RATE_MCS_LDPC_MSK)
rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
- if (rate_n_flags & RATE_MCS_HT_MSK) {
+ if (format == RATE_MCS_HT_MSK) {
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
- RATE_MCS_STBC_POS;
+ RATE_MCS_STBC_POS;
rx_status->encoding = RX_ENC_HT;
- rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+ rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags);
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
- } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+ } else if (format == RATE_MCS_VHT_MSK) {
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
- RATE_MCS_STBC_POS;
- rx_status->nss =
- ((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
- RATE_VHT_MCS_NSS_POS) + 1;
- rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
+ RATE_MCS_STBC_POS;
+ rx_status->nss =
+ ((rate_n_flags & RATE_MCS_NSS_MSK) >>
+ RATE_MCS_NSS_POS) + 1;
+ rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK;
rx_status->encoding = RX_ENC_VHT;
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
if (rate_n_flags & RATE_MCS_BF_MSK)
rx_status->enc_flags |= RX_ENC_FLAG_BF;
- } else if (!(rate_n_flags & RATE_MCS_HE_MSK)) {
- int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
- rx_status->band);
+ } else if (!(format == RATE_MCS_HE_MSK)) {
+ int rate = iwl_mvm_legacy_hw_idx_to_mac80211_idx(rate_n_flags,
+ rx_status->band);
if (WARN(rate < 0 || rate > 0xFF,
"Invalid rate flags 0x%x, band %d,\n",
@@ -1994,7 +2002,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc))
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue,
- sta, csi);
+ sta);
out:
rcu_read_unlock();
}
@@ -2013,12 +2021,24 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
struct ieee80211_sta *sta = NULL;
struct sk_buff *skb;
u8 channel, energy_a, energy_b;
+ u32 format;
struct iwl_mvm_rx_phy_data phy_data = {
.info_type = le32_get_bits(desc->phy_info[1],
IWL_RX_PHY_DATA1_INFO_TYPE_MASK),
.d0 = desc->phy_info[0],
.d1 = desc->phy_info[1],
};
+ bool is_sgi;
+
+ if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
+ RX_NO_DATA_NOTIF, 0) < 2) {
+ IWL_DEBUG_DROP(mvm, "Got an old rate format. Old rate: 0x%x\n",
+ rate_n_flags);
+ rate_n_flags = iwl_new_rate_from_v1(rate_n_flags);
+ IWL_DEBUG_DROP(mvm, " Rate after conversion to the new format: 0x%x\n",
+ rate_n_flags);
+ }
+ format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*desc)))
return;
@@ -2075,7 +2095,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
break;
}
- if (rate_n_flags & RATE_MCS_HE_MSK)
+ if (format == RATE_MCS_HE_MSK)
iwl_mvm_rx_he(mvm, skb, &phy_data, rate_n_flags,
phy_info, queue);
@@ -2091,23 +2111,24 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
rcu_read_lock();
- if (!(rate_n_flags & RATE_MCS_CCK_MSK) &&
- rate_n_flags & RATE_MCS_SGI_MSK)
+ is_sgi = format == RATE_MCS_HE_MSK ?
+ iwl_he_is_sgi(rate_n_flags) :
+ rate_n_flags & RATE_MCS_SGI_MSK;
+
+ if (!(format == RATE_MCS_CCK_MSK) && is_sgi)
rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
- if (rate_n_flags & RATE_HT_MCS_GF_MSK)
- rx_status->enc_flags |= RX_ENC_FLAG_HT_GF;
if (rate_n_flags & RATE_MCS_LDPC_MSK)
rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
- if (rate_n_flags & RATE_MCS_HT_MSK) {
+ if (format == RATE_MCS_HT_MSK) {
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
RATE_MCS_STBC_POS;
rx_status->encoding = RX_ENC_HT;
- rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
+ rx_status->rate_idx = RATE_HT_MCS_INDEX(rate_n_flags);
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
- } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+ } else if (format == RATE_MCS_VHT_MSK) {
u8 stbc = (rate_n_flags & RATE_MCS_STBC_MSK) >>
RATE_MCS_STBC_POS;
- rx_status->rate_idx = rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK;
+ rx_status->rate_idx = rate_n_flags & RATE_MCS_CODE_MSK;
rx_status->encoding = RX_ENC_VHT;
rx_status->enc_flags |= stbc << RX_ENC_FLAG_STBC_SHIFT;
if (rate_n_flags & RATE_MCS_BF_MSK)
@@ -2120,12 +2141,12 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_status->nss =
le32_get_bits(desc->rx_vec[0],
RX_NO_DATA_RX_VEC0_VHT_NSTS_MSK) + 1;
- } else if (rate_n_flags & RATE_MCS_HE_MSK) {
+ } else if (format == RATE_MCS_HE_MSK) {
rx_status->nss =
le32_get_bits(desc->rx_vec[0],
RX_NO_DATA_RX_VEC0_HE_NSTS_MSK) + 1;
} else {
- int rate = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
+ int rate = iwl_mvm_legacy_hw_idx_to_mac80211_idx(rate_n_flags,
rx_status->band);
if (WARN(rate < 0 || rate > 0xFF,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index d78e436fa8b5..a138b5c4cce8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -163,7 +163,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum nl80211_band band,
tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
if (band == NL80211_BAND_2GHZ && !no_cck)
- return cpu_to_le32(IWL_RATE_1M_PLCP | RATE_MCS_CCK_MSK |
+ return cpu_to_le32(IWL_RATE_1M_PLCP | RATE_MCS_CCK_MSK_V1 |
tx_ant);
else
return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant);
@@ -1995,8 +1995,16 @@ static u16 iwl_mvm_scan_umac_flags_v2(struct iwl_mvm *mvm,
{
u16 flags = 0;
+ /*
+ * If no direct SSIDs are provided perform a passive scan. Otherwise,
+ * if there is a single SSID which is not the broadcast SSID, assume
+ * that the scan is intended for roaming purposes and thus enable Rx on
+ * all chains to improve chances of hearing the beacons/probe responses.
+ */
if (params->n_ssids == 0)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE;
+ else if (params->n_ssids == 1 && params->ssids[0].ssid_len)
+ flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_USE_ALL_RX_CHAINS;
if (iwl_mvm_is_scan_fragmented(params->type))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index 25af88a3edce..e91f8e889df7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -662,12 +662,13 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
u32 *uid)
{
u32 id;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+ struct iwl_mvm_vif *mvmvif;
enum nl80211_iftype iftype;
if (!te_data->vif)
return false;
+ mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
iftype = te_data->vif->type;
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 0a13c2bda2ee..bdd4ee432548 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -268,6 +268,7 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm,
int rate_idx = -1;
u8 rate_plcp;
u32 rate_flags = 0;
+ bool is_cck;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
/* info->control is only relevant for non HW rate control */
@@ -299,11 +300,18 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm,
BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
/* Get PLCP rate for tx_cmd->rate_n_flags */
- rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
+ rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate_idx);
+ is_cck = (rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE);
- /* Set CCK flag as needed */
- if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
- rate_flags |= RATE_MCS_CCK_MSK;
+ /* Set CCK or OFDM flag */
+ if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) > 8) {
+ if (!is_cck)
+ rate_flags |= RATE_MCS_LEGACY_OFDM_MSK;
+ else
+ rate_flags |= RATE_MCS_CCK_MSK;
+ } else if (is_cck) {
+ rate_flags |= RATE_MCS_CCK_MSK_V1;
+ }
return (u32)rate_plcp | rate_flags;
}
@@ -1284,31 +1292,72 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status)
}
#endif /* CONFIG_IWLWIFI_DEBUG */
-void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
- enum nl80211_band band,
- struct ieee80211_tx_rate *r)
+static int iwl_mvm_get_hwrate_chan_width(u32 chan_width)
{
- if (rate_n_flags & RATE_HT_MCS_GF_MSK)
- r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
- switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
+ switch (chan_width) {
case RATE_MCS_CHAN_WIDTH_20:
- break;
+ return 0;
case RATE_MCS_CHAN_WIDTH_40:
- r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- break;
+ return IEEE80211_TX_RC_40_MHZ_WIDTH;
case RATE_MCS_CHAN_WIDTH_80:
- r->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
- break;
+ return IEEE80211_TX_RC_80_MHZ_WIDTH;
case RATE_MCS_CHAN_WIDTH_160:
- r->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH;
- break;
+ return IEEE80211_TX_RC_160_MHZ_WIDTH;
+ default:
+ return 0;
}
+}
+
+void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
+ enum nl80211_band band,
+ struct ieee80211_tx_rate *r)
+{
+ u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
+ u32 rate = format == RATE_MCS_HT_MSK ?
+ RATE_HT_MCS_INDEX(rate_n_flags) :
+ rate_n_flags & RATE_MCS_CODE_MSK;
+
+ r->flags |=
+ iwl_mvm_get_hwrate_chan_width(rate_n_flags &
+ RATE_MCS_CHAN_WIDTH_MSK);
+
if (rate_n_flags & RATE_MCS_SGI_MSK)
r->flags |= IEEE80211_TX_RC_SHORT_GI;
- if (rate_n_flags & RATE_MCS_HT_MSK) {
+ if (format == RATE_MCS_HT_MSK) {
r->flags |= IEEE80211_TX_RC_MCS;
- r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
- } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
+ r->idx = rate;
+ } else if (format == RATE_MCS_VHT_MSK) {
+ ieee80211_rate_set_vht(r, rate,
+ ((rate_n_flags & RATE_MCS_NSS_MSK) >>
+ RATE_MCS_NSS_POS) + 1);
+ r->flags |= IEEE80211_TX_RC_VHT_MCS;
+ } else if (format == RATE_MCS_HE_MSK) {
+ /* mac80211 cannot do this without ieee80211_tx_status_ext()
+ * but it only matters for radiotap */
+ r->idx = 0;
+ } else {
+ r->idx = iwl_mvm_legacy_hw_idx_to_mac80211_idx(rate_n_flags,
+ band);
+ }
+}
+
+void iwl_mvm_hwrate_to_tx_rate_v1(u32 rate_n_flags,
+ enum nl80211_band band,
+ struct ieee80211_tx_rate *r)
+{
+ if (rate_n_flags & RATE_HT_MCS_GF_MSK)
+ r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+
+ r->flags |=
+ iwl_mvm_get_hwrate_chan_width(rate_n_flags &
+ RATE_MCS_CHAN_WIDTH_MSK_V1);
+
+ if (rate_n_flags & RATE_MCS_SGI_MSK_V1)
+ r->flags |= IEEE80211_TX_RC_SHORT_GI;
+ if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
+ r->flags |= IEEE80211_TX_RC_MCS;
+ r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK_V1;
+ } else if (rate_n_flags & RATE_MCS_VHT_MSK_V1) {
ieee80211_rate_set_vht(
r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK,
((rate_n_flags & RATE_VHT_MCS_NSS_MSK) >>
@@ -1323,14 +1372,20 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
/*
* translate ucode response to mac80211 tx status control values
*/
-static void iwl_mvm_hwrate_to_tx_status(u32 rate_n_flags,
+static void iwl_mvm_hwrate_to_tx_status(const struct iwl_fw *fw,
+ u32 rate_n_flags,
struct ieee80211_tx_info *info)
{
struct ieee80211_tx_rate *r = &info->status.rates[0];
+ if (iwl_fw_lookup_notif_ver(fw, LONG_GROUP,
+ TX_CMD, 0) > 6)
+ rate_n_flags = iwl_new_rate_from_v1(rate_n_flags);
+
info->status.antenna =
- ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
- iwl_mvm_hwrate_to_tx_rate(rate_n_flags, info->band, r);
+ ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS);
+ iwl_mvm_hwrate_to_tx_rate(rate_n_flags,
+ info->band, r);
}
static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm,
@@ -1450,7 +1505,9 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
/* the FW should have stopped the queue and not
* return this status
*/
- WARN_ON(1);
+ IWL_ERR_LIMIT(mvm,
+ "FW reported TX filtered, status=0x%x, FC=0x%x\n",
+ status, le16_to_cpu(hdr->frame_control));
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
break;
default:
@@ -1472,8 +1529,14 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
iwl_mvm_tx_status_check_trigger(mvm, status, hdr->frame_control);
info->status.rates[0].count = tx_resp->failure_frame + 1;
- iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate),
+
+ iwl_mvm_hwrate_to_tx_status(mvm->fw,
+ le32_to_cpu(tx_resp->initial_rate),
info);
+
+ /* Don't assign the converted initial_rate, because driver
+ * TLC uses this and doesn't support the new FW rate
+ */
info->status.status_driver_data[1] =
(void *)(uintptr_t)le32_to_cpu(tx_resp->initial_rate);
@@ -1835,7 +1898,7 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,
info->flags |= IEEE80211_TX_STAT_AMPDU;
memcpy(&info->status, &tx_info->status,
sizeof(tx_info->status));
- iwl_mvm_hwrate_to_tx_status(rate, info);
+ iwl_mvm_hwrate_to_tx_status(mvm->fw, rate, info);
}
}
@@ -1856,7 +1919,7 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,
goto out;
tx_info->band = chanctx_conf->def.chan->band;
- iwl_mvm_hwrate_to_tx_status(rate, tx_info);
+ iwl_mvm_hwrate_to_tx_status(mvm->fw, rate, tx_info);
if (!iwl_mvm_has_tlc_offload(mvm)) {
IWL_DEBUG_TX_REPLY(mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 4a3d2971a98b..caf1dcf48888 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -135,31 +135,25 @@ int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len,
return iwl_mvm_send_cmd_status(mvm, &cmd, status);
}
-#define IWL_DECLARE_RATE_INFO(r) \
- [IWL_RATE_##r##M_INDEX] = IWL_RATE_##r##M_PLCP
+int iwl_mvm_legacy_hw_idx_to_mac80211_idx(u32 rate_n_flags,
+ enum nl80211_band band)
+{
+ int format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
+ int rate = rate_n_flags & RATE_LEGACY_RATE_MSK;
+ bool is_LB = band == NL80211_BAND_2GHZ;
-/*
- * Translate from fw_rate_index (IWL_RATE_XXM_INDEX) to PLCP
- */
-static const u8 fw_rate_idx_to_plcp[IWL_RATE_COUNT] = {
- IWL_DECLARE_RATE_INFO(1),
- IWL_DECLARE_RATE_INFO(2),
- IWL_DECLARE_RATE_INFO(5),
- IWL_DECLARE_RATE_INFO(11),
- IWL_DECLARE_RATE_INFO(6),
- IWL_DECLARE_RATE_INFO(9),
- IWL_DECLARE_RATE_INFO(12),
- IWL_DECLARE_RATE_INFO(18),
- IWL_DECLARE_RATE_INFO(24),
- IWL_DECLARE_RATE_INFO(36),
- IWL_DECLARE_RATE_INFO(48),
- IWL_DECLARE_RATE_INFO(54),
-};
+ if (format == RATE_MCS_LEGACY_OFDM_MSK)
+ return is_LB ? rate + IWL_FIRST_OFDM_RATE :
+ rate;
+
+ /* CCK is not allowed in HB */
+ return is_LB ? rate : -1;
+}
int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
enum nl80211_band band)
{
- int rate = rate_n_flags & RATE_LEGACY_RATE_MSK;
+ int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1;
int idx;
int band_offset = 0;
@@ -167,16 +161,24 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags,
if (band != NL80211_BAND_2GHZ)
band_offset = IWL_FIRST_OFDM_RATE;
for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
- if (fw_rate_idx_to_plcp[idx] == rate)
+ if (iwl_fw_rate_idx_to_plcp(idx) == rate)
return idx - band_offset;
return -1;
}
-u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx)
+u8 iwl_mvm_mac80211_idx_to_hwrate(const struct iwl_fw *fw, int rate_idx)
{
- /* Get PLCP rate for tx_cmd->rate_n_flags */
- return fw_rate_idx_to_plcp[rate_idx];
+ if (iwl_fw_lookup_cmd_ver(fw, LONG_GROUP,
+ TX_CMD, 0) > 8)
+ /* In the new rate legacy rates are indexed:
+ * 0 - 3 for CCK and 0 - 7 for OFDM.
+ */
+ return (rate_idx >= IWL_FIRST_OFDM_RATE ?
+ rate_idx - IWL_FIRST_OFDM_RATE :
+ rate_idx);
+
+ return iwl_fw_rate_idx_to_plcp(rate_idx);
}
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac)
@@ -217,6 +219,7 @@ u8 first_antenna(u8 mask)
return BIT(ffs(mask) - 1);
}
+#define MAX_ANT_NUM 2
/*
* Toggles between TX antennas to send the probe request on.
* Receives the bitmask of valid TX antennas and the *index* used
@@ -405,6 +408,9 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
+ if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
+ return false;
+
if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)
return false;