aboutsummaryrefslogtreecommitdiffstats
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/Makefile4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/coex.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c813
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c229
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c654
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c244
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c148
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/led.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c322
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c577
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h262
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/nvm.c15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c177
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/power.c23
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c21
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.c56
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rx.c12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c197
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c20
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sf.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c519
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tdls.c33
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tof.c305
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tof.h89
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c186
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c66
32 files changed, 2854 insertions, 2190 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile
index 9ffd21918b5a..dd268c4bd371 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile
@@ -5,9 +5,9 @@ iwlmvm-y += utils.o rx.o rxmq.o tx.o binding.o quota.o sta.o sf.o
iwlmvm-y += scan.o time-event.o rs.o rs-fw.o
iwlmvm-y += power.o coex.o
iwlmvm-y += tt.o offloading.o tdls.o
+iwlmvm-y += ftm-responder.o ftm-initiator.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
-iwlmvm-y += tof.o
iwlmvm-$(CONFIG_PM) += d3.o
-ccflags-y += -I$(src)/../
+ccflags-y += -I $(srctree)/$(src)/../
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
index 730e37744dc0..3d2abbc5c76c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
@@ -241,7 +241,6 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
struct iwl_bt_coex_reduced_txp_update_cmd cmd = {};
struct iwl_mvm_sta *mvmsta;
u32 value;
- int ret;
mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id);
if (!mvmsta)
@@ -262,10 +261,8 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
cmd.reduced_txp = cpu_to_le32(value);
mvmsta->bt_reduced_txpower = enable;
- ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP, CMD_ASYNC,
- sizeof(cmd), &cmd);
-
- return ret;
+ return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP,
+ CMD_ASYNC, sizeof(cmd), &cmd);
}
struct iwl_bt_iterator_data {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
index d96ada3c06fc..dff14f1ec55f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
@@ -8,6 +8,7 @@
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2018 - 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,6 +65,7 @@
#define __MVM_CONSTANTS_H
#include <linux/ieee80211.h>
+#include "fw-api.h"
#define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20
@@ -114,6 +117,7 @@
#define IWL_MVM_TCM_LOWLAT_ENABLE_THRESH 100 /* packets/10 seconds */
#define IWL_MVM_UAPSD_NONAGG_PERIOD 5000 /* msecs */
#define IWL_MVM_UAPSD_NOAGG_LIST_LEN IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM
+#define IWL_MVM_NON_TRANSMITTING_AP 0
#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1
@@ -145,5 +149,8 @@
#define IWL_MVM_RS_TPC_SR_NO_INCREASE 85 /* percent */
#define IWL_MVM_RS_TPC_TX_POWER_STEP 3
#define IWL_MVM_ENABLE_EBS 1
+#define IWL_MVM_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE
+#define IWL_MVM_FTM_INITIATOR_DYNACK true
+#define IWL_MVM_D3_DEBUG false
#endif /* __MVM_CONSTANTS_H */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 01b5338201d6..808bc6f363d0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1899,7 +1899,7 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
static int iwl_mvm_check_rt_status(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
- u32 base = mvm->error_event_table[0];
+ u32 base = mvm->trans->lmac_error_event_table[0];
struct error_table_start {
/* cf. struct iwl_error_event_table */
u32 valid;
@@ -2125,7 +2125,6 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
file->private_data = inode->i_private;
- ieee80211_stop_queues(mvm->hw);
synchronize_net();
mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;
@@ -2140,10 +2139,9 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
rtnl_unlock();
if (err > 0)
err = -EINVAL;
- if (err) {
- ieee80211_wake_queues(mvm->hw);
+ if (err)
return err;
- }
+
mvm->d3_test_active = true;
mvm->keep_vif = NULL;
return 0;
@@ -2223,8 +2221,6 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif);
- ieee80211_wake_queues(mvm->hw);
-
return 0;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index 33b0af24a537..2453ceabf00d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -60,7 +60,6 @@
*
*****************************************************************************/
#include "mvm.h"
-#include "fw/api/tof.h"
#include "debugfs.h"
static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
@@ -523,753 +522,30 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
-static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
- char *buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- u32 value;
- int ret = -EINVAL;
- char *data;
-
- mutex_lock(&mvm->mutex);
-
- data = iwl_dbgfs_is_match("tof_disabled=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.tof_cfg.tof_disabled = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("one_sided_disabled=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.tof_cfg.one_sided_disabled = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("is_debug_mode=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.tof_cfg.is_debug_mode = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("is_buf=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.tof_cfg.is_buf_required = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("send_tof_cfg=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0 && value) {
- ret = iwl_mvm_tof_config_cmd(mvm);
- goto out;
- }
- }
-
-out:
- mutex_unlock(&mvm->mutex);
-
- return ret ?: count;
-}
-
-static ssize_t iwl_dbgfs_tof_enable_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_vif *vif = file->private_data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- char buf[256];
- int pos = 0;
- const size_t bufsz = sizeof(buf);
- struct iwl_tof_config_cmd *cmd;
-
- cmd = &mvm->tof_data.tof_cfg;
-
- mutex_lock(&mvm->mutex);
-
- pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n",
- cmd->tof_disabled);
- pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n",
- cmd->one_sided_disabled);
- pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n",
- cmd->is_debug_mode);
- pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n",
- cmd->is_buf_required);
-
- mutex_unlock(&mvm->mutex);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_tof_responder_params_write(struct ieee80211_vif *vif,
- char *buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- u32 value;
- int ret = 0;
- char *data;
-
- mutex_lock(&mvm->mutex);
-
- data = iwl_dbgfs_is_match("burst_period=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (!ret)
- mvm->tof_data.responder_cfg.burst_period =
- cpu_to_le16(value);
- goto out;
- }
-
- data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.min_delta_ftm = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("burst_duration=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.burst_duration = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("num_of_burst_exp=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.num_of_burst_exp = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("abort_responder=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.abort_responder = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("get_ch_est=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.get_ch_est = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("recv_sta_req_params=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.recv_sta_req_params = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("channel_num=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.channel_num = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("bandwidth=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.bandwidth = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("rate=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.rate = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("bssid=", buf);
- if (data) {
- u8 *mac = mvm->tof_data.responder_cfg.bssid;
-
- if (!mac_pton(data, mac)) {
- ret = -EINVAL;
- goto out;
- }
- }
-
- data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.tsf_timer_offset_msecs =
- cpu_to_le16(value);
- goto out;
- }
-
- data = iwl_dbgfs_is_match("toa_offset=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.toa_offset =
- cpu_to_le16(value);
- goto out;
- }
-
- data = iwl_dbgfs_is_match("center_freq=", buf);
- if (data) {
- struct iwl_tof_responder_config_cmd *cmd =
- &mvm->tof_data.responder_cfg;
-
- ret = kstrtou32(data, 10, &value);
- if (ret == 0 && value) {
- enum nl80211_band band = (cmd->channel_num <= 14) ?
- NL80211_BAND_2GHZ :
- NL80211_BAND_5GHZ;
- struct ieee80211_channel chn = {
- .band = band,
- .center_freq = ieee80211_channel_to_frequency(
- cmd->channel_num, band),
- };
- struct cfg80211_chan_def chandef = {
- .chan = &chn,
- .center_freq1 =
- ieee80211_channel_to_frequency(value,
- band),
- };
-
- cmd->ctrl_ch_position = iwl_mvm_get_ctrl_pos(&chandef);
- }
- goto out;
- }
-
- data = iwl_dbgfs_is_match("ftm_per_burst=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.ftm_per_burst = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("asap_mode=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.responder_cfg.asap_mode = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("send_responder_cfg=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0 && value) {
- ret = iwl_mvm_tof_responder_cmd(mvm, vif);
- goto out;
- }
- }
-
-out:
- mutex_unlock(&mvm->mutex);
-
- return ret ?: count;
-}
-
-static ssize_t iwl_dbgfs_tof_responder_params_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_vif *vif = file->private_data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- char buf[256];
- int pos = 0;
- const size_t bufsz = sizeof(buf);
- struct iwl_tof_responder_config_cmd *cmd;
-
- cmd = &mvm->tof_data.responder_cfg;
-
- mutex_lock(&mvm->mutex);
-
- pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n",
- le16_to_cpu(cmd->burst_period));
- pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n",
- cmd->burst_duration);
- pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n",
- cmd->bandwidth);
- pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n",
- cmd->channel_num);
- pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n",
- cmd->ctrl_ch_position);
- pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n",
- cmd->bssid);
- pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n",
- cmd->min_delta_ftm);
- pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n",
- cmd->num_of_burst_exp);
- pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate);
- pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n",
- cmd->abort_responder);
- pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n",
- cmd->get_ch_est);
- pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n",
- cmd->recv_sta_req_params);
- pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n",
- cmd->ftm_per_burst);
- pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n",
- cmd->ftm_resp_ts_avail);
- pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n",
- cmd->asap_mode);
- pos += scnprintf(buf + pos, bufsz - pos,
- "tsf_timer_offset_msecs = %d\n",
- le16_to_cpu(cmd->tsf_timer_offset_msecs));
- pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n",
- le16_to_cpu(cmd->toa_offset));
-
- mutex_unlock(&mvm->mutex);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_tof_range_request_write(struct ieee80211_vif *vif,
- char *buf, size_t count,
- loff_t *ppos)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- u32 value;
- int ret = 0;
- char *data;
-
- mutex_lock(&mvm->mutex);
-
- data = iwl_dbgfs_is_match("request_id=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req.request_id = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("initiator=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req.initiator = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("one_sided_los_disable=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req.one_sided_los_disable = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("req_timeout=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req.req_timeout = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("report_policy=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req.report_policy = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("macaddr_random=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req.macaddr_random = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("num_of_ap=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req.num_of_ap = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("macaddr_template=", buf);
- if (data) {
- u8 mac[ETH_ALEN];
-
- if (!mac_pton(data, mac)) {
- ret = -EINVAL;
- goto out;
- }
- memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN);
- goto out;
- }
-
- data = iwl_dbgfs_is_match("macaddr_mask=", buf);
- if (data) {
- u8 mac[ETH_ALEN];
-
- if (!mac_pton(data, mac)) {
- ret = -EINVAL;
- goto out;
- }
- memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN);
- goto out;
- }
-
- data = iwl_dbgfs_is_match("ap=", buf);
- if (data) {
- struct iwl_tof_range_req_ap_entry ap = {};
- int size = sizeof(struct iwl_tof_range_req_ap_entry);
- u16 burst_period;
- u8 *mac = ap.bssid;
- unsigned int i;
-
- if (sscanf(data, "%u %hhd %hhd %hhd"
- "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"
- "%hhd %hhd %hd"
- "%hhd %hhd %d"
- "%hhx %hhd %hhd %hhd",
- &i, &ap.channel_num, &ap.bandwidth,
- &ap.ctrl_ch_position,
- mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5,
- &ap.measure_type, &ap.num_of_bursts,
- &burst_period,
- &ap.samples_per_burst, &ap.retries_per_sample,
- &ap.tsf_delta, &ap.location_req, &ap.asap_mode,
- &ap.enable_dyn_ack, &ap.rssi) != 20) {
- ret = -EINVAL;
- goto out;
- }
- if (i >= IWL_MVM_TOF_MAX_APS) {
- IWL_ERR(mvm, "Invalid AP index %d\n", i);
- ret = -EINVAL;
- goto out;
- }
-
- ap.burst_period = cpu_to_le16(burst_period);
-
- memcpy(&mvm->tof_data.range_req.ap[i], &ap, size);
- goto out;
- }
-
- data = iwl_dbgfs_is_match("send_range_request=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0 && value)
- ret = iwl_mvm_tof_range_request_cmd(mvm, vif);
- goto out;
- }
-
- ret = -EINVAL;
-out:
- mutex_unlock(&mvm->mutex);
- return ret ?: count;
-}
-
-static ssize_t iwl_dbgfs_tof_range_request_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_vif *vif = file->private_data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- char buf[512];
- int pos = 0;
- const size_t bufsz = sizeof(buf);
- struct iwl_tof_range_req_cmd *cmd;
- int i;
-
- cmd = &mvm->tof_data.range_req;
-
- mutex_lock(&mvm->mutex);
-
- pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n",
- cmd->request_id);
- pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n",
- cmd->initiator);
- pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n",
- cmd->one_sided_los_disable);
- pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n",
- cmd->req_timeout);
- pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n",
- cmd->report_policy);
- pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n",
- cmd->macaddr_random);
- pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n",
- cmd->macaddr_template);
- pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n",
- cmd->macaddr_mask);
- pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n",
- cmd->num_of_ap);
- for (i = 0; i < cmd->num_of_ap; i++) {
- struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i];
-
- pos += scnprintf(buf + pos, bufsz - pos,
- "ap %.2d: channel_num=%hhd bw=%hhd"
- " control=%hhd bssid=%pM type=%hhd"
- " num_of_bursts=%hhd burst_period=%hd ftm=%hhd"
- " retries=%hhd tsf_delta=%d"
- " tsf_delta_direction=%hhd location_req=0x%hhx "
- " asap=%hhd enable=%hhd rssi=%hhd\n",
- i, ap->channel_num, ap->bandwidth,
- ap->ctrl_ch_position, ap->bssid,
- ap->measure_type, ap->num_of_bursts,
- ap->burst_period, ap->samples_per_burst,
- ap->retries_per_sample, ap->tsf_delta,
- ap->tsf_delta_direction,
- ap->location_req, ap->asap_mode,
- ap->enable_dyn_ack, ap->rssi);
- }
-
- mutex_unlock(&mvm->mutex);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_tof_range_req_ext_write(struct ieee80211_vif *vif,
- char *buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- u32 value;
- int ret = 0;
- char *data;
-
- mutex_lock(&mvm->mutex);
-
- data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req_ext.tsf_timer_offset_msec =
- cpu_to_le16(value);
- goto out;
- }
-
- data = iwl_dbgfs_is_match("min_delta_ftm=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req_ext.min_delta_ftm = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req_ext.ftm_format_and_bw20M =
- value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req_ext.ftm_format_and_bw40M =
- value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.range_req_ext.ftm_format_and_bw80M =
- value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("send_range_req_ext=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0 && value)
- ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif);
- goto out;
- }
-
- ret = -EINVAL;
-out:
- mutex_unlock(&mvm->mutex);
- return ret ?: count;
-}
-
-static ssize_t iwl_dbgfs_tof_range_req_ext_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_vif *vif = file->private_data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- char buf[256];
- int pos = 0;
- const size_t bufsz = sizeof(buf);
- struct iwl_tof_range_req_ext_cmd *cmd;
-
- cmd = &mvm->tof_data.range_req_ext;
-
- mutex_lock(&mvm->mutex);
-
- pos += scnprintf(buf + pos, bufsz - pos,
- "tsf_timer_offset_msec = %hd\n",
- cmd->tsf_timer_offset_msec);
- pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhd\n",
- cmd->min_delta_ftm);
- pos += scnprintf(buf + pos, bufsz - pos,
- "ftm_format_and_bw20M = %hhd\n",
- cmd->ftm_format_and_bw20M);
- pos += scnprintf(buf + pos, bufsz - pos,
- "ftm_format_and_bw40M = %hhd\n",
- cmd->ftm_format_and_bw40M);
- pos += scnprintf(buf + pos, bufsz - pos,
- "ftm_format_and_bw80M = %hhd\n",
- cmd->ftm_format_and_bw80M);
-
- mutex_unlock(&mvm->mutex);
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_tof_range_abort_write(struct ieee80211_vif *vif,
- char *buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- u32 value;
- int abort_id, ret = 0;
- char *data;
-
- mutex_lock(&mvm->mutex);
-
- data = iwl_dbgfs_is_match("abort_id=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0)
- mvm->tof_data.last_abort_id = value;
- goto out;
- }
-
- data = iwl_dbgfs_is_match("send_range_abort=", buf);
- if (data) {
- ret = kstrtou32(data, 10, &value);
- if (ret == 0 && value) {
- abort_id = mvm->tof_data.last_abort_id;
- ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id);
- goto out;
- }
- }
-
-out:
- mutex_unlock(&mvm->mutex);
- return ret ?: count;
-}
-
-static ssize_t iwl_dbgfs_tof_range_abort_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_vif *vif = file->private_data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- char buf[32];
- int pos = 0;
- const size_t bufsz = sizeof(buf);
- int last_abort_id;
-
- mutex_lock(&mvm->mutex);
- last_abort_id = mvm->tof_data.last_abort_id;
- mutex_unlock(&mvm->mutex);
-
- pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n",
- last_abort_id);
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_tof_range_response_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
+static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
+ size_t count, loff_t *ppos)
{
- struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
- char *buf;
- int pos = 0;
- const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256;
- struct iwl_tof_range_rsp_ntfy *cmd;
- int i, ret;
+ u8 value;
+ int ret;
- buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ ret = kstrtou8(buf, 0, &value);
+ if (ret)
+ return ret;
+ if (value > 1)
+ return -EINVAL;
mutex_lock(&mvm->mutex);
- cmd = &mvm->tof_data.range_resp;
-
- pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n",
- cmd->request_id);
- pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n",
- cmd->request_status);
- pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n",
- cmd->last_in_batch);
- pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n",
- cmd->num_of_aps);
- for (i = 0; i < cmd->num_of_aps; i++) {
- struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i];
-
- pos += scnprintf(buf + pos, bufsz - pos,
- "ap %.2d: bssid=%pM status=%hhd bw=%hhd"
- " rtt=%d rtt_var=%d rtt_spread=%d"
- " rssi=%hhd rssi_spread=%hhd"
- " range=%d range_var=%d"
- " time_stamp=%d\n",
- i, ap->bssid, ap->measure_status,
- ap->measure_bw,
- ap->rtt, ap->rtt_variance, ap->rtt_spread,
- ap->rssi, ap->rssi_spread, ap->range,
- ap->range_variance, ap->timestamp);
- }
+ iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS);
mutex_unlock(&mvm->mutex);
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- kfree(buf);
- return ret;
+ return count;
}
-static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
- size_t count, loff_t *ppos)
+static ssize_t
+iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf,
+ size_t count, loff_t *ppos)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = mvmvif->mvm;
@@ -1279,13 +555,24 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
ret = kstrtou8(buf, 0, &value);
if (ret)
return ret;
- if (value > 1)
+
+ if (value > NUM_LOW_LATENCY_FORCE)
return -EINVAL;
mutex_lock(&mvm->mutex);
- iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS);
+ if (value == LOW_LATENCY_FORCE_UNSET) {
+ iwl_mvm_update_low_latency(mvm, vif, false,
+ LOW_LATENCY_DEBUGFS_FORCE);
+ iwl_mvm_update_low_latency(mvm, vif, false,
+ LOW_LATENCY_DEBUGFS_FORCE_ENABLE);
+ } else {
+ iwl_mvm_update_low_latency(mvm, vif,
+ value == LOW_LATENCY_FORCE_ON,
+ LOW_LATENCY_DEBUGFS_FORCE);
+ iwl_mvm_update_low_latency(mvm, vif, true,
+ LOW_LATENCY_DEBUGFS_FORCE_ENABLE);
+ }
mutex_unlock(&mvm->mutex);
-
return count;
}
@@ -1295,15 +582,25 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
{
struct ieee80211_vif *vif = file->private_data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- char buf[30] = {};
+ char format[] = "traffic=%d\ndbgfs=%d\nvcmd=%d\nvif_type=%d\n"
+ "dbgfs_force_enable=%d\ndbgfs_force=%d\nactual=%d\n";
+
+ /*
+ * all values in format are boolean so the size of format is enough
+ * for holding the result string
+ */
+ char buf[sizeof(format) + 1] = {};
int len;
- len = scnprintf(buf, sizeof(buf) - 1,
- "traffic=%d\ndbgfs=%d\nvcmd=%d\nvif_type=%d\n",
+ len = scnprintf(buf, sizeof(buf) - 1, format,
!!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC),
!!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS),
!!(mvmvif->low_latency & LOW_LATENCY_VCMD),
- !!(mvmvif->low_latency & LOW_LATENCY_VIF_TYPE));
+ !!(mvmvif->low_latency & LOW_LATENCY_VIF_TYPE),
+ !!(mvmvif->low_latency &
+ LOW_LATENCY_DEBUGFS_FORCE_ENABLE),
+ !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS_FORCE),
+ !!(mvmvif->low_latency_actual));
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1456,14 +753,9 @@ MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
+MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10);
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32);
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512);
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
-MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
-MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
@@ -1497,6 +789,7 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400);
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400);
MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600);
+ MVM_DEBUGFS_ADD_FILE_VIF(low_latency_force, mvmvif->dbgfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600);
@@ -1506,24 +799,6 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif == mvm->bf_allowed_vif)
MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600);
- if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) &&
- !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) {
- if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP)
- MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params,
- mvmvif->dbgfs_dir, 0600);
-
- MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir,
- 0600);
- MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir,
- 0600);
- MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir,
- 0600);
- MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir,
- 0600);
- MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir,
- 0400);
- }
-
/*
* Create symlink for convenience pointing to interface specific
* debugfs entries for the driver. For example, under
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 52c361a6124c..776b24f54200 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -8,7 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -69,6 +69,7 @@
#include "sta.h"
#include "iwl-io.h"
#include "debugfs.h"
+#include "iwl-modparams.h"
#include "fw/error-dump.h"
static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file,
@@ -1187,64 +1188,128 @@ out:
return ret ?: count;
}
-static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
+static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len)
{
- struct iwl_mvm *mvm = file->private_data;
- int conf;
- char buf[8];
- const size_t bufsz = sizeof(buf);
- int pos = 0;
+ struct ieee80211_vif *vif;
+ struct iwl_mvm_vif *mvmvif;
+ struct sk_buff *beacon;
+ struct ieee80211_tx_info *info;
+ struct iwl_mac_beacon_cmd beacon_cmd = {};
+ u8 rate;
+ u16 flags;
+ int i;
+
+ len /= 2;
+
+ /* Element len should be represented by u8 */
+ if (len >= U8_MAX)
+ return -EINVAL;
+
+ if (!iwl_mvm_firmware_running(mvm))
+ return -EIO;
+
+ if (!iwl_mvm_has_new_tx_api(mvm) &&
+ !fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE))
+ return -EINVAL;
+
+ rcu_read_lock();
+
+ for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) {
+ vif = iwl_mvm_rcu_dereference_vif_id(mvm, i, true);
+ if (!vif)
+ continue;
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ break;
+ }
+
+ if (i == NUM_MAC_INDEX_DRIVER || !vif)
+ goto out_err;
+
+ mvm->hw->extra_beacon_tailroom = len;
+
+ beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL);
+ if (!beacon)
+ goto out_err;
+
+ if (len && hex2bin(skb_put_zero(beacon, len), bin, len)) {
+ dev_kfree_skb(beacon);
+ goto out_err;
+ }
+
+ mvm->beacon_inject_active = true;
+
+ 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.byte_cnt = cpu_to_le16((u16)beacon->len);
+ beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
+
+ iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx,
+ &beacon_cmd.tim_size,
+ beacon->data, beacon->len);
mutex_lock(&mvm->mutex);
- conf = mvm->fwrt.dump.conf;
+ iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd,
+ sizeof(beacon_cmd));
mutex_unlock(&mvm->mutex);
- pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf);
+ dev_kfree_skb(beacon);
- return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ rcu_read_unlock();
+ return 0;
+
+out_err:
+ rcu_read_unlock();
+ return -EINVAL;
}
-/*
- * Enable / Disable continuous recording.
- * Cause the FW to start continuous recording, by sending the relevant hcmd.
- * Enable: input of every integer larger than 0, ENABLE_CONT_RECORDING.
- * Disable: for 0 as input, DISABLE_CONT_RECORDING.
- */
-static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
- char *buf, size_t count,
- loff_t *ppos)
+static ssize_t iwl_dbgfs_inject_beacon_ie_write(struct iwl_mvm *mvm,
+ char *buf, size_t count,
+ loff_t *ppos)
{
- struct iwl_trans *trans = mvm->trans;
- const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
- struct iwl_continuous_record_cmd cont_rec = {};
- int ret, rec_mode;
+ int ret = _iwl_dbgfs_inject_beacon_ie(mvm, buf, count);
- if (!iwl_mvm_firmware_running(mvm))
- return -EIO;
-
- if (!dest)
- return -EOPNOTSUPP;
+ mvm->hw->extra_beacon_tailroom = 0;
+ return ret ?: count;
+}
- if (dest->monitor_mode != SMEM_MODE ||
- trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)
- return -EOPNOTSUPP;
+static ssize_t iwl_dbgfs_inject_beacon_ie_restore_write(struct iwl_mvm *mvm,
+ char *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int ret = _iwl_dbgfs_inject_beacon_ie(mvm, NULL, 0);
- ret = kstrtoint(buf, 0, &rec_mode);
- if (ret)
- return ret;
+ mvm->hw->extra_beacon_tailroom = 0;
+ mvm->beacon_inject_active = false;
+ return ret ?: count;
+}
- cont_rec.record_mode.enable_recording = rec_mode ?
- cpu_to_le16(ENABLE_CONT_RECORDING) :
- cpu_to_le16(DISABLE_CONT_RECORDING);
+static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ int conf;
+ char buf[8];
+ const size_t bufsz = sizeof(buf);
+ int pos = 0;
mutex_lock(&mvm->mutex);
- ret = iwl_mvm_send_cmd_pdu(mvm, LDBG_CONFIG_CMD, 0,
- sizeof(cont_rec), &cont_rec);
+ conf = mvm->fwrt.dump.conf;
mutex_unlock(&mvm->mutex);
- return ret ?: count;
+ pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
@@ -1722,11 +1787,36 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf,
return ret ?: count;
}
+struct iwl_mvm_sniffer_apply {
+ struct iwl_mvm *mvm;
+ u8 *bssid;
+ u16 aid;
+};
+
+static bool iwl_mvm_sniffer_apply(struct iwl_notif_wait_data *notif_data,
+ struct iwl_rx_packet *pkt, void *data)
+{
+ struct iwl_mvm_sniffer_apply *apply = data;
+
+ apply->mvm->cur_aid = cpu_to_le16(apply->aid);
+ memcpy(apply->mvm->cur_bssid, apply->bssid,
+ sizeof(apply->mvm->cur_bssid));
+
+ return true;
+}
+
static ssize_t
iwl_dbgfs_he_sniffer_params_write(struct iwl_mvm *mvm, char *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
+ struct iwl_notification_wait wait;
struct iwl_he_monitor_cmd he_mon_cmd = {};
+ struct iwl_mvm_sniffer_apply apply = {
+ .mvm = mvm,
+ };
+ u16 wait_cmds[] = {
+ iwl_cmd_id(HE_AIR_SNIFFER_CONFIG_CMD, DATA_PATH_GROUP, 0),
+ };
u32 aid;
int ret;
@@ -1742,16 +1832,54 @@ iwl_dbgfs_he_sniffer_params_write(struct iwl_mvm *mvm, char *buf,
he_mon_cmd.aid = cpu_to_le16(aid);
+ apply.aid = aid;
+ apply.bssid = (void *)he_mon_cmd.bssid;
+
mutex_lock(&mvm->mutex);
+
+ /*
+ * Use the notification waiter to get our function triggered
+ * in sequence with other RX. This ensures that frames we get
+ * on the RX queue _before_ the new configuration is applied
+ * still have mvm->cur_aid pointing to the old AID, and that
+ * frames on the RX queue _after_ the firmware processed the
+ * new configuration (and sent the response, synchronously)
+ * get mvm->cur_aid correctly set to the new AID.
+ */
+ iwl_init_notification_wait(&mvm->notif_wait, &wait,
+ wait_cmds, ARRAY_SIZE(wait_cmds),
+ iwl_mvm_sniffer_apply, &apply);
+
ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(HE_AIR_SNIFFER_CONFIG_CMD,
DATA_PATH_GROUP, 0), 0,
sizeof(he_mon_cmd), &he_mon_cmd);
+
+ /* no need to really wait, we already did anyway */
+ iwl_remove_notification(&mvm->notif_wait, &wait);
+
mutex_unlock(&mvm->mutex);
return ret ?: count;
}
static ssize_t
+iwl_dbgfs_he_sniffer_params_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ u8 buf[32];
+ int len;
+
+ len = scnprintf(buf, sizeof(buf),
+ "%d %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ le16_to_cpu(mvm->cur_aid), mvm->cur_bssid[0],
+ mvm->cur_bssid[1], mvm->cur_bssid[2], mvm->cur_bssid[3],
+ mvm->cur_bssid[4], mvm->cur_bssid[5]);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t
iwl_dbgfs_uapsd_noagg_bssids_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -1800,11 +1928,12 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
-MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
(IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512);
+MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie, 512);
+MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie_restore, 512);
MVM_DEBUGFS_READ_FILE_OPS(uapsd_noagg_bssids);
@@ -1820,7 +1949,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
#endif
-MVM_DEBUGFS_WRITE_FILE_OPS(he_sniffer_params, 32);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32);
static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
@@ -2004,13 +2133,14 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200);
- MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(inject_beacon_ie, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(inject_beacon_ie_restore, mvm->debugfs_dir, 0200);
#ifdef CONFIG_ACPI
MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, 0400);
#endif
- MVM_DEBUGFS_ADD_FILE(he_sniffer_params, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(he_sniffer_params, mvm->debugfs_dir, 0600);
if (!debugfs_create_bool("enable_scan_iteration_notif",
0600,
@@ -2071,6 +2201,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
if (!debugfs_create_blob("nvm_phy_sku", 0400,
mvm->debugfs_dir, &mvm->nvm_phy_sku_blob))
goto err;
+ if (!debugfs_create_blob("nvm_reg", S_IRUSR,
+ mvm->debugfs_dir, &mvm->nvm_reg_blob))
+ goto err;
debugfs_create_file("mem", 0600, dbgfs_dir, mvm, &iwl_dbgfs_mem_ops);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
new file mode 100644
index 000000000000..e9822a3ec373
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
@@ -0,0 +1,654 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <linuxwifi@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2019 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/etherdevice.h>
+#include <linux/math64.h>
+#include <net/cfg80211.h>
+#include "mvm.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "constants.h"
+
+struct iwl_mvm_loc_entry {
+ struct list_head list;
+ u8 addr[ETH_ALEN];
+ u8 lci_len, civic_len;
+ u8 buf[];
+};
+
+static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm)
+{
+ struct iwl_mvm_loc_entry *e, *t;
+
+ mvm->ftm_initiator.req = NULL;
+ mvm->ftm_initiator.req_wdev = NULL;
+ memset(mvm->ftm_initiator.responses, 0,
+ sizeof(mvm->ftm_initiator.responses));
+ list_for_each_entry_safe(e, t, &mvm->ftm_initiator.loc_list, list) {
+ list_del(&e->list);
+ kfree(e);
+ }
+}
+
+void iwl_mvm_ftm_restart(struct iwl_mvm *mvm)
+{
+ struct cfg80211_pmsr_result result = {
+ .status = NL80211_PMSR_STATUS_FAILURE,
+ .final = 1,
+ .host_time = ktime_get_boot_ns(),
+ .type = NL80211_PMSR_TYPE_FTM,
+ };
+ int i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (!mvm->ftm_initiator.req)
+ return;
+
+ for (i = 0; i < mvm->ftm_initiator.req->n_peers; i++) {
+ memcpy(result.addr, mvm->ftm_initiator.req->peers[i].addr,
+ ETH_ALEN);
+ result.ftm.burst_index = mvm->ftm_initiator.responses[i];
+
+ cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
+ mvm->ftm_initiator.req,
+ &result, GFP_KERNEL);
+ }
+
+ cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev,
+ mvm->ftm_initiator.req, GFP_KERNEL);
+ iwl_mvm_ftm_reset(mvm);
+}
+
+static int
+iwl_ftm_range_request_status_to_err(enum iwl_tof_range_request_status s)
+{
+ switch (s) {
+ case IWL_TOF_RANGE_REQUEST_STATUS_SUCCESS:
+ return 0;
+ case IWL_TOF_RANGE_REQUEST_STATUS_BUSY:
+ return -EBUSY;
+ default:
+ WARN_ON_ONCE(1);
+ return -EIO;
+ }
+}
+
+static void iwl_mvm_ftm_cmd_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_tof_range_req_cmd_v5 *cmd,
+ struct cfg80211_pmsr_request *req)
+{
+ int i;
+
+ cmd->request_id = req->cookie;
+ cmd->num_of_ap = req->n_peers;
+
+ /* use maximum for "no timeout" or bigger than what we can do */
+ if (!req->timeout || req->timeout > 255 * 100)
+ cmd->req_timeout = 255;
+ else
+ cmd->req_timeout = DIV_ROUND_UP(req->timeout, 100);
+
+ /*
+ * We treat it always as random, since if not we'll
+ * have filled our local address there instead.
+ */
+ cmd->macaddr_random = 1;
+ memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN);
+ for (i = 0; i < ETH_ALEN; i++)
+ cmd->macaddr_mask[i] = ~req->mac_addr_mask[i];
+
+ if (vif->bss_conf.assoc)
+ memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN);
+ else
+ eth_broadcast_addr(cmd->range_req_bssid);
+}
+
+static void iwl_mvm_ftm_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_tof_range_req_cmd *cmd,
+ struct cfg80211_pmsr_request *req)
+{
+ int i;
+
+ cmd->initiator_flags =
+ cpu_to_le32(IWL_TOF_INITIATOR_FLAGS_MACADDR_RANDOM |
+ IWL_TOF_INITIATOR_FLAGS_NON_ASAP_SUPPORT);
+ cmd->request_id = req->cookie;
+ cmd->num_of_ap = req->n_peers;
+
+ /*
+ * Use a large value for "no timeout". Don't use the maximum value
+ * because of fw limitations.
+ */
+ if (req->timeout)
+ cmd->req_timeout_ms = cpu_to_le32(req->timeout);
+ else
+ cmd->req_timeout_ms = cpu_to_le32(0xfffff);
+
+ memcpy(cmd->macaddr_template, req->mac_addr, ETH_ALEN);
+ for (i = 0; i < ETH_ALEN; i++)
+ cmd->macaddr_mask[i] = ~req->mac_addr_mask[i];
+
+ if (vif->bss_conf.assoc)
+ memcpy(cmd->range_req_bssid, vif->bss_conf.bssid, ETH_ALEN);
+ else
+ eth_broadcast_addr(cmd->range_req_bssid);
+
+ /* TODO: fill in tsf_mac_id if needed */
+ cmd->tsf_mac_id = cpu_to_le32(0xff);
+}
+
+static int iwl_mvm_ftm_target_chandef(struct iwl_mvm *mvm,
+ struct cfg80211_pmsr_request_peer *peer,
+ u8 *channel, u8 *bandwidth,
+ u8 *ctrl_ch_position)
+{
+ u32 freq = peer->chandef.chan->center_freq;
+
+ *channel = ieee80211_frequency_to_channel(freq);
+
+ switch (peer->chandef.width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ *bandwidth = IWL_TOF_BW_20_LEGACY;
+ break;
+ case NL80211_CHAN_WIDTH_20:
+ *bandwidth = IWL_TOF_BW_20_HT;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ *bandwidth = IWL_TOF_BW_40;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ *bandwidth = IWL_TOF_BW_80;
+ break;
+ default:
+ IWL_ERR(mvm, "Unsupported BW in FTM request (%d)\n",
+ peer->chandef.width);
+ return -EINVAL;
+ }
+
+ *ctrl_ch_position = (peer->chandef.width > NL80211_CHAN_WIDTH_20) ?
+ iwl_mvm_get_ctrl_pos(&peer->chandef) : 0;
+
+ return 0;
+}
+
+static int
+iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm,
+ struct cfg80211_pmsr_request_peer *peer,
+ struct iwl_tof_range_req_ap_entry_v2 *target)
+{
+ int ret;
+
+ ret = iwl_mvm_ftm_target_chandef(mvm, peer, &target->channel_num,
+ &target->bandwidth,
+ &target->ctrl_ch_position);
+ if (ret)
+ return ret;
+
+ memcpy(target->bssid, peer->addr, ETH_ALEN);
+ target->burst_period =
+ cpu_to_le16(peer->ftm.burst_period);
+ target->samples_per_burst = peer->ftm.ftms_per_burst;
+ target->num_of_bursts = peer->ftm.num_bursts_exp;
+ target->measure_type = 0; /* regular two-sided FTM */
+ target->retries_per_sample = peer->ftm.ftmr_retries;
+ target->asap_mode = peer->ftm.asap;
+ target->enable_dyn_ack = IWL_MVM_FTM_INITIATOR_DYNACK;
+
+ if (peer->ftm.request_lci)
+ target->location_req |= IWL_TOF_LOC_LCI;
+ if (peer->ftm.request_civicloc)
+ target->location_req |= IWL_TOF_LOC_CIVIC;
+
+ target->algo_type = IWL_MVM_FTM_INITIATOR_ALGO;
+
+ return 0;
+}
+
+#define FTM_PUT_FLAG(flag) (target->initiator_ap_flags |= \
+ cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag))
+
+static int iwl_mvm_ftm_put_target(struct iwl_mvm *mvm,
+ struct cfg80211_pmsr_request_peer *peer,
+ struct iwl_tof_range_req_ap_entry *target)
+{
+ int ret;
+
+ ret = iwl_mvm_ftm_target_chandef(mvm, peer, &target->channel_num,
+ &target->bandwidth,
+ &target->ctrl_ch_position);
+ if (ret)
+ return ret;
+
+ memcpy(target->bssid, peer->addr, ETH_ALEN);
+ target->burst_period =
+ cpu_to_le16(peer->ftm.burst_period);
+ target->samples_per_burst = peer->ftm.ftms_per_burst;
+ target->num_of_bursts = peer->ftm.num_bursts_exp;
+ target->ftmr_max_retries = peer->ftm.ftmr_retries;
+ target->initiator_ap_flags = cpu_to_le32(0);
+
+ if (peer->ftm.asap)
+ FTM_PUT_FLAG(ASAP);
+
+ if (peer->ftm.request_lci)
+ FTM_PUT_FLAG(LCI_REQUEST);
+
+ if (peer->ftm.request_civicloc)
+ FTM_PUT_FLAG(CIVIC_REQUEST);
+
+ if (IWL_MVM_FTM_INITIATOR_DYNACK)
+ FTM_PUT_FLAG(DYN_ACK);
+
+ if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG)
+ FTM_PUT_FLAG(ALGO_LR);
+ else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT)
+ FTM_PUT_FLAG(ALGO_FFT);
+
+ return 0;
+}
+
+int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct cfg80211_pmsr_request *req)
+{
+ struct iwl_tof_range_req_cmd_v5 cmd_v5;
+ struct iwl_tof_range_req_cmd cmd;
+ bool new_api = fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
+ u8 num_of_ap;
+ struct iwl_host_cmd hcmd = {
+ .id = iwl_cmd_id(TOF_RANGE_REQ_CMD, LOCATION_GROUP, 0),
+ .dataflags[0] = IWL_HCMD_DFL_DUP,
+ };
+ u32 status = 0;
+ int err, i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (mvm->ftm_initiator.req)
+ return -EBUSY;
+
+ if (new_api) {
+ iwl_mvm_ftm_cmd(mvm, vif, &cmd, req);
+ hcmd.data[0] = &cmd;
+ hcmd.len[0] = sizeof(cmd);
+ num_of_ap = cmd.num_of_ap;
+ } else {
+ iwl_mvm_ftm_cmd_v5(mvm, vif, &cmd_v5, req);
+ hcmd.data[0] = &cmd_v5;
+ hcmd.len[0] = sizeof(cmd_v5);
+ num_of_ap = cmd_v5.num_of_ap;
+ }
+
+ for (i = 0; i < num_of_ap; i++) {
+ struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
+
+ if (new_api)
+ err = iwl_mvm_ftm_put_target(mvm, peer, &cmd.ap[i]);
+ else
+ err = iwl_mvm_ftm_put_target_v2(mvm, peer,
+ &cmd_v5.ap[i]);
+
+ if (err)
+ return err;
+ }
+
+ err = iwl_mvm_send_cmd_status(mvm, &hcmd, &status);
+ if (!err && status) {
+ IWL_ERR(mvm, "FTM range request command failure, status: %u\n",
+ status);
+ err = iwl_ftm_range_request_status_to_err(status);
+ }
+
+ if (!err) {
+ mvm->ftm_initiator.req = req;
+ mvm->ftm_initiator.req_wdev = ieee80211_vif_to_wdev(vif);
+ }
+
+ return err;
+}
+
+void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req)
+{
+ struct iwl_tof_range_abort_cmd cmd = {
+ .request_id = req->cookie,
+ };
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (req != mvm->ftm_initiator.req)
+ return;
+
+ if (iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RANGE_ABORT_CMD,
+ LOCATION_GROUP, 0),
+ 0, sizeof(cmd), &cmd))
+ IWL_ERR(mvm, "failed to abort FTM process\n");
+}
+
+static int iwl_mvm_ftm_find_peer(struct cfg80211_pmsr_request *req,
+ const u8 *addr)
+{
+ int i;
+
+ for (i = 0; i < req->n_peers; i++) {
+ struct cfg80211_pmsr_request_peer *peer = &req->peers[i];
+
+ if (ether_addr_equal_unaligned(peer->addr, addr))
+ return i;
+ }
+
+ return -ENOENT;
+}
+
+static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts)
+{
+ u32 gp2_ts = le32_to_cpu(fw_gp2_ts);
+ u32 curr_gp2, diff;
+ u64 now_from_boot_ns;
+
+ iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns);
+
+ if (curr_gp2 >= gp2_ts)
+ diff = curr_gp2 - gp2_ts;
+ else
+ diff = curr_gp2 + (U32_MAX - gp2_ts + 1);
+
+ return now_from_boot_ns - (u64)diff * 1000;
+}
+
+static void iwl_mvm_ftm_get_lci_civic(struct iwl_mvm *mvm,
+ struct cfg80211_pmsr_result *res)
+{
+ struct iwl_mvm_loc_entry *entry;
+
+ list_for_each_entry(entry, &mvm->ftm_initiator.loc_list, list) {
+ if (!ether_addr_equal_unaligned(res->addr, entry->addr))
+ continue;
+
+ if (entry->lci_len) {
+ res->ftm.lci_len = entry->lci_len;
+ res->ftm.lci = entry->buf;
+ }
+
+ if (entry->civic_len) {
+ res->ftm.civicloc_len = entry->civic_len;
+ res->ftm.civicloc = entry->buf + entry->lci_len;
+ }
+
+ /* we found the entry we needed */
+ break;
+ }
+}
+
+static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id,
+ u8 num_of_aps)
+{
+ lockdep_assert_held(&mvm->mutex);
+
+ if (request_id != (u8)mvm->ftm_initiator.req->cookie) {
+ IWL_ERR(mvm, "Request ID mismatch, got %u, active %u\n",
+ request_id, (u8)mvm->ftm_initiator.req->cookie);
+ return -EINVAL;
+ }
+
+ if (num_of_aps > mvm->ftm_initiator.req->n_peers) {
+ IWL_ERR(mvm, "FTM range response invalid\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index,
+ struct cfg80211_pmsr_result *res)
+{
+ s64 rtt_avg = res->ftm.rtt_avg * 100;
+
+ do_div(rtt_avg, 6666);
+
+ IWL_DEBUG_INFO(mvm, "entry %d\n", index);
+ IWL_DEBUG_INFO(mvm, "\tstatus: %d\n", res->status);
+ IWL_DEBUG_INFO(mvm, "\tBSSID: %pM\n", res->addr);
+ IWL_DEBUG_INFO(mvm, "\thost time: %llu\n", res->host_time);
+ IWL_DEBUG_INFO(mvm, "\tburst index: %hhu\n", res->ftm.burst_index);
+ IWL_DEBUG_INFO(mvm, "\tsuccess num: %u\n", res->ftm.num_ftmr_successes);
+ IWL_DEBUG_INFO(mvm, "\trssi: %d\n", res->ftm.rssi_avg);
+ IWL_DEBUG_INFO(mvm, "\trssi spread: %hhu\n", res->ftm.rssi_spread);
+ IWL_DEBUG_INFO(mvm, "\trtt: %lld\n", res->ftm.rtt_avg);
+ IWL_DEBUG_INFO(mvm, "\trtt var: %llu\n", res->ftm.rtt_variance);
+ IWL_DEBUG_INFO(mvm, "\trtt spread: %llu\n", res->ftm.rtt_spread);
+ IWL_DEBUG_INFO(mvm, "\tdistance: %lld\n", rtt_avg);
+}
+
+void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_tof_range_rsp_ntfy_v5 *fw_resp_v5 = (void *)pkt->data;
+ struct iwl_tof_range_rsp_ntfy *fw_resp = (void *)pkt->data;
+ int i;
+ bool new_api = fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_FTM_NEW_RANGE_REQ);
+ u8 num_of_aps, last_in_batch;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (!mvm->ftm_initiator.req) {
+ IWL_ERR(mvm, "Got FTM response but have no request?\n");
+ return;
+ }
+
+ if (new_api) {
+ if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp->request_id,
+ fw_resp->num_of_aps))
+ return;
+
+ num_of_aps = fw_resp->num_of_aps;
+ last_in_batch = fw_resp->last_report;
+ } else {
+ if (iwl_mvm_ftm_range_resp_valid(mvm, fw_resp_v5->request_id,
+ fw_resp_v5->num_of_aps))
+ return;
+
+ num_of_aps = fw_resp_v5->num_of_aps;
+ last_in_batch = fw_resp_v5->last_in_batch;
+ }
+
+ IWL_DEBUG_INFO(mvm, "Range response received\n");
+ IWL_DEBUG_INFO(mvm, "request id: %lld, num of entries: %hhu\n",
+ mvm->ftm_initiator.req->cookie, num_of_aps);
+
+ for (i = 0; i < num_of_aps && i < IWL_MVM_TOF_MAX_APS; i++) {
+ struct cfg80211_pmsr_result result = {};
+ struct iwl_tof_range_rsp_ap_entry_ntfy *fw_ap;
+ int peer_idx;
+
+ if (new_api) {
+ fw_ap = &fw_resp->ap[i];
+ result.final = fw_resp->ap[i].last_burst;
+ } else {
+ /* the first part is the same for old and new APIs */
+ fw_ap = (void *)&fw_resp_v5->ap[i];
+ /*
+ * FIXME: the firmware needs to report this, we don't
+ * even know the number of bursts the responder picked
+ * (if we asked it to)
+ */
+ result.final = 0;
+ }
+
+ peer_idx = iwl_mvm_ftm_find_peer(mvm->ftm_initiator.req,
+ fw_ap->bssid);
+ if (peer_idx < 0) {
+ IWL_WARN(mvm,
+ "Unknown address (%pM, target #%d) in FTM response\n",
+ fw_ap->bssid, i);
+ continue;
+ }
+
+ switch (fw_ap->measure_status) {
+ case IWL_TOF_ENTRY_SUCCESS:
+ result.status = NL80211_PMSR_STATUS_SUCCESS;
+ break;
+ case IWL_TOF_ENTRY_TIMING_MEASURE_TIMEOUT:
+ result.status = NL80211_PMSR_STATUS_TIMEOUT;
+ break;
+ case IWL_TOF_ENTRY_NO_RESPONSE:
+ result.status = NL80211_PMSR_STATUS_FAILURE;
+ result.ftm.failure_reason =
+ NL80211_PMSR_FTM_FAILURE_NO_RESPONSE;
+ break;
+ case IWL_TOF_ENTRY_REQUEST_REJECTED:
+ result.status = NL80211_PMSR_STATUS_FAILURE;
+ result.ftm.failure_reason =
+ NL80211_PMSR_FTM_FAILURE_PEER_BUSY;
+ result.ftm.busy_retry_time = fw_ap->refusal_period;
+ break;
+ default:
+ result.status = NL80211_PMSR_STATUS_FAILURE;
+ result.ftm.failure_reason =
+ NL80211_PMSR_FTM_FAILURE_UNSPECIFIED;
+ break;
+ }
+ memcpy(result.addr, fw_ap->bssid, ETH_ALEN);
+ result.host_time = iwl_mvm_ftm_get_host_time(mvm,
+ fw_ap->timestamp);
+ result.type = NL80211_PMSR_TYPE_FTM;
+ result.ftm.burst_index = mvm->ftm_initiator.responses[peer_idx];
+ mvm->ftm_initiator.responses[peer_idx]++;
+ result.ftm.rssi_avg = fw_ap->rssi;
+ result.ftm.rssi_avg_valid = 1;
+ result.ftm.rssi_spread = fw_ap->rssi_spread;
+ result.ftm.rssi_spread_valid = 1;
+ result.ftm.rtt_avg = (s32)le32_to_cpu(fw_ap->rtt);
+ result.ftm.rtt_avg_valid = 1;
+ result.ftm.rtt_variance = le32_to_cpu(fw_ap->rtt_variance);
+ result.ftm.rtt_variance_valid = 1;
+ result.ftm.rtt_spread = le32_to_cpu(fw_ap->rtt_spread);
+ result.ftm.rtt_spread_valid = 1;
+
+ iwl_mvm_ftm_get_lci_civic(mvm, &result);
+
+ cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
+ mvm->ftm_initiator.req,
+ &result, GFP_KERNEL);
+
+ iwl_mvm_debug_range_resp(mvm, i, &result);
+ }
+
+ if (last_in_batch) {
+ cfg80211_pmsr_complete(mvm->ftm_initiator.req_wdev,
+ mvm->ftm_initiator.req,
+ GFP_KERNEL);
+ iwl_mvm_ftm_reset(mvm);
+ }
+}
+
+void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ const struct ieee80211_mgmt *mgmt = (void *)pkt->data;
+ size_t len = iwl_rx_packet_payload_len(pkt);
+ struct iwl_mvm_loc_entry *entry;
+ const u8 *ies, *lci, *civic, *msr_ie;
+ size_t ies_len, lci_len = 0, civic_len = 0;
+ size_t baselen = IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.ftm);
+ static const u8 rprt_type_lci = IEEE80211_SPCT_MSR_RPRT_TYPE_LCI;
+ static const u8 rprt_type_civic = IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC;
+
+ if (len <= baselen)
+ return;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ ies = mgmt->u.action.u.ftm.variable;
+ ies_len = len - baselen;
+
+ msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
+ &rprt_type_lci, 1, 4);
+ if (msr_ie) {
+ lci = msr_ie + 2;
+ lci_len = msr_ie[1];
+ }
+
+ msr_ie = cfg80211_find_ie_match(WLAN_EID_MEASURE_REPORT, ies, ies_len,
+ &rprt_type_civic, 1, 4);
+ if (msr_ie) {
+ civic = msr_ie + 2;
+ civic_len = msr_ie[1];
+ }
+
+ entry = kmalloc(sizeof(*entry) + lci_len + civic_len, GFP_KERNEL);
+ if (!entry)
+ return;
+
+ memcpy(entry->addr, mgmt->bssid, ETH_ALEN);
+
+ entry->lci_len = lci_len;
+ if (lci_len)
+ memcpy(entry->buf, lci, lci_len);
+
+ entry->civic_len = civic_len;
+ if (civic_len)
+ memcpy(entry->buf + lci_len, civic, civic_len);
+
+ list_add_tail(&entry->list, &mvm->ftm_initiator.loc_list);
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
new file mode 100644
index 000000000000..1513b8b4062f
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
@@ -0,0 +1,244 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <linuxwifi@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <net/cfg80211.h>
+#include <linux/etherdevice.h>
+#include "mvm.h"
+#include "constants.h"
+
+static int
+iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *chandef)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_tof_responder_config_cmd cmd = {
+ .channel_num = chandef->chan->hw_value,
+ .cmd_valid_fields =
+ cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO |
+ IWL_TOF_RESPONDER_CMD_VALID_BSSID |
+ IWL_TOF_RESPONDER_CMD_VALID_STA_ID),
+ .sta_id = mvmvif->bcast_sta.sta_id,
+ };
+
+ lockdep_assert_held(&mvm->mutex);
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ cmd.bandwidth = IWL_TOF_BW_20_LEGACY;
+ break;
+ case NL80211_CHAN_WIDTH_20:
+ cmd.bandwidth = IWL_TOF_BW_20_HT;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ cmd.bandwidth = IWL_TOF_BW_40;
+ cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ cmd.bandwidth = IWL_TOF_BW_80;
+ cmd.ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ memcpy(cmd.bssid, vif->addr, ETH_ALEN);
+
+ return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_RESPONDER_CONFIG_CMD,
+ LOCATION_GROUP, 0),
+ 0, sizeof(cmd), &cmd);
+}
+
+static int
+iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_ftm_responder_params *params)
+{
+ struct iwl_tof_responder_dyn_config_cmd cmd = {
+ .lci_len = cpu_to_le32(params->lci_len + 2),
+ .civic_len = cpu_to_le32(params->civicloc_len + 2),
+ };
+ u8 data[IWL_LCI_CIVIC_IE_MAX_SIZE] = {0};
+ struct iwl_host_cmd hcmd = {
+ .id = iwl_cmd_id(TOF_RESPONDER_DYN_CONFIG_CMD,
+ LOCATION_GROUP, 0),
+ .data[0] = &cmd,
+ .len[0] = sizeof(cmd),
+ .data[1] = &data,
+ /* .len[1] set later */
+ /* may not be able to DMA from stack */
+ .dataflags[1] = IWL_HCMD_DFL_DUP,
+ };
+ u32 aligned_lci_len = ALIGN(params->lci_len + 2, 4);
+ u32 aligned_civicloc_len = ALIGN(params->civicloc_len + 2, 4);
+ u8 *pos = data;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (aligned_lci_len + aligned_civicloc_len > sizeof(data)) {
+ IWL_ERR(mvm, "LCI/civicloc data too big (%zd + %zd)\n",
+ params->lci_len, params->civicloc_len);
+ return -ENOBUFS;
+ }
+
+ pos[0] = WLAN_EID_MEASURE_REPORT;
+ pos[1] = params->lci_len;
+ memcpy(pos + 2, params->lci, params->lci_len);
+
+ pos += aligned_lci_len;
+ pos[0] = WLAN_EID_MEASURE_REPORT;
+ pos[1] = params->civicloc_len;
+ memcpy(pos + 2, params->civicloc, params->civicloc_len);
+
+ hcmd.len[1] = aligned_lci_len + aligned_civicloc_len;
+
+ return iwl_mvm_send_cmd(mvm, &hcmd);
+}
+
+int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct ieee80211_ftm_responder_params *params;
+ struct ieee80211_chanctx_conf ctx, *pctx;
+ u16 *phy_ctxt_id;
+ struct iwl_mvm_phy_ctxt *phy_ctxt;
+ int ret;
+
+ params = vif->bss_conf.ftmr_params;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder))
+ return -EINVAL;
+
+ if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||
+ !mvmvif->ap_ibss_active) {
+ IWL_ERR(mvm, "Cannot start responder, not in AP mode\n");
+ return -EIO;
+ }
+
+ rcu_read_lock();
+ pctx = rcu_dereference(vif->chanctx_conf);
+ /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care
+ * about changes in the ctx after releasing the lock because the driver
+ * is still protected by the mutex. */
+ ctx = *pctx;
+ phy_ctxt_id = (u16 *)pctx->drv_priv;
+ rcu_read_unlock();
+
+ phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
+ ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def,
+ ctx.rx_chains_static,
+ ctx.rx_chains_dynamic);
+ if (ret)
+ return ret;
+
+ ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def);
+ if (ret)
+ return ret;
+
+ if (params)
+ ret = iwl_mvm_ftm_responder_dyn_cfg_cmd(mvm, vif, params);
+
+ return ret;
+}
+
+void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ if (!vif->bss_conf.ftm_responder)
+ return;
+
+ iwl_mvm_ftm_start_responder(mvm, vif);
+}
+
+void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_ftm_responder_stats *resp = (void *)pkt->data;
+ struct cfg80211_ftm_responder_stats *stats = &mvm->ftm_resp_stats;
+ u32 flags = le32_to_cpu(resp->flags);
+
+ if (resp->success_ftm == resp->ftm_per_burst)
+ stats->success_num++;
+ else if (resp->success_ftm >= 2)
+ stats->partial_num++;
+ else
+ stats->failed_num++;
+
+ if ((flags & FTM_RESP_STAT_ASAP_REQ) &&
+ (flags & FTM_RESP_STAT_ASAP_RESP))
+ stats->asap_num++;
+
+ if (flags & FTM_RESP_STAT_NON_ASAP_RESP)
+ stats->non_asap_num++;
+
+ stats->total_duration_ms += le32_to_cpu(resp->duration) / USEC_PER_MSEC;
+
+ if (flags & FTM_RESP_STAT_TRIGGER_UNKNOWN)
+ stats->unknown_triggers_num++;
+
+ if (flags & FTM_RESP_STAT_DUP)
+ stats->reschedule_requests_num++;
+
+ if (flags & FTM_RESP_STAT_NON_ASAP_OUT_WIN)
+ stats->out_of_window_triggers_num++;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
index 143c7fcaea41..e3eb812e0248 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,7 +91,7 @@
#include "fw/api/sf.h"
#include "fw/api/sta.h"
#include "fw/api/stats.h"
-#include "fw/api/tof.h"
+#include "fw/api/location.h"
#include "fw/api/tx.h"
#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 0d6c313b6669..00a47f6f1d81 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -8,7 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -105,12 +105,12 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm)
int i;
struct iwl_rss_config_cmd cmd = {
.flags = cpu_to_le32(IWL_RSS_ENABLE),
- .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
- IWL_RSS_HASH_TYPE_IPV4_UDP |
- IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
- IWL_RSS_HASH_TYPE_IPV6_TCP |
- IWL_RSS_HASH_TYPE_IPV6_UDP |
- IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
+ .hash_mask = BIT(IWL_RSS_HASH_TYPE_IPV4_TCP) |
+ BIT(IWL_RSS_HASH_TYPE_IPV4_UDP) |
+ BIT(IWL_RSS_HASH_TYPE_IPV4_PAYLOAD) |
+ BIT(IWL_RSS_HASH_TYPE_IPV6_TCP) |
+ BIT(IWL_RSS_HASH_TYPE_IPV6_UDP) |
+ BIT(IWL_RSS_HASH_TYPE_IPV6_PAYLOAD),
};
if (mvm->trans->num_rx_queues == 1)
@@ -127,13 +127,17 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm)
static int iwl_configure_rxq(struct iwl_mvm *mvm)
{
- int i, num_queues, size;
+ int i, num_queues, size, ret;
struct iwl_rfh_queue_config *cmd;
+ struct iwl_host_cmd hcmd = {
+ .id = WIDE_ID(DATA_PATH_GROUP, RFH_QUEUE_CONFIG_CMD),
+ .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+ };
/* Do not configure default queue, it is configured via context info */
num_queues = mvm->trans->num_rx_queues - 1;
- size = sizeof(*cmd) + num_queues * sizeof(struct iwl_rfh_queue_data);
+ size = struct_size(cmd, data, num_queues);
cmd = kzalloc(size, GFP_KERNEL);
if (!cmd)
@@ -154,10 +158,14 @@ static int iwl_configure_rxq(struct iwl_mvm *mvm)
cmd->data[i].fr_bd_wid = cpu_to_le32(data.fr_bd_wid);
}
- return iwl_mvm_send_cmd_pdu(mvm,
- WIDE_ID(DATA_PATH_GROUP,
- RFH_QUEUE_CONFIG_CMD),
- 0, size, cmd);
+ hcmd.data[0] = cmd;
+ hcmd.len[0] = size;
+
+ ret = iwl_mvm_send_cmd(mvm, &hcmd);
+
+ kfree(cmd);
+
+ return ret;
}
static int iwl_mvm_send_dqa_cmd(struct iwl_mvm *mvm)
@@ -210,7 +218,7 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
struct iwl_lmac_alive *lmac1;
struct iwl_lmac_alive *lmac2 = NULL;
u16 status;
- u32 umac_error_event_table;
+ u32 lmac_error_event_table, umac_error_event_table;
if (iwl_rx_packet_payload_len(pkt) == sizeof(*palive)) {
palive = (void *)pkt->data;
@@ -225,30 +233,35 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
status = le16_to_cpu(palive3->status);
}
- mvm->error_event_table[0] = le32_to_cpu(lmac1->error_event_table_ptr);
+ lmac_error_event_table =
+ le32_to_cpu(lmac1->dbg_ptrs.error_event_table_ptr);
+ iwl_fw_lmac1_set_alive_err_table(mvm->trans, lmac_error_event_table);
+
if (lmac2)
- mvm->error_event_table[1] =
- le32_to_cpu(lmac2->error_event_table_ptr);
- mvm->log_event_table = le32_to_cpu(lmac1->log_event_table_ptr);
+ mvm->trans->lmac_error_event_table[1] =
+ le32_to_cpu(lmac2->dbg_ptrs.error_event_table_ptr);
- umac_error_event_table = le32_to_cpu(umac->error_info_addr);
+ umac_error_event_table = le32_to_cpu(umac->dbg_ptrs.error_info_addr);
if (!umac_error_event_table) {
mvm->support_umac_log = false;
} else if (umac_error_event_table >=
mvm->trans->cfg->min_umac_error_event_table) {
mvm->support_umac_log = true;
- mvm->umac_error_event_table = umac_error_event_table;
} else {
IWL_ERR(mvm,
"Not valid error log pointer 0x%08X for %s uCode\n",
- mvm->umac_error_event_table,
+ umac_error_event_table,
(mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) ?
"Init" : "RT");
mvm->support_umac_log = false;
}
- alive_data->scd_base_addr = le32_to_cpu(lmac1->scd_base_ptr);
+ if (mvm->support_umac_log)
+ iwl_fw_umac_set_alive_err_table(mvm->trans,
+ umac_error_event_table);
+
+ alive_data->scd_base_addr = le32_to_cpu(lmac1->dbg_ptrs.scd_base_ptr);
alive_data->valid = status == IWL_ALIVE_STATUS_OK;
IWL_DEBUG_FW(mvm,
@@ -293,13 +306,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
enum iwl_ucode_type ucode_type)
{
struct iwl_notification_wait alive_wait;
- struct iwl_mvm_alive_data alive_data;
+ struct iwl_mvm_alive_data alive_data = {};
const struct fw_img *fw;
- int ret, i;
+ int ret;
enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img;
static const u16 alive_cmd[] = { MVM_ALIVE };
- set_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status);
if (ucode_type == IWL_UCODE_REGULAR &&
iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) &&
!(fw_has_capa(&mvm->fw->ucode_capa,
@@ -332,11 +344,16 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
if (ret) {
struct iwl_trans *trans = mvm->trans;
+ if (ret == -ETIMEDOUT)
+ iwl_fw_dbg_error_collect(&mvm->fwrt,
+ FW_DBG_TRIGGER_ALIVE_TIMEOUT);
+
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_22000)
IWL_ERR(mvm,
"SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n",
- iwl_read_prph(trans, UMAG_SB_CPU_1_STATUS),
- iwl_read_prph(trans, UMAG_SB_CPU_2_STATUS));
+ iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS),
+ iwl_read_umac_prph(trans,
+ UMAG_SB_CPU_2_STATUS));
else if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
IWL_ERR(mvm,
"SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n",
@@ -373,14 +390,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].tid_bitmap =
BIT(IWL_MAX_TID_COUNT + 2);
- for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
- atomic_set(&mvm->mac80211_queue_stop_count[i], 0);
-
set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_fw_set_dbg_rec_on(&mvm->fwrt);
#endif
- clear_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status);
return 0;
}
@@ -406,13 +419,15 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
iwl_wait_init_complete,
NULL);
+ iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_EARLY);
+
/* Will also start the device */
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
if (ret) {
IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);
- iwl_fw_assert_error_dump(&mvm->fwrt);
goto error;
}
+ iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_AFTER_ALIVE);
/* Send init config command to mark that we are sending NVM access
* commands
@@ -631,10 +646,10 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
}
#ifdef CONFIG_ACPI
-static int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm,
- union acpi_object *table,
- struct iwl_mvm_sar_profile *profile,
- bool enabled)
+static inline int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm,
+ union acpi_object *table,
+ struct iwl_mvm_sar_profile *profile,
+ bool enabled)
{
int i;
@@ -965,6 +980,57 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
}
#endif /* CONFIG_ACPI */
+void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
+{
+ u32 error_log_size = mvm->fw->ucode_capa.error_log_size;
+ int ret;
+ u32 resp;
+
+ struct iwl_fw_error_recovery_cmd recovery_cmd = {
+ .flags = cpu_to_le32(flags),
+ .buf_size = 0,
+ };
+ struct iwl_host_cmd host_cmd = {
+ .id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD),
+ .flags = CMD_WANT_SKB,
+ .data = {&recovery_cmd, },
+ .len = {sizeof(recovery_cmd), },
+ };
+
+ /* no error log was defined in TLV */
+ if (!error_log_size)
+ return;
+
+ if (flags & ERROR_RECOVERY_UPDATE_DB) {
+ /* no buf was allocated while HW reset */
+ if (!mvm->error_recovery_buf)
+ return;
+
+ host_cmd.data[1] = mvm->error_recovery_buf;
+ host_cmd.len[1] = error_log_size;
+ host_cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
+ recovery_cmd.buf_size = cpu_to_le32(error_log_size);
+ }
+
+ ret = iwl_mvm_send_cmd(mvm, &host_cmd);
+ kfree(mvm->error_recovery_buf);
+ mvm->error_recovery_buf = NULL;
+
+ if (ret) {
+ IWL_ERR(mvm, "Failed to send recovery cmd %d\n", ret);
+ return;
+ }
+
+ /* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */
+ if (flags & ERROR_RECOVERY_UPDATE_DB) {
+ resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data);
+ if (resp)
+ IWL_ERR(mvm,
+ "Failed to send recovery cmd blob was invalid %d\n",
+ resp);
+ }
+}
+
static int iwl_mvm_sar_init(struct iwl_mvm *mvm)
{
int ret;
@@ -1055,7 +1121,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
ret = iwl_mvm_load_rt_fw(mvm);
if (ret) {
IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret);
- iwl_fw_assert_error_dump(&mvm->fwrt);
+ iwl_fw_dbg_error_collect(&mvm->fwrt, FW_DBG_TRIGGER_DRIVER);
goto error;
}
@@ -1201,6 +1267,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB);
+
+ if (iwl_acpi_get_eckv(mvm->dev, &mvm->ext_clock_valid))
+ IWL_DEBUG_INFO(mvm, "ECKV table doesn't exist in BIOS\n");
+
ret = iwl_mvm_sar_init(mvm);
if (ret == 0) {
ret = iwl_mvm_sar_geo_init(mvm);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c
index 9bb1de1cad64..4348bb00e761 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c
@@ -7,6 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -28,6 +29,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -113,6 +115,7 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
switch (mode) {
case IWL_LED_BLINK:
IWL_ERR(mvm, "Blink led mode not supported, used default\n");
+ /* fall through */
case IWL_LED_DEFAULT:
case IWL_LED_RF_STATE:
mode = IWL_LED_RF_STATE;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index 7779951a9533..6a70dece447d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -97,11 +97,6 @@ struct iwl_mvm_mac_iface_iterator_data {
bool found_vif;
};
-struct iwl_mvm_hw_queues_iface_iterator_data {
- struct ieee80211_vif *exclude_vif;
- unsigned long used_hw_queues;
-};
-
static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -208,61 +203,6 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
data->preferred_tsf = NUM_TSF_IDS;
}
-/*
- * Get the mask of the queues used by the vif
- */
-u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
-{
- u32 qmask = 0, ac;
-
- if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
- return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
-
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
- if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
- qmask |= BIT(vif->hw_queue[ac]);
- }
-
- if (vif->type == NL80211_IFTYPE_AP ||
- vif->type == NL80211_IFTYPE_ADHOC)
- qmask |= BIT(vif->cab_queue);
-
- return qmask;
-}
-
-static void iwl_mvm_iface_hw_queues_iter(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
-{
- struct iwl_mvm_hw_queues_iface_iterator_data *data = _data;
-
- /* exclude the given vif */
- if (vif == data->exclude_vif)
- return;
-
- data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif);
-}
-
-unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
- struct ieee80211_vif *exclude_vif)
-{
- struct iwl_mvm_hw_queues_iface_iterator_data data = {
- .exclude_vif = exclude_vif,
- .used_hw_queues =
- BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
- BIT(mvm->aux_queue) |
- BIT(IWL_MVM_DQA_GCAST_QUEUE),
- };
-
- lockdep_assert_held(&mvm->mutex);
-
- /* mark all VIF used hw queues */
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
- iwl_mvm_iface_hw_queues_iter, &data);
-
- return data.used_hw_queues;
-}
-
static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -360,8 +300,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
iwl_mvm_mac_iface_iterator, &data);
- used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, vif);
-
/*
* In the case we're getting here during resume, it's similar to
* firmware restart, and with RESUME_ALL the iterator will find
@@ -416,9 +354,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
* the ones here - no real limit
*/
queue_limit = IEEE80211_MAX_QUEUES;
- BUILD_BUG_ON(IEEE80211_MAX_QUEUES >
- BITS_PER_BYTE *
- sizeof(mvm->hw_queue_to_mac80211[0]));
/*
* Find available queues, and allocate them to the ACs. When in
@@ -446,9 +381,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
* queue value (when queue is enabled).
*/
mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
- vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
- } else {
- vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
}
mvmvif->bcast_sta.sta_id = IWL_MVM_INVALID_STA;
@@ -462,8 +394,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
exit_fail:
memset(mvmvif, 0, sizeof(struct iwl_mvm_vif));
- memset(vif->hw_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(vif->hw_queue));
- vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
return ret;
}
@@ -776,29 +706,10 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
if (vif->probe_req_reg && vif->bss_conf.assoc && vif->p2p)
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
- if (vif->bss_conf.assoc && vif->bss_conf.he_support &&
- !iwlwifi_mod_params.disable_11ax) {
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- u8 sta_id = mvmvif->ap_sta_id;
-
+ if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) {
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX);
- if (sta_id != IWL_MVM_INVALID_STA) {
- struct ieee80211_sta *sta;
-
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
- lockdep_is_held(&mvm->mutex));
-
- /*
- * TODO: we should check the ext cap IE but it is
- * unclear why the spec requires two bits (one in HE
- * cap IE, and one in the ext cap IE). In the meantime
- * rely on the HE cap IE only.
- */
- if (sta && (sta->he_cap.he_cap_elem.mac_cap_info[0] &
- IEEE80211_HE_MAC_CAP0_TWT_RES))
- ctxt_sta->data_policy |=
- cpu_to_le32(TWT_SUPPORTED);
- }
+ if (vif->bss_conf.twt_requester)
+ ctxt_sta->data_policy |= cpu_to_le32(TWT_SUPPORTED);
}
@@ -881,8 +792,6 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
- cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
-
/* Override the filter flags to accept only probe requests */
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
@@ -902,9 +811,9 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
-static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
- __le32 *tim_index, __le32 *tim_size,
- u8 *beacon, u32 frame_size)
+void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
+ __le32 *tim_index, __le32 *tim_size,
+ u8 *beacon, u32 frame_size)
{
u32 tim_idx;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)beacon;
@@ -944,8 +853,8 @@ static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)
return ie - beacon;
}
-static u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
- struct ieee80211_vif *vif)
+u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
+ struct ieee80211_vif *vif)
{
u8 rate;
@@ -995,9 +904,9 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm,
}
-static int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
- struct sk_buff *beacon,
- void *data, int len)
+int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
+ struct sk_buff *beacon,
+ void *data, int len)
{
struct iwl_host_cmd cmd = {
.id = BEACON_TEMPLATE_CMD,
@@ -1100,13 +1009,16 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
sizeof(beacon_cmd));
}
-static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct sk_buff *beacon)
+int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct sk_buff *beacon)
{
if (WARN_ON(!beacon))
return -EINVAL;
+ if (IWL_MVM_NON_TRANSMITTING_AP)
+ return 0;
+
if (!fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD))
return iwl_mvm_mac_ctxt_send_beacon_v6(mvm, vif, beacon);
@@ -1132,6 +1044,11 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
if (!beacon)
return -ENOMEM;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (mvm->beacon_inject_active)
+ return -EBUSY;
+#endif
+
ret = iwl_mvm_mac_ctxt_send_beacon(mvm, vif, beacon);
dev_kfree_skb(beacon);
return ret;
@@ -1203,7 +1120,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
if (!fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_STA_TYPE))
- ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue);
+ ctxt_ap->mcast_qid = cpu_to_le32(mvmvif->cab_queue);
/*
* Only set the beacon time when the MAC is being added, when we
@@ -1420,7 +1337,7 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_extended_beacon_notif *beacon = (void *)pkt->data;
- struct iwl_mvm_tx_resp *beacon_notify_hdr;
+ struct iwl_extended_beacon_notif_v5 *beacon_v5 = (void *)pkt->data;
struct ieee80211_vif *csa_vif;
struct ieee80211_vif *tx_blocked_vif;
struct agg_tx_status *agg_status;
@@ -1428,18 +1345,29 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
- beacon_notify_hdr = &beacon->beacon_notify_hdr;
mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2);
- mvm->ibss_manager = beacon->ibss_mgr_status != 0;
- agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr);
- status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK;
- IWL_DEBUG_RX(mvm,
- "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n",
- status, beacon_notify_hdr->failure_frame,
- le64_to_cpu(beacon->tsf),
- mvm->ap_last_beacon_gp2,
- le32_to_cpu(beacon_notify_hdr->initial_rate));
+ if (!iwl_mvm_is_short_beacon_notif_supported(mvm)) {
+ struct iwl_mvm_tx_resp *beacon_notify_hdr =
+ &beacon_v5->beacon_notify_hdr;
+
+ mvm->ibss_manager = beacon_v5->ibss_mgr_status != 0;
+ agg_status = iwl_mvm_get_agg_status(mvm, beacon_notify_hdr);
+ status = le16_to_cpu(agg_status->status) & TX_STATUS_MSK;
+ IWL_DEBUG_RX(mvm,
+ "beacon status %#x retries:%d tsf:0x%016llX gp2:0x%X rate:%d\n",
+ status, beacon_notify_hdr->failure_frame,
+ le64_to_cpu(beacon->tsf),
+ mvm->ap_last_beacon_gp2,
+ le32_to_cpu(beacon_notify_hdr->initial_rate));
+ } else {
+ mvm->ibss_manager = beacon->ibss_mgr_status != 0;
+ status = le32_to_cpu(beacon->status) & TX_STATUS_MSK;
+ IWL_DEBUG_RX(mvm,
+ "beacon status %#x tsf:0x%016llX gp2:0x%X\n",
+ status, le64_to_cpu(beacon->tsf),
+ mvm->ap_last_beacon_gp2);
+ }
csa_vif = rcu_dereference_protected(mvm->csa_vif,
lockdep_is_held(&mvm->mutex));
@@ -1472,35 +1400,48 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
}
}
-static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
+void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb)
{
- struct iwl_missed_beacons_notif *missed_beacons = _data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_missed_beacons_notif *mb = (void *)pkt->data;
struct iwl_fw_dbg_trigger_missed_bcon *bcon_trig;
struct iwl_fw_dbg_trigger_tlv *trigger;
u32 stop_trig_missed_bcon, stop_trig_missed_bcon_since_rx;
u32 rx_missed_bcon, rx_missed_bcon_since_rx;
+ struct ieee80211_vif *vif;
+ u32 id = le32_to_cpu(mb->mac_id);
- if (mvmvif->id != (u16)le32_to_cpu(missed_beacons->mac_id))
- return;
+ IWL_DEBUG_INFO(mvm,
+ "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n",
+ le32_to_cpu(mb->mac_id),
+ le32_to_cpu(mb->consec_missed_beacons),
+ le32_to_cpu(mb->consec_missed_beacons_since_last_rx),
+ le32_to_cpu(mb->num_recvd_beacons),
+ le32_to_cpu(mb->num_expected_beacons));
+
+ rcu_read_lock();
+
+ vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true);
+ if (!vif)
+ goto out;
- rx_missed_bcon = le32_to_cpu(missed_beacons->consec_missed_beacons);
+ rx_missed_bcon = le32_to_cpu(mb->consec_missed_beacons);
rx_missed_bcon_since_rx =
- le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx);
+ le32_to_cpu(mb->consec_missed_beacons_since_last_rx);
/*
* TODO: the threshold should be adjusted based on latency conditions,
* and/or in case of a CS flow on one of the other AP vifs.
*/
- if (le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx) >
- IWL_MVM_MISSED_BEACONS_THRESHOLD)
+ if (rx_missed_bcon > IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG)
+ iwl_mvm_connection_loss(mvm, vif, "missed beacons");
+ else if (rx_missed_bcon_since_rx > IWL_MVM_MISSED_BEACONS_THRESHOLD)
ieee80211_beacon_loss(vif);
trigger = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif),
FW_DBG_TRIGGER_MISSED_BEACONS);
if (!trigger)
- return;
+ goto out;
bcon_trig = (void *)trigger->data;
stop_trig_missed_bcon = le32_to_cpu(bcon_trig->stop_consec_missed_bcon);
@@ -1512,28 +1453,11 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
if (rx_missed_bcon_since_rx >= stop_trig_missed_bcon_since_rx ||
rx_missed_bcon >= stop_trig_missed_bcon)
iwl_fw_dbg_collect_trig(&mvm->fwrt, trigger, NULL);
-}
-
-void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_missed_beacons_notif *mb = (void *)pkt->data;
-
- IWL_DEBUG_INFO(mvm,
- "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n",
- le32_to_cpu(mb->mac_id),
- le32_to_cpu(mb->consec_missed_beacons),
- le32_to_cpu(mb->consec_missed_beacons_since_last_rx),
- le32_to_cpu(mb->num_recvd_beacons),
- le32_to_cpu(mb->num_expected_beacons));
-
- ieee80211_iterate_active_interfaces_atomic(mvm->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_beacon_loss_iterator,
- mb);
iwl_fw_dbg_apply_point(&mvm->fwrt, IWL_FW_INI_APPLY_MISSED_BEACONS);
+
+out:
+ rcu_read_unlock();
}
void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
@@ -1575,16 +1499,29 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
ieee80211_rx_napi(mvm->hw, NULL, skb, NULL);
}
-static void iwl_mvm_probe_resp_data_iter(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
+void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb)
{
- struct iwl_probe_resp_data_notif *notif = _data;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_probe_resp_data_notif *notif = (void *)pkt->data;
struct iwl_probe_resp_data *old_data, *new_data;
+ int len = iwl_rx_packet_payload_len(pkt);
+ u32 id = le32_to_cpu(notif->mac_id);
+ struct ieee80211_vif *vif;
+ struct iwl_mvm_vif *mvmvif;
+
+ if (WARN_ON_ONCE(len < sizeof(*notif)))
+ return;
+
+ IWL_DEBUG_INFO(mvm, "Probe response data notif: noa %d, csa %d\n",
+ notif->noa_active, notif->csa_counter);
- if (mvmvif->id != (u16)le32_to_cpu(notif->mac_id))
+ vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false);
+ if (!vif)
return;
+ mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
if (!new_data)
return;
@@ -1615,66 +1552,63 @@ static void iwl_mvm_probe_resp_data_iter(void *_data, u8 *mac,
ieee80211_csa_set_counter(vif, notif->csa_counter);
}
-void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_probe_resp_data_notif *notif = (void *)pkt->data;
- int len = iwl_rx_packet_payload_len(pkt);
-
- if (WARN_ON_ONCE(len < sizeof(*notif)))
- return;
-
- IWL_DEBUG_INFO(mvm, "Probe response data notif: noa %d, csa %d\n",
- notif->noa_active, notif->csa_counter);
-
- ieee80211_iterate_active_interfaces(mvm->hw,
- IEEE80211_IFACE_ITER_ACTIVE,
- iwl_mvm_probe_resp_data_iter,
- notif);
-}
-
void iwl_mvm_channel_switch_noa_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 ieee80211_vif *csa_vif;
+ struct ieee80211_vif *csa_vif, *vif;
struct iwl_mvm_vif *mvmvif;
int len = iwl_rx_packet_payload_len(pkt);
- u32 id_n_color;
+ u32 id_n_color, csa_id, mac_id;
if (WARN_ON_ONCE(len < sizeof(*notif)))
return;
- rcu_read_lock();
-
- csa_vif = rcu_dereference(mvm->csa_vif);
- if (WARN_ON(!csa_vif || !csa_vif->csa_active))
- goto out_unlock;
-
id_n_color = le32_to_cpu(notif->id_and_color);
+ mac_id = id_n_color & FW_CTXT_ID_MSK;
+
+ if (WARN_ON_ONCE(mac_id >= NUM_MAC_INDEX_DRIVER))
+ return;
- mvmvif = iwl_mvm_vif_from_mac80211(csa_vif);
- if (WARN(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color) != id_n_color,
- "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)",
- FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color), id_n_color))
- goto out_unlock;
+ rcu_read_lock();
+ vif = rcu_dereference(mvm->vif_id_to_mac[mac_id]);
- IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n");
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ csa_vif = rcu_dereference(mvm->csa_vif);
+ if (WARN_ON(!csa_vif || !csa_vif->csa_active ||
+ csa_vif != vif))
+ goto out_unlock;
- schedule_delayed_work(&mvm->cs_tx_unblock_dwork,
- msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT *
- csa_vif->bss_conf.beacon_int));
+ mvmvif = iwl_mvm_vif_from_mac80211(csa_vif);
+ csa_id = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color);
+ if (WARN(csa_id != id_n_color,
+ "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)",
+ csa_id, id_n_color))
+ goto out_unlock;
- ieee80211_csa_finish(csa_vif);
+ IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n");
- rcu_read_unlock();
+ schedule_delayed_work(&mvm->cs_tx_unblock_dwork,
+ msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT *
+ csa_vif->bss_conf.beacon_int));
- RCU_INIT_POINTER(mvm->csa_vif, NULL);
+ ieee80211_csa_finish(csa_vif);
- return;
+ rcu_read_unlock();
+ RCU_INIT_POINTER(mvm->csa_vif, NULL);
+ return;
+ case NL80211_IFTYPE_STATION:
+ iwl_mvm_csa_client_absent(mvm, vif);
+ ieee80211_chswitch_done(vif, true);
+ break;
+ default:
+ /* should never happen */
+ WARN_ON_ONCE(1);
+ break;
+ }
out_unlock:
rcu_read_unlock();
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 97dc464379d2..3a92c09d4692 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -184,6 +184,29 @@ static const struct iwl_fw_bcast_filter iwl_mvm_default_bcast_filters[] = {
};
#endif
+static const struct cfg80211_pmsr_capabilities iwl_mvm_pmsr_capa = {
+ .max_peers = IWL_MVM_TOF_MAX_APS,
+ .report_ap_tsf = 1,
+ .randomize_mac_addr = 1,
+
+ .ftm = {
+ .supported = 1,
+ .asap = 1,
+ .non_asap = 1,
+ .request_lci = 1,
+ .request_civicloc = 1,
+ .max_bursts_exponent = -1, /* all supported */
+ .max_ftms_per_burst = 0, /* no limits */
+ .bandwidths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80),
+ .preambles = BIT(NL80211_PREAMBLE_LEGACY) |
+ BIT(NL80211_PREAMBLE_HT) |
+ BIT(NL80211_PREAMBLE_VHT),
+ },
+};
+
void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
{
if (!iwl_mvm_is_d0i3_supported(mvm))
@@ -395,6 +418,21 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm)
return ret;
}
+const static u8 he_if_types_ext_capa_sta[] = {
+ [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
+ [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
+ [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT,
+};
+
+const static struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = {
+ {
+ .iftype = NL80211_IFTYPE_STATION,
+ .extended_capabilities = he_if_types_ext_capa_sta,
+ .extended_capabilities_mask = he_if_types_ext_capa_sta,
+ .extended_capabilities_len = sizeof(he_if_types_ext_capa_sta),
+ },
+};
+
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
{
struct ieee80211_hw *hw = mvm->hw;
@@ -405,12 +443,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
};
+#ifdef CONFIG_PM_SLEEP
+ bool unified = fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
+#endif
/* Tell mac80211 our characteristics */
ieee80211_hw_set(hw, SIGNAL_DBM);
ieee80211_hw_set(hw, SPECTRUM_MGMT);
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
- ieee80211_hw_set(hw, QUEUE_CONTROL);
ieee80211_hw_set(hw, WANT_MONITOR_VIF);
ieee80211_hw_set(hw, SUPPORTS_PS);
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
@@ -424,6 +465,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
ieee80211_hw_set(hw, DEAUTH_NEED_MGD_TX_PREP);
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
+ ieee80211_hw_set(hw, BUFF_MMPDU_TXQ);
+ ieee80211_hw_set(hw, STA_MMPDU_TXQ);
+ ieee80211_hw_set(hw, TX_AMSDU);
+ ieee80211_hw_set(hw, TX_FRAG_LIST);
if (iwl_mvm_has_tlc_offload(mvm)) {
ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
@@ -469,6 +514,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
+ hw->max_tx_fragments = mvm->trans->max_skb_frags;
BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 6);
memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
@@ -525,6 +571,13 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->n_cipher_suites++;
}
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_FTM_CALIBRATED)) {
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
+ hw->wiphy->pmsr_capa = &iwl_mvm_pmsr_capa;
+ }
+
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
hw->wiphy->features |=
NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
@@ -534,6 +587,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->sta_data_size = sizeof(struct iwl_mvm_sta);
hw->vif_data_size = sizeof(struct iwl_mvm_vif);
hw->chanctx_data_size = sizeof(u16);
+ hw->txq_data_size = sizeof(struct iwl_mvm_txq);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
@@ -673,6 +727,13 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE);
}
+ if (mvm->nvm_data->sku_cap_11ax_enable &&
+ !iwlwifi_mod_params.disable_11ax) {
+ hw->wiphy->iftype_ext_capab = he_iftypes_ext_capa;
+ hw->wiphy->num_iftype_ext_capab =
+ ARRAY_SIZE(he_iftypes_ext_capa);
+ }
+
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
#ifdef CONFIG_PM_SLEEP
@@ -682,7 +743,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->wowlan = &mvm->wowlan;
}
- if (mvm->fw->img[IWL_UCODE_WOWLAN].num_sec &&
+ if ((unified || mvm->fw->img[IWL_UCODE_WOWLAN].num_sec) &&
mvm->trans->ops->d3_suspend &&
mvm->trans->ops->d3_resume &&
device_can_wakeup(mvm->trans->dev)) {
@@ -735,15 +796,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->netdev_features |= IWL_TX_CSUM_NETIF_FLAGS;
}
- ret = ieee80211_register_hw(mvm->hw);
- if (ret)
- iwl_mvm_leds_exit(mvm);
- mvm->init_status |= IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;
-
if (mvm->cfg->vht_mu_mimo_supported)
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
+ ret = ieee80211_register_hw(mvm->hw);
+ if (ret) {
+ iwl_mvm_leds_exit(mvm);
+ }
+
return ret;
}
@@ -776,7 +837,6 @@ static bool iwl_mvm_defer_tx(struct iwl_mvm *mvm,
goto out;
__skb_queue_tail(&mvm->d0i3_tx, skb);
- ieee80211_stop_queues(mvm->hw);
/* trigger wakeup */
iwl_mvm_ref(mvm, IWL_MVM_REF_TX);
@@ -796,13 +856,15 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
struct ieee80211_sta *sta = control->sta;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (void *)skb->data;
+ bool offchannel = IEEE80211_SKB_CB(skb)->flags &
+ IEEE80211_TX_CTL_TX_OFFCHAN;
if (iwl_mvm_is_radio_killed(mvm)) {
IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n");
goto drop;
}
- if (info->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
+ if (offchannel &&
!test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) &&
!test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status))
goto drop;
@@ -815,8 +877,8 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
sta = NULL;
/* If there is no sta, and it's not offchannel - send through AP */
- if (info->control.vif->type == NL80211_IFTYPE_STATION &&
- info->hw_queue != IWL_MVM_OFFCHANNEL_QUEUE && !sta) {
+ if (!sta && info->control.vif->type == NL80211_IFTYPE_STATION &&
+ !offchannel) {
struct iwl_mvm_vif *mvmvif =
iwl_mvm_vif_from_mac80211(info->control.vif);
u8 ap_sta_id = READ_ONCE(mvmvif->ap_sta_id);
@@ -844,22 +906,101 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
ieee80211_free_txskb(hw, skb);
}
-static inline bool iwl_enable_rx_ampdu(const struct iwl_cfg *cfg)
+void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
{
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_RXAGG)
- return false;
- return true;
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq);
+ struct sk_buff *skb = NULL;
+
+ /*
+ * No need for threads to be pending here, they can leave the first
+ * taker all the work.
+ *
+ * mvmtxq->tx_request logic:
+ *
+ * If 0, no one is currently TXing, set to 1 to indicate current thread
+ * will now start TX and other threads should quit.
+ *
+ * If 1, another thread is currently TXing, set to 2 to indicate to
+ * that thread that there was another request. Since that request may
+ * have raced with the check whether the queue is empty, the TXing
+ * thread should check the queue's status one more time before leaving.
+ * This check is done in order to not leave any TX hanging in the queue
+ * until the next TX invocation (which may not even happen).
+ *
+ * If 2, another thread is currently TXing, and it will already double
+ * check the queue, so do nothing.
+ */
+ if (atomic_fetch_add_unless(&mvmtxq->tx_request, 1, 2))
+ return;
+
+ rcu_read_lock();
+ do {
+ while (likely(!mvmtxq->stopped &&
+ (mvm->trans->system_pm_mode ==
+ IWL_PLAT_PM_MODE_DISABLED))) {
+ skb = ieee80211_tx_dequeue(hw, txq);
+
+ if (!skb) {
+ if (txq->sta)
+ IWL_DEBUG_TX(mvm,
+ "TXQ of sta %pM tid %d is now empty\n",
+ txq->sta->addr,
+ txq->tid);
+ break;
+ }
+
+ if (!txq->sta)
+ iwl_mvm_tx_skb_non_sta(mvm, skb);
+ else
+ iwl_mvm_tx_skb(mvm, skb, txq->sta);
+ }
+ } while (atomic_dec_return(&mvmtxq->tx_request));
+ rcu_read_unlock();
}
-static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
+static void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq)
{
- if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG)
- return false;
- if (iwlwifi_mod_params.disable_11n & IWL_ENABLE_HT_TXAGG)
- return true;
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq);
- /* enabled by default */
- return true;
+ /*
+ * Please note that racing is handled very carefully here:
+ * mvmtxq->txq_id is updated during allocation, and mvmtxq->list is
+ * deleted afterwards.
+ * This means that if:
+ * mvmtxq->txq_id != INVALID_QUEUE && list_empty(&mvmtxq->list):
+ * queue is allocated and we can TX.
+ * mvmtxq->txq_id != INVALID_QUEUE && !list_empty(&mvmtxq->list):
+ * a race, should defer the frame.
+ * mvmtxq->txq_id == INVALID_QUEUE && list_empty(&mvmtxq->list):
+ * need to allocate the queue and defer the frame.
+ * mvmtxq->txq_id == INVALID_QUEUE && !list_empty(&mvmtxq->list):
+ * queue is already scheduled for allocation, no need to allocate,
+ * should defer the frame.
+ */
+
+ /* If the queue is allocated TX and return. */
+ if (!txq->sta || mvmtxq->txq_id != IWL_MVM_INVALID_QUEUE) {
+ /*
+ * Check that list is empty to avoid a race where txq_id is
+ * already updated, but the queue allocation work wasn't
+ * finished
+ */
+ if (unlikely(txq->sta && !list_empty(&mvmtxq->list)))
+ return;
+
+ iwl_mvm_mac_itxq_xmit(hw, txq);
+ return;
+ }
+
+ /* The list is being deleted only after the queue is fully allocated. */
+ if (!list_empty(&mvmtxq->list))
+ return;
+
+ list_add_tail(&mvmtxq->list, &mvm->add_stream_txqs);
+ schedule_work(&mvm->add_stream_wk);
}
#define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \
@@ -974,7 +1115,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
mvmvif = iwl_mvm_vif_from_mac80211(vif);
cancel_delayed_work(&mvmvif->uapsd_nonagg_detected_wk);
}
- if (!iwl_enable_rx_ampdu(mvm->cfg)) {
+ if (!iwl_enable_rx_ampdu()) {
ret = -EINVAL;
break;
}
@@ -986,7 +1127,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
timeout);
break;
case IEEE80211_AMPDU_TX_START:
- if (!iwl_enable_tx_ampdu(mvm->cfg)) {
+ if (!iwl_enable_tx_ampdu()) {
ret = -EINVAL;
break;
}
@@ -1066,6 +1207,8 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
iwl_mvm_stop_device(mvm);
+ mvm->cur_aid = 0;
+
mvm->scan_status = 0;
mvm->ps_disabled = false;
mvm->calibrating = false;
@@ -1074,6 +1217,8 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
iwl_mvm_cleanup_roc_te(mvm);
ieee80211_remain_on_channel_expired(mvm->hw);
+ iwl_mvm_ftm_restart(mvm);
+
/*
* cleanup all interfaces, even inactive ones, as some might have
* gone down during the HW restart
@@ -1085,7 +1230,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
iwl_mvm_reset_phy_ctxts(mvm);
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
- memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames));
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
@@ -1188,6 +1332,8 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
/* allow transport/FW low power modes */
iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
+ iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_END_OF_RECOVERY);
+
/*
* If we have TDLS peers, remove them. We don't know the last seqno/PN
* of packets the FW sent out, so we must reconnect.
@@ -1391,6 +1537,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out_unlock;
+ rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif);
+
/* Counting number of interfaces is needed for legacy PM */
if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count++;
@@ -1549,6 +1697,9 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
IEEE80211_VIF_SUPPORTS_CQM_RSSI);
}
+ if (vif->bss_conf.ftm_responder)
+ memset(&mvm->ftm_resp_stats, 0, sizeof(mvm->ftm_resp_stats));
+
iwl_mvm_vif_dbgfs_clean(mvm, vif);
/*
@@ -1582,6 +1733,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
iwl_mvm_power_update_mac(mvm);
iwl_mvm_mac_ctxt_remove(mvm, vif);
+ RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL);
+
if (vif->type == NL80211_IFTYPE_MONITOR)
mvm->monitor_on = false;
@@ -2076,6 +2229,46 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
}
flags |= STA_CTXT_HE_PACKET_EXT;
+ } else if ((sta->he_cap.he_cap_elem.phy_cap_info[9] &
+ IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) !=
+ IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED) {
+ int low_th = -1;
+ int high_th = -1;
+
+ /* Take the PPE thresholds from the nominal padding info */
+ switch (sta->he_cap.he_cap_elem.phy_cap_info[9] &
+ IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_MASK) {
+ case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_0US:
+ low_th = IWL_HE_PKT_EXT_NONE;
+ high_th = IWL_HE_PKT_EXT_NONE;
+ break;
+ case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_8US:
+ low_th = IWL_HE_PKT_EXT_BPSK;
+ high_th = IWL_HE_PKT_EXT_NONE;
+ break;
+ case IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US:
+ low_th = IWL_HE_PKT_EXT_NONE;
+ high_th = IWL_HE_PKT_EXT_BPSK;
+ break;
+ }
+
+ /* Set the PPE thresholds accordingly */
+ if (low_th >= 0 && high_th >= 0) {
+ u8 ***pkt_ext_qam =
+ (void *)sta_ctxt_cmd.pkt_ext.pkt_ext_qam_th;
+
+ for (i = 0; i < MAX_HE_SUPP_NSS; i++) {
+ u8 bw;
+
+ for (bw = 0; bw < MAX_HE_CHANNEL_BW_INDX;
+ bw++) {
+ pkt_ext_qam[i][bw][0] = low_th;
+ pkt_ext_qam[i][bw][1] = high_th;
+ }
+ }
+
+ flags |= STA_CTXT_HE_PACKET_EXT;
+ }
}
rcu_read_unlock();
@@ -2146,6 +2339,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
}
+ /* Update MU EDCA params */
+ if (changes & BSS_CHANGED_QOS && mvmvif->associated &&
+ bss_conf->assoc && vif->bss_conf.he_support &&
+ !iwlwifi_mod_params.disable_11ax)
+ iwl_mvm_cfg_he_sta(mvm, vif, mvmvif->ap_sta_id);
+
/*
* If we're not associated yet, take the (new) BSSID before associating
* so the firmware knows. If we're already associated, then use the old
@@ -2211,7 +2410,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
* If update fails - SF might be running in associated
* mode while disassociated - which is forbidden.
*/
- WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false),
+ ret = iwl_mvm_sf_update(mvm, vif, false);
+ WARN_ONCE(ret &&
+ !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
+ &mvm->status),
"Failed to update SF upon disassociation\n");
/*
@@ -2432,6 +2634,8 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
if (iwl_mvm_phy_ctx_count(mvm) > 1)
iwl_mvm_teardown_tdls_peers(mvm);
+ iwl_mvm_ftm_restart_responder(mvm, vif);
+
goto out_unlock;
out_quota_failed:
@@ -2543,6 +2747,15 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
bss_conf->txpower);
iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
}
+
+ if (changes & BSS_CHANGED_FTM_RESPONDER) {
+ int ret = iwl_mvm_ftm_start_responder(mvm, vif);
+
+ if (ret)
+ IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n",
+ ret);
+ }
+
}
static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
@@ -2672,7 +2885,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
return;
spin_lock_bh(&mvmsta->lock);
- for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+ for (tid = 0; tid < ARRAY_SIZE(mvmsta->tid_data); tid++) {
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
if (tid_data->txq_id == IWL_MVM_INVALID_QUEUE)
@@ -2861,32 +3074,6 @@ iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm,
peer_addr, action);
}
-static void iwl_mvm_purge_deferred_tx_frames(struct iwl_mvm *mvm,
- struct iwl_mvm_sta *mvm_sta)
-{
- struct iwl_mvm_tid_data *tid_data;
- struct sk_buff *skb;
- int i;
-
- spin_lock_bh(&mvm_sta->lock);
- for (i = 0; i <= IWL_MAX_TID_COUNT; i++) {
- tid_data = &mvm_sta->tid_data[i];
-
- while ((skb = __skb_dequeue(&tid_data->deferred_tx_frames))) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
- /*
- * The first deferred frame should've stopped the MAC
- * queues, so we should never get a second deferred
- * frame for the RA/TID.
- */
- iwl_mvm_start_mac_queues(mvm, BIT(info->hw_queue));
- ieee80211_free_txskb(mvm->hw, skb);
- }
- }
- spin_unlock_bh(&mvm_sta->lock);
-}
-
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -2920,7 +3107,6 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
*/
if (old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_NOTEXIST) {
- iwl_mvm_purge_deferred_tx_frames(mvm, mvm_sta);
flush_work(&mvm->add_stream_wk);
/*
@@ -2967,6 +3153,8 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,
NL80211_TDLS_SETUP);
}
+
+ sta->max_rc_amsdu_len = 1;
} else if (old_state == IEEE80211_STA_NONE &&
new_state == IEEE80211_STA_AUTH) {
/*
@@ -2979,11 +3167,15 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC) {
if (vif->type == NL80211_IFTYPE_AP) {
+ vif->bss_conf.he_support = sta->he_cap.has_he;
mvmvif->ap_assoc_sta_count++;
iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
if (vif->bss_conf.he_support &&
!iwlwifi_mod_params.disable_11ax)
iwl_mvm_cfg_he_sta(mvm, vif, mvm_sta->sta_id);
+ } else if (vif->type == NL80211_IFTYPE_STATION) {
+ vif->bss_conf.he_support = sta->he_cap.has_he;
+ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
}
iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
@@ -2991,6 +3183,24 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
ret = iwl_mvm_update_sta(mvm, vif, sta);
} else if (old_state == IEEE80211_STA_ASSOC &&
new_state == IEEE80211_STA_AUTHORIZED) {
+ /* if wep is used, need to set the key for the station now */
+ if (vif->type == NL80211_IFTYPE_AP && mvmvif->ap_wep_key) {
+ mvm_sta->wep_key =
+ kmemdup(mvmvif->ap_wep_key,
+ sizeof(*mvmvif->ap_wep_key) +
+ mvmvif->ap_wep_key->keylen,
+ GFP_KERNEL);
+ if (!mvm_sta->wep_key) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta,
+ mvm_sta->wep_key,
+ STA_KEY_IDX_INVALID);
+ } else {
+ ret = 0;
+ }
/* we don't support TDLS during DCM */
if (iwl_mvm_phy_ctx_count(mvm) > 1)
@@ -3005,18 +3215,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
true);
-
- /* if wep is used, need to set the key for the station now */
- if (vif->type == NL80211_IFTYPE_AP && mvmvif->ap_wep_key)
- ret = iwl_mvm_set_sta_key(mvm, vif, sta,
- mvmvif->ap_wep_key,
- STA_KEY_IDX_INVALID);
- else
- ret = 0;
} else if (old_state == IEEE80211_STA_AUTHORIZED &&
new_state == IEEE80211_STA_ASSOC) {
/* disable beacon filtering */
- WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif, 0));
+ 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) {
@@ -3036,6 +3241,22 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,
NL80211_TDLS_DISABLE_LINK);
}
+
+ /* Remove STA key if this is an AP using WEP */
+ if (vif->type == NL80211_IFTYPE_AP && mvmvif->ap_wep_key) {
+ int rm_ret = iwl_mvm_remove_sta_key(mvm, vif, sta,
+ mvm_sta->wep_key);
+
+ if (!ret)
+ ret = rm_ret;
+ kfree(mvm_sta->wep_key);
+ mvm_sta->wep_key = NULL;
+ }
+
+ if (unlikely(ret &&
+ test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
+ &mvm->status)))
+ ret = 0;
} else {
ret = -EIO;
}
@@ -3431,14 +3652,20 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
.id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)),
.sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id),
- /* Set the channel info data */
- .channel_info.band = (channel->band == NL80211_BAND_2GHZ) ?
- PHY_BAND_24 : PHY_BAND_5,
- .channel_info.channel = channel->hw_value,
- .channel_info.width = PHY_VHT_CHANNEL_MODE20,
- /* Set the time and duration */
- .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)),
- };
+ };
+ struct iwl_hs20_roc_req_tail *tail = iwl_mvm_chan_info_cmd_tail(mvm,
+ &aux_roc_req.channel_info);
+ u16 len = sizeof(aux_roc_req) - iwl_mvm_chan_info_padding(mvm);
+
+ /* Set the channel info data */
+ iwl_mvm_set_chan_info(mvm, &aux_roc_req.channel_info, channel->hw_value,
+ (channel->band == NL80211_BAND_2GHZ) ?
+ PHY_BAND_24 : PHY_BAND_5,
+ PHY_VHT_CHANNEL_MODE20,
+ 0);
+
+ /* Set the time and duration */
+ tail->apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg));
delay = AUX_ROC_MIN_DELAY;
req_dur = MSEC_TO_TU(duration);
@@ -3463,15 +3690,15 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
}
}
- aux_roc_req.duration = cpu_to_le32(req_dur);
- aux_roc_req.apply_time_max_delay = cpu_to_le32(delay);
+ tail->duration = cpu_to_le32(req_dur);
+ tail->apply_time_max_delay = cpu_to_le32(delay);
IWL_DEBUG_TE(mvm,
"ROC: Requesting to remain on channel %u for %ums (requested = %ums, max_delay = %ums, dtim_interval = %ums)\n",
channel->hw_value, req_dur, duration, delay,
dtim_interval);
/* Set the node address */
- memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
+ memcpy(tail->node_addr, vif->addr, ETH_ALEN);
lockdep_assert_held(&mvm->mutex);
@@ -3502,7 +3729,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
ARRAY_SIZE(time_event_response),
iwl_mvm_rx_aux_roc, te_data);
- res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req),
+ res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, len,
&aux_roc_req);
if (res) {
@@ -3673,11 +3900,43 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw)
return 0;
}
+struct iwl_mvm_ftm_responder_iter_data {
+ bool responder;
+ struct ieee80211_chanctx_conf *ctx;
+};
+
+static void iwl_mvm_ftm_responder_chanctx_iter(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_ftm_responder_iter_data *data = _data;
+
+ if (rcu_access_pointer(vif->chanctx_conf) == data->ctx &&
+ vif->type == NL80211_IFTYPE_AP && vif->bss_conf.ftmr_params)
+ data->responder = true;
+}
+
+static bool iwl_mvm_is_ftm_responder_chanctx(struct iwl_mvm *mvm,
+ struct ieee80211_chanctx_conf *ctx)
+{
+ struct iwl_mvm_ftm_responder_iter_data data = {
+ .responder = false,
+ .ctx = ctx,
+ };
+
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+ IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_ftm_responder_chanctx_iter,
+ &data);
+ return data.responder;
+}
+
static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm,
struct ieee80211_chanctx_conf *ctx)
{
u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
struct iwl_mvm_phy_ctxt *phy_ctxt;
+ bool responder = iwl_mvm_is_ftm_responder_chanctx(mvm, ctx);
+ struct cfg80211_chan_def *def = responder ? &ctx->def : &ctx->min_def;
int ret;
lockdep_assert_held(&mvm->mutex);
@@ -3690,7 +3949,7 @@ static int __iwl_mvm_add_chanctx(struct iwl_mvm *mvm,
goto out;
}
- ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
+ ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def,
ctx->rx_chains_static,
ctx->rx_chains_dynamic);
if (ret) {
@@ -3745,6 +4004,8 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
+ bool responder = iwl_mvm_is_ftm_responder_chanctx(mvm, ctx);
+ struct cfg80211_chan_def *def = responder ? &ctx->def : &ctx->min_def;
if (WARN_ONCE((phy_ctxt->ref > 1) &&
(changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |
@@ -3759,17 +4020,17 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
/* we are only changing the min_width, may be a noop */
if (changed == IEEE80211_CHANCTX_CHANGE_MIN_WIDTH) {
- if (phy_ctxt->width == ctx->min_def.width)
+ if (phy_ctxt->width == def->width)
goto out_unlock;
/* we are just toggling between 20_NOHT and 20 */
if (phy_ctxt->width <= NL80211_CHAN_WIDTH_20 &&
- ctx->min_def.width <= NL80211_CHAN_WIDTH_20)
+ def->width <= NL80211_CHAN_WIDTH_20)
goto out_unlock;
}
iwl_mvm_bt_coex_vif_change(mvm);
- iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->min_def,
+ iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, def,
ctx->rx_chains_static,
ctx->rx_chains_dynamic);
@@ -3798,6 +4059,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
mvmvif->ap_ibss_active = true;
break;
}
+ /* fall through */
case NL80211_IFTYPE_ADHOC:
/*
* The AP binding flow is handled as part of the start_ap flow
@@ -3850,25 +4112,30 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
}
if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) {
- u32 duration = 3 * vif->bss_conf.beacon_int;
+ mvmvif->csa_bcn_pending = true;
- /* iwl_mvm_protect_session() reads directly from the
- * device (the system time), so make sure it is
- * available.
- */
- ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA);
- if (ret)
- goto out_remove_binding;
+ if (!fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD)) {
+ u32 duration = 3 * vif->bss_conf.beacon_int;
- /* Protect the session to make sure we hear the first
- * beacon on the new channel.
- */
- mvmvif->csa_bcn_pending = true;
- iwl_mvm_protect_session(mvm, vif, duration, duration,
- vif->bss_conf.beacon_int / 2,
- true);
- iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA);
+ /* iwl_mvm_protect_session() reads directly from the
+ * device (the system time), so make sure it is
+ * available.
+ */
+ ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_CSA);
+ if (ret)
+ goto out_remove_binding;
+
+ /* Protect the session to make sure we hear the first
+ * beacon on the new channel.
+ */
+ iwl_mvm_protect_session(mvm, vif, duration, duration,
+ vif->bss_conf.beacon_int / 2,
+ true);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA);
+ }
iwl_mvm_update_quotas(mvm, false, NULL);
}
@@ -3938,7 +4205,9 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
disabled_vif = vif;
- iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
+ if (!fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD))
+ iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
break;
default:
break;
@@ -4189,6 +4458,27 @@ static void iwl_mvm_channel_switch(struct ieee80211_hw *hw,
"dummy channel switch op\n");
}
+static int iwl_mvm_schedule_client_csa(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_channel_switch *chsw)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_chan_switch_te_cmd cmd = {
+ .mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
+ mvmvif->color)),
+ .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
+ .tsf = cpu_to_le32(chsw->timestamp),
+ .cs_count = chsw->count,
+ };
+
+ lockdep_assert_held(&mvm->mutex);
+
+ return iwl_mvm_send_cmd_pdu(mvm,
+ WIDE_ID(MAC_CONF_GROUP,
+ CHANNEL_SWITCH_TIME_EVENT_CMD),
+ 0, sizeof(cmd), &cmd);
+}
+
static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *chsw)
@@ -4256,14 +4546,19 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
if (chsw->block_tx)
iwl_mvm_csa_client_absent(mvm, vif);
- iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int,
- apply_time);
if (mvmvif->bf_data.bf_enabled) {
ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
if (ret)
goto out_unlock;
}
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_CHANNEL_SWITCH_CMD))
+ iwl_mvm_schedule_client_csa(mvm, vif, chsw);
+ else
+ iwl_mvm_schedule_csa_period(mvm, vif,
+ vif->bss_conf.beacon_int,
+ apply_time);
break;
default:
break;
@@ -4656,8 +4951,89 @@ static void iwl_mvm_sync_rx_queues(struct ieee80211_hw *hw)
mutex_unlock(&mvm->mutex);
}
+static int
+iwl_mvm_mac_get_ftm_responder_stats(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_ftm_responder_stats *stats)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||
+ !mvmvif->ap_ibss_active || !vif->bss_conf.ftm_responder)
+ return -EINVAL;
+
+ mutex_lock(&mvm->mutex);
+ *stats = mvm->ftm_resp_stats;
+ mutex_unlock(&mvm->mutex);
+
+ stats->filled = BIT(NL80211_FTM_STATS_SUCCESS_NUM) |
+ BIT(NL80211_FTM_STATS_PARTIAL_NUM) |
+ BIT(NL80211_FTM_STATS_FAILED_NUM) |
+ BIT(NL80211_FTM_STATS_ASAP_NUM) |
+ BIT(NL80211_FTM_STATS_NON_ASAP_NUM) |
+ BIT(NL80211_FTM_STATS_TOTAL_DURATION_MSEC) |
+ BIT(NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM) |
+ BIT(NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM) |
+ BIT(NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM);
+
+ return 0;
+}
+
+static int iwl_mvm_start_pmsr(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_pmsr_request *request)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_ftm_start(mvm, vif, request);
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_pmsr_request *request)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ mutex_lock(&mvm->mutex);
+ iwl_mvm_ftm_abort(mvm, request);
+ mutex_unlock(&mvm->mutex);
+}
+
+static bool iwl_mvm_can_hw_csum(struct sk_buff *skb)
+{
+ u8 protocol = ip_hdr(skb)->protocol;
+
+ if (!IS_ENABLED(CONFIG_INET))
+ return false;
+
+ return protocol == IPPROTO_TCP || protocol == IPPROTO_UDP;
+}
+
+static bool iwl_mvm_mac_can_aggregate(struct ieee80211_hw *hw,
+ struct sk_buff *head,
+ struct sk_buff *skb)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ /* For now don't aggregate IPv6 in AMSDU */
+ if (skb->protocol != htons(ETH_P_IP))
+ return false;
+
+ if (!iwl_mvm_is_csum_supported(mvm))
+ return true;
+
+ return iwl_mvm_can_hw_csum(skb) == iwl_mvm_can_hw_csum(head);
+}
+
const struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
+ .wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
.ampdu_action = iwl_mvm_mac_ampdu_action,
.start = iwl_mvm_mac_start,
.reconfig_complete = iwl_mvm_mac_reconfig_complete,
@@ -4731,6 +5107,11 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
#endif
.get_survey = iwl_mvm_mac_get_survey,
.sta_statistics = iwl_mvm_mac_sta_statistics,
+ .get_ftm_responder_stats = iwl_mvm_mac_get_ftm_responder_stats,
+ .start_pmsr = iwl_mvm_start_pmsr,
+ .abort_pmsr = iwl_mvm_abort_pmsr,
+
+ .can_aggregate_in_amsdu = iwl_mvm_mac_can_aggregate,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.sta_add_debugfs = iwl_mvm_sta_add_debugfs,
#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 1aa690e081ff..bca6f6b536d9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -83,7 +83,6 @@
#include "sta.h"
#include "fw-api.h"
#include "constants.h"
-#include "tof.h"
#include "fw/runtime.h"
#include "fw/dbg.h"
#include "fw/acpi.h"
@@ -95,6 +94,8 @@
/* RSSI offset for WkP */
#define IWL_RSSI_OFFSET 50
#define IWL_MVM_MISSED_BEACONS_THRESHOLD 8
+#define IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG 16
+
/* A TimeUnit is 1024 microsecond */
#define MSEC_TO_TU(_msec) (_msec*1000/1024)
@@ -299,17 +300,38 @@ enum iwl_bt_force_ant_mode {
};
/**
+ * struct iwl_mvm_low_latency_force - low latency force mode set by debugfs
+ * @LOW_LATENCY_FORCE_UNSET: unset force mode
+ * @LOW_LATENCY_FORCE_ON: for low latency on
+ * @LOW_LATENCY_FORCE_OFF: for low latency off
+ * @NUM_LOW_LATENCY_FORCE: max num of modes
+ */
+enum iwl_mvm_low_latency_force {
+ LOW_LATENCY_FORCE_UNSET,
+ LOW_LATENCY_FORCE_ON,
+ LOW_LATENCY_FORCE_OFF,
+ NUM_LOW_LATENCY_FORCE
+};
+
+/**
* struct iwl_mvm_low_latency_cause - low latency set causes
* @LOW_LATENCY_TRAFFIC: indicates low latency traffic was detected
* @LOW_LATENCY_DEBUGFS: low latency mode set from debugfs
* @LOW_LATENCY_VCMD: low latency mode set from vendor command
* @LOW_LATENCY_VIF_TYPE: low latency mode set because of vif type (ap)
+* @LOW_LATENCY_DEBUGFS_FORCE_ENABLE: indicate that force mode is enabled
+* the actual set/unset is done with LOW_LATENCY_DEBUGFS_FORCE
+* @LOW_LATENCY_DEBUGFS_FORCE: low latency force mode from debugfs
+* set this with LOW_LATENCY_DEBUGFS_FORCE_ENABLE flag
+* in low_latency.
*/
enum iwl_mvm_low_latency_cause {
LOW_LATENCY_TRAFFIC = BIT(0),
LOW_LATENCY_DEBUGFS = BIT(1),
LOW_LATENCY_VCMD = BIT(2),
LOW_LATENCY_VIF_TYPE = BIT(3),
+ LOW_LATENCY_DEBUGFS_FORCE_ENABLE = BIT(4),
+ LOW_LATENCY_DEBUGFS_FORCE = BIT(5),
};
/**
@@ -360,8 +382,10 @@ struct iwl_probe_resp_data {
* @pm_enabled - Indicate if MAC power management is allowed
* @monitor_active: indicates that monitor context is configured, and that the
* interface should get quota etc.
- * @low_latency: indicates low latency is set, see
- * enum &iwl_mvm_low_latency_cause for causes.
+ * @low_latency: bit flags for low latency
+ * 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.
* @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
@@ -393,7 +417,8 @@ struct iwl_mvm_vif {
bool ap_ibss_active;
bool pm_enabled;
bool monitor_active;
- u8 low_latency;
+ u8 low_latency: 6;
+ u8 low_latency_actual: 1;
bool ps_disabled;
struct iwl_mvm_vif_bf_data bf_data;
@@ -778,6 +803,39 @@ struct iwl_mvm_geo_profile {
u8 values[ACPI_GEO_TABLE_SIZE];
};
+struct iwl_mvm_txq {
+ struct list_head list;
+ u16 txq_id;
+ atomic_t tx_request;
+ bool stopped;
+};
+
+static inline struct iwl_mvm_txq *
+iwl_mvm_txq_from_mac80211(struct ieee80211_txq *txq)
+{
+ return (void *)txq->drv_priv;
+}
+
+static inline struct iwl_mvm_txq *
+iwl_mvm_txq_from_tid(struct ieee80211_sta *sta, u8 tid)
+{
+ if (tid == IWL_MAX_TID_COUNT)
+ tid = IEEE80211_NUM_TIDS;
+
+ return (void *)sta->txq[tid]->drv_priv;
+}
+
+/**
+ * struct iwl_mvm_tvqm_txq_info - maps TVQM hw queue to tid
+ *
+ * @sta_id: sta id
+ * @txq_tid: txq tid
+ */
+struct iwl_mvm_tvqm_txq_info {
+ u8 sta_id;
+ u8 txq_tid;
+};
+
struct iwl_mvm_dqa_txq_info {
u8 ra_sta_id; /* The RA this queue is mapped to, if exists */
bool reserved; /* Is this the TXQ reserved for a STA */
@@ -821,9 +879,6 @@ struct iwl_mvm {
bool hw_registered;
bool calibrating;
- u32 error_event_table[2];
- u32 log_event_table;
- u32 umac_error_event_table;
bool support_umac_log;
u32 ampdu_ref;
@@ -843,13 +898,13 @@ struct iwl_mvm {
u64 on_time_scan;
} radio_stats, accu_radio_stats;
- u16 hw_queue_to_mac80211[IWL_MAX_TVQM_QUEUES];
-
- struct iwl_mvm_dqa_txq_info queue_info[IWL_MAX_HW_QUEUES];
+ struct list_head add_stream_txqs;
+ union {
+ struct iwl_mvm_dqa_txq_info queue_info[IWL_MAX_HW_QUEUES];
+ struct iwl_mvm_tvqm_txq_info tvqm_info[IWL_MAX_TVQM_QUEUES];
+ };
struct work_struct add_stream_wk; /* To add streams to queues */
- atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
-
const char *nvm_file_name;
struct iwl_nvm_data *nvm_data;
/* NVM sections */
@@ -863,7 +918,6 @@ struct iwl_mvm {
/* data related to data path */
struct iwl_rx_phy_info last_phy_info;
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
- unsigned long sta_deferred_frames[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
u8 rx_ba_sessions;
/* configured by mac80211 */
@@ -924,6 +978,7 @@ struct iwl_mvm {
u32 dbgfs_prph_reg_addr;
bool disable_power_off;
bool disable_power_off_d3;
+ bool beacon_inject_active;
bool scan_iter_notif_enabled;
@@ -932,6 +987,7 @@ struct iwl_mvm {
struct debugfs_blob_wrapper nvm_calib_blob;
struct debugfs_blob_wrapper nvm_prod_blob;
struct debugfs_blob_wrapper nvm_phy_sku_blob;
+ struct debugfs_blob_wrapper nvm_reg_blob;
struct iwl_mvm_frame_stats drv_rx_stats;
spinlock_t drv_stats_lock;
@@ -955,9 +1011,11 @@ struct iwl_mvm {
u8 refs[IWL_MVM_REF_COUNT];
u8 vif_count;
+ struct ieee80211_vif __rcu *vif_id_to_mac[NUM_MAC_INDEX_DRIVER];
/* -1 for always, 0 for never, >0 for that many times */
s8 fw_restart;
+ u8 *error_recovery_buf;
#ifdef CONFIG_IWLWIFI_LEDS
struct led_classdev led;
@@ -1047,6 +1105,8 @@ struct iwl_mvm {
/* Indicate if device power save is allowed */
u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */
+ /* Indicate if 32Khz external clock is valid */
+ u32 ext_clock_valid;
unsigned int max_amsdu_len; /* used for debugfs only */
struct ieee80211_vif __rcu *csa_vif;
@@ -1090,7 +1150,14 @@ struct iwl_mvm {
u32 ciphers[IWL_MVM_NUM_CIPHERS];
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
- struct iwl_mvm_tof_data tof_data;
+
+ struct cfg80211_ftm_responder_stats ftm_resp_stats;
+ struct {
+ struct cfg80211_pmsr_request *req;
+ struct wireless_dev *req_wdev;
+ struct list_head loc_list;
+ int responses[IWL_MVM_TOF_MAX_APS];
+ } ftm_initiator;
struct ieee80211_vif *nan_vif;
#define IWL_MAX_BAID 32
@@ -1106,6 +1173,11 @@ struct iwl_mvm {
/* does a monitor vif exist (only one can exist hence bool) */
bool monitor_on;
+
+ /* sniffer data to include in radiotap */
+ __le16 cur_aid;
+ u8 cur_bssid[ETH_ALEN];
+
#ifdef CONFIG_ACPI
struct iwl_mvm_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM];
struct iwl_mvm_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES];
@@ -1149,8 +1221,6 @@ enum iwl_mvm_status {
enum iwl_mvm_init_status {
IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE = BIT(0),
IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE = BIT(1),
- IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE = BIT(2),
- IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE = BIT(3),
};
static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
@@ -1207,6 +1277,19 @@ iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id)
return iwl_mvm_sta_from_mac80211(sta);
}
+static inline struct ieee80211_vif *
+iwl_mvm_rcu_dereference_vif_id(struct iwl_mvm *mvm, u8 vif_id, bool rcu)
+{
+ if (WARN_ON(vif_id >= ARRAY_SIZE(mvm->vif_id_to_mac)))
+ return NULL;
+
+ if (rcu)
+ return rcu_dereference(mvm->vif_id_to_mac[vif_id]);
+
+ return rcu_dereference_protected(mvm->vif_id_to_mac[vif_id],
+ lockdep_is_held(&mvm->mutex));
+}
+
static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
{
return !iwlwifi_mod_params.d0i3_disable &&
@@ -1237,6 +1320,12 @@ static inline bool iwl_mvm_is_frag_ebs_supported(struct iwl_mvm *mvm)
return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_FRAG_EBS);
}
+static inline bool iwl_mvm_is_short_beacon_notif_supported(struct iwl_mvm *mvm)
+{
+ return fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_SHORT_BEACON_NOTIF);
+}
+
static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm)
{
/* For now we only use this mode to differentiate between
@@ -1470,6 +1559,11 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta, __le16 fc);
+void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
+unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ unsigned int tid);
+
#ifdef CONFIG_IWLWIFI_DEBUG
const char *iwl_mvm_get_tx_fail_reason(u32 status);
#else
@@ -1567,6 +1661,7 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
+void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags);
void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
@@ -1599,9 +1694,19 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool force_assoc_off, const u8 *bssid_override);
int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
-u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
+int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct sk_buff *beacon);
+int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm,
+ struct sk_buff *beacon,
+ void *data, int len);
+u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info,
+ struct ieee80211_vif *vif);
+void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
+ __le32 *tim_index, __le32 *tim_size,
+ u8 *beacon, u32 frame_size);
void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
@@ -1615,8 +1720,6 @@ void iwl_mvm_window_status_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
-unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
- struct ieee80211_vif *exclude_vif);
void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
@@ -1870,17 +1973,43 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
* binding, so this has no real impact. For now, just return
* the current desired low-latency state.
*/
- return mvmvif->low_latency;
+ return mvmvif->low_latency_actual;
}
static inline
void iwl_mvm_vif_set_low_latency(struct iwl_mvm_vif *mvmvif, bool set,
enum iwl_mvm_low_latency_cause cause)
{
+ u8 new_state;
+
if (set)
mvmvif->low_latency |= cause;
else
mvmvif->low_latency &= ~cause;
+
+ /*
+ * if LOW_LATENCY_DEBUGFS_FORCE_ENABLE is enabled no changes are
+ * allowed to actual mode.
+ */
+ if (mvmvif->low_latency & LOW_LATENCY_DEBUGFS_FORCE_ENABLE &&
+ cause != LOW_LATENCY_DEBUGFS_FORCE_ENABLE)
+ return;
+
+ if (cause == LOW_LATENCY_DEBUGFS_FORCE_ENABLE && set)
+ /*
+ * We enter force state
+ */
+ new_state = !!(mvmvif->low_latency &
+ LOW_LATENCY_DEBUGFS_FORCE);
+ else
+ /*
+ * Check if any other one set low latency
+ */
+ new_state = !!(mvmvif->low_latency &
+ ~(LOW_LATENCY_DEBUGFS_FORCE_ENABLE |
+ LOW_LATENCY_DEBUGFS_FORCE));
+
+ mvmvif->low_latency_actual = new_state;
}
/* Return a bitmask with all the hw supported queues, except for the
@@ -1895,21 +2024,24 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)
static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
{
lockdep_assert_held(&mvm->mutex);
- /* calling this function without using dump_start/end since at this
- * point we already hold the op mode mutex
+ /* If IWL_MVM_STATUS_HW_RESTART_REQUESTED bit is set then we received
+ * an assert. Since we failed to bring the interface up, mac80211
+ * will not attempt to reconfig the device,
+ * which handles the dump collection in assert flow,
+ * so trigger dump collection here.
*/
- iwl_fw_dbg_collect_sync(&mvm->fwrt);
+ if (test_and_clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
+ &mvm->status))
+ iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert,
+ false, 0);
+
iwl_fw_cancel_timestamp(&mvm->fwrt);
- iwl_free_fw_paging(&mvm->fwrt);
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
+ iwl_fwrt_stop_device(&mvm->fwrt);
+ iwl_free_fw_paging(&mvm->fwrt);
iwl_fw_dump_conf_clear(&mvm->fwrt);
- iwl_trans_stop_device(mvm->trans);
}
-/* Stop/start all mac queues in a given bitmap */
-void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq);
-void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq);
-
/* Re-configure the SCD for a queue that has already been configured */
int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
int tid, int frame_limit, u16 ssn);
@@ -1949,6 +2081,23 @@ void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm);
int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool added_vif);
+/* FTM responder */
+int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif);
+void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb);
+
+/* FTM initiator */
+void iwl_mvm_ftm_restart(struct iwl_mvm *mvm);
+void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb);
+void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb);
+int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct cfg80211_pmsr_request *request);
+void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req);
+
/* TDLS */
/*
@@ -2015,4 +2164,59 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
struct dentry *dir);
#endif
+/* Channel info utils */
+static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm)
+{
+ return fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_ULTRA_HB_CHANNELS);
+}
+
+static inline void *iwl_mvm_chan_info_cmd_tail(struct iwl_mvm *mvm,
+ struct iwl_fw_channel_info *ci)
+{
+ return (u8 *)ci + (iwl_mvm_has_ultra_hb_channel(mvm) ?
+ sizeof(struct iwl_fw_channel_info) :
+ sizeof(struct iwl_fw_channel_info_v1));
+}
+
+static inline size_t iwl_mvm_chan_info_padding(struct iwl_mvm *mvm)
+{
+ return iwl_mvm_has_ultra_hb_channel(mvm) ? 0 :
+ sizeof(struct iwl_fw_channel_info) -
+ sizeof(struct iwl_fw_channel_info_v1);
+}
+
+static inline void iwl_mvm_set_chan_info(struct iwl_mvm *mvm,
+ struct iwl_fw_channel_info *ci,
+ u32 chan, u8 band, u8 width,
+ u8 ctrl_pos)
+{
+ if (iwl_mvm_has_ultra_hb_channel(mvm)) {
+ ci->channel = cpu_to_le32(chan);
+ ci->band = band;
+ ci->width = width;
+ ci->ctrl_pos = ctrl_pos;
+ } else {
+ struct iwl_fw_channel_info_v1 *ci_v1 =
+ (struct iwl_fw_channel_info_v1 *)ci;
+
+ ci_v1->channel = chan;
+ ci_v1->band = band;
+ ci_v1->width = width;
+ ci_v1->ctrl_pos = ctrl_pos;
+ }
+}
+
+static inline void
+iwl_mvm_set_chan_info_chandef(struct iwl_mvm *mvm,
+ struct iwl_fw_channel_info *ci,
+ struct cfg80211_chan_def *chandef)
+{
+ iwl_mvm_set_chan_info(mvm, ci, chandef->chan->hw_value,
+ (chandef->chan->band == NL80211_BAND_2GHZ ?
+ PHY_BAND_24 : PHY_BAND_5),
+ iwl_mvm_get_channel_width(chandef),
+ iwl_mvm_get_ctrl_pos(chandef));
+}
+
#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index 6fc5cc1f2b5b..7bdbd010ae6b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -179,7 +179,7 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
IWL_DEBUG_EEPROM(mvm->trans->dev,
"NVM access command failed with status %d (device: %s)\n",
ret, mvm->cfg->name);
- ret = -EIO;
+ ret = -ENODATA;
}
goto exit;
}
@@ -380,8 +380,12 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
/* we override the constness for initial read */
ret = iwl_nvm_read_section(mvm, section, nvm_buffer,
size_read);
- if (ret < 0)
+ if (ret == -ENODATA) {
+ ret = 0;
continue;
+ }
+ if (ret < 0)
+ break;
size_read += ret;
temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
if (!temp) {
@@ -412,6 +416,11 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
mvm->nvm_phy_sku_blob.data = temp;
mvm->nvm_phy_sku_blob.size = ret;
break;
+ case NVM_SECTION_TYPE_REGULATORY_SDP:
+ case NVM_SECTION_TYPE_REGULATORY:
+ mvm->nvm_reg_blob.data = temp;
+ mvm->nvm_reg_blob.size = ret;
+ break;
default:
if (section == mvm->cfg->nvm_hw_section_num) {
mvm->nvm_hw_blob.data = temp;
@@ -454,7 +463,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
IWL_DEBUG_EEPROM(mvm->trans->dev, "nvm version = %x\n",
mvm->nvm_data->nvm_version);
- return 0;
+ return ret < 0 ? ret : 0;
}
struct iwl_mcc_update_resp *
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 30c5127034a0..ba27dce4c2bb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -82,7 +82,6 @@
#include "fw/api/scan.h"
#include "time-event.h"
#include "fw-api.h"
-#include "fw/api/scan.h"
#include "fw/acpi.h"
#define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux"
@@ -301,8 +300,14 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER_ASYNC_LOCKED),
RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif,
RX_HANDLER_SYNC),
- RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler,
- RX_HANDLER_ASYNC_LOCKED),
+ RX_HANDLER_GRP(LOCATION_GROUP, TOF_RESPONDER_STATS,
+ iwl_mvm_ftm_responder_stats, RX_HANDLER_ASYNC_LOCKED),
+
+ RX_HANDLER_GRP(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF,
+ iwl_mvm_ftm_range_resp, RX_HANDLER_ASYNC_LOCKED),
+ RX_HANDLER_GRP(LOCATION_GROUP, TOF_LC_NOTIF,
+ iwl_mvm_ftm_lc_notif, RX_HANDLER_ASYNC_LOCKED),
+
RX_HANDLER_GRP(DEBUG_GROUP, MFU_ASSERT_DUMP_NTF,
iwl_mvm_mfu_assert_dump_notif, RX_HANDLER_SYNC),
RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF,
@@ -329,8 +334,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
HCMD_NAME(SCAN_REQ_UMAC),
HCMD_NAME(SCAN_ABORT_UMAC),
HCMD_NAME(SCAN_COMPLETE_UMAC),
- HCMD_NAME(TOF_CMD),
- HCMD_NAME(TOF_NOTIFICATION),
HCMD_NAME(BA_WINDOW_STATUS_NOTIFICATION_ID),
HCMD_NAME(ADD_STA_KEY),
HCMD_NAME(ADD_STA),
@@ -419,12 +422,14 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
HCMD_NAME(SHARED_MEM_CFG_CMD),
HCMD_NAME(INIT_EXTENDED_CFG_CMD),
+ HCMD_NAME(FW_ERROR_RECOVERY_CMD),
};
/* Please keep this array *SORTED* by hex value.
* Access is done through binary search
*/
static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
+ HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD),
HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF),
};
@@ -449,6 +454,8 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {
HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD),
HCMD_NAME(STA_HE_CTXT_CMD),
HCMD_NAME(RFH_QUEUE_CONFIG_CMD),
+ HCMD_NAME(TLC_MNG_CONFIG_CMD),
+ HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD),
HCMD_NAME(STA_PM_NOTIF),
HCMD_NAME(MU_GROUP_MGMT_NOTIF),
HCMD_NAME(RX_QUEUES_NOTIFICATION),
@@ -464,6 +471,22 @@ static const struct iwl_hcmd_names iwl_mvm_debug_names[] = {
/* Please keep this array *SORTED* by hex value.
* Access is done through binary search
*/
+static const struct iwl_hcmd_names iwl_mvm_location_names[] = {
+ HCMD_NAME(TOF_RANGE_REQ_CMD),
+ HCMD_NAME(TOF_CONFIG_CMD),
+ HCMD_NAME(TOF_RANGE_ABORT_CMD),
+ HCMD_NAME(TOF_RANGE_REQ_EXT_CMD),
+ HCMD_NAME(TOF_RESPONDER_CONFIG_CMD),
+ HCMD_NAME(TOF_RESPONDER_DYN_CONFIG_CMD),
+ HCMD_NAME(TOF_LC_NOTIF),
+ HCMD_NAME(TOF_RESPONDER_STATS),
+ HCMD_NAME(TOF_MCSI_DEBUG_NOTIF),
+ HCMD_NAME(TOF_RANGE_RESPONSE_NOTIF),
+};
+
+/* Please keep this array *SORTED* by hex value.
+ * Access is done through binary search
+ */
static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = {
HCMD_NAME(STORED_BEACON_NTF),
};
@@ -483,6 +506,7 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
[MAC_CONF_GROUP] = HCMD_ARR(iwl_mvm_mac_conf_names),
[PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names),
[DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names),
+ [LOCATION_GROUP] = HCMD_ARR(iwl_mvm_location_names),
[PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names),
[REGULATORY_AND_NVM_GROUP] =
HCMD_ARR(iwl_mvm_regulatory_and_nvm_names),
@@ -577,11 +601,17 @@ static int iwl_mvm_fwrt_send_hcmd(void *ctx, struct iwl_host_cmd *host_cmd)
return ret;
}
+static bool iwl_mvm_d3_debug_enable(void *ctx)
+{
+ return IWL_MVM_D3_DEBUG;
+}
+
static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = {
.dump_start = iwl_mvm_fwrt_dump_start,
.dump_end = iwl_mvm_fwrt_dump_end,
.fw_running = iwl_mvm_fwrt_fw_running,
.send_hcmd = iwl_mvm_fwrt_send_hcmd,
+ .d3_debug_enable = iwl_mvm_d3_debug_enable,
};
static struct iwl_op_mode *
@@ -676,6 +706,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_LIST_HEAD(&mvm->aux_roc_te_list);
INIT_LIST_HEAD(&mvm->async_handlers_list);
spin_lock_init(&mvm->time_event_lock);
+ INIT_LIST_HEAD(&mvm->ftm_initiator.loc_list);
INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk);
INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk);
@@ -685,6 +716,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);
INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk);
INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk);
+ INIT_LIST_HEAD(&mvm->add_stream_txqs);
spin_lock_init(&mvm->d0i3_tx_lock);
spin_lock_init(&mvm->refs_lock);
@@ -736,6 +768,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans_cfg.rx_buf_size = rb_size_default;
}
+ BUILD_BUG_ON(sizeof(struct iwl_ldbg_config_cmd) !=
+ LDBG_CFG_COMMAND_SIZE);
+
trans->wide_cmd_header = true;
trans_cfg.bc_table_dword =
mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_22560;
@@ -799,8 +834,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_lock(&mvm->mutex);
iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE);
err = iwl_run_init_mvm_ucode(mvm, true);
- if (test_bit(IWL_FWRT_STATUS_WAIT_ALIVE, &mvm->fwrt.status))
- iwl_fw_alive_error_dump(&mvm->fwrt);
+ if (err)
+ iwl_fw_dbg_error_collect(&mvm->fwrt, FW_DBG_TRIGGER_DRIVER);
if (!iwlmvm_mod_params.init_dbg || !err)
iwl_mvm_stop_device(mvm);
iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);
@@ -842,8 +877,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (iwl_mvm_is_d0i3_supported(mvm))
iwl_trans_unref(mvm->trans);
- iwl_mvm_tof_init(mvm);
-
iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx);
return op_mode;
@@ -886,15 +919,15 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
iwl_mvm_thermal_exit(mvm);
- if (mvm->init_status & IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE) {
- ieee80211_unregister_hw(mvm->hw);
- mvm->init_status &= ~IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;
- }
+ ieee80211_unregister_hw(mvm->hw);
kfree(mvm->scan_cmd);
kfree(mvm->mcast_filter_cmd);
mvm->mcast_filter_cmd = NULL;
+ kfree(mvm->error_recovery_buf);
+ mvm->error_recovery_buf = NULL;
+
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree(mvm->d3_resume_sram);
#endif
@@ -909,8 +942,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
cancel_delayed_work_sync(&mvm->tcm.work);
- iwl_mvm_tof_clean(mvm);
-
iwl_fw_runtime_free(&mvm->fwrt);
mutex_destroy(&mvm->mutex);
mutex_destroy(&mvm->d0i3_suspend_mutex);
@@ -1079,24 +1110,6 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
iwl_mvm_rx_common(mvm, rxb, pkt);
}
-void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq)
-{
- int q;
-
- if (WARN_ON_ONCE(!mq))
- return;
-
- for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) {
- if (atomic_inc_return(&mvm->mac80211_queue_stop_count[q]) > 1) {
- IWL_DEBUG_TX_QUEUES(mvm,
- "mac80211 %d already stopped\n", q);
- continue;
- }
-
- ieee80211_stop_queue(mvm->hw, q);
- }
-}
-
static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode,
const struct iwl_device_cmd *cmd)
{
@@ -1109,38 +1122,81 @@ static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode,
iwl_trans_block_txq_ptrs(mvm->trans, false);
}
-static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int hw_queue)
+static int iwl_mvm_is_static_queue(struct iwl_mvm *mvm, int queue)
{
- struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
- unsigned long mq = mvm->hw_queue_to_mac80211[hw_queue];
-
- iwl_mvm_stop_mac_queues(mvm, mq);
+ return queue == mvm->aux_queue || queue == mvm->probe_queue ||
+ queue == mvm->p2p_dev_queue || queue == mvm->snif_queue;
}
-void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq)
+static void iwl_mvm_queue_state_change(struct iwl_op_mode *op_mode,
+ int hw_queue, bool start)
{
- int q;
+ struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+ struct ieee80211_sta *sta;
+ struct ieee80211_txq *txq;
+ struct iwl_mvm_txq *mvmtxq;
+ int i;
+ unsigned long tid_bitmap;
+ struct iwl_mvm_sta *mvmsta;
+ u8 sta_id;
+
+ sta_id = iwl_mvm_has_new_tx_api(mvm) ?
+ mvm->tvqm_info[hw_queue].sta_id :
+ mvm->queue_info[hw_queue].ra_sta_id;
- if (WARN_ON_ONCE(!mq))
+ if (WARN_ON_ONCE(sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)))
return;
- for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) {
- if (atomic_dec_return(&mvm->mac80211_queue_stop_count[q]) > 0) {
- IWL_DEBUG_TX_QUEUES(mvm,
- "mac80211 %d still stopped\n", q);
- continue;
- }
+ rcu_read_lock();
+
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+ if (IS_ERR_OR_NULL(sta))
+ goto out;
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+ if (iwl_mvm_is_static_queue(mvm, hw_queue)) {
+ if (!start)
+ ieee80211_stop_queues(mvm->hw);
+ else if (mvmsta->sta_state != IEEE80211_STA_NOTEXIST)
+ ieee80211_wake_queues(mvm->hw);
+
+ goto out;
+ }
+
+ if (iwl_mvm_has_new_tx_api(mvm)) {
+ int tid = mvm->tvqm_info[hw_queue].txq_tid;
+
+ tid_bitmap = BIT(tid);
+ } else {
+ tid_bitmap = mvm->queue_info[hw_queue].tid_bitmap;
+ }
+
+ for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
+ int tid = i;
+
+ if (tid == IWL_MAX_TID_COUNT)
+ tid = IEEE80211_NUM_TIDS;
- ieee80211_wake_queue(mvm->hw, q);
+ txq = sta->txq[tid];
+ mvmtxq = iwl_mvm_txq_from_mac80211(txq);
+ mvmtxq->stopped = !start;
+
+ if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST)
+ iwl_mvm_mac_itxq_xmit(mvm->hw, txq);
}
+
+out:
+ rcu_read_unlock();
}
-static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue)
+static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int hw_queue)
{
- struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
- unsigned long mq = mvm->hw_queue_to_mac80211[hw_queue];
+ iwl_mvm_queue_state_change(op_mode, hw_queue, false);
+}
- iwl_mvm_start_mac_queues(mvm, mq);
+static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue)
+{
+ iwl_mvm_queue_state_change(op_mode, hw_queue, true);
}
static void iwl_mvm_set_rfkill_state(struct iwl_mvm *mvm)
@@ -1261,12 +1317,29 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
reprobe->dev = mvm->trans->dev;
INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
schedule_work(&reprobe->work);
+ } else if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
+ &mvm->status)) {
+ IWL_ERR(mvm, "HW restart already requested, but not started\n");
} else if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR &&
mvm->hw_registered &&
!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) {
/* don't let the transport/FW power down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
+ if (mvm->fw->ucode_capa.error_log_size) {
+ u32 src_size = mvm->fw->ucode_capa.error_log_size;
+ u32 src_addr = mvm->fw->ucode_capa.error_log_addr;
+ u8 *recover_buf = kzalloc(src_size, GFP_ATOMIC);
+
+ if (recover_buf) {
+ mvm->error_recovery_buf = recover_buf;
+ iwl_trans_read_mem_bytes(mvm->trans,
+ src_addr,
+ recover_buf,
+ src_size);
+ }
+ }
+
if (fw_error && mvm->fw_restart > 0)
mvm->fw_restart--;
set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
index 7f5434b34d0d..86e40bae57e3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
@@ -109,6 +109,7 @@ u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef)
return PHY_VHT_CTRL_POS_4_ABOVE;
default:
WARN(1, "Invalid channel definition");
+ /* fall through */
case 0:
/*
* The FW is expected to check the control channel position only
@@ -143,14 +144,11 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
u8 chains_static, u8 chains_dynamic)
{
u8 active_cnt, idle_cnt;
+ struct iwl_phy_context_cmd_tail *tail =
+ iwl_mvm_chan_info_cmd_tail(mvm, &cmd->ci);
/* Set the channel info data */
- cmd->ci.band = (chandef->chan->band == NL80211_BAND_2GHZ ?
- PHY_BAND_24 : PHY_BAND_5);
-
- cmd->ci.channel = chandef->chan->hw_value;
- cmd->ci.width = iwl_mvm_get_channel_width(chandef);
- cmd->ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef);
+ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef);
/* Set rx the chains */
idle_cnt = chains_static;
@@ -168,17 +166,17 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
active_cnt = 2;
}
- cmd->rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) <<
+ tail->rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) <<
PHY_RX_CHAIN_VALID_POS);
- cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
- cmd->rxchain_info |= cpu_to_le32(active_cnt <<
+ tail->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
+ tail->rxchain_info |= cpu_to_le32(active_cnt <<
PHY_RX_CHAIN_MIMO_CNT_POS);
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (unlikely(mvm->dbgfs_rx_phyinfo))
- cmd->rxchain_info = cpu_to_le32(mvm->dbgfs_rx_phyinfo);
+ tail->rxchain_info = cpu_to_le32(mvm->dbgfs_rx_phyinfo);
#endif
- cmd->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
+ tail->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
}
/*
@@ -195,6 +193,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm,
{
struct iwl_phy_context_cmd cmd;
int ret;
+ u16 len = sizeof(cmd) - iwl_mvm_chan_info_padding(mvm);
/* Set the command header fields */
iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action, apply_time);
@@ -203,9 +202,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm,
iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef,
chains_static, chains_dynamic);
- ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0,
- sizeof(struct iwl_phy_context_cmd),
- &cmd);
+ ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, 0, len, &cmd);
if (ret)
IWL_ERR(mvm, "PHY ctxt cmd error. ret=%d\n", ret);
return ret;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
index 5a0a28fd762d..36f5fa1ee793 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
@@ -8,6 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -30,6 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright (C) 2018 - 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -79,6 +81,8 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
struct iwl_beacon_filter_cmd *cmd,
u32 flags)
{
+ u16 len;
+
IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n",
le32_to_cpu(cmd->ba_enable_beacon_abort));
IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n",
@@ -101,9 +105,23 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm,
le32_to_cpu(cmd->bf_temp_fast_filter));
IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n",
le32_to_cpu(cmd->bf_temp_slow_filter));
+ IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_low is: %d, %d\n",
+ le32_to_cpu(cmd->bf_threshold_absolute_low[0]),
+ le32_to_cpu(cmd->bf_threshold_absolute_low[1]));
+
+ IWL_DEBUG_POWER(mvm, "bf_threshold_absolute_high is: %d, %d\n",
+ le32_to_cpu(cmd->bf_threshold_absolute_high[0]),
+ le32_to_cpu(cmd->bf_threshold_absolute_high[1]));
+
+ if (fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_BEACON_FILTER_V4))
+ len = sizeof(struct iwl_beacon_filter_cmd);
+ else
+ len = offsetof(struct iwl_beacon_filter_cmd,
+ bf_threshold_absolute_low);
return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags,
- sizeof(struct iwl_beacon_filter_cmd), cmd);
+ len, cmd);
}
static
@@ -526,6 +544,9 @@ int iwl_mvm_power_update_device(struct iwl_mvm *mvm)
cmd.flags &=
cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK);
#endif
+ if (mvm->ext_clock_valid)
+ cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK);
+
IWL_DEBUG_POWER(mvm,
"Sending device power command with flags = 0x%X\n",
cmd.flags);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index dabbc04853ac..a28283ff7295 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -149,14 +149,9 @@ static u16 rs_fw_set_config_flags(struct iwl_mvm *mvm,
if (he_cap && he_cap->has_he &&
(he_cap->he_cap_elem.phy_cap_info[3] &
- IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK)) {
+ IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK))
flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK;
- if (he_cap->he_cap_elem.phy_cap_info[3] &
- IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2)
- flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK;
- }
-
return flags;
}
@@ -320,12 +315,26 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
if (flags & IWL_TLC_NOTIF_FLAG_AMSDU) {
u16 size = le32_to_cpu(notif->amsdu_size);
+ int i;
if (WARN_ON(sta->max_amsdu_len < size))
goto out;
mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled);
mvmsta->max_amsdu_len = size;
+ sta->max_rc_amsdu_len = mvmsta->max_amsdu_len;
+
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ if (mvmsta->amsdu_enabled & BIT(i))
+ sta->max_tid_amsdu_len[i] =
+ iwl_mvm_max_amsdu_size(mvm, sta, i);
+ else
+ /*
+ * Not so elegant, but this will effectively
+ * prevent AMSDU on this TID
+ */
+ sta->max_tid_amsdu_len[i] = 1;
+ }
IWL_DEBUG_RATE(mvm,
"AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n",
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 089972280daa..e231a44d2423 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -3,7 +3,7 @@
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
@@ -1643,8 +1643,26 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
{
+ struct ieee80211_sta_vht_cap *sta_vht_cap = &sta->vht_cap;
+ struct ieee80211_vht_cap vht_cap = {
+ .vht_cap_info = cpu_to_le32(sta_vht_cap->cap),
+ .supp_mcs = sta_vht_cap->vht_mcs,
+ };
+
switch (sta->bandwidth) {
case IEEE80211_STA_RX_BW_160:
+ /*
+ * Don't use 160 MHz if VHT extended NSS support
+ * says we cannot use 2 streams, we don't want to
+ * deal with this.
+ * We only check MCS 0 - they will support that if
+ * we got here at all and we don't care which MCS,
+ * we want to determine a more global state.
+ */
+ if (ieee80211_get_vht_max_nss(&vht_cap,
+ IEEE80211_VHT_CHANWIDTH_160MHZ,
+ 0, true) < sta->rx_nss)
+ return RATE_MCS_CHAN_WIDTH_80;
return RATE_MCS_CHAN_WIDTH_160;
case IEEE80211_STA_RX_BW_80:
return RATE_MCS_CHAN_WIDTH_80;
@@ -1744,6 +1762,7 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
enum rs_action scale_action)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ int i;
/*
* In case TLC offload is not active amsdu_enabled is either 0xFFFF
@@ -1756,7 +1775,25 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
else
mvmsta->amsdu_enabled = 0xFFFF;
- mvmsta->max_amsdu_len = sta->max_amsdu_len;
+ if (mvmsta->vif->bss_conf.he_support &&
+ !iwlwifi_mod_params.disable_11ax)
+ mvmsta->max_amsdu_len = sta->max_amsdu_len;
+ else
+ mvmsta->max_amsdu_len = min_t(int, sta->max_amsdu_len, 8500);
+
+ sta->max_rc_amsdu_len = mvmsta->max_amsdu_len;
+
+ for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
+ if (mvmsta->amsdu_enabled)
+ sta->max_tid_amsdu_len[i] =
+ iwl_mvm_max_amsdu_size(mvm, sta, i);
+ else
+ /*
+ * Not so elegant, but this will effectively
+ * prevent AMSDU on this TID
+ */
+ sta->max_tid_amsdu_len[i] = 1;
+ }
}
/*
@@ -1777,7 +1814,7 @@ static bool rs_tweak_rate_tbl(struct iwl_mvm *mvm,
struct iwl_scale_tbl_info *tbl,
enum rs_action scale_action)
{
- if (sta->bandwidth != IEEE80211_STA_RX_BW_80)
+ if (rs_bw_from_sta_bw(sta) != RATE_MCS_CHAN_WIDTH_80)
return false;
if (!is_vht_siso(&tbl->rate))
@@ -3332,12 +3369,12 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
/* Building the rate table is non trivial. When we're in MIMO2/VHT/80Mhz/SGI
* column the rate table should look like this:
*
- * rate[0] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
- * rate[1] 0x400D019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
- * rate[2] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
- * rate[3] 0x400D018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
- * rate[4] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
- * rate[5] 0x400D017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
+ * rate[0] 0x400F019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
+ * rate[1] 0x400F019 VHT | ANT: AB BW: 80Mhz MCS: 9 NSS: 2 SGI
+ * rate[2] 0x400F018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
+ * rate[3] 0x400F018 VHT | ANT: AB BW: 80Mhz MCS: 8 NSS: 2 SGI
+ * rate[4] 0x400F017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
+ * rate[5] 0x400F017 VHT | ANT: AB BW: 80Mhz MCS: 7 NSS: 2 SGI
* rate[6] 0x4005007 VHT | ANT: A BW: 80Mhz MCS: 7 NSS: 1 NGI
* rate[7] 0x4009006 VHT | ANT: B BW: 80Mhz MCS: 6 NSS: 1 NGI
* rate[8] 0x4005005 VHT | ANT: A BW: 80Mhz MCS: 5 NSS: 1 NGI
@@ -4108,6 +4145,7 @@ static const struct rate_control_ops rs_mvm_ops_drv = {
.add_sta_debugfs = rs_drv_add_sta_debugfs,
.remove_sta_debugfs = rs_remove_sta_debugfs,
#endif
+ .capa = RATE_CTRL_CAPA_VHT_EXT_NSS_BW,
};
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index 6653a238f32e..fbd3014e8b82 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -222,7 +222,7 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK))
return 0;
*crypt_len = IEEE80211_TKIP_IV_LEN;
- /* fall through if TTAK OK */
+ /* fall through */
case RX_MPDU_RES_STATUS_SEC_WEP_ENC:
if (!(rx_pkt_status & RX_MPDU_RES_STATUS_ICV_OK))
@@ -599,8 +599,8 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
* data copied into the "data" struct, but rather the data from
* the notification directly.
*/
- if (iwl_mvm_is_cdb_supported(mvm)) {
- struct mvm_statistics_general_cdb *general =
+ if (iwl_mvm_has_new_rx_stats_api(mvm)) {
+ struct mvm_statistics_general *general =
data->general;
mvmvif->beacon_stats.num_beacons =
@@ -723,7 +723,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
else
expected_size = sizeof(struct iwl_notif_statistics_v10);
} else {
- expected_size = sizeof(struct iwl_notif_statistics_cdb);
+ expected_size = sizeof(struct iwl_notif_statistics);
}
if (WARN_ONCE(iwl_rx_packet_payload_len(pkt) != expected_size,
@@ -753,7 +753,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
flags = stats->flag;
} else {
- struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data;
+ struct iwl_notif_statistics *stats = (void *)&pkt->data;
data.mac_id = stats->rx.general.mac_id;
data.beacon_filter_average_energy =
@@ -792,7 +792,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
bytes = (void *)&v11->load_stats.byte_count;
air_time = (void *)&v11->load_stats.air_time;
} else {
- struct iwl_notif_statistics_cdb *stats = (void *)&pkt->data;
+ struct iwl_notif_statistics *stats = (void *)&pkt->data;
energy = (void *)&stats->load_stats.avg_energy;
bytes = (void *)&stats->load_stats.byte_count;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 7bd8676508f5..1e03acf30762 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -66,11 +66,37 @@
#include "mvm.h"
#include "fw-api.h"
+static void *iwl_mvm_skb_get_hdr(struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+ u8 *data = skb->data;
+
+ /* Alignment concerns */
+ BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) % 4);
+ BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) % 4);
+ BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) % 4);
+ BUILD_BUG_ON(sizeof(struct ieee80211_vendor_radiotap) % 4);
+
+ if (rx_status->flag & RX_FLAG_RADIOTAP_HE)
+ data += sizeof(struct ieee80211_radiotap_he);
+ if (rx_status->flag & RX_FLAG_RADIOTAP_HE_MU)
+ data += sizeof(struct ieee80211_radiotap_he_mu);
+ if (rx_status->flag & RX_FLAG_RADIOTAP_LSIG)
+ data += sizeof(struct ieee80211_radiotap_lsig);
+ if (rx_status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
+ struct ieee80211_vendor_radiotap *radiotap = (void *)data;
+
+ data += sizeof(*radiotap) + radiotap->len + radiotap->pad;
+ }
+
+ return data;
+}
+
static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
int queue, struct ieee80211_sta *sta)
{
struct iwl_mvm_sta *mvmsta;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb);
struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);
struct iwl_mvm_key_pn *ptk_pn;
int res;
@@ -192,27 +218,50 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr,
}
}
+static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm,
+ struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+ struct ieee80211_vendor_radiotap *radiotap;
+ const int size = sizeof(*radiotap) + sizeof(__le16);
+
+ if (!mvm->cur_aid)
+ return;
+
+ /* ensure alignment */
+ BUILD_BUG_ON((size + 2) % 4);
+
+ radiotap = skb_put(skb, size + 2);
+ radiotap->align = 1;
+ /* Intel OUI */
+ radiotap->oui[0] = 0xf6;
+ radiotap->oui[1] = 0x54;
+ radiotap->oui[2] = 0x25;
+ /* radiotap sniffer config sub-namespace */
+ radiotap->subns = 1;
+ radiotap->present = 0x1;
+ radiotap->len = size - sizeof(*radiotap);
+ radiotap->pad = 2;
+
+ /* fill the data now */
+ memcpy(radiotap->data, &mvm->cur_aid, sizeof(mvm->cur_aid));
+ /* and clear the padding */
+ memset(radiotap->data + sizeof(__le16), 0, radiotap->pad);
+
+ rx_status->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA;
+}
+
/* iwl_mvm_pass_packet_to_mac80211 - passes the packet for mac80211 */
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)
+ struct ieee80211_sta *sta,
+ bool csi)
{
- struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
-
- if (!(rx_status->flag & RX_FLAG_NO_PSDU) &&
- iwl_mvm_check_pn(mvm, skb, queue, sta)) {
+ if (iwl_mvm_check_pn(mvm, skb, queue, sta))
kfree_skb(skb);
- } else {
- unsigned int radiotap_len = 0;
-
- if (rx_status->flag & RX_FLAG_RADIOTAP_HE)
- radiotap_len += sizeof(struct ieee80211_radiotap_he);
- if (rx_status->flag & RX_FLAG_RADIOTAP_HE_MU)
- radiotap_len += sizeof(struct ieee80211_radiotap_he_mu);
- __skb_push(skb, radiotap_len);
+ else
ieee80211_rx_napi(mvm->hw, sta, skb, napi);
- }
}
static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
@@ -289,7 +338,7 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
stats->flag |= RX_FLAG_MMIC_ERROR;
*crypt_len = IEEE80211_TKIP_IV_LEN;
- /* fall through if TTAK OK */
+ /* fall through */
case IWL_RX_MPDU_STATUS_SEC_WEP:
if (!(status & IWL_RX_MPDU_STATUS_ICV_OK))
return -1;
@@ -473,7 +522,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);
+ sta, false);
reorder_buf->num_stored--;
}
}
@@ -642,7 +691,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
struct sk_buff *skb,
struct iwl_rx_mpdu_desc *desc)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb);
struct iwl_mvm_sta *mvm_sta;
struct iwl_mvm_baid_data *baid_data;
struct iwl_mvm_reorder_buffer *buffer;
@@ -666,6 +715,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
* This also covers the case of receiving a Block Ack Request
* outside a BA session; we'll pass it to mac80211 and that
* then sends a delBA action frame.
+ * This also covers pure monitor mode, in which case we won't
+ * have any BA sessions.
*/
if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
return false;
@@ -937,6 +988,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;
u8 offs = 0;
rx_status->bw = RATE_INFO_BW_HE_RU;
@@ -979,19 +1031,27 @@ iwl_mvm_decode_he_phy_ru_alloc(struct iwl_mvm_rx_phy_data *phy_data,
he->data2 |=
cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC);
- if (he_mu) {
#define CHECK_BW(bw) \
BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_ ## bw ## MHZ != \
+ RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS); \
+ BUILD_BUG_ON(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_ ## bw ## MHZ != \
RATE_MCS_CHAN_WIDTH_##bw >> RATE_MCS_CHAN_WIDTH_POS)
- CHECK_BW(20);
- CHECK_BW(40);
- CHECK_BW(80);
- CHECK_BW(160);
+ CHECK_BW(20);
+ CHECK_BW(40);
+ CHECK_BW(80);
+ CHECK_BW(160);
+
+ if (he_mu)
he_mu->flags2 |=
le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
rate_n_flags),
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW);
- }
+ else if (he_type == RATE_MCS_HE_TYPE_TRIG)
+ he->data6 |=
+ cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW_KNOWN) |
+ le16_encode_bits(FIELD_GET(RATE_MCS_CHAN_WIDTH_MSK,
+ rate_n_flags),
+ IEEE80211_RADIOTAP_HE_DATA6_TB_PPDU_BW);
}
static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
@@ -1014,16 +1074,16 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN |
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN |
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN);
- he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d0,
+ he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2,
IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE1),
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1);
- he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d0,
+ he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2,
IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE2),
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2);
- he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d0,
+ he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2,
IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE3),
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3);
- he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d0,
+ he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d2,
IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE4),
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4);
/* fall through */
@@ -1033,7 +1093,6 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
case IWL_RX_PHY_INFO_TYPE_HE_TB:
/* HE common */
he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN |
- IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN |
IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN |
IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN);
he->data2 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN |
@@ -1053,9 +1112,6 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
he->data3 |= le16_encode_bits(le32_get_bits(phy_data->d0,
IWL_RX_PHY_DATA0_HE_LDPC_EXT_SYM),
IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG);
- he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d0,
- IWL_RX_PHY_DATA0_HE_SPATIAL_REUSE_MASK),
- IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE);
he->data5 |= le16_encode_bits(le32_get_bits(phy_data->d0,
IWL_RX_PHY_DATA0_HE_PRE_FEC_PAD_MASK),
IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD);
@@ -1076,6 +1132,20 @@ static void iwl_mvm_decode_he_phy_data(struct iwl_mvm *mvm,
switch (phy_data->info_type) {
case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT:
+ case IWL_RX_PHY_INFO_TYPE_HE_MU:
+ case IWL_RX_PHY_INFO_TYPE_HE_SU:
+ he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN);
+ he->data4 |= le16_encode_bits(le32_get_bits(phy_data->d0,
+ IWL_RX_PHY_DATA0_HE_SPATIAL_REUSE_MASK),
+ IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE);
+ break;
+ default:
+ /* nothing here */
+ break;
+ }
+
+ switch (phy_data->info_type) {
+ case IWL_RX_PHY_INFO_TYPE_HE_MU_EXT:
he_mu->flags1 |=
le16_encode_bits(le16_get_bits(phy_data->d4,
IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_DCM),
@@ -1142,30 +1212,22 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
.flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN |
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
};
- unsigned int radiotap_len = 0;
he = skb_put_data(skb, &known, sizeof(known));
- radiotap_len += sizeof(known);
rx_status->flag |= RX_FLAG_RADIOTAP_HE;
if (phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU ||
phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU_EXT) {
he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known));
- radiotap_len += sizeof(mu_known);
rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU;
}
- /* temporarily hide the radiotap data */
- __skb_pull(skb, radiotap_len);
-
- if (phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_SU) {
- /* report the AMPDU-EOF bit on single frames */
- if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
- rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
- rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
- if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF))
- rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
- }
+ /* report the AMPDU-EOF bit on single frames */
+ if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
+ rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
+ rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
+ if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF))
+ rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
}
if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD)
@@ -1178,9 +1240,7 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
/* toggle is switched whenever new aggregation starts */
- if (toggle_bit != mvm->ampdu_toggle &&
- (he_type == RATE_MCS_HE_TYPE_MU ||
- he_type == RATE_MCS_HE_TYPE_SU)) {
+ if (toggle_bit != mvm->ampdu_toggle) {
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN;
if (phy_data->d0 & cpu_to_le32(IWL_RX_PHY_DATA0_HE_DELIM_EOF))
rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT;
@@ -1314,6 +1374,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
.d4 = desc->phy_data4,
.info_type = IWL_RX_PHY_INFO_TYPE_NONE,
};
+ bool csi = false;
if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))
return;
@@ -1412,7 +1473,8 @@ 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 (phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)
+ if (rate_n_flags & RATE_MCS_CCK_MSK &&
+ phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)
rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) {
@@ -1441,14 +1503,23 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
- rx_status->ampdu_reference = mvm->ampdu_ref;
- /* toggle is switched whenever new aggregation starts */
+ /*
+ * Toggle is switched whenever new aggregation starts. Make
+ * sure ampdu_reference is never 0 so we can later use it to
+ * see if the frame was really part of an A-MPDU or not.
+ */
if (toggle_bit != mvm->ampdu_toggle) {
mvm->ampdu_ref++;
+ if (mvm->ampdu_ref == 0)
+ mvm->ampdu_ref++;
mvm->ampdu_toggle = toggle_bit;
}
+ rx_status->ampdu_reference = mvm->ampdu_ref;
}
+ if (unlikely(mvm->monitor_on))
+ iwl_mvm_add_rtap_sniffer_config(mvm, skb);
+
rcu_read_lock();
if (desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) {
@@ -1602,7 +1673,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb);
if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc))
- iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta);
+ iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue,
+ sta, csi);
out:
rcu_read_unlock();
}
@@ -1705,15 +1777,24 @@ void iwl_mvm_rx_monitor_ndp(struct iwl_mvm *mvm, struct napi_struct *napi,
} else if (rate_n_flags & 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;
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)) {
+ /*
+ * take the nss from the rx_vec since the rate_n_flags has
+ * only 2 bits for the nss which gives a max of 4 ss but
+ * there may be up to 8 spatial streams
+ */
+ 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) {
+ 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,
rx_status->band);
@@ -1726,7 +1807,7 @@ void iwl_mvm_rx_monitor_ndp(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_status->rate_idx = rate;
}
- iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta);
+ ieee80211_rx_napi(mvm->hw, sta, skb, napi);
out:
rcu_read_unlock();
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 86d598d5b68f..78694bc38e76 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -8,7 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1580,6 +1580,11 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
* scheduled scan before starting a normal scan.
*/
+ /* FW supports only a single periodic scan */
+ if ((type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) &&
+ mvm->scan_status & (IWL_MVM_SCAN_SCHED | IWL_MVM_SCAN_NETDETECT))
+ return -EBUSY;
+
if (iwl_mvm_num_scans(mvm) < mvm->max_scans)
return 0;
@@ -1616,10 +1621,10 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK)
return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED,
true);
-
- /* fall through, something is wrong if no scan was
- * running but we ran out of scans.
+ /* Something is wrong if no scan was running but we
+ * ran out of scans.
*/
+ /* fall through */
default:
WARN_ON(1);
break;
@@ -1976,9 +1981,8 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type)
return ret;
}
- ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
-
- return ret;
+ return iwl_wait_notification(&mvm->notif_wait, &wait_scan_done,
+ 1 * HZ);
}
int iwl_mvm_scan_size(struct iwl_mvm *mvm)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
index d1d76bb9a750..9da0dae78510 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
@@ -7,6 +7,7 @@
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2018 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -28,6 +29,7 @@
*
* Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -64,7 +66,7 @@ struct iwl_mvm_active_iface_iterator_data {
struct ieee80211_vif *ignore_vif;
u8 sta_vif_ap_sta_id;
enum iwl_sf_state sta_vif_state;
- int num_active_macs;
+ u32 num_active_macs;
};
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index e28009832da0..498c315291cf 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -314,7 +314,6 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue,
struct iwl_mvm_sta *mvmsta;
u32 status;
u8 sta_id;
- int ret;
if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
return -EINVAL;
@@ -349,31 +348,21 @@ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue,
/* Notify FW of queue removal from the STA queues */
status = ADD_STA_SUCCESS;
- ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
- iwl_mvm_add_sta_cmd_size(mvm),
- &cmd, &status);
-
- return ret;
+ return iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+ iwl_mvm_add_sta_cmd_size(mvm),
+ &cmd, &status);
}
-static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue,
- int mac80211_queue, u8 tid, u8 flags)
+static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ int queue, u8 tid, u8 flags)
{
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
.action = SCD_CFG_DISABLE_QUEUE,
};
- bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE;
int ret;
- if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES))
- return -EINVAL;
-
if (iwl_mvm_has_new_tx_api(mvm)) {
- if (remove_mac_queue)
- mvm->hw_queue_to_mac80211[queue] &=
- ~BIT(mac80211_queue);
-
iwl_trans_txq_free(mvm->trans, queue);
return 0;
@@ -384,36 +373,15 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue,
mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
- /*
- * If there is another TID with the same AC - don't remove the MAC queue
- * from the mapping
- */
- if (tid < IWL_MAX_TID_COUNT) {
- unsigned long tid_bitmap =
- mvm->queue_info[queue].tid_bitmap;
- int ac = tid_to_mac80211_ac[tid];
- int i;
-
- for_each_set_bit(i, &tid_bitmap, IWL_MAX_TID_COUNT) {
- if (tid_to_mac80211_ac[i] == ac)
- remove_mac_queue = false;
- }
- }
-
- if (remove_mac_queue)
- mvm->hw_queue_to_mac80211[queue] &=
- ~BIT(mac80211_queue);
-
cmd.action = mvm->queue_info[queue].tid_bitmap ?
SCD_CFG_ENABLE_QUEUE : SCD_CFG_DISABLE_QUEUE;
if (cmd.action == SCD_CFG_DISABLE_QUEUE)
mvm->queue_info[queue].status = IWL_MVM_QUEUE_FREE;
IWL_DEBUG_TX_QUEUES(mvm,
- "Disabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n",
+ "Disabling TXQ #%d tids=0x%x\n",
queue,
- mvm->queue_info[queue].tid_bitmap,
- mvm->hw_queue_to_mac80211[queue]);
+ mvm->queue_info[queue].tid_bitmap);
/* If the queue is still enabled - nothing left to do in this func */
if (cmd.action == SCD_CFG_ENABLE_QUEUE)
@@ -423,15 +391,19 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue,
cmd.tid = mvm->queue_info[queue].txq_tid;
/* Make sure queue info is correct even though we overwrite it */
- WARN(mvm->queue_info[queue].tid_bitmap ||
- mvm->hw_queue_to_mac80211[queue],
- "TXQ #%d info out-of-sync - mac map=0x%x, tids=0x%x\n",
- queue, mvm->hw_queue_to_mac80211[queue],
- mvm->queue_info[queue].tid_bitmap);
+ WARN(mvm->queue_info[queue].tid_bitmap,
+ "TXQ #%d info out-of-sync - tids=0x%x\n",
+ queue, mvm->queue_info[queue].tid_bitmap);
/* If we are here - the queue is freed and we can zero out these vals */
mvm->queue_info[queue].tid_bitmap = 0;
- mvm->hw_queue_to_mac80211[queue] = 0;
+
+ if (sta) {
+ struct iwl_mvm_txq *mvmtxq =
+ iwl_mvm_txq_from_tid(sta, tid);
+
+ mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE;
+ }
/* Regardless if this is a reserved TXQ for a STA - mark it as false */
mvm->queue_info[queue].reserved = false;
@@ -517,9 +489,14 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue)
spin_lock_bh(&mvmsta->lock);
/* Unmap MAC queues and TIDs from this queue */
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
+ struct iwl_mvm_txq *mvmtxq =
+ iwl_mvm_txq_from_tid(sta, tid);
+
if (mvmsta->tid_data[tid].state == IWL_AGG_ON)
disable_agg_tids |= BIT(tid);
mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE;
+
+ mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE;
}
mvmsta->tfd_queue_msk &= ~BIT(queue); /* Don't use this queue anymore */
@@ -541,10 +518,11 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue)
}
static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue,
+ struct ieee80211_sta *old_sta,
u8 new_sta_id)
{
struct iwl_mvm_sta *mvmsta;
- u8 txq_curr_ac, sta_id, tid;
+ u8 sta_id, tid;
unsigned long disable_agg_tids = 0;
bool same_sta;
int ret;
@@ -554,7 +532,6 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue,
if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
return -EINVAL;
- txq_curr_ac = mvm->queue_info[queue].mac80211_ac;
sta_id = mvm->queue_info[queue].ra_sta_id;
tid = mvm->queue_info[queue].txq_tid;
@@ -570,9 +547,7 @@ static int iwl_mvm_free_inactive_queue(struct iwl_mvm *mvm, int queue,
iwl_mvm_invalidate_sta_queue(mvm, queue,
disable_agg_tids, false);
- ret = iwl_mvm_disable_txq(mvm, queue,
- mvmsta->vif->hw_queue[txq_curr_ac],
- tid, 0);
+ ret = iwl_mvm_disable_txq(mvm, old_sta, queue, tid, 0);
if (ret) {
IWL_ERR(mvm,
"Failed to free inactive queue %d (ret=%d)\n",
@@ -662,16 +637,15 @@ static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm,
* in such a case, otherwise - if no redirection required - it does nothing,
* unless the %force param is true.
*/
-static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
- int ac, int ssn, unsigned int wdg_timeout,
- bool force)
+static int iwl_mvm_redirect_queue(struct iwl_mvm *mvm, int queue, int tid,
+ int ac, int ssn, unsigned int wdg_timeout,
+ bool force, struct iwl_mvm_txq *txq)
{
struct iwl_scd_txq_cfg_cmd cmd = {
.scd_queue = queue,
.action = SCD_CFG_DISABLE_QUEUE,
};
bool shared_queue;
- unsigned long mq;
int ret;
if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
@@ -695,14 +669,14 @@ static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[mvm->queue_info[queue].mac80211_ac];
cmd.tid = mvm->queue_info[queue].txq_tid;
- mq = mvm->hw_queue_to_mac80211[queue];
shared_queue = hweight16(mvm->queue_info[queue].tid_bitmap) > 1;
IWL_DEBUG_TX_QUEUES(mvm, "Redirecting TXQ #%d to FIFO #%d\n",
queue, iwl_mvm_ac_to_tx_fifo[ac]);
- /* Stop MAC queues and wait for this queue to empty */
- iwl_mvm_stop_mac_queues(mvm, mq);
+ /* Stop the queue and wait for it to empty */
+ txq->stopped = true;
+
ret = iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(queue));
if (ret) {
IWL_ERR(mvm, "Error draining queue %d before reconfig\n",
@@ -743,8 +717,8 @@ static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
iwl_trans_txq_set_shared_mode(mvm->trans, queue, true);
out:
- /* Continue using the MAC queues */
- iwl_mvm_start_mac_queues(mvm, mq);
+ /* Continue using the queue */
+ txq->stopped = false;
return ret;
}
@@ -769,14 +743,15 @@ static int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id,
return -ENOSPC;
}
-static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue,
+static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm,
u8 sta_id, u8 tid, unsigned int timeout)
{
int queue, size = IWL_DEFAULT_QUEUE_SIZE;
if (tid == IWL_MAX_TID_COUNT) {
tid = IWL_MGMT_TID;
- size = IWL_MGMT_QUEUE_SIZE;
+ size = max_t(u32, IWL_MGMT_QUEUE_SIZE,
+ mvm->trans->cfg->min_txq_size);
}
queue = iwl_trans_txq_alloc(mvm->trans,
cpu_to_le16(TX_QUEUE_CFG_ENABLE_QUEUE),
@@ -792,10 +767,7 @@ static int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue,
IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d for sta %d tid %d\n",
queue, sta_id, tid);
- mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue);
- IWL_DEBUG_TX_QUEUES(mvm,
- "Enabling TXQ #%d (mac80211 map:0x%x)\n",
- queue, mvm->hw_queue_to_mac80211[queue]);
+ IWL_DEBUG_TX_QUEUES(mvm, "Enabling TXQ #%d\n", queue);
return queue;
}
@@ -805,9 +777,10 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm,
int tid)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_mvm_txq *mvmtxq =
+ iwl_mvm_txq_from_tid(sta, tid);
unsigned int wdg_timeout =
iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false);
- u8 mac_queue = mvmsta->vif->hw_queue[ac];
int queue = -1;
lockdep_assert_held(&mvm->mutex);
@@ -815,11 +788,14 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm,
IWL_DEBUG_TX_QUEUES(mvm,
"Allocating queue for sta %d on tid %d\n",
mvmsta->sta_id, tid);
- queue = iwl_mvm_tvqm_enable_txq(mvm, mac_queue, mvmsta->sta_id, tid,
- wdg_timeout);
+ queue = iwl_mvm_tvqm_enable_txq(mvm, mvmsta->sta_id, tid, wdg_timeout);
if (queue < 0)
return queue;
+ mvmtxq->txq_id = queue;
+ mvm->tvqm_info[queue].txq_tid = tid;
+ mvm->tvqm_info[queue].sta_id = mvmsta->sta_id;
+
IWL_DEBUG_TX_QUEUES(mvm, "Allocated queue is %d\n", queue);
spin_lock_bh(&mvmsta->lock);
@@ -829,8 +805,9 @@ static int iwl_mvm_sta_alloc_queue_tvqm(struct iwl_mvm *mvm,
return 0;
}
-static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue,
- int mac80211_queue, u8 sta_id, u8 tid)
+static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ int queue, u8 sta_id, u8 tid)
{
bool enable_queue = true;
@@ -845,14 +822,6 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue,
if (mvm->queue_info[queue].tid_bitmap)
enable_queue = false;
- if (mac80211_queue != IEEE80211_INVAL_HW_QUEUE) {
- WARN(mac80211_queue >=
- BITS_PER_BYTE * sizeof(mvm->hw_queue_to_mac80211[0]),
- "cannot track mac80211 queue %d (queue %d, sta %d, tid %d)\n",
- mac80211_queue, queue, sta_id, tid);
- mvm->hw_queue_to_mac80211[queue] |= BIT(mac80211_queue);
- }
-
mvm->queue_info[queue].tid_bitmap |= BIT(tid);
mvm->queue_info[queue].ra_sta_id = sta_id;
@@ -866,16 +835,22 @@ static bool iwl_mvm_update_txq_mapping(struct iwl_mvm *mvm, int queue,
mvm->queue_info[queue].txq_tid = tid;
}
+ if (sta) {
+ struct iwl_mvm_txq *mvmtxq =
+ iwl_mvm_txq_from_tid(sta, tid);
+
+ mvmtxq->txq_id = queue;
+ }
+
IWL_DEBUG_TX_QUEUES(mvm,
- "Enabling TXQ #%d tids=0x%x (mac80211 map:0x%x)\n",
- queue, mvm->queue_info[queue].tid_bitmap,
- mvm->hw_queue_to_mac80211[queue]);
+ "Enabling TXQ #%d tids=0x%x\n",
+ queue, mvm->queue_info[queue].tid_bitmap);
return enable_queue;
}
-static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue,
- int mac80211_queue, u16 ssn,
+static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ int queue, u16 ssn,
const struct iwl_trans_txq_scd_cfg *cfg,
unsigned int wdg_timeout)
{
@@ -895,8 +870,7 @@ static bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue,
return false;
/* Send the enabling command if we need to */
- if (!iwl_mvm_update_txq_mapping(mvm, queue, mac80211_queue,
- cfg->sta_id, cfg->tid))
+ if (!iwl_mvm_update_txq_mapping(mvm, sta, queue, cfg->sta_id, cfg->tid))
return false;
inc_ssn = iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn,
@@ -989,9 +963,10 @@ static void iwl_mvm_unshare_queue(struct iwl_mvm *mvm, int queue)
ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number);
- ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid,
- tid_to_mac80211_ac[tid], ssn,
- wdg_timeout, true);
+ ret = iwl_mvm_redirect_queue(mvm, queue, tid,
+ tid_to_mac80211_ac[tid], ssn,
+ wdg_timeout, true,
+ iwl_mvm_txq_from_tid(sta, tid));
if (ret) {
IWL_ERR(mvm, "Failed to redirect TXQ %d\n", queue);
return;
@@ -1068,11 +1043,9 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,
* Remove the ones that did.
*/
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
- int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]];
u16 tid_bitmap;
mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE;
- mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac_queue);
mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
tid_bitmap = mvm->queue_info[queue].tid_bitmap;
@@ -1105,10 +1078,6 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,
* sure all TIDs have existing corresponding mac queues enabled
*/
tid_bitmap = mvm->queue_info[queue].tid_bitmap;
- for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
- mvm->hw_queue_to_mac80211[queue] |=
- BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]);
- }
/* If the queue is marked as shared - "unshare" it */
if (hweight16(mvm->queue_info[queue].tid_bitmap) == 1 &&
@@ -1136,6 +1105,7 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta)
unsigned long unshare_queues = 0;
unsigned long changetid_queues = 0;
int i, ret, free_queue = -ENOSPC;
+ struct ieee80211_sta *queue_owner = NULL;
lockdep_assert_held(&mvm->mutex);
@@ -1201,13 +1171,14 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta)
inactive_tid_bitmap,
&unshare_queues,
&changetid_queues);
- if (ret >= 0 && free_queue < 0)
+ if (ret >= 0 && free_queue < 0) {
+ queue_owner = sta;
free_queue = ret;
+ }
/* only unlock sta lock - we still need the queue info lock */
spin_unlock_bh(&mvmsta->lock);
}
- rcu_read_unlock();
/* Reconfigure queues requiring reconfiguation */
for_each_set_bit(i, &unshare_queues, IWL_MAX_HW_QUEUES)
@@ -1216,18 +1187,21 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta)
iwl_mvm_change_queue_tid(mvm, i);
if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) {
- ret = iwl_mvm_free_inactive_queue(mvm, free_queue,
+ ret = iwl_mvm_free_inactive_queue(mvm, free_queue, queue_owner,
alloc_for_sta);
- if (ret)
+ if (ret) {
+ rcu_read_unlock();
return ret;
+ }
}
+ rcu_read_unlock();
+
return free_queue;
}
static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta, u8 ac, int tid,
- struct ieee80211_hdr *hdr)
+ struct ieee80211_sta *sta, u8 ac, int tid)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_trans_txq_scd_cfg cfg = {
@@ -1238,7 +1212,6 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
};
unsigned int wdg_timeout =
iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false);
- u8 mac_queue = mvmsta->vif->hw_queue[ac];
int queue = -1;
unsigned long disable_agg_tids = 0;
enum iwl_mvm_agg_state queue_state;
@@ -1257,12 +1230,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
ssn = IEEE80211_SEQ_TO_SN(mvmsta->tid_data[tid].seq_number);
spin_unlock_bh(&mvmsta->lock);
- /*
- * Non-QoS, QoS NDP and MGMT frames should go to a MGMT queue, if one
- * exists
- */
- if (!ieee80211_is_data_qos(hdr->frame_control) ||
- ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+ if (tid == IWL_MAX_TID_COUNT) {
queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
IWL_MVM_DQA_MIN_MGMT_QUEUE,
IWL_MVM_DQA_MAX_MGMT_QUEUE);
@@ -1341,8 +1309,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
}
}
- inc_ssn = iwl_mvm_enable_txq(mvm, queue, mac_queue,
- ssn, &cfg, wdg_timeout);
+ inc_ssn = iwl_mvm_enable_txq(mvm, sta, queue, ssn, &cfg, wdg_timeout);
/*
* Mark queue as shared in transport if shared
@@ -1384,8 +1351,9 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
}
} else {
/* Redirect queue, if needed */
- ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, ac, ssn,
- wdg_timeout, false);
+ ret = iwl_mvm_redirect_queue(mvm, queue, tid, ac, ssn,
+ wdg_timeout, false,
+ iwl_mvm_txq_from_tid(sta, tid));
if (ret)
goto out_err;
}
@@ -1393,7 +1361,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
return 0;
out_err:
- iwl_mvm_disable_txq(mvm, queue, mac_queue, tid, 0);
+ iwl_mvm_disable_txq(mvm, sta, queue, tid, 0);
return ret;
}
@@ -1406,87 +1374,32 @@ static inline u8 iwl_mvm_tid_to_ac_queue(int tid)
return tid_to_mac80211_ac[tid];
}
-static void iwl_mvm_tx_deferred_stream(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta, int tid)
-{
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
- struct sk_buff *skb;
- struct ieee80211_hdr *hdr;
- struct sk_buff_head deferred_tx;
- u8 mac_queue;
- bool no_queue = false; /* Marks if there is a problem with the queue */
- u8 ac;
-
- lockdep_assert_held(&mvm->mutex);
-
- skb = skb_peek(&tid_data->deferred_tx_frames);
- if (!skb)
- return;
- hdr = (void *)skb->data;
-
- ac = iwl_mvm_tid_to_ac_queue(tid);
- mac_queue = IEEE80211_SKB_CB(skb)->hw_queue;
-
- if (tid_data->txq_id == IWL_MVM_INVALID_QUEUE &&
- iwl_mvm_sta_alloc_queue(mvm, sta, ac, tid, hdr)) {
- IWL_ERR(mvm,
- "Can't alloc TXQ for sta %d tid %d - dropping frame\n",
- mvmsta->sta_id, tid);
-
- /*
- * Mark queue as problematic so later the deferred traffic is
- * freed, as we can do nothing with it
- */
- no_queue = true;
- }
-
- __skb_queue_head_init(&deferred_tx);
-
- /* Disable bottom-halves when entering TX path */
- local_bh_disable();
- spin_lock(&mvmsta->lock);
- skb_queue_splice_init(&tid_data->deferred_tx_frames, &deferred_tx);
- mvmsta->deferred_traffic_tid_map &= ~BIT(tid);
- spin_unlock(&mvmsta->lock);
-
- while ((skb = __skb_dequeue(&deferred_tx)))
- if (no_queue || iwl_mvm_tx_skb(mvm, skb, sta))
- ieee80211_free_txskb(mvm->hw, skb);
- local_bh_enable();
-
- /* Wake queue */
- iwl_mvm_start_mac_queues(mvm, BIT(mac_queue));
-}
-
void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)
{
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm,
add_stream_wk);
- struct ieee80211_sta *sta;
- struct iwl_mvm_sta *mvmsta;
- unsigned long deferred_tid_traffic;
- int sta_id, tid;
mutex_lock(&mvm->mutex);
iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA);
- /* Go over all stations with deferred traffic */
- for_each_set_bit(sta_id, mvm->sta_deferred_frames,
- IWL_MVM_STATION_COUNT) {
- clear_bit(sta_id, mvm->sta_deferred_frames);
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
- lockdep_is_held(&mvm->mutex));
- if (IS_ERR_OR_NULL(sta))
- continue;
+ while (!list_empty(&mvm->add_stream_txqs)) {
+ struct iwl_mvm_txq *mvmtxq;
+ struct ieee80211_txq *txq;
+ u8 tid;
- mvmsta = iwl_mvm_sta_from_mac80211(sta);
- deferred_tid_traffic = mvmsta->deferred_traffic_tid_map;
+ mvmtxq = list_first_entry(&mvm->add_stream_txqs,
+ struct iwl_mvm_txq, list);
+
+ txq = container_of((void *)mvmtxq, struct ieee80211_txq,
+ drv_priv);
+ tid = txq->tid;
+ if (tid == IEEE80211_NUM_TIDS)
+ tid = IWL_MAX_TID_COUNT;
- for_each_set_bit(tid, &deferred_tid_traffic,
- IWL_MAX_TID_COUNT + 1)
- iwl_mvm_tx_deferred_stream(mvm, sta, tid);
+ iwl_mvm_sta_alloc_queue(mvm, txq->sta, txq->ac, tid);
+ list_del_init(&mvmtxq->list);
+ iwl_mvm_mac_itxq_xmit(mvm->hw, txq);
}
mutex_unlock(&mvm->mutex);
@@ -1542,10 +1455,11 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
* Note that re-enabling aggregations isn't done in this function.
*/
static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,
- struct iwl_mvm_sta *mvm_sta)
+ struct ieee80211_sta *sta)
{
- unsigned int wdg_timeout =
- iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif, false, false);
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+ unsigned int wdg =
+ iwl_mvm_get_wd_timeout(mvm, mvm_sta->vif, false, false);
int i;
struct iwl_trans_txq_scd_cfg cfg = {
.sta_id = mvm_sta->sta_id,
@@ -1561,23 +1475,18 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,
struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[i];
int txq_id = tid_data->txq_id;
int ac;
- u8 mac_queue;
if (txq_id == IWL_MVM_INVALID_QUEUE)
continue;
- skb_queue_head_init(&tid_data->deferred_tx_frames);
-
ac = tid_to_mac80211_ac[i];
- mac_queue = mvm_sta->vif->hw_queue[ac];
if (iwl_mvm_has_new_tx_api(mvm)) {
IWL_DEBUG_TX_QUEUES(mvm,
"Re-mapping sta %d tid %d\n",
mvm_sta->sta_id, i);
- txq_id = iwl_mvm_tvqm_enable_txq(mvm, mac_queue,
- mvm_sta->sta_id,
- i, wdg_timeout);
+ txq_id = iwl_mvm_tvqm_enable_txq(mvm, mvm_sta->sta_id,
+ i, wdg);
tid_data->txq_id = txq_id;
/*
@@ -1600,8 +1509,7 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,
"Re-mapping sta %d tid %d to queue %d\n",
mvm_sta->sta_id, i, txq_id);
- iwl_mvm_enable_txq(mvm, txq_id, mac_queue, seq, &cfg,
- wdg_timeout);
+ iwl_mvm_enable_txq(mvm, sta, txq_id, seq, &cfg, wdg);
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY;
}
}
@@ -1691,7 +1599,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
if (ret)
goto err;
- iwl_mvm_realloc_queues_after_restart(mvm, mvm_sta);
+ iwl_mvm_realloc_queues_after_restart(mvm, sta);
sta_update = true;
sta_flags = iwl_mvm_has_new_tx_api(mvm) ? 0 : STA_MODIFY_QUEUES;
goto update_fw;
@@ -1724,9 +1632,17 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
* frames until the queue is allocated
*/
mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE;
- skb_queue_head_init(&mvm_sta->tid_data[i].deferred_tx_frames);
}
- mvm_sta->deferred_traffic_tid_map = 0;
+
+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
+ struct iwl_mvm_txq *mvmtxq =
+ iwl_mvm_txq_from_mac80211(sta->txq[i]);
+
+ mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE;
+ INIT_LIST_HEAD(&mvmtxq->list);
+ atomic_set(&mvmtxq->tx_request, 0);
+ }
+
mvm_sta->agg_tids = 0;
if (iwl_mvm_has_new_rx_api(mvm) &&
@@ -1861,9 +1777,9 @@ static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id)
static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- struct iwl_mvm_sta *mvm_sta)
+ struct ieee80211_sta *sta)
{
- int ac;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
int i;
lockdep_assert_held(&mvm->mutex);
@@ -1872,11 +1788,17 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm,
if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE)
continue;
- ac = iwl_mvm_tid_to_ac_queue(i);
- iwl_mvm_disable_txq(mvm, mvm_sta->tid_data[i].txq_id,
- vif->hw_queue[ac], i, 0);
+ iwl_mvm_disable_txq(mvm, sta, mvm_sta->tid_data[i].txq_id, i,
+ 0);
mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE;
}
+
+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
+ struct iwl_mvm_txq *mvmtxq =
+ iwl_mvm_txq_from_mac80211(sta->txq[i]);
+
+ mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE;
+ }
}
int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm,
@@ -1938,7 +1860,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
ret = iwl_mvm_drain_sta(mvm, mvm_sta, false);
- iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta);
+ iwl_mvm_disable_sta_queues(mvm, vif, sta);
/* If there is a TXQ still marked as reserved - free it */
if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) {
@@ -2044,7 +1966,7 @@ static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 *queue,
if (iwl_mvm_has_new_tx_api(mvm)) {
int tvqm_queue =
- iwl_mvm_tvqm_enable_txq(mvm, *queue, sta_id,
+ iwl_mvm_tvqm_enable_txq(mvm, sta_id,
IWL_MAX_TID_COUNT,
wdg_timeout);
*queue = tvqm_queue;
@@ -2057,7 +1979,7 @@ static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 *queue,
.frame_limit = IWL_FRAME_LIMIT,
};
- iwl_mvm_enable_txq(mvm, *queue, *queue, 0, &cfg, wdg_timeout);
+ iwl_mvm_enable_txq(mvm, NULL, *queue, 0, &cfg, wdg_timeout);
}
}
@@ -2135,8 +2057,7 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
lockdep_assert_held(&mvm->mutex);
- iwl_mvm_disable_txq(mvm, mvm->snif_queue, mvm->snif_queue,
- IWL_MAX_TID_COUNT, 0);
+ iwl_mvm_disable_txq(mvm, NULL, mvm->snif_queue, IWL_MAX_TID_COUNT, 0);
ret = iwl_mvm_rm_sta_common(mvm, mvm->snif_sta.sta_id);
if (ret)
IWL_WARN(mvm, "Failed sending remove station\n");
@@ -2195,8 +2116,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
bsta->tfd_queue_msk |= BIT(queue);
- iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[0], 0,
- &cfg, wdg_timeout);
+ iwl_mvm_enable_txq(mvm, NULL, queue, 0, &cfg, wdg_timeout);
}
if (vif->type == NL80211_IFTYPE_ADHOC)
@@ -2215,8 +2135,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
* to firmware so enable queue here - after the station was added
*/
if (iwl_mvm_has_new_tx_api(mvm)) {
- queue = iwl_mvm_tvqm_enable_txq(mvm, vif->hw_queue[0],
- bsta->sta_id,
+ queue = iwl_mvm_tvqm_enable_txq(mvm, bsta->sta_id,
IWL_MAX_TID_COUNT,
wdg_timeout);
@@ -2254,7 +2173,7 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm,
return;
}
- iwl_mvm_disable_txq(mvm, queue, vif->hw_queue[0], IWL_MAX_TID_COUNT, 0);
+ iwl_mvm_disable_txq(mvm, NULL, queue, IWL_MAX_TID_COUNT, 0);
if (iwl_mvm_has_new_tx_api(mvm))
return;
@@ -2377,10 +2296,8 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
* Note that this is done here as we want to avoid making DQA
* changes in mac80211 layer.
*/
- if (vif->type == NL80211_IFTYPE_ADHOC) {
- vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
- mvmvif->cab_queue = vif->cab_queue;
- }
+ if (vif->type == NL80211_IFTYPE_ADHOC)
+ mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
/*
* While in previous FWs we had to exclude cab queue from TFD queue
@@ -2388,9 +2305,9 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
*/
if (!iwl_mvm_has_new_tx_api(mvm) &&
fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) {
- iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0,
- &cfg, timeout);
- msta->tfd_queue_msk |= BIT(vif->cab_queue);
+ iwl_mvm_enable_txq(mvm, NULL, mvmvif->cab_queue, 0, &cfg,
+ timeout);
+ msta->tfd_queue_msk |= BIT(mvmvif->cab_queue);
}
ret = iwl_mvm_add_int_sta_common(mvm, msta, maddr,
mvmvif->id, mvmvif->color);
@@ -2407,24 +2324,25 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
* tfd_queue_mask.
*/
if (iwl_mvm_has_new_tx_api(mvm)) {
- int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue,
- msta->sta_id,
+ int queue = iwl_mvm_tvqm_enable_txq(mvm, msta->sta_id,
0,
timeout);
mvmvif->cab_queue = queue;
} else if (!fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_STA_TYPE))
- iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0,
- &cfg, timeout);
+ iwl_mvm_enable_txq(mvm, NULL, mvmvif->cab_queue, 0, &cfg,
+ timeout);
if (mvmvif->ap_wep_key) {
u8 key_offset = iwl_mvm_set_fw_key_idx(mvm);
+ __set_bit(key_offset, mvm->fw_key_table);
+
if (key_offset == STA_KEY_IDX_INVALID)
return -ENOSPC;
ret = iwl_mvm_send_sta_key(mvm, mvmvif->mcast_sta.sta_id,
- mvmvif->ap_wep_key, 1, 0, NULL, 0,
+ mvmvif->ap_wep_key, true, 0, NULL, 0,
key_offset, 0);
if (ret)
return ret;
@@ -2433,6 +2351,59 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return 0;
}
+static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
+ struct ieee80211_key_conf *keyconf,
+ bool mcast)
+{
+ union {
+ struct iwl_mvm_add_sta_key_cmd_v1 cmd_v1;
+ struct iwl_mvm_add_sta_key_cmd cmd;
+ } u = {};
+ bool new_api = fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_TKIP_MIC_KEYS);
+ __le16 key_flags;
+ int ret, size;
+ u32 status;
+
+ /* This is a valid situation for GTK removal */
+ if (sta_id == IWL_MVM_INVALID_STA)
+ return 0;
+
+ key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
+ STA_KEY_FLG_KEYID_MSK);
+ key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP);
+ key_flags |= cpu_to_le16(STA_KEY_NOT_VALID);
+
+ if (mcast)
+ key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
+
+ /*
+ * The fields assigned here are in the same location at the start
+ * of the command, so we can do this union trick.
+ */
+ u.cmd.common.key_flags = key_flags;
+ u.cmd.common.key_offset = keyconf->hw_key_idx;
+ u.cmd.common.sta_id = sta_id;
+
+ size = new_api ? sizeof(u.cmd) : sizeof(u.cmd_v1);
+
+ status = ADD_STA_SUCCESS;
+ ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, size, &u.cmd,
+ &status);
+
+ switch (status) {
+ case ADD_STA_SUCCESS:
+ IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n");
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n");
+ break;
+ }
+
+ return ret;
+}
+
/*
* Send the FW a request to remove the station from it's internal data
* structures, and in addition remove it from the local data structure.
@@ -2446,8 +2417,29 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0);
- iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue,
- 0, 0);
+ iwl_mvm_disable_txq(mvm, NULL, mvmvif->cab_queue, 0, 0);
+
+ if (mvmvif->ap_wep_key) {
+ int i;
+
+ if (!__test_and_clear_bit(mvmvif->ap_wep_key->hw_key_idx,
+ mvm->fw_key_table)) {
+ IWL_ERR(mvm, "offset %d not used in fw key table.\n",
+ mvmvif->ap_wep_key->hw_key_idx);
+ return -ENOENT;
+ }
+
+ /* track which key was deleted last */
+ for (i = 0; i < STA_KEY_MAX_NUM; i++) {
+ if (mvm->fw_key_deleted[i] < U8_MAX)
+ mvm->fw_key_deleted[i]++;
+ }
+ mvm->fw_key_deleted[mvmvif->ap_wep_key->hw_key_idx] = 0;
+ ret = __iwl_mvm_remove_sta_key(mvm, mvmvif->mcast_sta.sta_id,
+ mvmvif->ap_wep_key, true);
+ if (ret)
+ return ret;
+ }
ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id);
if (ret)
@@ -2781,7 +2773,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_tid_data *tid_data;
u16 normalized_ssn;
- int txq_id;
+ u16 txq_id;
int ret;
if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
@@ -2823,17 +2815,24 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
*/
txq_id = mvmsta->tid_data[tid].txq_id;
if (txq_id == IWL_MVM_INVALID_QUEUE) {
- txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
- IWL_MVM_DQA_MIN_DATA_QUEUE,
- IWL_MVM_DQA_MAX_DATA_QUEUE);
- if (txq_id < 0) {
- ret = txq_id;
+ ret = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
+ IWL_MVM_DQA_MIN_DATA_QUEUE,
+ IWL_MVM_DQA_MAX_DATA_QUEUE);
+ if (ret < 0) {
IWL_ERR(mvm, "Failed to allocate agg queue\n");
goto out;
}
+ txq_id = ret;
+
/* TXQ hasn't yet been enabled, so mark it only as reserved */
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED;
+ } else if (WARN_ON(txq_id >= IWL_MAX_HW_QUEUES)) {
+ ret = -ENXIO;
+ IWL_ERR(mvm, "tid_id %d out of range (0, %d)!\n",
+ tid, IWL_MAX_HW_QUEUES - 1);
+ goto out;
+
} else if (unlikely(mvm->queue_info[txq_id].status ==
IWL_MVM_QUEUE_SHARED)) {
ret = -ENXIO;
@@ -2976,8 +2975,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
}
if (alloc_queue)
- iwl_mvm_enable_txq(mvm, queue,
- vif->hw_queue[tid_to_mac80211_ac[tid]], ssn,
+ iwl_mvm_enable_txq(mvm, sta, queue, ssn,
&cfg, wdg_timeout);
/* Send ADD_STA command to enable aggs only if the queue isn't shared */
@@ -3474,59 +3472,6 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
return ret;
}
-static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
- struct ieee80211_key_conf *keyconf,
- bool mcast)
-{
- union {
- struct iwl_mvm_add_sta_key_cmd_v1 cmd_v1;
- struct iwl_mvm_add_sta_key_cmd cmd;
- } u = {};
- bool new_api = fw_has_api(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_API_TKIP_MIC_KEYS);
- __le16 key_flags;
- int ret, size;
- u32 status;
-
- /* This is a valid situation for GTK removal */
- if (sta_id == IWL_MVM_INVALID_STA)
- return 0;
-
- key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
- STA_KEY_FLG_KEYID_MSK);
- key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP);
- key_flags |= cpu_to_le16(STA_KEY_NOT_VALID);
-
- if (mcast)
- key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
-
- /*
- * The fields assigned here are in the same location at the start
- * of the command, so we can do this union trick.
- */
- u.cmd.common.key_flags = key_flags;
- u.cmd.common.key_offset = keyconf->hw_key_idx;
- u.cmd.common.sta_id = sta_id;
-
- size = new_api ? sizeof(u.cmd) : sizeof(u.cmd_v1);
-
- status = ADD_STA_SUCCESS;
- ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA_KEY, size, &u.cmd,
- &status);
-
- switch (status) {
- case ADD_STA_SUCCESS:
- IWL_DEBUG_WEP(mvm, "MODIFY_STA: remove sta key passed\n");
- break;
- default:
- ret = -EIO;
- IWL_ERR(mvm, "MODIFY_STA: remove sta key failed\n");
- break;
- }
-
- return ret;
-}
-
int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index d52cd888f77d..79700c7310a1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -297,7 +297,6 @@ enum iwl_mvm_agg_state {
/**
* struct iwl_mvm_tid_data - holds the states for each RA / TID
- * @deferred_tx_frames: deferred TX frames for this RA/TID
* @seq_number: the next WiFi sequence number to use
* @next_reclaimed: the WiFi sequence number of the next packet to be acked.
* This is basically (last acked packet++).
@@ -318,7 +317,6 @@ enum iwl_mvm_agg_state {
* tpt_meas_start
*/
struct iwl_mvm_tid_data {
- struct sk_buff_head deferred_tx_frames;
u16 seq_number;
u16 next_reclaimed;
/* The rest is Tx AGG related */
@@ -396,6 +394,7 @@ struct iwl_mvm_rxq_dup_data {
* the BA window. To be used for UAPSD only.
* @ptk_pn: per-queue PTK PN data structures
* @dup_data: per queue duplicate packet detection data
+ * @wep_key: used in AP mode. Is a duplicate of the WEP key.
* @deferred_traffic_tid_map: indication bitmap of deferred traffic per-TID
* @tx_ant: the index of the antenna to use for data tx to this station. Only
* used during connection establishment (e.g. for the 4 way handshake
@@ -427,7 +426,7 @@ struct iwl_mvm_sta {
struct iwl_mvm_key_pn __rcu *ptk_pn[4];
struct iwl_mvm_rxq_dup_data *dup_data;
- u16 deferred_traffic_tid_map;
+ struct ieee80211_key_conf *wep_key;
u8 reserved_queue;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
index e02f4eb20359..859aa5a4e6b5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c
@@ -399,6 +399,9 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
struct ieee80211_tx_info *info;
struct ieee80211_hdr *hdr;
struct iwl_tdls_channel_switch_cmd cmd = {0};
+ struct iwl_tdls_channel_switch_cmd_tail *tail =
+ iwl_mvm_chan_info_cmd_tail(mvm, &cmd.ci);
+ u16 len = sizeof(cmd) - iwl_mvm_chan_info_padding(mvm);
int ret;
lockdep_assert_held(&mvm->mutex);
@@ -414,9 +417,9 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
}
cmd.switch_type = type;
- cmd.timing.frame_timestamp = cpu_to_le32(timestamp);
- cmd.timing.switch_time = cpu_to_le32(switch_time);
- cmd.timing.switch_timeout = cpu_to_le32(switch_timeout);
+ tail->timing.frame_timestamp = cpu_to_le32(timestamp);
+ tail->timing.switch_time = cpu_to_le32(switch_time);
+ tail->timing.switch_timeout = cpu_to_le32(switch_timeout);
rcu_read_lock();
sta = ieee80211_find_sta(vif, peer);
@@ -448,21 +451,16 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
}
}
- if (chandef) {
- cmd.ci.band = (chandef->chan->band == NL80211_BAND_2GHZ ?
- PHY_BAND_24 : PHY_BAND_5);
- cmd.ci.channel = chandef->chan->hw_value;
- cmd.ci.width = iwl_mvm_get_channel_width(chandef);
- cmd.ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef);
- }
+ if (chandef)
+ iwl_mvm_set_chan_info_chandef(mvm, &cmd.ci, chandef);
/* keep quota calculation simple for now - 50% of DTIM for TDLS */
- cmd.timing.max_offchan_duration =
+ tail->timing.max_offchan_duration =
cpu_to_le32(TU_TO_US(vif->bss_conf.dtim_period *
vif->bss_conf.beacon_int) / 2);
/* Switch time is the first element in the switch-timing IE. */
- cmd.frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2);
+ tail->frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2);
info = IEEE80211_SKB_CB(skb);
hdr = (void *)skb->data;
@@ -472,20 +470,19 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
ret = -EINVAL;
goto out;
}
- iwl_mvm_set_tx_cmd_ccmp(info, &cmd.frame.tx_cmd);
+ iwl_mvm_set_tx_cmd_ccmp(info, &tail->frame.tx_cmd);
}
- iwl_mvm_set_tx_cmd(mvm, skb, &cmd.frame.tx_cmd, info,
+ iwl_mvm_set_tx_cmd(mvm, skb, &tail->frame.tx_cmd, info,
mvmsta->sta_id);
- iwl_mvm_set_tx_cmd_rate(mvm, &cmd.frame.tx_cmd, info, sta,
+ iwl_mvm_set_tx_cmd_rate(mvm, &tail->frame.tx_cmd, info, sta,
hdr->frame_control);
rcu_read_unlock();
- memcpy(cmd.frame.data, skb->data, skb->len);
+ memcpy(tail->frame.data, skb->data, skb->len);
- ret = iwl_mvm_send_cmd_pdu(mvm, TDLS_CHANNEL_SWITCH_CMD, 0,
- sizeof(cmd), &cmd);
+ ret = iwl_mvm_send_cmd_pdu(mvm, TDLS_CHANNEL_SWITCH_CMD, 0, len, &cmd);
if (ret) {
IWL_ERR(mvm, "Failed to send TDLS_CHANNEL_SWITCH cmd: %d\n",
ret);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index e1a6f4e22253..9693fa4cdc39 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -85,7 +85,7 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
{
lockdep_assert_held(&mvm->time_event_lock);
- if (!te_data->vif)
+ if (!te_data || !te_data->vif)
return;
list_del(&te_data->list);
@@ -334,6 +334,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
switch (te_data->vif->type) {
case NL80211_IFTYPE_P2P_DEVICE:
ieee80211_remain_on_channel_expired(mvm->hw);
+ set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status);
iwl_mvm_roc_finished(mvm);
break;
case NL80211_IFTYPE_STATION:
@@ -686,6 +687,8 @@ static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm,
struct iwl_mvm_time_event_data *te_data)
{
struct iwl_hs20_roc_req aux_cmd = {};
+ u16 len = sizeof(aux_cmd) - iwl_mvm_chan_info_padding(mvm);
+
u32 uid;
int ret;
@@ -699,7 +702,7 @@ static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm,
IWL_DEBUG_TE(mvm, "Removing BSS AUX ROC TE 0x%x\n",
le32_to_cpu(aux_cmd.event_unique_id));
ret = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0,
- sizeof(aux_cmd), &aux_cmd);
+ len, &aux_cmd);
if (WARN_ON(ret))
return;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c
deleted file mode 100644
index 01e0a999063b..000000000000
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2015 Intel Deutschland GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * Contact Information:
- * Intel Linux Wireless <linuxwifi@intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2015 Intel Deutschland GmbH
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#include "mvm.h"
-#include "fw/api/tof.h"
-
-#define IWL_MVM_TOF_RANGE_REQ_MAX_ID 256
-
-void iwl_mvm_tof_init(struct iwl_mvm *mvm)
-{
- struct iwl_mvm_tof_data *tof_data = &mvm->tof_data;
-
- if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT))
- return;
-
- memset(tof_data, 0, sizeof(*tof_data));
-
- tof_data->tof_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_CONFIG_CMD);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- if (IWL_MVM_TOF_IS_RESPONDER) {
- tof_data->responder_cfg.sub_grp_cmd_id =
- cpu_to_le32(TOF_RESPONDER_CONFIG_CMD);
- tof_data->responder_cfg.sta_id = IWL_MVM_INVALID_STA;
- }
-#endif
-
- tof_data->range_req.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_CMD);
- tof_data->range_req.req_timeout = 1;
- tof_data->range_req.initiator = 1;
- tof_data->range_req.report_policy = 3;
-
- tof_data->range_req_ext.sub_grp_cmd_id =
- cpu_to_le32(TOF_RANGE_REQ_EXT_CMD);
-
- mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
- mvm->init_status |= IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE;
-}
-
-void iwl_mvm_tof_clean(struct iwl_mvm *mvm)
-{
- struct iwl_mvm_tof_data *tof_data = &mvm->tof_data;
-
- if (!fw_has_capa(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_TOF_SUPPORT) ||
- !(mvm->init_status & IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE))
- return;
-
- memset(tof_data, 0, sizeof(*tof_data));
- mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
- mvm->init_status &= ~IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE;
-}
-
-static void iwl_tof_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
-{
- bool *enabled = _data;
-
- /* non bss vif exists */
- if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION)
- *enabled = false;
-}
-
-int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm)
-{
- struct iwl_tof_config_cmd *cmd = &mvm->tof_data.tof_cfg;
- bool enabled;
-
- lockdep_assert_held(&mvm->mutex);
-
- if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT))
- return -EINVAL;
-
- ieee80211_iterate_active_interfaces_atomic(mvm->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- iwl_tof_iterator, &enabled);
- if (!enabled) {
- IWL_DEBUG_INFO(mvm, "ToF is not supported (non bss vif)\n");
- return -EINVAL;
- }
-
- mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
- return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD,
- IWL_ALWAYS_LONG_GROUP, 0),
- 0, sizeof(*cmd), cmd);
-}
-
-int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id)
-{
- struct iwl_tof_range_abort_cmd cmd = {
- .sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_ABORT_CMD),
- .request_id = id,
- };
-
- lockdep_assert_held(&mvm->mutex);
-
- if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT))
- return -EINVAL;
-
- if (id != mvm->tof_data.active_range_request) {
- IWL_ERR(mvm, "Invalid range request id %d (active %d)\n",
- id, mvm->tof_data.active_range_request);
- return -EINVAL;
- }
-
- /* after abort is sent there's no active request anymore */
- mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
-
- return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD,
- IWL_ALWAYS_LONG_GROUP, 0),
- 0, sizeof(cmd), &cmd);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- struct iwl_tof_responder_config_cmd *cmd = &mvm->tof_data.responder_cfg;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
- lockdep_assert_held(&mvm->mutex);
-
- if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT))
- return -EINVAL;
-
- if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||
- !mvmvif->ap_ibss_active) {
- IWL_ERR(mvm, "Cannot start responder, not in AP mode\n");
- return -EIO;
- }
-
- cmd->sta_id = mvmvif->bcast_sta.sta_id;
- memcpy(cmd->bssid, vif->addr, ETH_ALEN);
- return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD,
- IWL_ALWAYS_LONG_GROUP, 0),
- 0, sizeof(*cmd), cmd);
-}
-#endif
-
-int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- struct iwl_host_cmd cmd = {
- .id = iwl_cmd_id(TOF_CMD, IWL_ALWAYS_LONG_GROUP, 0),
- .len = { sizeof(mvm->tof_data.range_req), },
- /* no copy because of the command size */
- .dataflags = { IWL_HCMD_DFL_NOCOPY, },
- };
-
- lockdep_assert_held(&mvm->mutex);
-
- if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT))
- return -EINVAL;
-
- if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {
- IWL_ERR(mvm, "Cannot send range request, not STA mode\n");
- return -EIO;
- }
-
- /* nesting of range requests is not supported in FW */
- if (mvm->tof_data.active_range_request !=
- IWL_MVM_TOF_RANGE_REQ_MAX_ID) {
- IWL_ERR(mvm, "Cannot send range req, already active req %d\n",
- mvm->tof_data.active_range_request);
- return -EIO;
- }
-
- mvm->tof_data.active_range_request = mvm->tof_data.range_req.request_id;
-
- cmd.data[0] = &mvm->tof_data.range_req;
- return iwl_mvm_send_cmd(mvm, &cmd);
-}
-
-int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- lockdep_assert_held(&mvm->mutex);
-
- if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT))
- return -EINVAL;
-
- if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {
- IWL_ERR(mvm, "Cannot send ext range req, not in STA mode\n");
- return -EIO;
- }
-
- return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD,
- IWL_ALWAYS_LONG_GROUP, 0),
- 0, sizeof(mvm->tof_data.range_req_ext),
- &mvm->tof_data.range_req_ext);
-}
-
-static int iwl_mvm_tof_range_resp(struct iwl_mvm *mvm, void *data)
-{
- struct iwl_tof_range_rsp_ntfy *resp = (void *)data;
-
- if (resp->request_id != mvm->tof_data.active_range_request) {
- IWL_ERR(mvm, "Request id mismatch, got %d, active %d\n",
- resp->request_id, mvm->tof_data.active_range_request);
- return -EIO;
- }
-
- memcpy(&mvm->tof_data.range_resp, resp,
- sizeof(struct iwl_tof_range_rsp_ntfy));
- mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
-
- return 0;
-}
-
-static int iwl_mvm_tof_mcsi_notif(struct iwl_mvm *mvm, void *data)
-{
- struct iwl_tof_mcsi_notif *resp = (struct iwl_tof_mcsi_notif *)data;
-
- IWL_DEBUG_INFO(mvm, "MCSI notification, token %d\n", resp->token);
- return 0;
-}
-
-static int iwl_mvm_tof_nb_report_notif(struct iwl_mvm *mvm, void *data)
-{
- struct iwl_tof_neighbor_report *report =
- (struct iwl_tof_neighbor_report *)data;
-
- IWL_DEBUG_INFO(mvm, "NB report, bssid %pM, token %d, status 0x%x\n",
- report->bssid, report->request_token, report->status);
- return 0;
-}
-
-void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_tof_gen_resp_cmd *resp = (void *)pkt->data;
-
- lockdep_assert_held(&mvm->mutex);
-
- switch (le32_to_cpu(resp->sub_grp_cmd_id)) {
- case TOF_RANGE_RESPONSE_NOTIF:
- iwl_mvm_tof_range_resp(mvm, resp->data);
- break;
- case TOF_MCSI_DEBUG_NOTIF:
- iwl_mvm_tof_mcsi_notif(mvm, resp->data);
- break;
- case TOF_NEIGHBOR_REPORT_RSP_NOTIF:
- iwl_mvm_tof_nb_report_notif(mvm, resp->data);
- break;
- default:
- IWL_ERR(mvm, "Unknown sub-group command 0x%x\n",
- resp->sub_grp_cmd_id);
- break;
- }
-}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h
deleted file mode 100644
index 8138d0606c52..000000000000
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2015 Intel Deutschland GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * Contact Information:
- * Intel Linux Wireless <linuxwifi@intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2015 Intel Deutschland GmbH
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#ifndef __tof_h__
-#define __tof_h__
-
-#include "fw/api/tof.h"
-
-struct iwl_mvm_tof_data {
- struct iwl_tof_config_cmd tof_cfg;
- struct iwl_tof_range_req_cmd range_req;
- struct iwl_tof_range_req_ext_cmd range_req_ext;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- struct iwl_tof_responder_config_cmd responder_cfg;
-#endif
- struct iwl_tof_range_rsp_ntfy range_resp;
- u8 last_abort_id;
- u16 active_range_request;
-};
-
-void iwl_mvm_tof_init(struct iwl_mvm *mvm);
-void iwl_mvm_tof_clean(struct iwl_mvm *mvm);
-int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm);
-int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id);
-int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
-void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm,
- struct iwl_rx_cmd_buffer *rxb);
-int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
-#endif
-#endif /* __tof_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 995fe2a6abbb..0c2aabc842f9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -8,7 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -209,7 +209,9 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
u16 offload_assist = 0;
u8 ac;
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) ||
+ (ieee80211_is_probe_resp(fc) &&
+ !is_multicast_ether_addr(hdr->addr1)))
tx_flags |= TX_CMD_FLG_ACK;
else
tx_flags &= ~TX_CMD_FLG_ACK;
@@ -278,7 +280,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
}
if (ieee80211_is_data(fc) && len > mvm->rts_threshold &&
- !is_multicast_ether_addr(ieee80211_get_DA(hdr)))
+ !is_multicast_ether_addr(hdr->addr1))
tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
if (fw_has_capa(&mvm->fw->ucode_capa,
@@ -533,10 +535,11 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
/*
* For data packets rate info comes from the fw. Only
- * set rate/antenna during connection establishment.
+ * set rate/antenna during connection establishment or in case
+ * no station is given.
*/
- if (sta && (!ieee80211_is_data(hdr->frame_control) ||
- mvmsta->sta_state < IEEE80211_STA_AUTHORIZED)) {
+ if (!sta || !ieee80211_is_data(hdr->frame_control) ||
+ mvmsta->sta_state < IEEE80211_STA_AUTHORIZED) {
flags |= IWL_TX_FLAGS_CMD_RATE;
rate_n_flags =
iwl_mvm_get_tx_rate_n_flags(mvm, info, sta,
@@ -602,11 +605,12 @@ static void iwl_mvm_skb_prepare_status(struct sk_buff *skb,
}
static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
- struct ieee80211_tx_info *info, __le16 fc)
+ struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr)
{
- struct iwl_mvm_vif *mvmvif;
-
- mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif);
+ struct iwl_mvm_vif *mvmvif =
+ iwl_mvm_vif_from_mac80211(info->control.vif);
+ __le16 fc = hdr->frame_control;
switch (info->control.vif->type) {
case NL80211_IFTYPE_AP:
@@ -625,7 +629,9 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
(!ieee80211_is_bufferable_mmpdu(fc) ||
ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc)))
return mvm->probe_queue;
- if (info->hw_queue == info->control.vif->cab_queue)
+
+ if (!ieee80211_has_order(fc) && !ieee80211_is_probe_req(fc) &&
+ is_multicast_ether_addr(hdr->addr1))
return mvmvif->cab_queue;
WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC,
@@ -634,8 +640,6 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
case NL80211_IFTYPE_P2P_DEVICE:
if (ieee80211_is_mgmt(fc))
return mvm->p2p_dev_queue;
- if (info->hw_queue == info->control.vif->cab_queue)
- return mvmvif->cab_queue;
WARN_ON_ONCE(1);
return mvm->p2p_dev_queue;
@@ -713,18 +717,18 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
u8 sta_id;
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
__le16 fc = hdr->frame_control;
+ bool offchannel = IEEE80211_SKB_CB(skb)->flags &
+ IEEE80211_TX_CTL_TX_OFFCHAN;
int queue = -1;
+ if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc))
+ return -1;
+
memcpy(&info, skb->cb, sizeof(info));
if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_AMPDU))
return -1;
- if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
- (!info.control.vif ||
- info.hw_queue != info.control.vif->cab_queue)))
- return -1;
-
if (info.control.vif) {
struct iwl_mvm_vif *mvmvif =
iwl_mvm_vif_from_mac80211(info.control.vif);
@@ -737,14 +741,12 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
else
sta_id = mvmvif->mcast_sta.sta_id;
- queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info,
- hdr->frame_control);
-
+ queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr);
} else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) {
queue = mvm->snif_queue;
sta_id = mvm->snif_sta.sta_id;
} else if (info.control.vif->type == NL80211_IFTYPE_STATION &&
- info.hw_queue == IWL_MVM_OFFCHANNEL_QUEUE) {
+ offchannel) {
/*
* IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets
* that can be used in 2 different types of vifs, P2P &
@@ -758,8 +760,10 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
}
}
- if (queue < 0)
+ if (queue < 0) {
+ IWL_ERR(mvm, "No queue was found. Dropping TX\n");
return -1;
+ }
if (unlikely(ieee80211_is_probe_resp(fc)))
iwl_mvm_probe_resp_set_noa(mvm, skb);
@@ -781,6 +785,35 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
return 0;
}
+unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta, unsigned int tid)
+{
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ enum nl80211_band band = mvmsta->vif->bss_conf.chandef.chan->band;
+ u8 ac = tid_to_mac80211_ac[tid];
+ unsigned int txf;
+ int lmac = IWL_LMAC_24G_INDEX;
+
+ if (iwl_mvm_is_cdb_supported(mvm) &&
+ band == NL80211_BAND_5GHZ)
+ lmac = IWL_LMAC_5G_INDEX;
+
+ /* For HE redirect to trigger based fifos */
+ if (sta->he_cap.has_he && !WARN_ON(!iwl_mvm_has_new_tx_api(mvm)))
+ ac += 4;
+
+ txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac);
+
+ /*
+ * Don't send an AMSDU that will be longer than the TXF.
+ * Add a security margin of 256 for the TX command + headers.
+ * We also want to have the start of the next packet inside the
+ * fifo to be able to send bursts.
+ */
+ return min_t(unsigned int, mvmsta->max_amsdu_len,
+ mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
+}
+
#ifdef CONFIG_INET
static int
@@ -850,36 +883,6 @@ iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
return 0;
}
-static unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta,
- unsigned int tid)
-{
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- enum nl80211_band band = mvmsta->vif->bss_conf.chandef.chan->band;
- u8 ac = tid_to_mac80211_ac[tid];
- unsigned int txf;
- int lmac = IWL_LMAC_24G_INDEX;
-
- if (iwl_mvm_is_cdb_supported(mvm) &&
- band == NL80211_BAND_5GHZ)
- lmac = IWL_LMAC_5G_INDEX;
-
- /* For HE redirect to trigger based fifos */
- if (sta->he_cap.has_he && !WARN_ON(!iwl_mvm_has_new_tx_api(mvm)))
- ac += 4;
-
- txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac);
-
- /*
- * Don't send an AMSDU that will be longer than the TXF.
- * Add a security margin of 256 for the TX command + headers.
- * We also want to have the start of the next packet inside the
- * fifo to be able to send bursts.
- */
- return min_t(unsigned int, mvmsta->max_amsdu_len,
- mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
-}
-
static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta,
@@ -1002,34 +1005,6 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
}
#endif
-static void iwl_mvm_tx_add_stream(struct iwl_mvm *mvm,
- struct iwl_mvm_sta *mvm_sta, u8 tid,
- struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- u8 mac_queue = info->hw_queue;
- struct sk_buff_head *deferred_tx_frames;
-
- lockdep_assert_held(&mvm_sta->lock);
-
- mvm_sta->deferred_traffic_tid_map |= BIT(tid);
- set_bit(mvm_sta->sta_id, mvm->sta_deferred_frames);
-
- deferred_tx_frames = &mvm_sta->tid_data[tid].deferred_tx_frames;
-
- skb_queue_tail(deferred_tx_frames, skb);
-
- /*
- * The first deferred frame should've stopped the MAC queues, so we
- * should never get a second deferred frame for the RA/TID.
- * In case of GSO the first packet may have been split, so don't warn.
- */
- if (skb_queue_len(deferred_tx_frames) == 1) {
- iwl_mvm_stop_mac_queues(mvm, BIT(mac_queue));
- schedule_work(&mvm->add_stream_wk);
- }
-}
-
/* Check if there are any timed-out TIDs on a given shared TXQ */
static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id)
{
@@ -1054,7 +1029,12 @@ static void iwl_mvm_tx_airtime(struct iwl_mvm *mvm,
int airtime)
{
int mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK;
- struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac];
+ struct iwl_mvm_tcm_mac *mdata;
+
+ if (mac >= NUM_MAC_INDEX_DRIVER)
+ return;
+
+ mdata = &mvm->tcm.data[mac];
if (mvm->tcm.paused)
return;
@@ -1065,14 +1045,21 @@ static void iwl_mvm_tx_airtime(struct iwl_mvm *mvm,
mdata->tx.airtime += airtime;
}
-static void iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm,
- struct iwl_mvm_sta *mvmsta, int tid)
+static int iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm,
+ struct iwl_mvm_sta *mvmsta, int tid)
{
u32 ac = tid_to_mac80211_ac[tid];
int mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK;
- struct iwl_mvm_tcm_mac *mdata = &mvm->tcm.data[mac];
+ struct iwl_mvm_tcm_mac *mdata;
+
+ if (mac >= NUM_MAC_INDEX_DRIVER)
+ return -EINVAL;
+
+ mdata = &mvm->tcm.data[mac];
mdata->tx.pkts[ac]++;
+
+ return 0;
}
/*
@@ -1088,7 +1075,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
__le16 fc;
u16 seq_number = 0;
u8 tid = IWL_MAX_TID_COUNT;
- u16 txq_id = info->hw_queue;
+ u16 txq_id;
bool is_ampdu = false;
int hdrlen;
@@ -1096,6 +1083,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
fc = hdr->frame_control;
hdrlen = ieee80211_hdrlen(fc);
+ if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc))
+ return -1;
+
if (WARN_ON_ONCE(!mvmsta))
return -1;
@@ -1125,12 +1115,14 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
*/
if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
tid = ieee80211_get_tid(hdr);
- if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+ if (WARN_ONCE(tid >= IWL_MAX_TID_COUNT, "Invalid TID %d", tid))
goto drop_unlock_sta;
is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
- if (WARN_ON_ONCE(is_ampdu &&
- mvmsta->tid_data[tid].state != IWL_AGG_ON))
+ if (WARN_ONCE(is_ampdu &&
+ mvmsta->tid_data[tid].state != IWL_AGG_ON,
+ "Invalid internal agg state %d for TID %d",
+ mvmsta->tid_data[tid].state, tid))
goto drop_unlock_sta;
seq_number = mvmsta->tid_data[tid].seq_number;
@@ -1152,14 +1144,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
- /* Check if TXQ needs to be allocated or re-activated */
- if (unlikely(txq_id == IWL_MVM_INVALID_QUEUE)) {
- iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb);
-
- /*
- * The frame is now deferred, and the worker scheduled
- * will re-allocate it, so we can free it for now.
- */
+ if (WARN_ONCE(txq_id == IWL_MVM_INVALID_QUEUE, "Invalid TXQ id")) {
iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
spin_unlock(&mvmsta->lock);
return 0;
@@ -1199,7 +1184,9 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
spin_unlock(&mvmsta->lock);
- iwl_mvm_tx_pkt_queued(mvm, mvmsta, tid == IWL_MAX_TID_COUNT ? 0 : tid);
+ if (iwl_mvm_tx_pkt_queued(mvm, mvmsta,
+ tid == IWL_MAX_TID_COUNT ? 0 : tid))
+ goto drop;
return 0;
@@ -1207,6 +1194,7 @@ drop_unlock_sta:
iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
spin_unlock(&mvmsta->lock);
drop:
+ IWL_DEBUG_TX(mvm, "TX to [%d|%d] dropped\n", mvmsta->sta_id, tid);
return -1;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index d116c6ae18ff..4649327abb45 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -248,7 +248,7 @@ void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
IWL_ERR(mvm, "FW Error notification: seq 0x%04X service 0x%08X\n",
le16_to_cpu(err_resp->bad_cmd_seq_num),
le32_to_cpu(err_resp->error_service));
- IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n",
+ IWL_ERR(mvm, "FW Error notification: timestamp 0x%016llX\n",
le64_to_cpu(err_resp->timestamp));
}
@@ -294,6 +294,7 @@ static const struct {
{ "SYSASSERT", 0x35 },
{ "UCODE_VERSION_MISMATCH", 0x37 },
{ "BAD_COMMAND", 0x38 },
+ { "BAD_COMMAND", 0x39 },
{ "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
{ "FATAL_ERROR", 0x3D },
{ "NMI_TRM_HW_ERR", 0x46 },
@@ -456,12 +457,17 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
{
struct iwl_trans *trans = mvm->trans;
struct iwl_umac_error_event_table table;
+ u32 base = mvm->trans->umac_error_event_table;
- if (!mvm->support_umac_log)
+ if (!mvm->support_umac_log &&
+ !(mvm->trans->error_event_table_tlv_status &
+ IWL_ERROR_EVENT_TABLE_UMAC))
return;
- iwl_trans_read_mem_bytes(trans, mvm->umac_error_event_table, &table,
- sizeof(table));
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ if (table.valid)
+ mvm->fwrt.dump.umac_err_id = table.error_id;
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@@ -486,11 +492,11 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref);
}
-static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base)
+static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num)
{
struct iwl_trans *trans = mvm->trans;
struct iwl_error_event_table table;
- u32 val;
+ u32 val, base = mvm->trans->lmac_error_event_table[lmac_num];
if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) {
if (!base)
@@ -519,29 +525,15 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base)
/* reset the device */
iwl_trans_sw_reset(trans);
- /* set INIT_DONE flag */
- iwl_set_bit(trans, CSR_GP_CNTRL,
- BIT(trans->cfg->csr->flag_init_done));
-
- /* and wait for clock stabilization */
- if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
- udelay(2);
-
- err = iwl_poll_bit(trans, CSR_GP_CNTRL,
- BIT(trans->cfg->csr->flag_mac_clock_ready),
- BIT(trans->cfg->csr->flag_mac_clock_ready),
- 25000);
- if (err < 0) {
- IWL_DEBUG_INFO(trans,
- "Failed to reset the card for the dump\n");
+ err = iwl_finish_nic_init(trans);
+ if (err)
return;
- }
}
iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
if (table.valid)
- mvm->fwrt.dump.rt_status = table.error_id;
+ mvm->fwrt.dump.lmac_err_id[lmac_num] = table.error_id;
if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
IWL_ERR(trans, "Start IWL Error Log Dump:\n");
@@ -598,10 +590,10 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
return;
}
- iwl_mvm_dump_lmac_error_log(mvm, mvm->error_event_table[0]);
+ iwl_mvm_dump_lmac_error_log(mvm, 0);
- if (mvm->error_event_table[1])
- iwl_mvm_dump_lmac_error_log(mvm, mvm->error_event_table[1]);
+ if (mvm->trans->lmac_error_event_table[1])
+ iwl_mvm_dump_lmac_error_log(mvm, 1);
iwl_mvm_dump_umac_error_log(mvm);
}
@@ -1133,19 +1125,14 @@ static void iwl_mvm_tcm_uapsd_nonagg_detected_wk(struct work_struct *wk)
"AP isn't using AMPDU with uAPSD enabled");
}
-static void iwl_mvm_uapsd_agg_disconnect_iter(void *data, u8 *mac,
- struct ieee80211_vif *vif)
+static void iwl_mvm_uapsd_agg_disconnect(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = mvmvif->mvm;
- int *mac_id = data;
if (vif->type != NL80211_IFTYPE_STATION)
return;
- if (mvmvif->id != *mac_id)
- return;
-
if (!vif->bss_conf.assoc)
return;
@@ -1155,10 +1142,10 @@ static void iwl_mvm_uapsd_agg_disconnect_iter(void *data, u8 *mac,
!mvmvif->queue_params[IEEE80211_AC_BK].uapsd)
return;
- if (mvm->tcm.data[*mac_id].uapsd_nonagg_detect.detected)
+ if (mvm->tcm.data[mvmvif->id].uapsd_nonagg_detect.detected)
return;
- mvm->tcm.data[*mac_id].uapsd_nonagg_detect.detected = true;
+ mvm->tcm.data[mvmvif->id].uapsd_nonagg_detect.detected = true;
IWL_INFO(mvm,
"detected AP should do aggregation but isn't, likely due to U-APSD\n");
schedule_delayed_work(&mvmvif->uapsd_nonagg_detected_wk, 15 * HZ);
@@ -1171,6 +1158,7 @@ static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm,
u64 bytes = mvm->tcm.data[mac].uapsd_nonagg_detect.rx_bytes;
u64 tpt;
unsigned long rate;
+ struct ieee80211_vif *vif;
rate = ewma_rate_read(&mvm->tcm.data[mac].uapsd_nonagg_detect.rate);
@@ -1199,9 +1187,11 @@ static void iwl_mvm_check_uapsd_agg_expected_tpt(struct iwl_mvm *mvm,
return;
}
- ieee80211_iterate_active_interfaces_atomic(
- mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
- iwl_mvm_uapsd_agg_disconnect_iter, &mac);
+ rcu_read_lock();
+ vif = rcu_dereference(mvm->vif_id_to_mac[mac]);
+ if (vif)
+ iwl_mvm_uapsd_agg_disconnect(mvm, vif);
+ rcu_read_unlock();
}
static void iwl_mvm_tcm_iterator(void *_data, u8 *mac,