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 @@ ...@@ -33,9 +33,6 @@
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include "iwl-devtrace.h" #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_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event); EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
......
...@@ -256,6 +256,10 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t; ...@@ -256,6 +256,10 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;
* instead of 3. * instead of 3.
* @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size * @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size
* (command version 3) that supports per-chain limits * (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 * @NUM_IWL_UCODE_TLV_API: number of bits used
*/ */
...@@ -267,6 +271,7 @@ enum iwl_ucode_tlv_api { ...@@ -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_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_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_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 NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__ #ifdef __CHECKER__
......
...@@ -99,8 +99,12 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, ...@@ -99,8 +99,12 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
continue; continue;
for (i = 0; i < w->n_cmds; i++) { for (i = 0; i < w->n_cmds; i++) {
if (w->cmds[i] == u16 rec_id = WIDE_ID(pkt->hdr.group_id,
WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) { pkt->hdr.cmd);
if (w->cmds[i] == rec_id ||
(!iwl_cmd_groupid(w->cmds[i]) &&
DEF_ID(w->cmds[i]) == rec_id)) {
found = true; found = true;
break; break;
} }
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/acpi.h>
#include "iwl-drv.h" #include "iwl-drv.h"
#include "iwl-modparams.h" #include "iwl-modparams.h"
#include "iwl-nvm-parse.h" #include "iwl-nvm-parse.h"
...@@ -564,11 +565,16 @@ static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, ...@@ -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_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP));
__le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP)); __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP));
/* If OEM did not fuse address - get it from OTP */ iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
if (!mac_addr0 && !mac_addr1) { /*
mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP)); * If the OEM fused a valid address, use it instead of the one in the
mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP)); * 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); 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, ...@@ -899,3 +905,91 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
return regd; return regd;
} }
IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info); 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 @@ ...@@ -5,7 +5,8 @@
* *
* GPL LICENSE SUMMARY * 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 * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -93,4 +94,21 @@ struct ieee80211_regdomain * ...@@ -93,4 +94,21 @@ struct ieee80211_regdomain *
iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
int num_of_ch, __le32 *channels, u16 fw_mcc); 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__ */ #endif /* __iwl_nvm_parse_h__ */
...@@ -110,7 +110,7 @@ enum iwl_phy_db_section_type { ...@@ -110,7 +110,7 @@ enum iwl_phy_db_section_type {
IWL_PHY_DB_MAX 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 * phy db - configure operational ucode
......
...@@ -78,7 +78,7 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, ...@@ -78,7 +78,7 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
static struct lock_class_key __key; static struct lock_class_key __key;
#endif #endif
trans = kzalloc(sizeof(*trans) + priv_size, GFP_KERNEL); trans = devm_kzalloc(dev, sizeof(*trans) + priv_size, GFP_KERNEL);
if (!trans) if (!trans)
return NULL; return NULL;
...@@ -103,18 +103,14 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, ...@@ -103,18 +103,14 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
SLAB_HWCACHE_ALIGN, SLAB_HWCACHE_ALIGN,
NULL); NULL);
if (!trans->dev_cmd_pool) if (!trans->dev_cmd_pool)
goto free; return NULL;
return trans; return trans;
free:
kfree(trans);
return NULL;
} }
void iwl_trans_free(struct iwl_trans *trans) void iwl_trans_free(struct iwl_trans *trans)
{ {
kmem_cache_destroy(trans->dev_cmd_pool); kmem_cache_destroy(trans->dev_cmd_pool);
kfree(trans);
} }
int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) 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) ...@@ -140,6 +136,9 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
if (!(cmd->flags & CMD_ASYNC)) if (!(cmd->flags & CMD_ASYNC))
lock_map_acquire_read(&trans->sync_cmd_lockdep_map); 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); ret = trans->ops->send_cmd(trans, cmd);
if (!(cmd->flags & CMD_ASYNC)) if (!(cmd->flags & CMD_ASYNC))
......
...@@ -153,6 +153,7 @@ static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) ...@@ -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 */ /* make u16 wide id out of u8 group and opcode */
#define WIDE_ID(grp, opcode) ((grp << 8) | 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 /* due to the conversion, this group is special; new groups
* should be defined in the appropriate fw-api header files * should be defined in the appropriate fw-api header files
...@@ -484,7 +485,6 @@ struct iwl_hcmd_arr { ...@@ -484,7 +485,6 @@ struct iwl_hcmd_arr {
* @bc_table_dword: set to true if the BC table expects the byte count to be * @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes) * in DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue * @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 * @sw_csum_tx: transport should compute the TCP checksum
* @command_groups: array of command groups, each member is an array of the * @command_groups: array of command groups, each member is an array of the
* commands in the group; for debugging only * commands in the group; for debugging only
...@@ -506,7 +506,6 @@ struct iwl_trans_config { ...@@ -506,7 +506,6 @@ struct iwl_trans_config {
enum iwl_amsdu_size rx_buf_size; enum iwl_amsdu_size rx_buf_size;
bool bc_table_dword; bool bc_table_dword;
bool scd_set_active; bool scd_set_active;
bool wide_cmd_header;
bool sw_csum_tx; bool sw_csum_tx;
const struct iwl_hcmd_arr *command_groups; const struct iwl_hcmd_arr *command_groups;
int command_groups_size; int command_groups_size;
...@@ -770,6 +769,7 @@ enum iwl_plat_pm_mode { ...@@ -770,6 +769,7 @@ enum iwl_plat_pm_mode {
* @hw_id_str: a string with info about HW ID. Set during transport allocation. * @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 * @pm_support: set to true in start_hw if link pm is supported
* @ltr_enabled: set to true if the LTR is enabled * @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; * @num_rx_queues: number of RX queues allocated by the transport;
* the transport must set this before calling iwl_drv_start() * the transport must set this before calling iwl_drv_start()
* @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
...@@ -821,6 +821,7 @@ struct iwl_trans { ...@@ -821,6 +821,7 @@ struct iwl_trans {
const struct iwl_hcmd_arr *command_groups; const struct iwl_hcmd_arr *command_groups;
int command_groups_size; int command_groups_size;
bool wide_cmd_header;
u8 num_rx_queues; u8 num_rx_queues;
......
...@@ -504,6 +504,28 @@ static inline char *iwl_dbgfs_is_match(char *name, char *buf) ...@@ -504,6 +504,28 @@ static inline char *iwl_dbgfs_is_match(char *name, char *buf)
return !strncmp(name, buf, len) ? buf + len : NULL; 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, static ssize_t iwl_dbgfs_tof_enable_write(struct ieee80211_vif *vif,
char *buf, char *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
...@@ -1530,6 +1552,8 @@ MVM_DEBUGFS_READ_FILE_OPS(tof_range_response); ...@@ -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(tof_responder_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
MVM_DEBUGFS_WRITE_FILE_OPS(lqm_send_cmd, 64); 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) 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) ...@@ -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, MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR); S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE_VIF(lqm_send_cmd, mvmvif->dbgfs_dir, 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 && if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif) mvmvif == mvm->bf_allowed_vif)
......
...@@ -917,6 +917,59 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm, ...@@ -917,6 +917,59 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
return ret ?: count; 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, static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
char __user *user_buf, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
...@@ -1454,6 +1507,7 @@ MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8); ...@@ -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(max_amsdu_len, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
(IWL_RSS_INDIRECTION_TABLE_SIZE * 2)); (IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512);
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
...@@ -1464,6 +1518,132 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256); ...@@ -1464,6 +1518,132 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
#endif #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) int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
{ {
struct dentry *bcast_dir __maybe_unused; struct dentry *bcast_dir __maybe_unused;
...@@ -1502,6 +1682,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) ...@@ -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(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(cont_recording, 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(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", if (!debugfs_create_bool("enable_scan_iteration_notif",
S_IRUSR | S_IWUSR, S_IRUSR | S_IWUSR,
mvm->debugfs_dir, mvm->debugfs_dir,
...@@ -1560,6 +1741,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_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)) mvm->debugfs_dir, &mvm->nvm_phy_sku_blob))
goto err; 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 * Create a symlink with mac80211. It will be removed when mac80211
* exists (before the opmode exists which removes the target.) * exists (before the opmode exists which removes the target.)
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* *
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * 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 * 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 * it under the terms of version 2 of the GNU General Public License as
...@@ -603,6 +604,8 @@ struct iwl_scan_req_umac_tail { ...@@ -603,6 +604,8 @@ struct iwl_scan_req_umac_tail {
* @uid: scan id, &enum iwl_umac_scan_uid_offsets * @uid: scan id, &enum iwl_umac_scan_uid_offsets
* @ooc_priority: out of channel priority - &enum iwl_scan_priority * @ooc_priority: out of channel priority - &enum iwl_scan_priority
* @general_flags: &enum iwl_umac_scan_general_flags * @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 * @extended_dwell: dwell time for channels 1, 6 and 11
* @active_dwell: dwell time for active scan * @active_dwell: dwell time for active scan
* @passive_dwell: dwell time for passive scan * @passive_dwell: dwell time for passive scan
...@@ -620,8 +623,10 @@ struct iwl_scan_req_umac { ...@@ -620,8 +623,10 @@ struct iwl_scan_req_umac {
__le32 flags; __le32 flags;
__le32 uid; __le32 uid;
__le32 ooc_priority; __le32 ooc_priority;
/* SCAN_GENERAL_PARAMS_API_S_VER_1 */ /* SCAN_GENERAL_PARAMS_API_S_VER_4 */
__le32 general_flags; __le16 general_flags;
u8 reserved2;
u8 scan_start_mac_id;
u8 extended_dwell; u8 extended_dwell;
u8 active_dwell; u8 active_dwell;
u8 passive_dwell; u8 passive_dwell;
...@@ -629,7 +634,7 @@ struct iwl_scan_req_umac { ...@@ -629,7 +634,7 @@ struct iwl_scan_req_umac {
__le32 max_out_time; __le32 max_out_time;
__le32 suspend_time; __le32 suspend_time;
__le32 scan_priority; __le32 scan_priority;
/* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ /* SCAN_CHANNEL_PARAMS_API_S_VER_4 */
u8 channel_flags; u8 channel_flags;
u8 n_channels; u8 n_channels;
__le16 reserved; __le16 reserved;
...@@ -718,8 +723,8 @@ struct iwl_scan_offload_profiles_query { ...@@ -718,8 +723,8 @@ struct iwl_scan_offload_profiles_query {
* @status: one of SCAN_COMP_STATUS_* * @status: one of SCAN_COMP_STATUS_*
* @bt_status: BT on/off status * @bt_status: BT on/off status
* @last_channel: last channel that was scanned * @last_channel: last channel that was scanned
* @tsf_low: TSF timer (lower half) in usecs * @start_tsf: TSF timer in usecs of the scan start time for the mac specified
* @tsf_high: TSF timer (higher half) in usecs * in &struct iwl_scan_req_umac.
* @results: array of scan results, only "scanned_channels" of them are valid * @results: array of scan results, only "scanned_channels" of them are valid
*/ */
struct iwl_umac_scan_iter_complete_notif { struct iwl_umac_scan_iter_complete_notif {
...@@ -728,9 +733,8 @@ struct iwl_umac_scan_iter_complete_notif { ...@@ -728,9 +733,8 @@ struct iwl_umac_scan_iter_complete_notif {
u8 status; u8 status;
u8 bt_status; u8 bt_status;
u8 last_channel; u8 last_channel;
__le32 tsf_low; __le64 start_tsf;
__le32 tsf_high;
struct iwl_scan_results_notif results[]; 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 #endif
...@@ -205,7 +205,7 @@ enum { ...@@ -205,7 +205,7 @@ enum {
/* Phy */ /* Phy */
PHY_CONFIGURATION_CMD = 0x6a, PHY_CONFIGURATION_CMD = 0x6a,
CALIB_RES_NOTIF_PHY_DB = 0x6b, CALIB_RES_NOTIF_PHY_DB = 0x6b,
/* PHY_DB_CMD = 0x6c, */ PHY_DB_CMD = 0x6c,
/* ToF - 802.11mc FTM */ /* ToF - 802.11mc FTM */
TOF_CMD = 0x10, TOF_CMD = 0x10,
...@@ -340,6 +340,11 @@ enum iwl_prot_offload_subcmd_ids { ...@@ -340,6 +340,11 @@ enum iwl_prot_offload_subcmd_ids {
STORED_BEACON_NTF = 0xFF, STORED_BEACON_NTF = 0xFF,
}; };
enum iwl_fmac_debug_cmds {
LMAC_RD_WR = 0x0,
UMAC_RD_WR = 0x1,
};
/* command groups */ /* command groups */
enum { enum {
LEGACY_GROUP = 0x0, LEGACY_GROUP = 0x0,
...@@ -349,6 +354,7 @@ enum { ...@@ -349,6 +354,7 @@ enum {
PHY_OPS_GROUP = 0x4, PHY_OPS_GROUP = 0x4,
DATA_PATH_GROUP = 0x5, DATA_PATH_GROUP = 0x5,
PROT_OFFLOAD_GROUP = 0xb, PROT_OFFLOAD_GROUP = 0xb,
DEBUG_GROUP = 0xf,
}; };
/** /**
...@@ -2149,4 +2155,48 @@ struct iwl_channel_switch_noa_notif { ...@@ -2149,4 +2155,48 @@ struct iwl_channel_switch_noa_notif {
__le32 id_and_color; __le32 id_and_color;
} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */ } __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__ */ #endif /* __fw_api_h__ */
...@@ -539,6 +539,11 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif) ...@@ -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_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
IWL_MVM_OFFCHANNEL_QUEUE, IWL_MVM_OFFCHANNEL_QUEUE,
IWL_MAX_TID_COUNT, 0); 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; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
...@@ -769,26 +774,6 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, ...@@ -769,26 +774,6 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->ac[txf].fifos_mask = BIT(txf); 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) if (vif->bss_conf.qos)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); 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, ...@@ -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, static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct iwl_mac_ctx_cmd *cmd,
struct iwl_mac_data_ap *ctxt_ap, struct iwl_mac_data_ap *ctxt_ap,
bool add) bool add)
{ {
...@@ -1196,6 +1182,23 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, ...@@ -1196,6 +1182,23 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
.beacon_device_ts = 0 .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 = cpu_to_le32(vif->bss_conf.beacon_int);
ctxt_ap->bi_reciprocal = ctxt_ap->bi_reciprocal =
cpu_to_le32(iwl_mvm_reciprocal(vif->bss_conf.beacon_int)); 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, ...@@ -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); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/* Fill the data specific for ap mode */ /* 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); action == FW_CTXT_ACTION_ADD);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); 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, ...@@ -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); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/* Fill the data specific for GO mode */ /* 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); action == FW_CTXT_ACTION_ADD);
cmd.go.ctwin = cpu_to_le32(noa->oppps_ctwindow & cmd.go.ctwin = cpu_to_le32(noa->oppps_ctwindow &
......
...@@ -653,6 +653,16 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -653,6 +653,16 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT)) IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT))
hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES; 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; mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -720,6 +730,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -720,6 +730,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (ret) if (ret)
iwl_mvm_leds_exit(mvm); 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; return ret;
} }
...@@ -2229,6 +2243,10 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2229,6 +2243,10 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes); iwl_mvm_bss_info_changed_ap_ibss(mvm, vif, bss_conf, changes);
break; break;
case NL80211_IFTYPE_MONITOR:
if (changes & BSS_CHANGED_MU_GROUPS)
iwl_mvm_update_mu_groups(mvm, vif);
break;
default: default:
/* shouldn't happen */ /* shouldn't happen */
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
......
...@@ -821,6 +821,12 @@ struct iwl_mvm { ...@@ -821,6 +821,12 @@ struct iwl_mvm {
/* UMAC scan tracking */ /* UMAC scan tracking */
u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS]; 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 */ /* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant; u8 scan_rx_ant;
...@@ -1262,6 +1268,7 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); ...@@ -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); void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
u8 first_antenna(u8 mask); u8 first_antenna(u8 mask);
u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); 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 */ /* Tx / Host Commands */
int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm, int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm,
......
...@@ -66,7 +66,6 @@ ...@@ -66,7 +66,6 @@
*****************************************************************************/ *****************************************************************************/
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/acpi.h>
#include "iwl-trans.h" #include "iwl-trans.h"
#include "iwl-csr.h" #include "iwl-csr.h"
#include "mvm.h" #include "mvm.h"
...@@ -751,96 +750,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, ...@@ -751,96 +750,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
return resp_cp; 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) int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
{ {
bool tlv_lar; bool tlv_lar;
...@@ -884,7 +793,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) ...@@ -884,7 +793,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
return -EIO; return -EIO;
if (iwl_mvm_is_wifi_mcc_supported(mvm) && if (iwl_mvm_is_wifi_mcc_supported(mvm) &&
!iwl_mvm_get_bios_mcc(mvm, mcc)) { !iwl_get_bios_mcc(mvm->dev, mcc)) {
kfree(regd); kfree(regd);
regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc,
MCC_SOURCE_BIOS, NULL); MCC_SOURCE_BIOS, NULL);
......
...@@ -359,6 +359,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { ...@@ -359,6 +359,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
HCMD_NAME(BT_COEX_CI), HCMD_NAME(BT_COEX_CI),
HCMD_NAME(PHY_CONFIGURATION_CMD), HCMD_NAME(PHY_CONFIGURATION_CMD),
HCMD_NAME(CALIB_RES_NOTIF_PHY_DB), HCMD_NAME(CALIB_RES_NOTIF_PHY_DB),
HCMD_NAME(PHY_DB_CMD),
HCMD_NAME(SCAN_OFFLOAD_COMPLETE), HCMD_NAME(SCAN_OFFLOAD_COMPLETE),
HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
HCMD_NAME(SCAN_OFFLOAD_CONFIG_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, ...@@ -652,8 +653,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
/* the hardware splits the A-MSDU */ /* the hardware splits the A-MSDU */
if (mvm->cfg->mq_rx_supported) if (mvm->cfg->mq_rx_supported)
trans_cfg.rx_buf_size = IWL_AMSDU_4K; trans_cfg.rx_buf_size = IWL_AMSDU_4K;
trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa, trans->wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_WIDE_CMD_HDR); IWL_UCODE_TLV_API_WIDE_CMD_HDR);
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)
trans_cfg.bc_table_dword = true; trans_cfg.bc_table_dword = true;
...@@ -857,9 +858,7 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk) ...@@ -857,9 +858,7 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk)
struct iwl_mvm *mvm = struct iwl_mvm *mvm =
container_of(wk, struct iwl_mvm, async_handlers_wk); container_of(wk, struct iwl_mvm, async_handlers_wk);
struct iwl_async_handler_entry *entry, *tmp; struct iwl_async_handler_entry *entry, *tmp;
struct list_head local_list; LIST_HEAD(local_list);
INIT_LIST_HEAD(&local_list);
/* Ensure that we are not in stop flow (check iwl_mvm_mac_stop) */ /* 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, ...@@ -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_rx_packet *pkt = rxb_addr(rxb);
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); 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); 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); iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
else else
iwl_mvm_rx_common(mvm, rxb, pkt); iwl_mvm_rx_common(mvm, rxb, pkt);
...@@ -981,13 +981,14 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, ...@@ -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_rx_packet *pkt = rxb_addr(rxb);
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); 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); iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0);
else if (unlikely(pkt->hdr.group_id == DATA_PATH_GROUP && else if (unlikely(cmd == WIDE_ID(DATA_PATH_GROUP,
pkt->hdr.cmd == RX_QUEUES_NOTIFICATION)) RX_QUEUES_NOTIFICATION)))
iwl_mvm_rx_queue_notif(mvm, rxb, 0); 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); iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
else else
iwl_mvm_rx_common(mvm, rxb, pkt); iwl_mvm_rx_common(mvm, rxb, pkt);
...@@ -1666,13 +1667,14 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode, ...@@ -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_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
struct iwl_rx_packet *pkt = rxb_addr(rxb); 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); iwl_mvm_rx_frame_release(mvm, napi, rxb, queue);
else if (unlikely(pkt->hdr.cmd == RX_QUEUES_NOTIFICATION && else if (unlikely(cmd == WIDE_ID(DATA_PATH_GROUP,
pkt->hdr.group_id == DATA_PATH_GROUP)) RX_QUEUES_NOTIFICATION)))
iwl_mvm_rx_queue_notif(mvm, rxb, queue); 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); iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue);
} }
......
...@@ -418,10 +418,11 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, ...@@ -418,10 +418,11 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
ssn = ieee80211_sn_inc(ssn); 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)) * Empty the list. Will have more than one frame for A-MSDU.
continue; * Empty list is valid as well since nssn indicates frames were
/* Empty the list. Will have more than one frame for A-MSDU */ * received.
*/
while ((skb = __skb_dequeue(skb_list))) { while ((skb = __skb_dequeue(skb_list))) {
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb,
reorder_buf->queue, reorder_buf->queue,
...@@ -434,7 +435,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, ...@@ -434,7 +435,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
if (reorder_buf->num_stored && !reorder_buf->removed) { if (reorder_buf->num_stored && !reorder_buf->removed) {
u16 index = reorder_buf->head_sn % reorder_buf->buf_size; 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; index = (index + 1) % reorder_buf->buf_size;
/* modify timer to match next frame's expiration time */ /* modify timer to match next frame's expiration time */
mod_timer(&reorder_buf->reorder_timer, mod_timer(&reorder_buf->reorder_timer,
...@@ -462,7 +463,7 @@ void iwl_mvm_reorder_timer_expired(unsigned long data) ...@@ -462,7 +463,7 @@ void iwl_mvm_reorder_timer_expired(unsigned long data)
for (i = 0; i < buf->buf_size ; i++) { for (i = 0; i < buf->buf_size ; i++) {
index = (buf->head_sn + i) % buf->buf_size; index = (buf->head_sn + i) % buf->buf_size;
if (!skb_peek_tail(&buf->entries[index])) if (skb_queue_empty(&buf->entries[index]))
continue; continue;
if (!time_after(jiffies, buf->reorder_time[index] + if (!time_after(jiffies, buf->reorder_time[index] +
RX_REORDER_BUF_TIMEOUT_MQ)) RX_REORDER_BUF_TIMEOUT_MQ))
...@@ -590,6 +591,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -590,6 +591,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK) >> baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK) >>
IWL_RX_MPDU_REORDER_BAID_SHIFT; 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) if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
return false; return false;
...@@ -599,9 +605,10 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -599,9 +605,10 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
mvm_sta = iwl_mvm_sta_from_mac80211(sta); mvm_sta = iwl_mvm_sta_from_mac80211(sta);
/* not a data packet */ /* not a data packet or a bar */
if (!ieee80211_is_data_qos(hdr->frame_control) || if (!ieee80211_is_back_req(hdr->frame_control) &&
is_multicast_ether_addr(hdr->addr1)) (!ieee80211_is_data_qos(hdr->frame_control) ||
is_multicast_ether_addr(hdr->addr1)))
return false; return false;
if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
...@@ -625,6 +632,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -625,6 +632,11 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
spin_lock_bh(&buffer->lock); 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 there was a significant jump in the nssn - adjust.
* If the SN is smaller than the NSSN it might need to first go into * If the SN is smaller than the NSSN it might need to first go into
......
...@@ -141,6 +141,7 @@ struct iwl_mvm_scan_params { ...@@ -141,6 +141,7 @@ struct iwl_mvm_scan_params {
struct cfg80211_match_set *match_sets; struct cfg80211_match_set *match_sets;
int n_scan_plans; int n_scan_plans;
struct cfg80211_sched_scan_plan *scan_plans; struct cfg80211_sched_scan_plan *scan_plans;
u32 measurement_dwell;
}; };
static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) 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) ...@@ -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; 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) static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm)
{ {
/* require rrm scan whenever the fw supports it */ /* require rrm scan whenever the fw supports it */
...@@ -1033,9 +1055,15 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, ...@@ -1033,9 +1055,15 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
struct iwl_scan_req_umac *cmd, struct iwl_scan_req_umac *cmd,
struct iwl_mvm_scan_params *params) struct iwl_mvm_scan_params *params)
{ {
cmd->extended_dwell = scan_timing[params->type].dwell_extended; if (params->measurement_dwell) {
cmd->active_dwell = scan_timing[params->type].dwell_active; cmd->active_dwell = params->measurement_dwell;
cmd->passive_dwell = scan_timing[params->type].dwell_passive; 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->fragmented_dwell = scan_timing[params->type].dwell_fragmented;
cmd->max_out_time = cpu_to_le32(scan_timing[params->type].max_out_time); 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); 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, ...@@ -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 iwl_mvm_scan_params *params,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
int flags = 0; u16 flags = 0;
if (params->n_ssids == 0) if (params->n_ssids == 0)
flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE; flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE;
...@@ -1093,6 +1121,9 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, ...@@ -1093,6 +1121,9 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
if (!iwl_mvm_is_regular_scan(params)) if (!iwl_mvm_is_regular_scan(params))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC; flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
if (params->measurement_dwell)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
if (mvm->scan_iter_notif_enabled) if (mvm->scan_iter_notif_enabled)
flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; 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, ...@@ -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; mvm->fw->ucode_capa.n_scan_channels;
int uid, i; int uid, i;
u32 ssid_bitmap = 0; u32 ssid_bitmap = 0;
struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif);
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
...@@ -1136,8 +1168,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ...@@ -1136,8 +1168,9 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvm->scan_uid_status[uid] = type; mvm->scan_uid_status[uid] = type;
cmd->uid = cpu_to_le32(uid); 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)); vif));
cmd->scan_start_mac_id = scan_vif->id;
if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT)
cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); 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, ...@@ -1289,6 +1322,12 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_get_scan_type(mvm, iwl_mvm_get_scan_type(mvm,
vif->type == NL80211_IFTYPE_P2P_DEVICE); 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); iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { 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, ...@@ -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"); IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
mvm->scan_status |= IWL_MVM_SCAN_REGULAR; mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
mvm->scan_vif = iwl_mvm_vif_from_mac80211(vif);
iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
queue_delayed_work(system_wq, &mvm->scan_timeout_dwork, 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, ...@@ -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) { if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) {
struct cfg80211_scan_info info = { struct cfg80211_scan_info info = {
.aborted = aborted, .aborted = aborted,
.scan_start_tsf = mvm->scan_start,
}; };
memcpy(info.tsf_bssid, mvm->scan_vif->bssid, ETH_ALEN);
ieee80211_scan_completed(mvm->hw, &info); ieee80211_scan_completed(mvm->hw, &info);
mvm->scan_vif = NULL;
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
cancel_delayed_work(&mvm->scan_timeout_dwork); cancel_delayed_work(&mvm->scan_timeout_dwork);
} else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) { } 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, ...@@ -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; struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data;
u8 buf[256]; u8 buf[256];
mvm->scan_start = le64_to_cpu(notif->start_tsf);
IWL_DEBUG_SCAN(mvm, IWL_DEBUG_SCAN(mvm,
"UMAC Scan iteration complete: status=0x%x scanned_channels=%d channels list: %s\n", "UMAC Scan iteration complete: status=0x%x scanned_channels=%d channels list: %s\n",
notif->status, notif->scanned_channels, notif->status, notif->scanned_channels,
...@@ -1485,6 +1530,10 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, ...@@ -1485,6 +1530,10 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
ieee80211_sched_scan_results(mvm->hw); ieee80211_sched_scan_results(mvm->hw);
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED; 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) 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, ...@@ -745,14 +745,14 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
.scd_queue = queue, .scd_queue = queue,
.action = SCD_CFG_DISABLE_QUEUE, .action = SCD_CFG_DISABLE_QUEUE,
}; };
u8 ac; u8 txq_curr_ac;
disable_agg_tids = iwl_mvm_remove_sta_queue_marking(mvm, queue); disable_agg_tids = iwl_mvm_remove_sta_queue_marking(mvm, queue);
spin_lock_bh(&mvm->queue_info_lock); 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.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; cmd.tid = mvm->queue_info[queue].txq_tid;
spin_unlock_bh(&mvm->queue_info_lock); spin_unlock_bh(&mvm->queue_info_lock);
...@@ -1297,13 +1297,6 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, ...@@ -1297,13 +1297,6 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
return ret; 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, int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool drain) bool drain)
{ {
......
...@@ -473,9 +473,14 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, ...@@ -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, int iwl_mvm_add_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
int iwl_mvm_update_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, static inline int iwl_mvm_update_sta(struct iwl_mvm *mvm,
struct ieee80211_sta *sta); 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, int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
......
...@@ -490,16 +490,34 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, ...@@ -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, static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
struct ieee80211_tx_info *info, __le16 fc) struct ieee80211_tx_info *info, __le16 fc)
{ {
if (iwl_mvm_is_dqa_supported(mvm)) { if (!iwl_mvm_is_dqa_supported(mvm))
if (info->control.vif->type == NL80211_IFTYPE_AP && return info->hw_queue;
ieee80211_is_probe_resp(fc))
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; return IWL_MVM_DQA_AP_PROBE_RESP_QUEUE;
else if (ieee80211_is_mgmt(fc) && if (info->hw_queue == info->control.vif->cab_queue)
info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE) 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; 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) 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) ...@@ -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; sta_id = mvmvif->bcast_sta.sta_id;
queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info,
hdr->frame_control); hdr->frame_control);
if (queue < 0)
return -1;
} else if (info.control.vif->type == NL80211_IFTYPE_STATION && } else if (info.control.vif->type == NL80211_IFTYPE_STATION &&
is_multicast_ether_addr(hdr->addr1)) { is_multicast_ether_addr(hdr->addr1)) {
u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id); u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id);
......
...@@ -1225,6 +1225,28 @@ void iwl_mvm_inactivity_check(struct iwl_mvm *mvm) ...@@ -1225,6 +1225,28 @@ void iwl_mvm_inactivity_check(struct iwl_mvm *mvm)
rcu_read_unlock(); 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, int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif,
enum iwl_lqm_cmd_operatrions operation, enum iwl_lqm_cmd_operatrions operation,
u32 duration, u32 timeout) u32 duration, u32 timeout)
......
...@@ -487,6 +487,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { ...@@ -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, 0x1130, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x0130, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0130, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x1010, 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, 0x0050, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x0150, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x0150, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x9010, iwl8265_2ac_cfg)}, {IWL_PCI_DEVICE(0x24FD, 0x9010, iwl8265_2ac_cfg)},
......
...@@ -332,7 +332,6 @@ enum iwl_shared_irq_flags { ...@@ -332,7 +332,6 @@ enum iwl_shared_irq_flags {
* @rx_buf_size: Rx buffer size * @rx_buf_size: Rx buffer size
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @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 * @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 * @sw_csum_tx: if true, then the transport will compute the csum of the TXed
* frame. * frame.
* @rx_page_order: page order for receive buffer size * @rx_page_order: page order for receive buffer size
...@@ -405,7 +404,6 @@ struct iwl_trans_pcie { ...@@ -405,7 +404,6 @@ struct iwl_trans_pcie {
enum iwl_amsdu_size rx_buf_size; enum iwl_amsdu_size rx_buf_size;
bool bc_table_dword; bool bc_table_dword;
bool scd_set_active; bool scd_set_active;
bool wide_cmd_header;
bool sw_csum_tx; bool sw_csum_tx;
u32 rx_page_order; u32 rx_page_order;
......
...@@ -487,15 +487,13 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans) ...@@ -487,15 +487,13 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
while (pending) { while (pending) {
int i; int i;
struct list_head local_allocated; LIST_HEAD(local_allocated);
gfp_t gfp_mask = GFP_KERNEL; gfp_t gfp_mask = GFP_KERNEL;
/* Do not post a warning if there are only a few requests */ /* Do not post a warning if there are only a few requests */
if (pending < RX_PENDING_WATERMARK) if (pending < RX_PENDING_WATERMARK)
gfp_mask |= __GFP_NOWARN; gfp_mask |= __GFP_NOWARN;
INIT_LIST_HEAD(&local_allocated);
for (i = 0; i < RX_CLAIM_REQ_ALLOC;) { for (i = 0; i < RX_CLAIM_REQ_ALLOC;) {
struct iwl_rx_mem_buffer *rxb; struct iwl_rx_mem_buffer *rxb;
struct page *page; struct page *page;
...@@ -1108,13 +1106,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, ...@@ -1108,13 +1106,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
FH_RSCSR_RXQ_POS != rxq->id); FH_RSCSR_RXQ_POS != rxq->id);
IWL_DEBUG_RX(trans, 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, rxcb._offset,
iwl_get_cmd_string(trans, iwl_get_cmd_string(trans,
iwl_cmd_id(pkt->hdr.cmd, iwl_cmd_id(pkt->hdr.cmd,
pkt->hdr.group_id, pkt->hdr.group_id,
0)), 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 = iwl_rx_packet_len(pkt);
len += sizeof(u32); /* account for status word */ len += sizeof(u32); /* account for status word */
......
...@@ -1605,24 +1605,22 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev, ...@@ -1605,24 +1605,22 @@ static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,
for (i = 0; i < trans_pcie->alloc_vecs; i++) { for (i = 0; i < trans_pcie->alloc_vecs; i++) {
int ret; int ret;
struct msix_entry *msix_entry;
ret = request_threaded_irq(trans_pcie->msix_entries[i].vector,
iwl_pcie_msix_isr, msix_entry = &trans_pcie->msix_entries[i];
(i == trans_pcie->def_irq) ? ret = devm_request_threaded_irq(&pdev->dev,
iwl_pcie_irq_msix_handler : msix_entry->vector,
iwl_pcie_irq_rx_msix_handler, iwl_pcie_msix_isr,
IRQF_SHARED, (i == trans_pcie->def_irq) ?
DRV_NAME, iwl_pcie_irq_msix_handler :
&trans_pcie->msix_entries[i]); iwl_pcie_irq_rx_msix_handler,
IRQF_SHARED,
DRV_NAME,
msix_entry);
if (ret) { if (ret) {
int j;
IWL_ERR(trans_pcie->trans, IWL_ERR(trans_pcie->trans,
"Error allocating IRQ %d\n", i); "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; return ret;
} }
} }
...@@ -1755,7 +1753,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, ...@@ -1755,7 +1753,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans_pcie->rx_page_order = trans_pcie->rx_page_order =
iwl_trans_get_rb_size_order(trans_pcie->rx_buf_size); 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->bc_table_dword = trans_cfg->bc_table_dword;
trans_pcie->scd_set_active = trans_cfg->scd_set_active; trans_pcie->scd_set_active = trans_cfg->scd_set_active;
trans_pcie->sw_csum_tx = trans_cfg->sw_csum_tx; trans_pcie->sw_csum_tx = trans_cfg->sw_csum_tx;
...@@ -1790,23 +1787,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) ...@@ -1790,23 +1787,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
irq_set_affinity_hint( irq_set_affinity_hint(
trans_pcie->msix_entries[i].vector, trans_pcie->msix_entries[i].vector,
NULL); 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; trans_pcie->msix_enabled = false;
} else { } else {
free_irq(trans_pcie->pci_dev->irq, trans);
iwl_pcie_free_ict(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); iwl_pcie_free_fw_monitor(trans);
...@@ -2913,6 +2899,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, ...@@ -2913,6 +2899,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
struct iwl_trans *trans; struct iwl_trans *trans;
int ret, addr_size; int ret, addr_size;
ret = pcim_enable_device(pdev);
if (ret)
return ERR_PTR(ret);
trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),
&pdev->dev, cfg, &trans_ops_pcie, 0); &pdev->dev, cfg, &trans_ops_pcie, 0);
if (!trans) if (!trans)
...@@ -2931,9 +2921,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, ...@@ -2931,9 +2921,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
goto out_no_pci; goto out_no_pci;
} }
ret = pci_enable_device(pdev);
if (ret)
goto out_no_pci;
if (!cfg->base_params->pcie_l1_allowed) { if (!cfg->base_params->pcie_l1_allowed) {
/* /*
...@@ -2953,7 +2940,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, ...@@ -2953,7 +2940,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
if (cfg->use_tfh) { if (cfg->use_tfh) {
trans_pcie->max_tbs = IWL_TFH_NUM_TBS; 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 { } else {
trans_pcie->max_tbs = IWL_NUM_OF_TBS; trans_pcie->max_tbs = IWL_NUM_OF_TBS;
...@@ -2975,21 +2962,21 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, ...@@ -2975,21 +2962,21 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
/* both attempts failed: */ /* both attempts failed: */
if (ret) { if (ret) {
dev_err(&pdev->dev, "No suitable DMA available\n"); 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) { if (ret) {
dev_err(&pdev->dev, "pci_request_regions failed\n"); dev_err(&pdev->dev, "pcim_iomap_regions_request_all failed\n");
goto out_pci_disable_device; 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) { 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; ret = -ENODEV;
goto out_pci_release_regions; goto out_no_pci;
} }
/* We disable the RETRY_TIMEOUT register (0x41) to keep /* We disable the RETRY_TIMEOUT register (0x41) to keep
...@@ -3016,7 +3003,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, ...@@ -3016,7 +3003,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
ret = iwl_pcie_prepare_card_hw(trans); ret = iwl_pcie_prepare_card_hw(trans);
if (ret) { if (ret) {
IWL_WARN(trans, "Exit HW not ready\n"); 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, ...@@ -3033,7 +3020,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
25000); 25000);
if (ret < 0) { if (ret < 0) {
IWL_DEBUG_INFO(trans, "Failed to wake up the nic\n"); 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)) { if (iwl_trans_grab_nic_access(trans, &flags)) {
...@@ -3065,15 +3052,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, ...@@ -3065,15 +3052,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
if (trans_pcie->msix_enabled) { if (trans_pcie->msix_enabled) {
if (iwl_pcie_init_msix_handler(pdev, trans_pcie)) if (iwl_pcie_init_msix_handler(pdev, trans_pcie))
goto out_pci_release_regions; goto out_no_pci;
} else { } else {
ret = iwl_pcie_alloc_ict(trans); ret = iwl_pcie_alloc_ict(trans);
if (ret) if (ret)
goto out_pci_disable_msi; goto out_no_pci;
ret = request_threaded_irq(pdev->irq, iwl_pcie_isr, ret = devm_request_threaded_irq(&pdev->dev, pdev->irq,
iwl_pcie_irq_handler, iwl_pcie_isr,
IRQF_SHARED, DRV_NAME, trans); iwl_pcie_irq_handler,
IRQF_SHARED, DRV_NAME, trans);
if (ret) { if (ret) {
IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
goto out_free_ict; goto out_free_ict;
...@@ -3091,12 +3079,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, ...@@ -3091,12 +3079,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
out_free_ict: out_free_ict:
iwl_pcie_free_ict(trans); 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: out_no_pci:
free_percpu(trans_pcie->tso_hdr_page); free_percpu(trans_pcie->tso_hdr_page);
iwl_trans_free(trans); iwl_trans_free(trans);
......
...@@ -1493,7 +1493,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, ...@@ -1493,7 +1493,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];
u16 cmdlen[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, group_id > IWL_ALWAYS_LONG_GROUP,
"unsupported wide command %#x\n", cmd->id)) "unsupported wide command %#x\n", cmd->id))
return -EINVAL; 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