Commit 9c95fd66 authored by Kalle Valo's avatar Kalle Valo

Merge tag 'iwlwifi-next-for-kalle-2016-09-19-2' of...

Merge tag 'iwlwifi-next-for-kalle-2016-09-19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

* added support for MU-MIMO sniffer
* added support for RRM by scan
* added support for packet injection
* migrate to devm memory allocation handling
* some fixes, mostly in DQA and new HW support
* other generic cleanups
parents 80ba4f1d 0979a913
......@@ -33,9 +33,6 @@
#define CREATE_TRACE_POINTS
#include "iwl-devtrace.h"
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
......
......@@ -256,6 +256,10 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;
* instead of 3.
* @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size
* (command version 3) that supports per-chain limits
* @IWL_UCODE_TLV_API_SCAN_TSF_REPORT: Scan start time reported in scan
* iteration complete notification, and the timestamp reported for RX
* received during scan, are reported in TSF of the mac specified in the
* scan request.
*
* @NUM_IWL_UCODE_TLV_API: number of bits used
*/
......@@ -267,6 +271,7 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20,
IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY = (__force iwl_ucode_tlv_api_t)24,
IWL_UCODE_TLV_API_TX_POWER_CHAIN = (__force iwl_ucode_tlv_api_t)27,
IWL_UCODE_TLV_API_SCAN_TSF_REPORT = (__force iwl_ucode_tlv_api_t)28,
NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__
......
......@@ -99,8 +99,12 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
continue;
for (i = 0; i < w->n_cmds; i++) {
if (w->cmds[i] ==
WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) {
u16 rec_id = WIDE_ID(pkt->hdr.group_id,
pkt->hdr.cmd);
if (w->cmds[i] == rec_id ||
(!iwl_cmd_groupid(w->cmds[i]) &&
DEF_ID(w->cmds[i]) == rec_id)) {
found = true;
break;
}
......
......@@ -67,6 +67,7 @@
#include <linux/export.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#include "iwl-drv.h"
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
......@@ -564,11 +565,16 @@ static void iwl_set_hw_address_from_csr(struct iwl_trans *trans,
__le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP));
__le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP));
/* If OEM did not fuse address - get it from OTP */
if (!mac_addr0 && !mac_addr1) {
mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP));
mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP));
}
iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
/*
* If the OEM fused a valid address, use it instead of the one in the
* OTP
*/
if (is_valid_ether_addr(data->hw_addr))
return;
mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP));
mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP));
iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
}
......@@ -899,3 +905,91 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
return regd;
}
IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);
#ifdef CONFIG_ACPI
#define WRDD_METHOD "WRDD"
#define WRDD_WIFI (0x07)
#define WRDD_WIGIG (0x10)
static u32 iwl_wrdd_get_mcc(struct device *dev, union acpi_object *wrdd)
{
union acpi_object *mcc_pkg, *domain_type, *mcc_value;
u32 i;
if (wrdd->type != ACPI_TYPE_PACKAGE ||
wrdd->package.count < 2 ||
wrdd->package.elements[0].type != ACPI_TYPE_INTEGER ||
wrdd->package.elements[0].integer.value != 0) {
IWL_DEBUG_EEPROM(dev, "Unsupported wrdd structure\n");
return 0;
}
for (i = 1 ; i < wrdd->package.count ; ++i) {
mcc_pkg = &wrdd->package.elements[i];
if (mcc_pkg->type != ACPI_TYPE_PACKAGE ||
mcc_pkg->package.count < 2 ||
mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
mcc_pkg = NULL;
continue;
}
domain_type = &mcc_pkg->package.elements[0];
if (domain_type->integer.value == WRDD_WIFI)
break;
mcc_pkg = NULL;
}
if (mcc_pkg) {
mcc_value = &mcc_pkg->package.elements[1];
return mcc_value->integer.value;
}
return 0;
}
int iwl_get_bios_mcc(struct device *dev, char *mcc)
{
acpi_handle root_handle;
acpi_handle handle;
struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_status status;
u32 mcc_val;
root_handle = ACPI_HANDLE(dev);
if (!root_handle) {
IWL_DEBUG_EEPROM(dev,
"Could not retrieve root port ACPI handle\n");
return -ENOENT;
}
/* Get the method's handle */
status = acpi_get_handle(root_handle, (acpi_string)WRDD_METHOD,
&handle);
if (ACPI_FAILURE(status)) {
IWL_DEBUG_EEPROM(dev, "WRD method not found\n");
return -ENOENT;
}
/* Call WRDD with no arguments */
status = acpi_evaluate_object(handle, NULL, NULL, &wrdd);
if (ACPI_FAILURE(status)) {
IWL_DEBUG_EEPROM(dev, "WRDC invocation failed (0x%x)\n",
status);
return -ENOENT;
}
mcc_val = iwl_wrdd_get_mcc(dev, wrdd.pointer);
kfree(wrdd.pointer);
if (!mcc_val)
return -ENOENT;
mcc[0] = (mcc_val >> 8) & 0xff;
mcc[1] = mcc_val & 0xff;
mcc[2] = '\0';
return 0;
}
IWL_EXPORT_SYMBOL(iwl_get_bios_mcc);
#endif
......@@ -5,7 +5,8 @@
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2008 - 2015 Intel Corporation. All rights reserved.
* Copyright(c) 2016 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
......@@ -93,4 +94,21 @@ struct ieee80211_regdomain *
iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
int num_of_ch, __le32 *channels, u16 fw_mcc);
#ifdef CONFIG_ACPI
/**
* iwl_get_bios_mcc - read MCC from BIOS, if available
*
* @dev: the struct device
* @mcc: output buffer (3 bytes) that will get the MCC
*
* This function tries to read the current MCC from ACPI if available.
*/
int iwl_get_bios_mcc(struct device *dev, char *mcc);
#else
static inline int iwl_get_bios_mcc(struct device *dev, char *mcc)
{
return -ENOENT;
}
#endif
#endif /* __iwl_nvm_parse_h__ */
......@@ -110,7 +110,7 @@ enum iwl_phy_db_section_type {
IWL_PHY_DB_MAX
};
#define PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */
#define PHY_DB_CMD 0x6c
/*
* phy db - configure operational ucode
......
......@@ -78,7 +78,7 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
static struct lock_class_key __key;
#endif
trans = kzalloc(sizeof(*trans) + priv_size, GFP_KERNEL);
trans = devm_kzalloc(dev, sizeof(*trans) + priv_size, GFP_KERNEL);
if (!trans)
return NULL;
......@@ -103,18 +103,14 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
SLAB_HWCACHE_ALIGN,
NULL);
if (!trans->dev_cmd_pool)
goto free;
return NULL;
return trans;
free:
kfree(trans);
return NULL;
}
void iwl_trans_free(struct iwl_trans *trans)
{
kmem_cache_destroy(trans->dev_cmd_pool);
kfree(trans);
}
int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
......@@ -140,6 +136,9 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
if (!(cmd->flags & CMD_ASYNC))
lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
if (trans->wide_cmd_header && !iwl_cmd_groupid(cmd->id))
cmd->id = DEF_ID(cmd->id);
ret = trans->ops->send_cmd(trans, cmd);
if (!(cmd->flags & CMD_ASYNC))
......
......@@ -153,6 +153,7 @@ static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version)
/* make u16 wide id out of u8 group and opcode */
#define WIDE_ID(grp, opcode) ((grp << 8) | opcode)
#define DEF_ID(opcode) ((1 << 8) | (opcode))
/* due to the conversion, this group is special; new groups
* should be defined in the appropriate fw-api header files
......@@ -484,7 +485,6 @@ struct iwl_hcmd_arr {
* @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue
* @wide_cmd_header: firmware supports wide host command header
* @sw_csum_tx: transport should compute the TCP checksum
* @command_groups: array of command groups, each member is an array of the
* commands in the group; for debugging only
......@@ -506,7 +506,6 @@ struct iwl_trans_config {
enum iwl_amsdu_size rx_buf_size;
bool bc_table_dword;
bool scd_set_active;
bool wide_cmd_header;
bool sw_csum_tx;
const struct iwl_hcmd_arr *command_groups;
int command_groups_size;
......@@ -770,6 +769,7 @@ enum iwl_plat_pm_mode {
* @hw_id_str: a string with info about HW ID. Set during transport allocation.
* @pm_support: set to true in start_hw if link pm is supported
* @ltr_enabled: set to true if the LTR is enabled
* @wide_cmd_header: true when ucode supports wide command header format
* @num_rx_queues: number of RX queues allocated by the transport;
* the transport must set this before calling iwl_drv_start()
* @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
......@@ -821,6 +821,7 @@ struct iwl_trans {
const struct iwl_hcmd_arr *command_groups;
int command_groups_size;
bool wide_cmd_header;
u8 num_rx_queues;
......
......@@ -504,6 +504,28 @@ static inline char *iwl_dbgfs_is_match(char *name, char *buf)
return !strncmp(name, buf, len) ? buf + len : NULL;
}
static ssize_t iwl_dbgfs_os_device_timediff_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;
u32 curr_gp2;
u64 curr_os;
s64 diff;
char buf[64];
const size_t bufsz = sizeof(buf);
int pos = 0;
iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os);
do_div(curr_os, NSEC_PER_USEC);
diff = curr_os - curr_gp2;
pos += scnprintf(buf + pos, bufsz - pos, "diff=%lld\n", diff);
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)
......@@ -1530,6 +1552,8 @@ 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_WRITE_FILE_OPS(lqm_send_cmd, 64);
MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff);
void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
......@@ -1570,6 +1594,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE_VIF(lqm_send_cmd, mvmvif->dbgfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff,
mvmvif->dbgfs_dir, S_IRUSR);
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
......
......@@ -917,6 +917,59 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
return ret ?: count;
}
static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm,
char *buf, size_t count,
loff_t *ppos)
{
struct iwl_rx_cmd_buffer rxb = {
._rx_page_order = 0,
.truesize = 0, /* not used */
._offset = 0,
};
struct iwl_rx_packet *pkt;
struct iwl_rx_mpdu_desc *desc;
int bin_len = count / 2;
int ret = -EINVAL;
/* supporting only 9000 descriptor */
if (!mvm->trans->cfg->mq_rx_supported)
return -ENOTSUPP;
rxb._page = alloc_pages(GFP_ATOMIC, 0);
if (!rxb._page)
return -ENOMEM;
pkt = rxb_addr(&rxb);
ret = hex2bin(page_address(rxb._page), buf, bin_len);
if (ret)
goto out;
/* avoid invalid memory access */
if (bin_len < sizeof(*pkt) + sizeof(*desc))
goto out;
/* check this is RX packet */
if (WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd) !=
WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD))
goto out;
/* check the length in metadata matches actual received length */
desc = (void *)pkt->data;
if (le16_to_cpu(desc->mpdu_len) !=
(bin_len - sizeof(*desc) - sizeof(*pkt)))
goto out;
local_bh_disable();
iwl_mvm_rx_mpdu_mq(mvm, NULL, &rxb, 0);
local_bh_enable();
ret = 0;
out:
iwl_free_rxb(&rxb);
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)
......@@ -1454,6 +1507,7 @@ 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);
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
......@@ -1464,6 +1518,132 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
#endif
static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
struct iwl_dbg_mem_access_cmd cmd = {};
struct iwl_dbg_mem_access_rsp *rsp;
struct iwl_host_cmd hcmd = {
.flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
.data = { &cmd, },
.len = { sizeof(cmd) },
};
size_t delta, len;
ssize_t ret;
hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
DEBUG_GROUP, 0);
cmd.op = cpu_to_le32(DEBUG_MEM_OP_READ);
/* Take care of alignment of both the position and the length */
delta = *ppos & 0x3;
cmd.addr = cpu_to_le32(*ppos - delta);
cmd.len = cpu_to_le32(min(ALIGN(count + delta, 4) / 4,
(size_t)DEBUG_MEM_MAX_SIZE_DWORDS));
mutex_lock(&mvm->mutex);
ret = iwl_mvm_send_cmd(mvm, &hcmd);
mutex_unlock(&mvm->mutex);
if (ret < 0)
return ret;
rsp = (void *)hcmd.resp_pkt->data;
if (le32_to_cpu(rsp->status) != DEBUG_MEM_STATUS_SUCCESS) {
ret = -ENXIO;
goto out;
}
len = min((size_t)le32_to_cpu(rsp->len) << 2,
iwl_rx_packet_payload_len(hcmd.resp_pkt) - sizeof(*rsp));
len = min(len - delta, count);
if (len < 0) {
ret = -EFAULT;
goto out;
}
ret = len - copy_to_user(user_buf, (void *)rsp->data + delta, len);
*ppos += ret;
out:
iwl_free_resp(&hcmd);
return ret;
}
static ssize_t iwl_dbgfs_mem_write(struct file *file,
const char __user *user_buf, size_t count,
loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
struct iwl_dbg_mem_access_cmd *cmd;
struct iwl_dbg_mem_access_rsp *rsp;
struct iwl_host_cmd hcmd = {};
size_t cmd_size;
size_t data_size;
u32 op, len;
ssize_t ret;
hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
DEBUG_GROUP, 0);
if (*ppos & 0x3 || count < 4) {
op = DEBUG_MEM_OP_WRITE_BYTES;
len = min(count, (size_t)(4 - (*ppos & 0x3)));
data_size = len;
} else {
op = DEBUG_MEM_OP_WRITE;
len = min(count >> 2, (size_t)DEBUG_MEM_MAX_SIZE_DWORDS);
data_size = len << 2;
}
cmd_size = sizeof(*cmd) + ALIGN(data_size, 4);
cmd = kzalloc(cmd_size, GFP_KERNEL);
if (!cmd)
return -ENOMEM;
cmd->op = cpu_to_le32(op);
cmd->len = cpu_to_le32(len);
cmd->addr = cpu_to_le32(*ppos);
if (copy_from_user((void *)cmd->data, user_buf, data_size)) {
kfree(cmd);
return -EFAULT;
}
hcmd.flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
hcmd.data[0] = (void *)cmd;
hcmd.len[0] = cmd_size;
mutex_lock(&mvm->mutex);
ret = iwl_mvm_send_cmd(mvm, &hcmd);
mutex_unlock(&mvm->mutex);
kfree(cmd);
if (ret < 0)
return ret;
rsp = (void *)hcmd.resp_pkt->data;
if (rsp->status != DEBUG_MEM_STATUS_SUCCESS) {
ret = -ENXIO;
goto out;
}
ret = data_size;
*ppos += ret;
out:
iwl_free_resp(&hcmd);
return ret;
}
static const struct file_operations iwl_dbgfs_mem_ops = {
.read = iwl_dbgfs_mem_read,
.write = iwl_dbgfs_mem_write,
.open = simple_open,
.llseek = default_llseek,
};
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
{
struct dentry *bcast_dir __maybe_unused;
......@@ -1502,6 +1682,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, S_IWUSR);
if (!debugfs_create_bool("enable_scan_iteration_notif",
S_IRUSR | S_IWUSR,
mvm->debugfs_dir,
......@@ -1560,6 +1741,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
mvm->debugfs_dir, &mvm->nvm_phy_sku_blob))
goto err;
debugfs_create_file("mem", S_IRUSR | S_IWUSR, dbgfs_dir, mvm,
&iwl_dbgfs_mem_ops);
/*
* Create a symlink with mac80211. It will be removed when mac80211
* exists (before the opmode exists which removes the target.)
......
......@@ -7,6 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 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
......@@ -603,6 +604,8 @@ struct iwl_scan_req_umac_tail {
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
* @ooc_priority: out of channel priority - &enum iwl_scan_priority
* @general_flags: &enum iwl_umac_scan_general_flags
* @reserved2: for future use and alignment
* @scan_start_mac_id: report the scan start TSF time according to this mac TSF
* @extended_dwell: dwell time for channels 1, 6 and 11
* @active_dwell: dwell time for active scan
* @passive_dwell: dwell time for passive scan
......@@ -620,8 +623,10 @@ struct iwl_scan_req_umac {
__le32 flags;
__le32 uid;
__le32 ooc_priority;
/* SCAN_GENERAL_PARAMS_API_S_VER_1 */
__le32 general_flags;
/* SCAN_GENERAL_PARAMS_API_S_VER_4 */
__le16 general_flags;
u8 reserved2;
u8 scan_start_mac_id;
u8 extended_dwell;
u8 active_dwell;
u8 passive_dwell;
......@@ -629,7 +634,7 @@ struct iwl_scan_req_umac {
__le32 max_out_time;
__le32 suspend_time;
__le32 scan_priority;
/* SCAN_CHANNEL_PARAMS_API_S_VER_1 */
/* SCAN_CHANNEL_PARAMS_API_S_VER_4 */
u8 channel_flags;
u8 n_channels;
__le16 reserved;
......@@ -718,8 +723,8 @@ struct iwl_scan_offload_profiles_query {
* @status: one of SCAN_COMP_STATUS_*
* @bt_status: BT on/off status
* @last_channel: last channel that was scanned
* @tsf_low: TSF timer (lower half) in usecs
* @tsf_high: TSF timer (higher half) in usecs
* @start_tsf: TSF timer in usecs of the scan start time for the mac specified
* in &struct iwl_scan_req_umac.
* @results: array of scan results, only "scanned_channels" of them are valid
*/
struct iwl_umac_scan_iter_complete_notif {
......@@ -728,9 +733,8 @@ struct iwl_umac_scan_iter_complete_notif {
u8 status;
u8 bt_status;
u8 last_channel;
__le32 tsf_low;
__le32 tsf_high;
__le64 start_tsf;
struct iwl_scan_results_notif results[];
} __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_1 */
} __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_2 */
#endif
......@@ -205,7 +205,7 @@ enum {
/* Phy */
PHY_CONFIGURATION_CMD = 0x6a,
CALIB_RES_NOTIF_PHY_DB = 0x6b,
/* PHY_DB_CMD = 0x6c, */
PHY_DB_CMD = 0x6c,
/* ToF - 802.11mc FTM */
TOF_CMD = 0x10,
......@@ -340,6 +340,11 @@ enum iwl_prot_offload_subcmd_ids {
STORED_BEACON_NTF = 0xFF,
};
enum iwl_fmac_debug_cmds {
LMAC_RD_WR = 0x0,
UMAC_RD_WR = 0x1,
};
/* command groups */
enum {
LEGACY_GROUP = 0x0,
......@@ -349,6 +354,7 @@ enum {
PHY_OPS_GROUP = 0x4,
DATA_PATH_GROUP = 0x5,
PROT_OFFLOAD_GROUP = 0xb,
DEBUG_GROUP = 0xf,
};
/**
......@@ -2149,4 +2155,48 @@ struct iwl_channel_switch_noa_notif {
__le32 id_and_color;
} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */
/* Operation types for the debug mem access */
enum {
DEBUG_MEM_OP_READ = 0,
DEBUG_MEM_OP_WRITE = 1,
DEBUG_MEM_OP_WRITE_BYTES = 2,
};
#define DEBUG_MEM_MAX_SIZE_DWORDS 32
/**
* struct iwl_dbg_mem_access_cmd - Request the device to read/write memory
* @op: DEBUG_MEM_OP_*
* @addr: address to read/write from/to
* @len: in dwords, to read/write
* @data: for write opeations, contains the source buffer
*/
struct iwl_dbg_mem_access_cmd {
__le32 op;
__le32 addr;
__le32 len;
__le32 data[];
} __packed; /* DEBUG_(U|L)MAC_RD_WR_CMD_API_S_VER_1 */
/* Status responses for the debug mem access */
enum {
DEBUG_MEM_STATUS_SUCCESS = 0x0,
DEBUG_MEM_STATUS_FAILED = 0x1,
DEBUG_MEM_STATUS_LOCKED = 0x2,
DEBUG_MEM_STATUS_HIDDEN = 0x3,
DEBUG_MEM_STATUS_LENGTH = 0x4,
};
/**
* struct iwl_dbg_mem_access_rsp - Response to debug mem commands
* @status: DEBUG_MEM_STATUS_*
* @len: read dwords (0 for write operations)
* @data: contains the read DWs
*/
struct iwl_dbg_mem_access_rsp {
__le32 status;
__le32 len;
__le32 data[];
} __packed; /* DEBUG_(U|L)MAC_RD_WR_RSP_API_S_VER_1 */
#endif /* __fw_api_h__ */
......@@ -539,6 +539,11 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
IWL_MVM_OFFCHANNEL_QUEUE,
IWL_MAX_TID_COUNT, 0);
else
iwl_mvm_disable_txq(mvm,
IWL_MVM_DQA_P2P_DEVICE_QUEUE,
vif->hw_queue[0], IWL_MAX_TID_COUNT,
0);
break;
case NL80211_IFTYPE_AP:
......@@ -769,26 +774,6 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->ac[txf].fifos_mask = BIT(txf);
}
if (vif->type == NL80211_IFTYPE_AP) {
/* in AP mode, the MCAST FIFO takes the EDCA params from VO */
cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |=
BIT(IWL_MVM_TX_FIFO_MCAST);
/*
* in AP mode, pass probe requests and beacons from other APs
* (needed for ht protection); when there're no any associated
* station don't ask FW to pass beacons to prevent unnecessary
* wake-ups.
*/
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
if (mvmvif->ap_assoc_sta_count || !mvm->drop_bcn_ap_mode) {
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
} else {
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
}
if (vif->bss_conf.qos)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
......@@ -1186,6 +1171,7 @@ static void iwl_mvm_mac_ap_iterator(void *_data, u8 *mac,
*/
static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_ctx_cmd *cmd,
struct iwl_mac_data_ap *ctxt_ap,
bool add)
{
......@@ -1196,6 +1182,23 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
.beacon_device_ts = 0
};
/* in AP mode, the MCAST FIFO takes the EDCA params from VO */
cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST);
/*
* in AP mode, pass probe requests and beacons from other APs
* (needed for ht protection); when there're no any associated
* station don't ask FW to pass beacons to prevent unnecessary
* wake-ups.
*/
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
if (mvmvif->ap_assoc_sta_count || !mvm->drop_bcn_ap_mode) {
cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
} else {
IWL_DEBUG_HC(mvm, "No need to receive beacons\n");
}
ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
ctxt_ap->bi_reciprocal =
cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int));
......@@ -1253,7 +1256,7 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/* Fill the data specific for ap mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap,
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd, &cmd.ap,
action == FW_CTXT_ACTION_ADD);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
......@@ -1272,7 +1275,7 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/* Fill the data specific for GO mode */
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd, &cmd.go.ap,
action == FW_CTXT_ACTION_ADD);
cmd.go.ctwin = cpu_to_le32(noa->oppps_ctwindow &
......
......@@ -653,6 +653,16 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES;
if (fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_SCAN_TSF_REPORT)) {
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_SCAN_START_TIME);
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_BSS_PARENT_TSF);
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_SET_SCAN_DWELL);
}
mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
#ifdef CONFIG_PM_SLEEP
......@@ -720,6 +730,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (ret)
iwl_mvm_leds_exit(mvm);
if (mvm->cfg->vht_mu_mimo_supported)
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
return ret;
}
......@@ -2229,6 +2243,10 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
case NL80211_IFTYPE_ADHOC:
iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes);
break;
case NL80211_IFTYPE_MONITOR:
if (changes & BSS_CHANGED_MU_GROUPS)
iwl_mvm_update_mu_groups(mvm, vif);
break;
default:
/* shouldn't happen */
WARN_ON_ONCE(1);
......
......@@ -821,6 +821,12 @@ struct iwl_mvm {
/* UMAC scan tracking */
u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS];
/* start time of last scan in TSF of the mac that requested the scan */
u64 scan_start;
/* the vif that requested the current scan */
struct iwl_mvm_vif *scan_vif;
/* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant;
......@@ -1262,6 +1268,7 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
u8 first_antenna(u8 mask);
u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime);
/* Tx / Host Commands */
int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm,
......
......@@ -66,7 +66,6 @@
*****************************************************************************/
#include <linux/firmware.h>
#include <linux/rtnetlink.h>
#include <linux/acpi.h>
#include "iwl-trans.h"
#include "iwl-csr.h"
#include "mvm.h"
......@@ -751,96 +750,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
return resp_cp;
}
#ifdef CONFIG_ACPI
#define WRD_METHOD "WRDD"
#define WRDD_WIFI (0x07)
#define WRDD_WIGIG (0x10)
static u32 iwl_mvm_wrdd_get_mcc(struct iwl_mvm *mvm, union acpi_object *wrdd)
{
union acpi_object *mcc_pkg, *domain_type, *mcc_value;
u32 i;
if (wrdd->type != ACPI_TYPE_PACKAGE ||
wrdd->package.count < 2 ||
wrdd->package.elements[0].type != ACPI_TYPE_INTEGER ||
wrdd->package.elements[0].integer.value != 0) {
IWL_DEBUG_LAR(mvm, "Unsupported wrdd structure\n");
return 0;
}
for (i = 1 ; i < wrdd->package.count ; ++i) {
mcc_pkg = &wrdd->package.elements[i];
if (mcc_pkg->type != ACPI_TYPE_PACKAGE ||
mcc_pkg->package.count < 2 ||
mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
mcc_pkg = NULL;
continue;
}
domain_type = &mcc_pkg->package.elements[0];
if (domain_type->integer.value == WRDD_WIFI)
break;
mcc_pkg = NULL;
}
if (mcc_pkg) {
mcc_value = &mcc_pkg->package.elements[1];
return mcc_value->integer.value;
}
return 0;
}
static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc)
{
acpi_handle root_handle;
acpi_handle handle;
struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_status status;
u32 mcc_val;
root_handle = ACPI_HANDLE(mvm->dev);
if (!root_handle) {
IWL_DEBUG_LAR(mvm,
"Could not retrieve root port ACPI handle\n");
return -ENOENT;
}
/* Get the method's handle */
status = acpi_get_handle(root_handle, (acpi_string)WRD_METHOD, &handle);
if (ACPI_FAILURE(status)) {
IWL_DEBUG_LAR(mvm, "WRD method not found\n");
return -ENOENT;
}
/* Call WRDD with no arguments */
status = acpi_evaluate_object(handle, NULL, NULL, &wrdd);
if (ACPI_FAILURE(status)) {
IWL_DEBUG_LAR(mvm, "WRDC invocation failed (0x%x)\n", status);
return -ENOENT;
}
mcc_val = iwl_mvm_wrdd_get_mcc(mvm, wrdd.pointer);
kfree(wrdd.pointer);
if (!mcc_val)
return -ENOENT;
mcc[0] = (mcc_val >> 8) & 0xff;
mcc[1] = mcc_val & 0xff;
mcc[2] = '\0';
return 0;
}
#else /* CONFIG_ACPI */
static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc)
{
return -ENOENT;
}
#endif
int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
{
bool tlv_lar;
......@@ -884,7 +793,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
return -EIO;
if (iwl_mvm_is_wifi_mcc_supported(mvm) &&
!iwl_mvm_get_bios_mcc(mvm, mcc)) {
!iwl_get_bios_mcc(mvm->dev, mcc)) {
kfree(regd);
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc,
MCC_SOURCE_BIOS, NULL);
......
......@@ -359,6 +359,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
HCMD_NAME(BT_COEX_CI),
HCMD_NAME(PHY_CONFIGURATION_CMD),
HCMD_NAME(CALIB_RES_NOTIF_PHY_DB),
HCMD_NAME(PHY_DB_CMD),
HCMD_NAME(SCAN_OFFLOAD_COMPLETE),
HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
HCMD_NAME(SCAN_OFFLOAD_CONFIG_CMD),
......@@ -652,8 +653,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
/* the hardware splits the A-MSDU */
if (mvm->cfg->mq_rx_supported)
trans_cfg.rx_buf_size = IWL_AMSDU_4K;
trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_WIDE_CMD_HDR);
trans->wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_WIDE_CMD_HDR);
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)
trans_cfg.bc_table_dword = true;
......@@ -857,9 +858,7 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk)
struct iwl_mvm *mvm =
container_of(wk, struct iwl_mvm, async_handlers_wk);
struct iwl_async_handler_entry *entry, *tmp;
struct list_head local_list;
INIT_LIST_HEAD(&local_list);
LIST_HEAD(local_list);
/* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */
......@@ -966,10 +965,11 @@ static void iwl_mvm_rx(struct iwl_op_mode *op_mode,
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
u16 cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
if (likely(cmd == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD)))
iwl_mvm_rx_rx_mpdu(mvm, napi, rxb);
else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
else if (cmd == WIDE_ID(LEGACY_GROUP, REPLY_RX_PHY_CMD))
iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
else
iwl_mvm_rx_common(mvm, rxb, pkt);
......@@ -981,13 +981,14 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
u16 cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
if (likely(cmd == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD)))
iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0);
else if (unlikely(pkt->hdr.group_id == DATA_PATH_GROUP &&
pkt->hdr.cmd == RX_QUEUES_NOTIFICATION))
else if (unlikely(cmd == WIDE_ID(DATA_PATH_GROUP,
RX_QUEUES_NOTIFICATION)))
iwl_mvm_rx_queue_notif(mvm, rxb, 0);
else if (pkt->hdr.cmd == FRAME_RELEASE)
else if (cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE))
iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
else
iwl_mvm_rx_common(mvm, rxb, pkt);
......@@ -1666,13 +1667,14 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode,
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
struct iwl_rx_packet *pkt = rxb_addr(rxb);
u16 cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
if (unlikely(pkt->hdr.cmd == FRAME_RELEASE))
if (unlikely(cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE)))
iwl_mvm_rx_frame_release(mvm, napi, rxb, queue);
else if (unlikely(pkt->hdr.cmd == RX_QUEUES_NOTIFICATION &&
pkt->hdr.group_id == DATA_PATH_GROUP))
else if (unlikely(cmd == WIDE_ID(DATA_PATH_GROUP,
RX_QUEUES_NOTIFICATION)))
iwl_mvm_rx_queue_notif(mvm, rxb, queue);
else if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
else if (likely(cmd == WIDE_ID(LEGACY_GROUP, REPLY_RX_MPDU_CMD)))
iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue);
}
......
......@@ -418,10 +418,11 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
ssn = ieee80211_sn_inc(ssn);
/* holes are valid since nssn indicates frames were received. */
if (skb_queue_empty(skb_list) || !skb_peek_tail(skb_list))
continue;
/* Empty the list. Will have more than one frame for A-MSDU */
/*
* Empty the list. Will have more than one frame for A-MSDU.
* Empty list is valid as well since nssn indicates frames were
* received.
*/
while ((skb = __skb_dequeue(skb_list))) {
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb,
reorder_buf->queue,
......@@ -434,7 +435,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
if (reorder_buf->num_stored && !reorder_buf->removed) {
u16 index = reorder_buf->head_sn % reorder_buf->buf_size;
while (!skb_peek_tail(&reorder_buf->entries[index]))
while (skb_queue_empty(&reorder_buf->entries[index]))
index = (index + 1) % reorder_buf->buf_size;
/* modify timer to match next frame's expiration time */
mod_timer(&reorder_buf->reorder_timer,
......@@ -462,7 +463,7 @@ void iwl_mvm_reorder_timer_expired(unsigned long data)
for (i = 0; i < buf->buf_size ; i++) {
index = (buf->head_sn + i) % buf->buf_size;
if (!skb_peek_tail(&buf->entries[index]))
if (skb_queue_empty(&buf->entries[index]))
continue;
if (!time_after(jiffies, buf->reorder_time[index] +
RX_REORDER_BUF_TIMEOUT_MQ))
......@@ -590,6 +591,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK) >>
IWL_RX_MPDU_REORDER_BAID_SHIFT;
/*
* 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.
*/
if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
return false;
......@@ -599,9 +605,10 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
/* not a data packet */
if (!ieee80211_is_data_qos(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1))
/* not a data packet or a bar */
if (!ieee80211_is_back_req(hdr->frame_control) &&
(!ieee80211_is_data_qos(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1)))
return false;
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
......@@ -625,6 +632,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
spin_lock_bh(&buffer->lock);
if (ieee80211_is_back_req(hdr->frame_control)) {
iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
goto drop;
}
/*
* If there was a significant jump in the nssn - adjust.
* If the SN is smaller than the NSSN it might need to first go into
......
......@@ -141,6 +141,7 @@ struct iwl_mvm_scan_params {
struct cfg80211_match_set *match_sets;
int n_scan_plans;
struct cfg80211_sched_scan_plan *scan_plans;
u32 measurement_dwell;
};
static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
......@@ -232,6 +233,27 @@ iwl_mvm_scan_type iwl_mvm_get_scan_type(struct iwl_mvm *mvm, bool p2p_device)
return IWL_SCAN_TYPE_WILD;
}
static int
iwl_mvm_get_measurement_dwell(struct iwl_mvm *mvm,
struct cfg80211_scan_request *req,
struct iwl_mvm_scan_params *params)
{
if (!req->duration)
return 0;
if (req->duration_mandatory &&
req->duration > scan_timing[params->type].max_out_time) {
IWL_DEBUG_SCAN(mvm,
"Measurement scan - too long dwell %hu (max out time %u)\n",
req->duration,
scan_timing[params->type].max_out_time);
return -EOPNOTSUPP;
}
return min_t(u32, (u32)req->duration,
scan_timing[params->type].max_out_time);
}
static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm)
{
/* require rrm scan whenever the fw supports it */
......@@ -1033,9 +1055,15 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
struct iwl_scan_req_umac *cmd,
struct iwl_mvm_scan_params *params)
{
cmd->extended_dwell = scan_timing[params->type].dwell_extended;
cmd->active_dwell = scan_timing[params->type].dwell_active;
cmd->passive_dwell = scan_timing[params->type].dwell_passive;
if (params->measurement_dwell) {
cmd->active_dwell = params->measurement_dwell;
cmd->passive_dwell = params->measurement_dwell;
cmd->extended_dwell = params->measurement_dwell;
} else {
cmd->active_dwell = scan_timing[params->type].dwell_active;
cmd->passive_dwell = scan_timing[params->type].dwell_passive;
cmd->extended_dwell = scan_timing[params->type].dwell_extended;
}
cmd->fragmented_dwell = scan_timing[params->type].dwell_fragmented;
cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time);
cmd->suspend_time = cpu_to_le32(scan_timing[params->type].suspend_time);
......@@ -1067,11 +1095,11 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm,
}
}
static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
struct ieee80211_vif *vif)
{
int flags = 0;
u16 flags = 0;
if (params->n_ssids == 0)
flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE;
......@@ -1093,6 +1121,9 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
if (!iwl_mvm_is_regular_scan(params))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
if (params->measurement_dwell)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
#ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvm->scan_iter_notif_enabled)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
......@@ -1119,6 +1150,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvm->fw->ucode_capa.n_scan_channels;
int uid, i;
u32 ssid_bitmap = 0;
struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif);
lockdep_assert_held(&mvm->mutex);
......@@ -1136,8 +1168,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvm->scan_uid_status[uid] = type;
cmd->uid = cpu_to_le32(uid);
cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params,
cmd->general_flags = cpu_to_le16(iwl_mvm_scan_umac_flags(mvm, params,
vif));
cmd->scan_start_mac_id = scan_vif->id;
if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT)
cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
......@@ -1289,6 +1322,12 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_get_scan_type(mvm,
vif->type == NL80211_IFTYPE_P2P_DEVICE);
ret = iwl_mvm_get_measurement_dwell(mvm, req, &params);
if (ret < 0)
return ret;
params.measurement_dwell = ret;
iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
......@@ -1315,6 +1354,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
mvm->scan_vif = iwl_mvm_vif_from_mac80211(vif);
iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
queue_delayed_work(system_wq, &mvm->scan_timeout_dwork,
......@@ -1437,9 +1477,12 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) {
struct cfg80211_scan_info info = {
.aborted = aborted,
.scan_start_tsf = mvm->scan_start,
};
memcpy(info.tsf_bssid, mvm->scan_vif->bssid, ETH_ALEN);
ieee80211_scan_completed(mvm->hw, &info);
mvm->scan_vif = NULL;
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
cancel_delayed_work(&mvm->scan_timeout_dwork);
} else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
......@@ -1473,6 +1516,8 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data;
u8 buf[256];
mvm->scan_start = le64_to_cpu(notif->start_tsf);
IWL_DEBUG_SCAN(mvm,
"UMAC Scan iteration complete: status=0x%x scanned_channels=%d channels list: %s\n",
notif->status, notif->scanned_channels,
......@@ -1485,6 +1530,10 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
ieee80211_sched_scan_results(mvm->hw);
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED;
}
IWL_DEBUG_SCAN(mvm,
"UMAC Scan iteration complete: scan started at %llu (TSF)\n",
mvm->scan_start);
}
static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
......
......@@ -745,14 +745,14 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
.scd_queue = queue,
.action = SCD_CFG_DISABLE_QUEUE,
};
u8 ac;
u8 txq_curr_ac;
disable_agg_tids = iwl_mvm_remove_sta_queue_marking(mvm, queue);
spin_lock_bh(&mvm->queue_info_lock);
ac = mvm->queue_info[queue].mac80211_ac;
txq_curr_ac = mvm->queue_info[queue].mac80211_ac;
cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[ac];
cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[txq_curr_ac];
cmd.tid = mvm->queue_info[queue].txq_tid;
spin_unlock_bh(&mvm->queue_info_lock);
......@@ -1297,13 +1297,6 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
return ret;
}
int iwl_mvm_update_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
return iwl_mvm_sta_send_to_fw(mvm, sta, true, 0);
}
int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool drain)
{
......
......@@ -473,9 +473,14 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int iwl_mvm_add_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int iwl_mvm_update_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
static inline int iwl_mvm_update_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
return iwl_mvm_sta_send_to_fw(mvm, sta, true, 0);
}
int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
......
......@@ -490,16 +490,34 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
struct ieee80211_tx_info *info, __le16 fc)
{
if (iwl_mvm_is_dqa_supported(mvm)) {
if (info->control.vif->type == NL80211_IFTYPE_AP &&
ieee80211_is_probe_resp(fc))
if (!iwl_mvm_is_dqa_supported(mvm))
return info->hw_queue;
switch (info->control.vif->type) {
case NL80211_IFTYPE_AP:
/*
* handle legacy hostapd as well, where station may be added
* only after assoc.
*/
if (ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc))
return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
else if (ieee80211_is_mgmt(fc) &&
info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE)
if (info->hw_queue == info->control.vif->cab_queue)
return info->hw_queue;
WARN_ON_ONCE(1);
return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
case NL80211_IFTYPE_P2P_DEVICE:
if (ieee80211_is_mgmt(fc))
return IWL_MVM_DQA_P2P_DEVICE_QUEUE;
}
if (info->hw_queue == info->control.vif->cab_queue)
return info->hw_queue;
return info->hw_queue;
WARN_ON_ONCE(1);
return IWL_MVM_DQA_P2P_DEVICE_QUEUE;
default:
WARN_ONCE(1, "Not a ctrl vif, no available queue\n");
return -1;
}
}
int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
......@@ -560,6 +578,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
sta_id = mvmvif->bcast_sta.sta_id;
queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info,
hdr->frame_control);
if (queue < 0)
return -1;
} else if (info.control.vif->type == NL80211_IFTYPE_STATION &&
is_multicast_ether_addr(hdr->addr1)) {
u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id);
......
......@@ -1225,6 +1225,28 @@ void iwl_mvm_inactivity_check(struct iwl_mvm *mvm)
rcu_read_unlock();
}
void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime)
{
bool ps_disabled;
lockdep_assert_held(&mvm->mutex);
/* Disable power save when reading GP2 */
ps_disabled = mvm->ps_disabled;
if (!ps_disabled) {
mvm->ps_disabled = true;
iwl_mvm_power_update_device(mvm);
}
*gp2 = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
*boottime = ktime_get_boot_ns();
if (!ps_disabled) {
mvm->ps_disabled = ps_disabled;
iwl_mvm_power_update_device(mvm);
}
}
int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif,
enum iwl_lqm_cmd_operatrions operation,
u32 duration, u32 timeout)
......
......@@ -487,6 +487,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x24FD, 0x1130, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x0130, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x1010, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x10D0, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x0050, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x0150, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x9010, iwl8265_2ac_cfg)},
......
......@@ -332,7 +332,6 @@ enum iwl_shared_irq_flags {
* @rx_buf_size: Rx buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue
* @wide_cmd_header: true when ucode supports wide command header format
* @sw_csum_tx: if true, then the transport will compute the csum of the TXed
* frame.
* @rx_page_order: page order for receive buffer size
......@@ -405,7 +404,6 @@ struct iwl_trans_pcie {
enum iwl_amsdu_size rx_buf_size;
bool bc_table_dword;
bool scd_set_active;
bool wide_cmd_header;
bool sw_csum_tx;
u32 rx_page_order;
......
......@@ -487,15 +487,13 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
while (pending) {
int i;
struct list_head local_allocated;
LIST_HEAD(local_allocated);
gfp_t gfp_mask = GFP_KERNEL;
/* Do not post a warning if there are only a few requests */
if (pending < RX_PENDING_WATERMARK)
gfp_mask |= __GFP_NOWARN;
INIT_LIST_HEAD(&local_allocated);
for (i = 0; i < RX_CLAIM_REQ_ALLOC;) {
struct iwl_rx_mem_buffer *rxb;
struct page *page;
......@@ -1108,13 +1106,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
FH_RSCSR_RXQ_POS != rxq->id);
IWL_DEBUG_RX(trans,
"cmd at offset %d: %s (0x%.2x, seq 0x%x)\n",
"cmd at offset %d: %s (%.2x.%2x, seq 0x%x)\n",
rxcb._offset,
iwl_get_cmd_string(trans,
iwl_cmd_id(pkt->hdr.cmd,
pkt->hdr.group_id,
0)),
pkt->hdr.cmd, le16_to_cpu(pkt->hdr.sequence));
pkt->hdr.group_id, pkt->hdr.cmd,
le16_to_cpu(pkt->hdr.sequence));
len = iwl_rx_packet_len(pkt);
len += sizeof(u32); /* account for status word */
......
......@@ -1605,24 +1605,22 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,
for (i = 0; i < trans_pcie->alloc_vecs; i++) {
int ret;
ret = request_threaded_irq(trans_pcie->msix_entries[i].vector,
iwl_pcie_msix_isr,
(i == trans_pcie->def_irq) ?
iwl_pcie_irq_msix_handler :
iwl_pcie_irq_rx_msix_handler,
IRQF_SHARED,
DRV_NAME,
&trans_pcie->msix_entries[i]);
struct msix_entry *msix_entry;
msix_entry = &trans_pcie->msix_entries[i];
ret = devm_request_threaded_irq(&pdev->dev,
msix_entry->vector,
iwl_pcie_msix_isr,
(i == trans_pcie->def_irq) ?
iwl_pcie_irq_msix_handler :
iwl_pcie_irq_rx_msix_handler,
IRQF_SHARED,
DRV_NAME,
msix_entry);
if (ret) {
int j;
IWL_ERR(trans_pcie->trans,
"Error allocating IRQ %d\n", i);
for (j = 0; j < i; j++)
free_irq(trans_pcie->msix_entries[j].vector,
&trans_pcie->msix_entries[j]);
pci_disable_msix(pdev);
return ret;
}
}
......@@ -1755,7 +1753,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans_pcie->rx_page_order =
iwl_trans_get_rb_size_order(trans_pcie->rx_buf_size);
trans_pcie->wide_cmd_header = trans_cfg->wide_cmd_header;
trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
trans_pcie->scd_set_active = trans_cfg->scd_set_active;
trans_pcie->sw_csum_tx = trans_cfg->sw_csum_tx;
......@@ -1790,23 +1787,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
irq_set_affinity_hint(
trans_pcie->msix_entries[i].vector,
NULL);
free_irq(trans_pcie->msix_entries[i].vector,
&trans_pcie->msix_entries[i]);
}
pci_disable_msix(trans_pcie->pci_dev);
trans_pcie->msix_enabled = false;
} else {
free_irq(trans_pcie->pci_dev->irq, trans);
iwl_pcie_free_ict(trans);
pci_disable_msi(trans_pcie->pci_dev);
}
iounmap(trans_pcie->hw_base);
pci_release_regions(trans_pcie->pci_dev);
pci_disable_device(trans_pcie->pci_dev);
iwl_pcie_free_fw_monitor(trans);
......@@ -2913,6 +2899,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
struct iwl_trans *trans;
int ret, addr_size;
ret = pcim_enable_device(pdev);
if (ret)
return ERR_PTR(ret);
trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),
&pdev->dev, cfg, &trans_ops_pcie, 0);
if (!trans)
......@@ -2931,9 +2921,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
goto out_no_pci;
}
ret = pci_enable_device(pdev);
if (ret)
goto out_no_pci;
if (!cfg->base_params->pcie_l1_allowed) {
/*
......@@ -2953,7 +2940,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
if (cfg->use_tfh) {
trans_pcie->max_tbs = IWL_TFH_NUM_TBS;
trans_pcie->tfd_size = sizeof(struct iwl_tfh_tb);
trans_pcie->tfd_size = sizeof(struct iwl_tfh_tfd);
} else {
trans_pcie->max_tbs = IWL_NUM_OF_TBS;
......@@ -2975,21 +2962,21 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
/* both attempts failed: */
if (ret) {
dev_err(&pdev->dev, "No suitable DMA available\n");
goto out_pci_disable_device;
goto out_no_pci;
}
}
ret = pci_request_regions(pdev, DRV_NAME);
ret = pcim_iomap_regions_request_all(pdev, BIT(0), DRV_NAME);
if (ret) {
dev_err(&pdev->dev, "pci_request_regions failed\n");
goto out_pci_disable_device;
dev_err(&pdev->dev, "pcim_iomap_regions_request_all failed\n");
goto out_no_pci;
}
trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
trans_pcie->hw_base = pcim_iomap_table(pdev)[0];
if (!trans_pcie->hw_base) {
dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
dev_err(&pdev->dev, "pcim_iomap_table failed\n");
ret = -ENODEV;
goto out_pci_release_regions;
goto out_no_pci;
}
/* We disable the RETRY_TIMEOUT register (0x41) to keep
......@@ -3016,7 +3003,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
ret = iwl_pcie_prepare_card_hw(trans);
if (ret) {
IWL_WARN(trans, "Exit HW not ready\n");
goto out_pci_disable_msi;
goto out_no_pci;
}
/*
......@@ -3033,7 +3020,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
25000);
if (ret < 0) {
IWL_DEBUG_INFO(trans, "Failed to wake up the nic\n");
goto out_pci_disable_msi;
goto out_no_pci;
}
if (iwl_trans_grab_nic_access(trans, &flags)) {
......@@ -3065,15 +3052,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
if (trans_pcie->msix_enabled) {
if (iwl_pcie_init_msix_handler(pdev, trans_pcie))
goto out_pci_release_regions;
goto out_no_pci;
} else {
ret = iwl_pcie_alloc_ict(trans);
if (ret)
goto out_pci_disable_msi;
goto out_no_pci;
ret = request_threaded_irq(pdev->irq, iwl_pcie_isr,
iwl_pcie_irq_handler,
IRQF_SHARED, DRV_NAME, trans);
ret = devm_request_threaded_irq(&pdev->dev, pdev->irq,
iwl_pcie_isr,
iwl_pcie_irq_handler,
IRQF_SHARED, DRV_NAME, trans);
if (ret) {
IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
goto out_free_ict;
......@@ -3091,12 +3079,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
out_free_ict:
iwl_pcie_free_ict(trans);
out_pci_disable_msi:
pci_disable_msi(pdev);
out_pci_release_regions:
pci_release_regions(pdev);
out_pci_disable_device:
pci_disable_device(pdev);
out_no_pci:
free_percpu(trans_pcie->tso_hdr_page);
iwl_trans_free(trans);
......
......@@ -1493,7 +1493,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];
u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];
if (WARN(!trans_pcie->wide_cmd_header &&
if (WARN(!trans->wide_cmd_header &&
group_id > IWL_ALWAYS_LONG_GROUP,
"unsupported wide command %#x\n", cmd->id))
return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment