Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

This commit is contained in:
John W. Linville 2013-03-08 15:53:47 -05:00
commit cd309ab393
85 changed files with 2005 additions and 701 deletions

View File

@ -6,7 +6,6 @@ config IWLWIFI
select LEDS_CLASS
select LEDS_TRIGGERS
select MAC80211_LEDS
select IWLDVM
---help---
Select to build the driver supporting the:
@ -45,6 +44,7 @@ config IWLWIFI
config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
depends on IWLWIFI
default IWLWIFI
help
This is the driver supporting the DVM firmware which is
currently the only firmware available for existing devices.
@ -58,6 +58,15 @@ config IWLMVM
Say yes if you have such a device.
# don't call it _MODULE -- will confuse Kconfig/fixdep/...
config IWLWIFI_OPMODE_MODULAR
bool
default y if IWLDVM=m
default y if IWLMVM=m
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
depends on IWLWIFI && IWLDVM=n && IWLMVM=n
menu "Debugging Options"
depends on IWLWIFI

View File

@ -7,8 +7,7 @@ iwlwifi-objs += iwl-notif-wait.o
iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o
iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
iwlwifi-objs += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o
iwlwifi-objs += pcie/7000.o
iwlwifi-objs += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o iwl-7000.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -1526,6 +1526,7 @@ struct iwl_compressed_ba_resp {
__le16 scd_ssn;
u8 txed; /* number of frames sent */
u8 txed_2_done; /* number of frames acked */
__le16 reserved1;
} __packed;
/*

View File

@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -2324,6 +2324,28 @@ static ssize_t iwl_dbgfs_calib_disabled_write(struct file *file,
return count;
}
static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
bool restart_fw = iwlwifi_mod_params.restart_fw;
int ret;
iwlwifi_mod_params.restart_fw = true;
mutex_lock(&priv->mutex);
/* take the return value to make compiler happy - it will fail anyway */
ret = iwl_dvm_send_cmd_pdu(priv, REPLY_ERROR, CMD_SYNC, 0, NULL);
mutex_unlock(&priv->mutex);
iwlwifi_mod_params.restart_fw = restart_fw;
return count;
}
DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
DEBUGFS_READ_FILE_OPS(ucode_general_stats);
@ -2343,6 +2365,7 @@ DEBUGFS_READ_FILE_OPS(bt_traffic);
DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
DEBUGFS_READ_FILE_OPS(reply_tx_error);
DEBUGFS_WRITE_FILE_OPS(echo_test);
DEBUGFS_WRITE_FILE_OPS(fw_restart);
#ifdef CONFIG_IWLWIFI_DEBUG
DEBUGFS_READ_WRITE_FILE_OPS(log_event);
#endif
@ -2400,6 +2423,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir)
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(fw_restart, dir_debug, S_IWUSR);
#ifdef CONFIG_IWLWIFI_DEBUG
DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
#endif

View File

@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -151,7 +151,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : "");
if (!(flags & CMD_ASYNC)) {
cmd.flags |= CMD_WANT_SKB | CMD_WANT_HCMD;
cmd.flags |= CMD_WANT_SKB;
might_sleep();
}

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -29,7 +29,6 @@
#include "iwl-config.h"
#include "iwl-csr.h"
#include "iwl-agn-hw.h"
#include "cfg.h"
/* Highest firmware API version supported */
#define IWL1000_UCODE_API_MAX 5

View File

@ -28,7 +28,6 @@
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-agn-hw.h"
#include "cfg.h"
#include "dvm/commands.h" /* needed for BT for now */
/* Highest firmware API version supported */

View File

@ -29,7 +29,6 @@
#include "iwl-config.h"
#include "iwl-agn-hw.h"
#include "iwl-csr.h"
#include "cfg.h"
/* Highest firmware API version supported */
#define IWL5000_UCODE_API_MAX 5

View File

@ -28,7 +28,6 @@
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-agn-hw.h"
#include "cfg.h"
#include "dvm/commands.h" /* needed for BT for now */
/* Highest firmware API version supported */

View File

@ -1,34 +1,70 @@
/******************************************************************************
*
* Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* 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
* GPL LICENSE SUMMARY
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include <linux/module.h>
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-agn-hw.h"
#include "cfg.h"
/* Highest firmware API version supported */
#define IWL7260_UCODE_API_MAX 6
@ -70,7 +106,6 @@ static const struct iwl_base_params iwl7000_base_params = {
};
static const struct iwl_ht_params iwl7000_ht_params = {
.ht_greenfield_support = true,
.use_rts_for_aggregation = true, /* use rts/cts protection */
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -275,4 +275,51 @@ struct iwl_cfg {
const bool temp_offset_v2;
};
/*
* This list declares the config structures for all devices.
*/
extern const struct iwl_cfg iwl5300_agn_cfg;
extern const struct iwl_cfg iwl5100_agn_cfg;
extern const struct iwl_cfg iwl5350_agn_cfg;
extern const struct iwl_cfg iwl5100_bgn_cfg;
extern const struct iwl_cfg iwl5100_abg_cfg;
extern const struct iwl_cfg iwl5150_agn_cfg;
extern const struct iwl_cfg iwl5150_abg_cfg;
extern const struct iwl_cfg iwl6005_2agn_cfg;
extern const struct iwl_cfg iwl6005_2abg_cfg;
extern const struct iwl_cfg iwl6005_2bg_cfg;
extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
extern const struct iwl_cfg iwl6005_2agn_d_cfg;
extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
extern const struct iwl_cfg iwl1030_bgn_cfg;
extern const struct iwl_cfg iwl1030_bg_cfg;
extern const struct iwl_cfg iwl6030_2agn_cfg;
extern const struct iwl_cfg iwl6030_2abg_cfg;
extern const struct iwl_cfg iwl6030_2bgn_cfg;
extern const struct iwl_cfg iwl6030_2bg_cfg;
extern const struct iwl_cfg iwl6000i_2agn_cfg;
extern const struct iwl_cfg iwl6000i_2abg_cfg;
extern const struct iwl_cfg iwl6000i_2bg_cfg;
extern const struct iwl_cfg iwl6000_3agn_cfg;
extern const struct iwl_cfg iwl6050_2agn_cfg;
extern const struct iwl_cfg iwl6050_2abg_cfg;
extern const struct iwl_cfg iwl6150_bgn_cfg;
extern const struct iwl_cfg iwl6150_bg_cfg;
extern const struct iwl_cfg iwl1000_bgn_cfg;
extern const struct iwl_cfg iwl1000_bg_cfg;
extern const struct iwl_cfg iwl100_bgn_cfg;
extern const struct iwl_cfg iwl100_bg_cfg;
extern const struct iwl_cfg iwl130_bgn_cfg;
extern const struct iwl_cfg iwl130_bg_cfg;
extern const struct iwl_cfg iwl2000_2bgn_cfg;
extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
extern const struct iwl_cfg iwl2030_2bgn_cfg;
extern const struct iwl_cfg iwl6035_2agn_cfg;
extern const struct iwl_cfg iwl105_bgn_cfg;
extern const struct iwl_cfg iwl105_bgn_d_cfg;
extern const struct iwl_cfg iwl135_bgn_cfg;
extern const struct iwl_cfg iwl7260_2ac_cfg;
extern const struct iwl_cfg iwl3160_ac_cfg;
#endif /* __IWL_CONFIG_H__ */

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -66,6 +66,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/export.h>
#include "iwl-drv.h"
#include "iwl-debug.h"
#include "iwl-devtrace.h"
@ -85,11 +86,11 @@ void __iwl_ ##fn(struct device *dev, const char *fmt, ...) \
}
__iwl_fn(warn)
EXPORT_SYMBOL_GPL(__iwl_warn);
IWL_EXPORT_SYMBOL(__iwl_warn);
__iwl_fn(info)
EXPORT_SYMBOL_GPL(__iwl_info);
IWL_EXPORT_SYMBOL(__iwl_info);
__iwl_fn(crit)
EXPORT_SYMBOL_GPL(__iwl_crit);
IWL_EXPORT_SYMBOL(__iwl_crit);
void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
const char *fmt, ...)
@ -110,7 +111,7 @@ void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
trace_iwlwifi_err(&vaf);
va_end(args);
}
EXPORT_SYMBOL_GPL(__iwl_err);
IWL_EXPORT_SYMBOL(__iwl_err);
#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
void __iwl_dbg(struct device *dev,
@ -133,5 +134,5 @@ void __iwl_dbg(struct device *dev,
trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
va_end(args);
}
EXPORT_SYMBOL_GPL(__iwl_dbg);
IWL_EXPORT_SYMBOL(__iwl_dbg);
#endif

View File

@ -298,7 +298,7 @@ TRACE_EVENT(iwlwifi_dbg,
MAX_MSG_LEN, vaf->fmt,
*vaf->va) >= MAX_MSG_LEN);
),
TP_printk("%s", (char *)__get_dynamic_array(msg))
TP_printk("%s", __get_str(msg))
);
#undef TRACE_SYSTEM
@ -349,25 +349,23 @@ TRACE_EVENT(iwlwifi_dev_rx_data,
TRACE_EVENT(iwlwifi_dev_hcmd,
TP_PROTO(const struct device *dev,
struct iwl_host_cmd *cmd, u16 total_size,
const void *hdr, size_t hdr_len),
TP_ARGS(dev, cmd, total_size, hdr, hdr_len),
struct iwl_cmd_header *hdr),
TP_ARGS(dev, cmd, total_size, hdr),
TP_STRUCT__entry(
DEV_ENTRY
__dynamic_array(u8, hcmd, total_size)
__field(u32, flags)
),
TP_fast_assign(
int i, offset = hdr_len;
int i, offset = sizeof(*hdr);
DEV_ASSIGN;
__entry->flags = cmd->flags;
memcpy(__get_dynamic_array(hcmd), hdr, hdr_len);
memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr));
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {
if (!cmd->len[i])
continue;
if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
continue;
memcpy((u8 *)__get_dynamic_array(hcmd) + offset,
cmd->data[i], cmd->len[i]);
offset += cmd->len[i];

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -1102,8 +1102,7 @@ void iwl_drv_stop(struct iwl_drv *drv)
/* shared module parameters */
struct iwl_mod_params iwlwifi_mod_params = {
.amsdu_size_8K = 1,
.restart_fw = 1,
.restart_fw = true,
.plcp_check = true,
.bt_coex_active = true,
.power_level = IWL_POWER_INDEX_1,
@ -1112,7 +1111,7 @@ struct iwl_mod_params iwlwifi_mod_params = {
.wd_disable = true,
/* the rest are 0 by default */
};
EXPORT_SYMBOL_GPL(iwlwifi_mod_params);
IWL_EXPORT_SYMBOL(iwlwifi_mod_params);
int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
{
@ -1136,7 +1135,7 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
mutex_unlock(&iwlwifi_opmode_table_mtx);
return -EIO;
}
EXPORT_SYMBOL_GPL(iwl_opmode_register);
IWL_EXPORT_SYMBOL(iwl_opmode_register);
void iwl_opmode_deregister(const char *name)
{
@ -1158,7 +1157,7 @@ void iwl_opmode_deregister(const char *name)
}
mutex_unlock(&iwlwifi_opmode_table_mtx);
}
EXPORT_SYMBOL_GPL(iwl_opmode_deregister);
IWL_EXPORT_SYMBOL(iwl_opmode_deregister);
static int __init iwl_drv_init(void)
{
@ -1207,9 +1206,9 @@ MODULE_PARM_DESC(11n_disable,
"disable 11n functionality, bitmap: 1: full, 2: agg TX, 4: agg RX");
module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,
int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");
module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO);
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)");
module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
int, S_IRUGO);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -63,6 +63,8 @@
#ifndef __iwl_drv_h__
#define __iwl_drv_h__
#include <linux/module.h>
/* for all modules */
#define DRV_NAME "iwlwifi"
#define IWLWIFI_VERSION "in-tree:"
@ -123,4 +125,17 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
*/
void iwl_drv_stop(struct iwl_drv *drv);
/*
* exported symbol management
*
* The driver can be split into multiple modules, in which case some symbols
* must be exported for the sub-modules. However, if it's not split and
* everything is built-in, then we can avoid that.
*/
#ifdef CONFIG_IWLWIFI_OPMODE_MODULAR
#define IWL_EXPORT_SYMBOL(sym) EXPORT_SYMBOL_GPL(sym)
#else
#define IWL_EXPORT_SYMBOL(sym)
#endif
#endif /* __iwl_drv_h__ */

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -62,6 +62,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/export.h>
#include "iwl-drv.h"
#include "iwl-modparams.h"
#include "iwl-eeprom-parse.h"
@ -749,7 +750,7 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
}
ht_info->ht_supported = true;
ht_info->cap = 0;
ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;
if (iwlwifi_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
@ -909,7 +910,7 @@ iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
kfree(data);
return NULL;
}
EXPORT_SYMBOL_GPL(iwl_parse_eeprom_data);
IWL_EXPORT_SYMBOL(iwl_parse_eeprom_data);
/* helper functions */
int iwl_nvm_check_version(struct iwl_nvm_data *data,
@ -928,4 +929,4 @@ int iwl_nvm_check_version(struct iwl_nvm_data *data,
data->calib_version, trans->cfg->nvm_calib_ver);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(iwl_nvm_check_version);
IWL_EXPORT_SYMBOL(iwl_nvm_check_version);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -63,6 +63,7 @@
#include <linux/slab.h>
#include <linux/export.h>
#include "iwl-drv.h"
#include "iwl-debug.h"
#include "iwl-eeprom-read.h"
#include "iwl-io.h"
@ -460,4 +461,4 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size)
return ret;
}
EXPORT_SYMBOL_GPL(iwl_read_eeprom);
IWL_EXPORT_SYMBOL(iwl_read_eeprom);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -73,12 +73,14 @@
* treats good CRC threshold as a boolean
* @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
* @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
* @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
*/
enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1),
IWL_UCODE_TLV_FLAGS_MFP = BIT(2),
IWL_UCODE_TLV_FLAGS_P2P = BIT(3),
IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4),
};
/* The default calibrate table size if not specified by firmware file */

View File

@ -29,6 +29,7 @@
#include <linux/device.h>
#include <linux/export.h>
#include "iwl-drv.h"
#include "iwl-io.h"
#include "iwl-csr.h"
#include "iwl-debug.h"
@ -49,7 +50,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
return -ETIMEDOUT;
}
EXPORT_SYMBOL_GPL(iwl_poll_bit);
IWL_EXPORT_SYMBOL(iwl_poll_bit);
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
{
@ -62,7 +63,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
return value;
}
EXPORT_SYMBOL_GPL(iwl_read_direct32);
IWL_EXPORT_SYMBOL(iwl_read_direct32);
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
{
@ -73,7 +74,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
iwl_trans_release_nic_access(trans, &flags);
}
}
EXPORT_SYMBOL_GPL(iwl_write_direct32);
IWL_EXPORT_SYMBOL(iwl_write_direct32);
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
int timeout)
@ -89,7 +90,7 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
return -ETIMEDOUT;
}
EXPORT_SYMBOL_GPL(iwl_poll_direct_bit);
IWL_EXPORT_SYMBOL(iwl_poll_direct_bit);
static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs)
{
@ -115,7 +116,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
}
return val;
}
EXPORT_SYMBOL_GPL(iwl_read_prph);
IWL_EXPORT_SYMBOL(iwl_read_prph);
void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
{
@ -126,7 +127,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
iwl_trans_release_nic_access(trans, &flags);
}
}
EXPORT_SYMBOL_GPL(iwl_write_prph);
IWL_EXPORT_SYMBOL(iwl_write_prph);
void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
{
@ -138,7 +139,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
iwl_trans_release_nic_access(trans, &flags);
}
}
EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
IWL_EXPORT_SYMBOL(iwl_set_bits_prph);
void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
u32 bits, u32 mask)
@ -151,7 +152,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
iwl_trans_release_nic_access(trans, &flags);
}
}
EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph);
void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
{
@ -164,4 +165,4 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
iwl_trans_release_nic_access(trans, &flags);
}
}
EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
IWL_EXPORT_SYMBOL(iwl_clear_bits_prph);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -91,7 +91,7 @@ enum iwl_power_level {
* @sw_crypto: using hardware encryption, default = 0
* @disable_11n: disable 11n capabilities, default = 0,
* use IWL_DISABLE_HT_* constants
* @amsdu_size_8K: enable 8K amsdu size, default = 1
* @amsdu_size_8K: enable 8K amsdu size, default = 0
* @restart_fw: restart firmware, default = 1
* @plcp_check: enable plcp health check, default = true
* @wd_disable: enable stuck queue check, default = 0
@ -109,7 +109,7 @@ struct iwl_mod_params {
int sw_crypto;
unsigned int disable_11n;
int amsdu_size_8K;
int restart_fw;
bool restart_fw;
bool plcp_check;
int wd_disable;
bool bt_coex_active;

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -63,6 +63,7 @@
#include <linux/sched.h>
#include <linux/export.h>
#include "iwl-drv.h"
#include "iwl-notif-wait.h"
@ -72,7 +73,7 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
INIT_LIST_HEAD(&notif_wait->notif_waits);
init_waitqueue_head(&notif_wait->notif_waitq);
}
EXPORT_SYMBOL_GPL(iwl_notification_wait_init);
IWL_EXPORT_SYMBOL(iwl_notification_wait_init);
void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
struct iwl_rx_packet *pkt)
@ -117,7 +118,7 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
if (triggered)
wake_up_all(&notif_wait->notif_waitq);
}
EXPORT_SYMBOL_GPL(iwl_notification_wait_notify);
IWL_EXPORT_SYMBOL(iwl_notification_wait_notify);
void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
{
@ -130,7 +131,7 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
wake_up_all(&notif_wait->notif_waitq);
}
EXPORT_SYMBOL_GPL(iwl_abort_notification_waits);
IWL_EXPORT_SYMBOL(iwl_abort_notification_waits);
void
iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
@ -154,7 +155,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
list_add(&wait_entry->list, &notif_wait->notif_waits);
spin_unlock_bh(&notif_wait->notif_wait_lock);
}
EXPORT_SYMBOL_GPL(iwl_init_notification_wait);
IWL_EXPORT_SYMBOL(iwl_init_notification_wait);
int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
struct iwl_notification_wait *wait_entry,
@ -178,7 +179,7 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
return -ETIMEDOUT;
return 0;
}
EXPORT_SYMBOL_GPL(iwl_wait_notification);
IWL_EXPORT_SYMBOL(iwl_wait_notification);
void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
struct iwl_notification_wait *wait_entry)
@ -187,4 +188,4 @@ void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
list_del(&wait_entry->list);
spin_unlock_bh(&notif_wait->notif_wait_lock);
}
EXPORT_SYMBOL_GPL(iwl_remove_notification);
IWL_EXPORT_SYMBOL(iwl_remove_notification);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -62,6 +62,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/export.h>
#include "iwl-drv.h"
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
@ -149,6 +150,8 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = {
* @NVM_CHANNEL_DFS: dynamic freq selection candidate
* @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
* @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
* @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
* @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
*/
enum iwl_nvm_channel_flags {
NVM_CHANNEL_VALID = BIT(0),
@ -158,6 +161,8 @@ enum iwl_nvm_channel_flags {
NVM_CHANNEL_DFS = BIT(7),
NVM_CHANNEL_WIDE = BIT(8),
NVM_CHANNEL_40MHZ = BIT(9),
NVM_CHANNEL_80MHZ = BIT(10),
NVM_CHANNEL_160MHZ = BIT(11),
};
#define CHECK_AND_PRINT_I(x) \
@ -210,6 +215,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
else
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
}
if (!(ch_flags & NVM_CHANNEL_80MHZ))
channel->flags |= IEEE80211_CHAN_NO_80MHZ;
if (!(ch_flags & NVM_CHANNEL_160MHZ))
channel->flags |= IEEE80211_CHAN_NO_160MHZ;
if (!(ch_flags & NVM_CHANNEL_IBSS))
channel->flags |= IEEE80211_CHAN_NO_IBSS;
@ -245,6 +254,43 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
return n_channels;
}
static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
struct ieee80211_sta_vht_cap *vht_cap)
{
/* For now, assume new devices with NVM are VHT capable */
vht_cap->vht_supported = true;
vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
IEEE80211_VHT_CAP_RXSTBC_1 |
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
if (iwlwifi_mod_params.amsdu_size_8K)
vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
vht_cap->vht_mcs.rx_mcs_map =
cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
if (data->valid_rx_ant == 1 || cfg->rx_with_siso_diversity) {
vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
/* this works because NOT_SUPPORTED == 3 */
vht_cap->vht_mcs.rx_mcs_map |=
cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
}
vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
}
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
struct iwl_nvm_data *data, const __le16 *nvm_sw)
{
@ -268,6 +314,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
n_used += iwl_init_sband_channels(data, sband, n_channels,
IEEE80211_BAND_5GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap);
if (n_channels != n_used)
IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
@ -343,4 +390,4 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
return data;
}
EXPORT_SYMBOL_GPL(iwl_parse_nvm_data);
IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -65,6 +65,7 @@
#include <linux/string.h>
#include <linux/export.h>
#include "iwl-drv.h"
#include "iwl-phy-db.h"
#include "iwl-debug.h"
#include "iwl-op-mode.h"
@ -136,12 +137,6 @@ struct iwl_calib_res_notif_phy_db {
u8 data[];
} __packed;
#define IWL_PHY_DB_STATIC_PIC cpu_to_le32(0x21436587)
static inline void iwl_phy_db_test_pic(__le32 pic)
{
WARN_ON(IWL_PHY_DB_STATIC_PIC != pic);
}
struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
{
struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db),
@ -155,7 +150,7 @@ struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
/* TODO: add default values of the phy db. */
return phy_db;
}
EXPORT_SYMBOL(iwl_phy_db_init);
IWL_EXPORT_SYMBOL(iwl_phy_db_init);
/*
* get phy db section: returns a pointer to a phy db section specified by
@ -221,7 +216,7 @@ void iwl_phy_db_free(struct iwl_phy_db *phy_db)
kfree(phy_db);
}
EXPORT_SYMBOL(iwl_phy_db_free);
IWL_EXPORT_SYMBOL(iwl_phy_db_free);
int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
gfp_t alloc_ctx)
@ -260,18 +255,13 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
(size - CHANNEL_NUM_SIZE) / phy_db->channel_num;
}
/* Test PIC */
if (type != IWL_PHY_DB_CFG)
iwl_phy_db_test_pic(*(((__le32 *)phy_db_notif->data) +
(size / sizeof(__le32)) - 1));
IWL_DEBUG_INFO(phy_db->trans,
"%s(%d): [PHYDB]SET: Type %d , Size: %d\n",
__func__, __LINE__, type, size);
return 0;
}
EXPORT_SYMBOL(iwl_phy_db_set_section);
IWL_EXPORT_SYMBOL(iwl_phy_db_set_section);
static int is_valid_channel(u16 ch_id)
{
@ -372,11 +362,6 @@ int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db,
*size = entry->size;
}
/* Test PIC */
if (type != IWL_PHY_DB_CFG)
iwl_phy_db_test_pic(*(((__le32 *)*data) +
(*size / sizeof(__le32)) - 1));
IWL_DEBUG_INFO(phy_db->trans,
"%s(%d): [PHYDB] GET: Type %d , Size: %d\n",
__func__, __LINE__, type, *size);
@ -511,4 +496,4 @@ int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
"Finished sending phy db non channel data\n");
return 0;
}
EXPORT_SYMBOL(iwl_send_phy_db_data);
IWL_EXPORT_SYMBOL(iwl_send_phy_db_data);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -64,6 +64,7 @@
#include <linux/export.h>
#include <net/netlink.h>
#include "iwl-drv.h"
#include "iwl-io.h"
#include "iwl-fh.h"
#include "iwl-prph.h"
@ -653,7 +654,7 @@ int iwl_test_parse(struct iwl_test *tst, struct nlattr **tb,
}
return 0;
}
EXPORT_SYMBOL_GPL(iwl_test_parse);
IWL_EXPORT_SYMBOL(iwl_test_parse);
/*
* Handle test commands.
@ -715,7 +716,7 @@ int iwl_test_handle_cmd(struct iwl_test *tst, struct nlattr **tb)
}
return result;
}
EXPORT_SYMBOL_GPL(iwl_test_handle_cmd);
IWL_EXPORT_SYMBOL(iwl_test_handle_cmd);
static int iwl_test_trace_dump(struct iwl_test *tst, struct sk_buff *skb,
struct netlink_callback *cb)
@ -803,7 +804,7 @@ int iwl_test_dump(struct iwl_test *tst, u32 cmd, struct sk_buff *skb,
}
return result;
}
EXPORT_SYMBOL_GPL(iwl_test_dump);
IWL_EXPORT_SYMBOL(iwl_test_dump);
/*
* Multicast a spontaneous messages from the device to the user space.
@ -849,4 +850,4 @@ void iwl_test_rx(struct iwl_test *tst, struct iwl_rx_cmd_buffer *rxb)
if (tst->notify)
iwl_test_send_rx(tst, rxb);
}
EXPORT_SYMBOL_GPL(iwl_test_rx);
IWL_EXPORT_SYMBOL(iwl_test_rx);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -183,19 +183,13 @@ struct iwl_rx_packet {
* @CMD_ASYNC: Return right away and don't want for the response
* @CMD_WANT_SKB: valid only with CMD_SYNC. The caller needs the buffer of the
* response. The caller needs to call iwl_free_resp when done.
* @CMD_WANT_HCMD: The caller needs to get the HCMD that was sent in the
* response handler. Chunks flagged by %IWL_HCMD_DFL_NOCOPY won't be
* copied. The pointer passed to the response handler is in the transport
* ownership and don't need to be freed by the op_mode. This also means
* that the pointer is invalidated after the op_mode's handler returns.
* @CMD_ON_DEMAND: This command is sent by the test mode pipe.
*/
enum CMD_MODE {
CMD_SYNC = 0,
CMD_ASYNC = BIT(0),
CMD_WANT_SKB = BIT(1),
CMD_WANT_HCMD = BIT(2),
CMD_ON_DEMAND = BIT(3),
CMD_ON_DEMAND = BIT(2),
};
#define DEF_CMD_PAYLOAD_SIZE 320
@ -214,7 +208,11 @@ struct iwl_device_cmd {
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
#define IWL_MAX_CMD_TFDS 2
/*
* number of transfer buffers (fragments) per transmit frame descriptor;
* this is just the driver's idea, the hardware supports 20
*/
#define IWL_MAX_CMD_TBS_PER_TFD 2
/**
* struct iwl_hcmd_dataflag - flag for each one of the chunks of the command
@ -251,15 +249,15 @@ enum iwl_hcmd_dataflag {
* @id: id of the host command
*/
struct iwl_host_cmd {
const void *data[IWL_MAX_CMD_TFDS];
const void *data[IWL_MAX_CMD_TBS_PER_TFD];
struct iwl_rx_packet *resp_pkt;
unsigned long _rx_page_addr;
u32 _rx_page_order;
int handler_status;
u32 flags;
u16 len[IWL_MAX_CMD_TFDS];
u8 dataflags[IWL_MAX_CMD_TFDS];
u16 len[IWL_MAX_CMD_TBS_PER_TFD];
u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD];
u8 id;
};

View File

@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o
iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o
iwlmvm-y += scan.o time-event.o rs.o
iwlmvm-y += power.o
iwlmvm-y += power.o bt-coex.o
iwlmvm-y += led.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -0,0 +1,347 @@
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include "fw-api-bt-coex.h"
#include "iwl-modparams.h"
#include "mvm.h"
#include "iwl-debug.h"
#define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \
[(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \
((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS))
static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1,
BT_COEX_PRIO_TBL_PRIO_BYPASS, 0),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2,
BT_COEX_PRIO_TBL_PRIO_BYPASS, 1),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1,
BT_COEX_PRIO_TBL_PRIO_LOW, 0),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2,
BT_COEX_PRIO_TBL_PRIO_LOW, 1),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1,
BT_COEX_PRIO_TBL_PRIO_HIGH, 0),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2,
BT_COEX_PRIO_TBL_PRIO_HIGH, 1),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM,
BT_COEX_PRIO_TBL_DISABLED, 0),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52,
BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24,
BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0),
EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE,
BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0),
0, 0, 0, 0, 0, 0,
};
#undef EVENT_PRIO_ANT
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
{
return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC,
sizeof(struct iwl_bt_coex_prio_tbl_cmd),
&iwl_bt_prio_tbl);
}
static int iwl_send_bt_env(struct iwl_mvm *mvm, u8 action, u8 type)
{
struct iwl_bt_coex_prot_env_cmd env_cmd;
int ret;
env_cmd.action = action;
env_cmd.type = type;
ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PROT_ENV, CMD_SYNC,
sizeof(env_cmd), &env_cmd);
if (ret)
IWL_ERR(mvm, "failed to send BT env command\n");
return ret;
}
enum iwl_bt_kill_msk {
BT_KILL_MSK_DEFAULT,
BT_KILL_MSK_SCO_HID_A2DP,
BT_KILL_MSK_REDUCED_TXPOW,
BT_KILL_MSK_MAX,
};
static const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = {
0xffffffff,
0xfffffc00,
0,
};
static const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = {
0xffffffff,
0xfffffc00,
0,
};
#define IWL_BT_DEFAULT_BOOST (0xf0f0f0f0)
/* Tight Coex */
static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = {
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaeaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xcc00ff28),
cpu_to_le32(0x0000aaaa),
cpu_to_le32(0xcc00aaaa),
cpu_to_le32(0x0000aaaa),
cpu_to_le32(0xc0004000),
cpu_to_le32(0x00000000),
cpu_to_le32(0xf0005000),
cpu_to_le32(0xf0005000),
};
/* Loose Coex */
static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = {
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaeaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xcc00ff28),
cpu_to_le32(0x0000aaaa),
cpu_to_le32(0xcc00aaaa),
cpu_to_le32(0x0000aaaa),
cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000),
cpu_to_le32(0xf0005000),
cpu_to_le32(0xf0005000),
};
/* Full concurrency */
static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = {
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0xaaaaaaaa),
cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000),
};
/* BT Antenna Coupling Threshold (dB) */
#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
{
struct iwl_bt_coex_cmd cmd = {
.max_kill = 5,
.bt3_time_t7_value = 1,
.bt3_prio_sample_time = 2,
.bt3_timer_t2_value = 0xc,
};
int ret;
cmd.flags = iwlwifi_mod_params.bt_coex_active ?
BT_COEX_NW : BT_COEX_DISABLE;
cmd.flags |= iwlwifi_mod_params.bt_ch_announce ?
BT_CH_PRIMARY_EN | BT_CH_SECONDARY_EN : 0;
cmd.flags |= BT_SYNC_2_BT_DISABLE;
cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE |
BT_VALID_BT_PRIO_BOOST |
BT_VALID_MAX_KILL |
BT_VALID_3W_TMRS |
BT_VALID_KILL_ACK |
BT_VALID_KILL_CTS |
BT_VALID_REDUCED_TX_POWER |
BT_VALID_LUT);
if (iwlwifi_mod_params.ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD)
memcpy(&cmd.decision_lut, iwl_loose_lookup,
sizeof(iwl_tight_lookup));
else
memcpy(&cmd.decision_lut, iwl_tight_lookup,
sizeof(iwl_tight_lookup));
cmd.bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST);
cmd.kill_ack_msk =
cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]);
cmd.kill_cts_msk =
cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]);
/* go to CALIB state in internal BT-Coex state machine */
ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN,
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
if (ret)
return ret;
ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE,
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
if (ret)
return ret;
return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC,
sizeof(cmd), &cmd);
}
struct iwl_bt_notif_iterator_data {
struct iwl_mvm *mvm;
struct iwl_bt_coex_profile_notif *notif;
};
static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_notif_iterator_data *data = _data;
struct ieee80211_chanctx_conf *chanctx_conf;
enum ieee80211_smps_mode smps_mode;
enum ieee80211_band band;
if (vif->type != NL80211_IFTYPE_STATION)
return;
rcu_read_lock();
chanctx_conf = rcu_dereference(vif->chanctx_conf);
if (chanctx_conf && chanctx_conf->def.chan)
band = chanctx_conf->def.chan->band;
else
band = -1;
rcu_read_unlock();
if (band != IEEE80211_BAND_2GHZ)
return;
smps_mode = IEEE80211_SMPS_AUTOMATIC;
if (data->notif->bt_status)
smps_mode = IEEE80211_SMPS_DYNAMIC;
if (data->notif->bt_traffic_load)
smps_mode = IEEE80211_SMPS_STATIC;
IWL_DEBUG_COEX(data->mvm,
"mac %d: bt_status %d traffic_load %d smps_req %d\n",
mvmvif->id, data->notif->bt_status,
data->notif->bt_traffic_load, smps_mode);
ieee80211_request_smps(vif, smps_mode);
}
int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *dev_cmd)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
struct iwl_bt_notif_iterator_data data = {
.mvm = mvm,
.notif = notif,
};
struct iwl_bt_coex_cmd cmd = {};
enum iwl_bt_kill_msk bt_kill_msk;
IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
IWL_DEBUG_COEX(mvm, "\tBT %salive\n", notif->bt_status ? "" : "not ");
IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn);
IWL_DEBUG_COEX(mvm, "\tBT traffic load %d\n", notif->bt_traffic_load);
IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n",
notif->bt_agg_traffic_load);
IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
/* remember this notification for future use: rssi fluctuations */
memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
ieee80211_iterate_active_interfaces_atomic(
mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_bt_notif_iterator, &data);
/* Low latency BT profile is active: give higher prio to BT */
if (BT_MBOX_MSG(notif, 3, SCO_STATE) ||
BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
BT_MBOX_MSG(notif, 3, SNIFF_STATE))
bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
else
bt_kill_msk = BT_KILL_MSK_DEFAULT;
/* Don't send HCMD if there is no update */
if (bt_kill_msk == mvm->bt_kill_msk)
return 0;
IWL_DEBUG_COEX(mvm,
"Udpate kill_msk: %d\n\t SCO %sactive A2DP %sactive SNIFF %sactive\n",
bt_kill_msk,
BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
mvm->bt_kill_msk = bt_kill_msk;
cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS);
if (iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC, sizeof(cmd), &cmd))
IWL_ERR(mvm, "Failed to sent BT Coex CMD\n");
/* This handler is ASYNC */
return 0;
}

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -61,8 +61,11 @@
*
*****************************************************************************/
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <net/cfg80211.h>
#include <net/ipv6.h>
#include <net/tcp.h>
#include "iwl-modparams.h"
#include "fw-api.h"
#include "mvm.h"
@ -192,6 +195,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
sizeof(wkc), &wkc);
data->error = ret != 0;
mvm->ptk_ivlen = key->iv_len;
mvm->ptk_icvlen = key->icv_len;
mvm->gtk_ivlen = key->iv_len;
mvm->gtk_icvlen = key->icv_len;
/* don't upload key again */
goto out_unlock;
}
@ -304,9 +312,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
*/
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
key->hw_key_idx = 0;
mvm->ptk_ivlen = key->iv_len;
mvm->ptk_icvlen = key->icv_len;
} else {
data->gtk_key_idx++;
key->hw_key_idx = data->gtk_key_idx;
mvm->gtk_ivlen = key->iv_len;
mvm->gtk_icvlen = key->icv_len;
}
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
@ -392,6 +404,233 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
sizeof(cmd), &cmd);
}
enum iwl_mvm_tcp_packet_type {
MVM_TCP_TX_SYN,
MVM_TCP_RX_SYNACK,
MVM_TCP_TX_DATA,
MVM_TCP_RX_ACK,
MVM_TCP_RX_WAKE,
MVM_TCP_TX_FIN,
};
static __le16 pseudo_hdr_check(int len, __be32 saddr, __be32 daddr)
{
__sum16 check = tcp_v4_check(len, saddr, daddr, 0);
return cpu_to_le16(be16_to_cpu((__force __be16)check));
}
static void iwl_mvm_build_tcp_packet(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct cfg80211_wowlan_tcp *tcp,
void *_pkt, u8 *mask,
__le16 *pseudo_hdr_csum,
enum iwl_mvm_tcp_packet_type ptype)
{
struct {
struct ethhdr eth;
struct iphdr ip;
struct tcphdr tcp;
u8 data[];
} __packed *pkt = _pkt;
u16 ip_tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
int i;
pkt->eth.h_proto = cpu_to_be16(ETH_P_IP),
pkt->ip.version = 4;
pkt->ip.ihl = 5;
pkt->ip.protocol = IPPROTO_TCP;
switch (ptype) {
case MVM_TCP_TX_SYN:
case MVM_TCP_TX_DATA:
case MVM_TCP_TX_FIN:
memcpy(pkt->eth.h_dest, tcp->dst_mac, ETH_ALEN);
memcpy(pkt->eth.h_source, vif->addr, ETH_ALEN);
pkt->ip.ttl = 128;
pkt->ip.saddr = tcp->src;
pkt->ip.daddr = tcp->dst;
pkt->tcp.source = cpu_to_be16(tcp->src_port);
pkt->tcp.dest = cpu_to_be16(tcp->dst_port);
/* overwritten for TX SYN later */
pkt->tcp.doff = sizeof(struct tcphdr) / 4;
pkt->tcp.window = cpu_to_be16(65000);
break;
case MVM_TCP_RX_SYNACK:
case MVM_TCP_RX_ACK:
case MVM_TCP_RX_WAKE:
memcpy(pkt->eth.h_dest, vif->addr, ETH_ALEN);
memcpy(pkt->eth.h_source, tcp->dst_mac, ETH_ALEN);
pkt->ip.saddr = tcp->dst;
pkt->ip.daddr = tcp->src;
pkt->tcp.source = cpu_to_be16(tcp->dst_port);
pkt->tcp.dest = cpu_to_be16(tcp->src_port);
break;
default:
WARN_ON(1);
return;
}
switch (ptype) {
case MVM_TCP_TX_SYN:
/* firmware assumes 8 option bytes - 8 NOPs for now */
memset(pkt->data, 0x01, 8);
ip_tot_len += 8;
pkt->tcp.doff = (sizeof(struct tcphdr) + 8) / 4;
pkt->tcp.syn = 1;
break;
case MVM_TCP_TX_DATA:
ip_tot_len += tcp->payload_len;
memcpy(pkt->data, tcp->payload, tcp->payload_len);
pkt->tcp.psh = 1;
pkt->tcp.ack = 1;
break;
case MVM_TCP_TX_FIN:
pkt->tcp.fin = 1;
pkt->tcp.ack = 1;
break;
case MVM_TCP_RX_SYNACK:
pkt->tcp.syn = 1;
pkt->tcp.ack = 1;
break;
case MVM_TCP_RX_ACK:
pkt->tcp.ack = 1;
break;
case MVM_TCP_RX_WAKE:
ip_tot_len += tcp->wake_len;
pkt->tcp.psh = 1;
pkt->tcp.ack = 1;
memcpy(pkt->data, tcp->wake_data, tcp->wake_len);
break;
}
switch (ptype) {
case MVM_TCP_TX_SYN:
case MVM_TCP_TX_DATA:
case MVM_TCP_TX_FIN:
pkt->ip.tot_len = cpu_to_be16(ip_tot_len);
pkt->ip.check = ip_fast_csum(&pkt->ip, pkt->ip.ihl);
break;
case MVM_TCP_RX_WAKE:
for (i = 0; i < DIV_ROUND_UP(tcp->wake_len, 8); i++) {
u8 tmp = tcp->wake_mask[i];
mask[i + 6] |= tmp << 6;
if (i + 1 < DIV_ROUND_UP(tcp->wake_len, 8))
mask[i + 7] = tmp >> 2;
}
/* fall through for ethernet/IP/TCP headers mask */
case MVM_TCP_RX_SYNACK:
case MVM_TCP_RX_ACK:
mask[0] = 0xff; /* match ethernet */
/*
* match ethernet, ip.version, ip.ihl
* the ip.ihl half byte is really masked out by firmware
*/
mask[1] = 0x7f;
mask[2] = 0x80; /* match ip.protocol */
mask[3] = 0xfc; /* match ip.saddr, ip.daddr */
mask[4] = 0x3f; /* match ip.daddr, tcp.source, tcp.dest */
mask[5] = 0x80; /* match tcp flags */
/* leave rest (0 or set for MVM_TCP_RX_WAKE) */
break;
};
*pseudo_hdr_csum = pseudo_hdr_check(ip_tot_len - sizeof(struct iphdr),
pkt->ip.saddr, pkt->ip.daddr);
}
static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct cfg80211_wowlan_tcp *tcp)
{
struct iwl_wowlan_remote_wake_config *cfg;
struct iwl_host_cmd cmd = {
.id = REMOTE_WAKE_CONFIG_CMD,
.len = { sizeof(*cfg), },
.dataflags = { IWL_HCMD_DFL_NOCOPY, },
.flags = CMD_SYNC,
};
int ret;
if (!tcp)
return 0;
cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
cmd.data[0] = cfg;
cfg->max_syn_retries = 10;
cfg->max_data_retries = 10;
cfg->tcp_syn_ack_timeout = 1; /* seconds */
cfg->tcp_ack_timeout = 1; /* seconds */
/* SYN (TX) */
iwl_mvm_build_tcp_packet(
mvm, vif, tcp, cfg->syn_tx.data, NULL,
&cfg->syn_tx.info.tcp_pseudo_header_checksum,
MVM_TCP_TX_SYN);
cfg->syn_tx.info.tcp_payload_length = 0;
/* SYN/ACK (RX) */
iwl_mvm_build_tcp_packet(
mvm, vif, tcp, cfg->synack_rx.data, cfg->synack_rx.rx_mask,
&cfg->synack_rx.info.tcp_pseudo_header_checksum,
MVM_TCP_RX_SYNACK);
cfg->synack_rx.info.tcp_payload_length = 0;
/* KEEPALIVE/ACK (TX) */
iwl_mvm_build_tcp_packet(
mvm, vif, tcp, cfg->keepalive_tx.data, NULL,
&cfg->keepalive_tx.info.tcp_pseudo_header_checksum,
MVM_TCP_TX_DATA);
cfg->keepalive_tx.info.tcp_payload_length =
cpu_to_le16(tcp->payload_len);
cfg->sequence_number_offset = tcp->payload_seq.offset;
/* length must be 0..4, the field is little endian */
cfg->sequence_number_length = tcp->payload_seq.len;
cfg->initial_sequence_number = cpu_to_le32(tcp->payload_seq.start);
cfg->keepalive_interval = cpu_to_le16(tcp->data_interval);
if (tcp->payload_tok.len) {
cfg->token_offset = tcp->payload_tok.offset;
cfg->token_length = tcp->payload_tok.len;
cfg->num_tokens =
cpu_to_le16(tcp->tokens_size % tcp->payload_tok.len);
memcpy(cfg->tokens, tcp->payload_tok.token_stream,
tcp->tokens_size);
} else {
/* set tokens to max value to almost never run out */
cfg->num_tokens = cpu_to_le16(65535);
}
/* ACK (RX) */
iwl_mvm_build_tcp_packet(
mvm, vif, tcp, cfg->keepalive_ack_rx.data,
cfg->keepalive_ack_rx.rx_mask,
&cfg->keepalive_ack_rx.info.tcp_pseudo_header_checksum,
MVM_TCP_RX_ACK);
cfg->keepalive_ack_rx.info.tcp_payload_length = 0;
/* WAKEUP (RX) */
iwl_mvm_build_tcp_packet(
mvm, vif, tcp, cfg->wake_rx.data, cfg->wake_rx.rx_mask,
&cfg->wake_rx.info.tcp_pseudo_header_checksum,
MVM_TCP_RX_WAKE);
cfg->wake_rx.info.tcp_payload_length =
cpu_to_le16(tcp->wake_len);
/* FIN */
iwl_mvm_build_tcp_packet(
mvm, vif, tcp, cfg->fin_tx.data, NULL,
&cfg->fin_tx.info.tcp_pseudo_header_checksum,
MVM_TCP_TX_FIN);
cfg->fin_tx.info.tcp_payload_length = 0;
ret = iwl_mvm_send_cmd(mvm, &cmd);
kfree(cfg);
return ret;
}
struct iwl_d3_iter_data {
struct iwl_mvm *mvm;
struct ieee80211_vif *vif;
@ -630,6 +869,22 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
d3_cfg_cmd.wakeup_flags |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
if (wowlan->tcp) {
/*
* The firmware currently doesn't really look at these, only
* the IWL_WOWLAN_WAKEUP_LINK_CHANGE bit. We have to set that
* reason bit since losing the connection to the AP implies
* losing the TCP connection.
* Set the flags anyway as long as they exist, in case this
* will be changed in the firmware.
*/
wowlan_config_cmd.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
IWL_WOWLAN_WAKEUP_LINK_CHANGE);
}
iwl_mvm_cancel_scan(mvm);
iwl_trans_stop_device(mvm->trans);
@ -649,6 +904,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
/* We reprogram keys and shouldn't allocate new key indices */
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
mvm->ptk_ivlen = 0;
mvm->ptk_icvlen = 0;
mvm->ptk_ivlen = 0;
mvm->ptk_icvlen = 0;
/*
* The D3 firmware still hardcodes the AP station ID for the
* BSS we're associated with as 0. As a result, we have to move
@ -740,6 +1000,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
if (ret)
goto out;
ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
if (ret)
goto out;
/* must be last -- this switches firmware state */
ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
sizeof(d3_cfg_cmd), &d3_cfg_cmd);
@ -783,7 +1047,6 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
struct iwl_wowlan_status *status;
u32 reasons;
int ret, len;
bool pkt8023 = false;
struct sk_buff *pkt = NULL;
iwl_trans_read_mem_bytes(mvm->trans, base,
@ -824,7 +1087,8 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
status = (void *)cmd.resp_pkt->data;
if (len - sizeof(struct iwl_cmd_header) !=
sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) {
sizeof(*status) +
ALIGN(le32_to_cpu(status->wake_packet_bufsize), 4)) {
IWL_ERR(mvm, "Invalid WoWLAN status response!\n");
goto out;
}
@ -836,61 +1100,105 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
goto report;
}
if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) {
if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET)
wakeup.magic_pkt = true;
pkt8023 = true;
}
if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) {
if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN)
wakeup.pattern_idx =
le16_to_cpu(status->pattern_number);
pkt8023 = true;
}
if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON |
IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH))
wakeup.disconnect = true;
if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) {
if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)
wakeup.gtk_rekey_failure = true;
pkt8023 = true;
}
if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) {
if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED)
wakeup.rfkill_release = true;
pkt8023 = true;
}
if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) {
if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST)
wakeup.eap_identity_req = true;
pkt8023 = true;
}
if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) {
if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)
wakeup.four_way_handshake = true;
pkt8023 = true;
}
if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS)
wakeup.tcp_connlost = true;
if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE)
wakeup.tcp_nomoretokens = true;
if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET)
wakeup.tcp_match = true;
if (status->wake_packet_bufsize) {
u32 pktsize = le32_to_cpu(status->wake_packet_bufsize);
u32 pktlen = le32_to_cpu(status->wake_packet_length);
int pktsize = le32_to_cpu(status->wake_packet_bufsize);
int pktlen = le32_to_cpu(status->wake_packet_length);
const u8 *pktdata = status->wake_packet;
struct ieee80211_hdr *hdr = (void *)pktdata;
int truncated = pktlen - pktsize;
/* this would be a firmware bug */
if (WARN_ON_ONCE(truncated < 0))
truncated = 0;
if (ieee80211_is_data(hdr->frame_control)) {
int hdrlen = ieee80211_hdrlen(hdr->frame_control);
int ivlen = 0, icvlen = 4; /* also FCS */
if (pkt8023) {
pkt = alloc_skb(pktsize, GFP_KERNEL);
if (!pkt)
goto report;
memcpy(skb_put(pkt, pktsize), status->wake_packet,
pktsize);
memcpy(skb_put(pkt, hdrlen), pktdata, hdrlen);
pktdata += hdrlen;
pktsize -= hdrlen;
if (ieee80211_has_protected(hdr->frame_control)) {
if (is_multicast_ether_addr(hdr->addr1)) {
ivlen = mvm->gtk_ivlen;
icvlen += mvm->gtk_icvlen;
} else {
ivlen = mvm->ptk_ivlen;
icvlen += mvm->ptk_icvlen;
}
}
/* if truncated, FCS/ICV is (partially) gone */
if (truncated >= icvlen) {
icvlen = 0;
truncated -= icvlen;
} else {
icvlen -= truncated;
truncated = 0;
}
pktsize -= ivlen + icvlen;
pktdata += ivlen;
memcpy(skb_put(pkt, pktsize), pktdata, pktsize);
if (ieee80211_data_to_8023(pkt, vif->addr, vif->type))
goto report;
wakeup.packet = pkt->data;
wakeup.packet_present_len = pkt->len;
wakeup.packet_len = pkt->len - (pktlen - pktsize);
wakeup.packet_len = pkt->len - truncated;
wakeup.packet_80211 = false;
} else {
int fcslen = 4;
if (truncated >= 4) {
truncated -= 4;
fcslen = 0;
} else {
fcslen -= truncated;
truncated = 0;
}
pktsize -= fcslen;
wakeup.packet = status->wake_packet;
wakeup.packet_present_len = pktsize;
wakeup.packet_len = pktlen;
wakeup.packet_len = pktlen - truncated;
wakeup.packet_80211 = true;
}
}

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -69,12 +69,6 @@ struct iwl_dbgfs_mvm_ctx {
struct ieee80211_vif *vif;
};
static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
@ -306,10 +300,130 @@ static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
return count;
}
#define BT_MBOX_MSG(_notif, _num, _field) \
((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
>> BT_MBOX##_num##_##_field##_POS)
#define BT_MBOX_PRINT(_num, _field, _end) \
pos += scnprintf(buf + pos, bufsz - pos, \
"\t%s: %d%s", \
#_field, \
BT_MBOX_MSG(notif, _num, _field), \
true ? "\n" : ", ");
static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
char *buf;
int ret, pos = 0, bufsz = sizeof(char) * 1024;
buf = kmalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
mutex_lock(&mvm->mutex);
pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
BT_MBOX_PRINT(0, LE_PROF1, false);
BT_MBOX_PRINT(0, LE_PROF2, false);
BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
BT_MBOX_PRINT(0, CHL_SEQ_N, false);
BT_MBOX_PRINT(0, INBAND_S, false);
BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
BT_MBOX_PRINT(0, LE_SCAN, false);
BT_MBOX_PRINT(0, LE_ADV, false);
BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
BT_MBOX_PRINT(0, OPEN_CON_1, true);
pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
BT_MBOX_PRINT(1, IP_SR, false);
BT_MBOX_PRINT(1, LE_MSTR, false);
BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
BT_MBOX_PRINT(1, MSG_TYPE, false);
BT_MBOX_PRINT(1, SSN, true);
pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
BT_MBOX_PRINT(2, SNIFF_ACT, false);
BT_MBOX_PRINT(2, PAG, false);
BT_MBOX_PRINT(2, INQUIRY, false);
BT_MBOX_PRINT(2, CONN, false);
BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
BT_MBOX_PRINT(2, DISC, false);
BT_MBOX_PRINT(2, SCO_TX_ACT, false);
BT_MBOX_PRINT(2, SCO_RX_ACT, false);
BT_MBOX_PRINT(2, ESCO_RE_TX, false);
BT_MBOX_PRINT(2, SCO_DURATION, true);
pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
BT_MBOX_PRINT(3, SCO_STATE, false);
BT_MBOX_PRINT(3, SNIFF_STATE, false);
BT_MBOX_PRINT(3, A2DP_STATE, false);
BT_MBOX_PRINT(3, ACL_STATE, false);
BT_MBOX_PRINT(3, MSTR_STATE, false);
BT_MBOX_PRINT(3, OBX_STATE, false);
BT_MBOX_PRINT(3, OPEN_CON_2, false);
BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
BT_MBOX_PRINT(3, INBAND_P, false);
BT_MBOX_PRINT(3, MSG_TYPE_2, false);
BT_MBOX_PRINT(3, SSN_2, false);
BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n",
notif->bt_status);
pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n",
notif->bt_open_conn);
pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n",
notif->bt_traffic_load);
pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n",
notif->bt_agg_traffic_load);
pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
notif->bt_ci_compliance);
mutex_unlock(&mvm->mutex);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
return ret;
}
#undef BT_MBOX_PRINT
static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_mvm *mvm = file->private_data;
bool restart_fw = iwlwifi_mod_params.restart_fw;
int ret;
iwlwifi_mod_params.restart_fw = true;
mutex_lock(&mvm->mutex);
/* take the return value to make compiler happy - it will fail anyway */
ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL);
mutex_unlock(&mvm->mutex);
iwlwifi_mod_params.restart_fw = restart_fw;
return count;
}
#define MVM_DEBUGFS_READ_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.read = iwl_dbgfs_##name##_read, \
.open = iwl_dbgfs_open_file_generic, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
@ -317,14 +431,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
.read = iwl_dbgfs_##name##_read, \
.open = iwl_dbgfs_open_file_generic, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
.open = iwl_dbgfs_open_file_generic, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
@ -345,8 +459,10 @@ MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
MVM_DEBUGFS_READ_FILE_OPS(stations);
MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
{
@ -358,8 +474,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
/*
* Create a symlink with mac80211. It will be removed when mac80211

View File

@ -0,0 +1,319 @@
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#ifndef __fw_api_bt_coex_h__
#define __fw_api_bt_coex_h__
#include <linux/types.h>
#include <linux/bitops.h>
#define BITS(nb) (BIT(nb) - 1)
/**
* enum iwl_bt_coex_flags - flags for BT_COEX command
* @BT_CH_PRIMARY_EN:
* @BT_CH_SECONDARY_EN:
* @BT_NOTIF_COEX_OFF:
* @BT_COEX_MODE_POS:
* @BT_COEX_MODE_MSK:
* @BT_COEX_DISABLE:
* @BT_COEX_2W:
* @BT_COEX_3W:
* @BT_COEX_NW:
* @BT_USE_DEFAULTS:
* @BT_SYNC_2_BT_DISABLE:
* @BT_COEX_CORUNNING_TBL_EN:
*/
enum iwl_bt_coex_flags {
BT_CH_PRIMARY_EN = BIT(0),
BT_CH_SECONDARY_EN = BIT(1),
BT_NOTIF_COEX_OFF = BIT(2),
BT_COEX_MODE_POS = 3,
BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS,
BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS,
BT_COEX_2W = 0x1 << BT_COEX_MODE_POS,
BT_COEX_3W = 0x2 << BT_COEX_MODE_POS,
BT_COEX_NW = 0x3 << BT_COEX_MODE_POS,
BT_USE_DEFAULTS = BIT(6),
BT_SYNC_2_BT_DISABLE = BIT(7),
/*
* For future use - when the flags will be enlarged
* BT_COEX_CORUNNING_TBL_EN = BIT(8),
*/
};
/*
* indicates what has changed in the BT_COEX command.
*/
enum iwl_bt_coex_valid_bit_msk {
BT_VALID_ENABLE = BIT(0),
BT_VALID_BT_PRIO_BOOST = BIT(1),
BT_VALID_MAX_KILL = BIT(2),
BT_VALID_3W_TMRS = BIT(3),
BT_VALID_KILL_ACK = BIT(4),
BT_VALID_KILL_CTS = BIT(5),
BT_VALID_REDUCED_TX_POWER = BIT(6),
BT_VALID_LUT = BIT(7),
BT_VALID_WIFI_RX_SW_PRIO_BOOST = BIT(8),
BT_VALID_WIFI_TX_SW_PRIO_BOOST = BIT(9),
BT_VALID_MULTI_PRIO_LUT = BIT(10),
BT_VALID_TRM_KICK_FILTER = BIT(11),
BT_VALID_CORUN_LUT_20 = BIT(12),
BT_VALID_CORUN_LUT_40 = BIT(13),
BT_VALID_ANT_ISOLATION = BIT(14),
BT_VALID_ANT_ISOLATION_THRS = BIT(15),
/*
* For future use - when the valid flags will be enlarged
* BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
* BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
*/
};
/**
* enum iwl_bt_reduced_tx_power - allows to reduce txpower for WiFi frames.
* @BT_REDUCED_TX_POWER_CTL: reduce Tx power for control frames
* @BT_REDUCED_TX_POWER_DATA: reduce Tx power for data frames
*
* This mechanism allows to have BT and WiFi run concurrently. Since WiFi
* reduces its Tx power, it can work along with BT, hence reducing the amount
* of WiFi frames being killed by BT.
*/
enum iwl_bt_reduced_tx_power {
BT_REDUCED_TX_POWER_CTL = BIT(0),
BT_REDUCED_TX_POWER_DATA = BIT(1),
};
#define BT_COEX_LUT_SIZE (12)
/**
* struct iwl_bt_coex_cmd - bt coex configuration command
* @flags:&enum iwl_bt_coex_flags
* @lead_time:
* @max_kill:
* @bt3_time_t7_value:
* @kill_ack_msk:
* @kill_cts_msk:
* @bt3_prio_sample_time:
* @bt3_timer_t2_value:
* @bt4_reaction_time:
* @decision_lut[12]:
* @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power
* @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
* @bt_prio_boost: values for PTA boost register
* @wifi_tx_prio_boost: SW boost of wifi tx priority
* @wifi_rx_prio_boost: SW boost of wifi rx priority
*
* The structure is used for the BT_COEX command.
*/
struct iwl_bt_coex_cmd {
u8 flags;
u8 lead_time;
u8 max_kill;
u8 bt3_time_t7_value;
__le32 kill_ack_msk;
__le32 kill_cts_msk;
u8 bt3_prio_sample_time;
u8 bt3_timer_t2_value;
__le16 bt4_reaction_time;
__le32 decision_lut[BT_COEX_LUT_SIZE];
u8 bt_reduced_tx_power;
u8 reserved;
__le16 valid_bit_msk;
__le32 bt_prio_boost;
u8 reserved2;
u8 wifi_tx_prio_boost;
__le16 wifi_rx_prio_boost;
} __packed; /* BT_COEX_CMD_API_S_VER_3 */
#define BT_MBOX(n_dw, _msg, _pos, _nbits) \
BT_MBOX##n_dw##_##_msg##_POS = (_pos), \
BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS
enum iwl_bt_mxbox_dw0 {
BT_MBOX(0, LE_SLAVE_LAT, 0, 3),
BT_MBOX(0, LE_PROF1, 3, 1),
BT_MBOX(0, LE_PROF2, 4, 1),
BT_MBOX(0, LE_PROF_OTHER, 5, 1),
BT_MBOX(0, CHL_SEQ_N, 8, 4),
BT_MBOX(0, INBAND_S, 13, 1),
BT_MBOX(0, LE_MIN_RSSI, 16, 4),
BT_MBOX(0, LE_SCAN, 20, 1),
BT_MBOX(0, LE_ADV, 21, 1),
BT_MBOX(0, LE_MAX_TX_POWER, 24, 4),
BT_MBOX(0, OPEN_CON_1, 28, 2),
};
enum iwl_bt_mxbox_dw1 {
BT_MBOX(1, BR_MAX_TX_POWER, 0, 4),
BT_MBOX(1, IP_SR, 4, 1),
BT_MBOX(1, LE_MSTR, 5, 1),
BT_MBOX(1, AGGR_TRFC_LD, 8, 6),
BT_MBOX(1, MSG_TYPE, 16, 3),
BT_MBOX(1, SSN, 19, 2),
};
enum iwl_bt_mxbox_dw2 {
BT_MBOX(2, SNIFF_ACT, 0, 3),
BT_MBOX(2, PAG, 3, 1),
BT_MBOX(2, INQUIRY, 4, 1),
BT_MBOX(2, CONN, 5, 1),
BT_MBOX(2, SNIFF_INTERVAL, 8, 5),
BT_MBOX(2, DISC, 13, 1),
BT_MBOX(2, SCO_TX_ACT, 16, 2),
BT_MBOX(2, SCO_RX_ACT, 18, 2),
BT_MBOX(2, ESCO_RE_TX, 20, 2),
BT_MBOX(2, SCO_DURATION, 24, 6),
};
enum iwl_bt_mxbox_dw3 {
BT_MBOX(3, SCO_STATE, 0, 1),
BT_MBOX(3, SNIFF_STATE, 1, 1),
BT_MBOX(3, A2DP_STATE, 2, 1),
BT_MBOX(3, ACL_STATE, 3, 1),
BT_MBOX(3, MSTR_STATE, 4, 1),
BT_MBOX(3, OBX_STATE, 5, 1),
BT_MBOX(3, OPEN_CON_2, 8, 2),
BT_MBOX(3, TRAFFIC_LOAD, 10, 2),
BT_MBOX(3, CHL_SEQN_LSB, 12, 1),
BT_MBOX(3, INBAND_P, 13, 1),
BT_MBOX(3, MSG_TYPE_2, 16, 3),
BT_MBOX(3, SSN_2, 19, 2),
BT_MBOX(3, UPDATE_REQUEST, 21, 1),
};
#define BT_MBOX_MSG(_notif, _num, _field) \
((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
>> BT_MBOX##_num##_##_field##_POS)
/**
* struct iwl_bt_coex_profile_notif - notification about BT coex
* @mbox_msg: message from BT to WiFi
* @:bt_status: 0 - off, 1 - on
* @:bt_open_conn: number of BT connections open
* @:bt_traffic_load: load of BT traffic
* @:bt_agg_traffic_load: aggregated load of BT traffic
* @:bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
*/
struct iwl_bt_coex_profile_notif {
__le32 mbox_msg[4];
u8 bt_status;
u8 bt_open_conn;
u8 bt_traffic_load;
u8 bt_agg_traffic_load;
u8 bt_ci_compliance;
u8 reserved[3];
} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */
enum iwl_bt_coex_prio_table_event {
BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3,
BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
BT_COEX_PRIO_TBL_EVT_DTIM = 6,
BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
BT_COEX_PRIO_TBL_EVT_IDLE = 9,
BT_COEX_PRIO_TBL_EVT_MAX = 16,
}; /* BT_COEX_PRIO_TABLE_EVENTS_API_E_VER_1 */
enum iwl_bt_coex_prio_table_prio {
BT_COEX_PRIO_TBL_DISABLED = 0,
BT_COEX_PRIO_TBL_PRIO_LOW = 1,
BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
BT_COEX_PRIO_TBL_PRIO_COEX_IDLE = 6,
BT_COEX_PRIO_TBL_MAX = 8,
}; /* BT_COEX_PRIO_TABLE_PRIORITIES_API_E_VER_1 */
#define BT_COEX_PRIO_TBL_SHRD_ANT_POS (0)
#define BT_COEX_PRIO_TBL_PRIO_POS (1)
#define BT_COEX_PRIO_TBL_RESERVED_POS (4)
/**
* struct iwl_bt_coex_prio_tbl_cmd - priority table for BT coex
* @prio_tbl:
*/
struct iwl_bt_coex_prio_tbl_cmd {
u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
} __packed;
enum iwl_bt_coex_env_action {
BT_COEX_ENV_CLOSE = 0,
BT_COEX_ENV_OPEN = 1,
}; /* BT_COEX_PROT_ENV_ACTION_API_E_VER_1 */
/**
* struct iwl_bt_coex_prot_env_cmd - BT Protection Envelope
* @action: enum %iwl_bt_coex_env_action
* @type: enum %iwl_bt_coex_prio_table_event
*/
struct iwl_bt_coex_prot_env_cmd {
u8 action; /* 0 = closed, 1 = open */
u8 type; /* 0 .. 15 */
u8 reserved[2];
} __packed;
#endif /* __fw_api_bt_coex_h__ */

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -258,7 +258,7 @@ enum iwl_wowlan_wakeup_reason {
IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8),
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9),
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10),
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11),
/* BIT(11) reserved */
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12),
}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
@ -277,6 +277,55 @@ struct iwl_wowlan_status {
u8 wake_packet[]; /* can be truncated from _length to _bufsize */
} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */
#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64
#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128
#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048
struct iwl_tcp_packet_info {
__le16 tcp_pseudo_header_checksum;
__le16 tcp_payload_length;
} __packed; /* TCP_PACKET_INFO_API_S_VER_2 */
struct iwl_tcp_packet {
struct iwl_tcp_packet_info info;
u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
u8 data[IWL_WOWLAN_TCP_MAX_PACKET_LEN];
} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */
struct iwl_remote_wake_packet {
struct iwl_tcp_packet_info info;
u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
u8 data[IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN];
} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */
struct iwl_wowlan_remote_wake_config {
__le32 connection_max_time; /* unused */
/* TCP_PROTOCOL_CONFIG_API_S_VER_1 */
u8 max_syn_retries;
u8 max_data_retries;
u8 tcp_syn_ack_timeout;
u8 tcp_ack_timeout;
struct iwl_tcp_packet syn_tx;
struct iwl_tcp_packet synack_rx;
struct iwl_tcp_packet keepalive_ack_rx;
struct iwl_tcp_packet fin_tx;
struct iwl_remote_wake_packet keepalive_tx;
struct iwl_remote_wake_packet wake_rx;
/* REMOTE_WAKE_OFFSET_INFO_API_S_VER_1 */
u8 sequence_number_offset;
u8 sequence_number_length;
u8 token_offset;
u8 token_length;
/* REMOTE_WAKE_PROTOCOL_PARAMS_API_S_VER_1 */
__le32 initial_sequence_number;
__le16 keepalive_interval;
__le16 num_tokens;
u8 tokens[IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS];
} __packed; /* REMOTE_WAKE_CONFIG_API_S_VER_2 */
/* TODO: NetDetect API */
#endif /* __fw_api_d3_h__ */

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -70,6 +70,7 @@
#include "fw-api-mac.h"
#include "fw-api-power.h"
#include "fw-api-d3.h"
#include "fw-api-bt-coex.h"
/* queue and FIFO numbers by usage */
enum {
@ -152,6 +153,7 @@ enum {
BEACON_TEMPLATE_CMD = 0x91,
TX_ANT_CONFIGURATION_CMD = 0x98,
BT_CONFIG = 0x9b,
STATISTICS_NOTIFICATION = 0x9d,
/* RF-KILL commands and notifications */
@ -162,6 +164,11 @@ enum {
REPLY_RX_MPDU_CMD = 0xc1,
BA_NOTIF = 0xc5,
/* BT Coex */
BT_COEX_PRIO_TABLE = 0xcc,
BT_COEX_PROT_ENV = 0xcd,
BT_PROFILE_NOTIFICATION = 0xce,
REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7,
@ -762,18 +769,20 @@ struct iwl_phy_context_cmd {
#define IWL_RX_INFO_PHY_CNT 8
#define IWL_RX_INFO_AGC_IDX 1
#define IWL_RX_INFO_RSSI_AB_IDX 2
#define IWL_RX_INFO_RSSI_C_IDX 3
#define IWL_OFDM_AGC_DB_MSK 0xfe00
#define IWL_OFDM_AGC_DB_POS 9
#define IWL_OFDM_AGC_A_MSK 0x0000007f
#define IWL_OFDM_AGC_A_POS 0
#define IWL_OFDM_AGC_B_MSK 0x00003f80
#define IWL_OFDM_AGC_B_POS 7
#define IWL_OFDM_AGC_CODE_MSK 0x3fe00000
#define IWL_OFDM_AGC_CODE_POS 20
#define IWL_OFDM_RSSI_INBAND_A_MSK 0x00ff
#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00
#define IWL_OFDM_RSSI_A_POS 0
#define IWL_OFDM_RSSI_ALLBAND_A_MSK 0xff00
#define IWL_OFDM_RSSI_ALLBAND_A_POS 8
#define IWL_OFDM_RSSI_INBAND_B_MSK 0xff0000
#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000
#define IWL_OFDM_RSSI_B_POS 16
#define IWL_OFDM_RSSI_INBAND_C_MSK 0x00ff
#define IWL_OFDM_RSSI_ALLBAND_C_MSK 0xff00
#define IWL_OFDM_RSSI_C_POS 0
#define IWL_OFDM_RSSI_ALLBAND_B_MSK 0xff000000
#define IWL_OFDM_RSSI_ALLBAND_B_POS 24
/**
* struct iwl_rx_phy_info - phy info
@ -792,6 +801,7 @@ struct iwl_phy_context_cmd {
* @byte_count: frame's byte-count
* @frame_time: frame's time on the air, based on byte count and frame rate
* calculation
* @mac_active_msk: what MACs were active when the frame was received
*
* Before each Rx, the device sends this data. It contains PHY information
* about the reception of the packet.
@ -809,7 +819,7 @@ struct iwl_rx_phy_info {
__le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT];
__le32 rate_n_flags;
__le32 byte_count;
__le16 reserved2;
__le16 mac_active_msk;
__le16 frame_time;
} __packed;

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -79,17 +79,8 @@
#define UCODE_VALID_OK cpu_to_le32(0x1)
/* Default calibration values for WkP - set to INIT image w/o running */
static const u8 wkp_calib_values_bb_filter[] = { 0xbf, 0x00, 0x5f, 0x00, 0x2f,
0x00, 0x18, 0x00 };
static const u8 wkp_calib_values_rx_dc[] = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f };
static const u8 wkp_calib_values_tx_lo[] = { 0x00, 0x00, 0x00, 0x00 };
static const u8 wkp_calib_values_tx_iq[] = { 0xff, 0x00, 0xff, 0x00, 0x00,
0x00 };
static const u8 wkp_calib_values_rx_iq[] = { 0xff, 0x00, 0x00, 0x00 };
static const u8 wkp_calib_values_rx_iq_skew[] = { 0x00, 0x00, 0x01, 0x00 };
static const u8 wkp_calib_values_tx_iq_skew[] = { 0x01, 0x00, 0x00, 0x00 };
static const u8 wkp_calib_values_xtal[] = { 0xd2, 0xd2 };
struct iwl_calib_default_data {
u16 size;
@ -99,12 +90,7 @@ struct iwl_calib_default_data {
#define CALIB_SIZE_N_DATA(_buf) {.size = sizeof(_buf), .data = &_buf}
static const struct iwl_calib_default_data wkp_calib_default_data[12] = {
[5] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_dc),
[6] = CALIB_SIZE_N_DATA(wkp_calib_values_bb_filter),
[7] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_lo),
[8] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq),
[9] = CALIB_SIZE_N_DATA(wkp_calib_values_tx_iq_skew),
[10] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq),
[11] = CALIB_SIZE_N_DATA(wkp_calib_values_rx_iq_skew),
};
@ -241,20 +227,6 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
return 0;
}
#define IWL_HW_REV_ID_RAINBOW 0x2
#define IWL_PROJ_TYPE_LHP 0x5
static u32 iwl_mvm_build_phy_cfg(struct iwl_mvm *mvm)
{
struct iwl_nvm_data *data = mvm->nvm_data;
/* Temp calls to static definitions, will be changed to CSR calls */
u8 hw_rev_id = IWL_HW_REV_ID_RAINBOW;
u8 project_type = IWL_PROJ_TYPE_LHP;
return data->radio_cfg_dash | (data->radio_cfg_step << 2) |
(hw_rev_id << 4) | ((project_type & 0x7f) << 6) |
(data->valid_tx_ant << 16) | (data->valid_rx_ant << 20);
}
static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
{
@ -262,7 +234,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
enum iwl_ucode_type ucode_type = mvm->cur_ucode;
/* Set parameters */
phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_build_phy_cfg(mvm));
phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config);
phy_cfg_cmd.calib_control.event_trigger =
mvm->fw->default_calib[ucode_type].event_trigger;
phy_cfg_cmd.calib_control.flow_trigger =
@ -275,103 +247,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
sizeof(phy_cfg_cmd), &phy_cfg_cmd);
}
/* Starting with the new PHY DB implementation - New calibs are enabled */
/* Value - 0x405e7 */
#define IWL_CALIB_DEFAULT_FLOW_INIT (IWL_CALIB_CFG_XTAL_IDX |\
IWL_CALIB_CFG_TEMPERATURE_IDX |\
IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
IWL_CALIB_CFG_DC_IDX |\
IWL_CALIB_CFG_BB_FILTER_IDX |\
IWL_CALIB_CFG_LO_LEAKAGE_IDX |\
IWL_CALIB_CFG_TX_IQ_IDX |\
IWL_CALIB_CFG_RX_IQ_IDX |\
IWL_CALIB_CFG_AGC_IDX)
#define IWL_CALIB_DEFAULT_EVENT_INIT 0x0
/* Value 0x41567 */
#define IWL_CALIB_DEFAULT_FLOW_RUN (IWL_CALIB_CFG_XTAL_IDX |\
IWL_CALIB_CFG_TEMPERATURE_IDX |\
IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
IWL_CALIB_CFG_BB_FILTER_IDX |\
IWL_CALIB_CFG_DC_IDX |\
IWL_CALIB_CFG_TX_IQ_IDX |\
IWL_CALIB_CFG_RX_IQ_IDX |\
IWL_CALIB_CFG_SENSITIVITY_IDX |\
IWL_CALIB_CFG_AGC_IDX)
#define IWL_CALIB_DEFAULT_EVENT_RUN (IWL_CALIB_CFG_XTAL_IDX |\
IWL_CALIB_CFG_TEMPERATURE_IDX |\
IWL_CALIB_CFG_VOLTAGE_READ_IDX |\
IWL_CALIB_CFG_TX_PWR_IDX |\
IWL_CALIB_CFG_DC_IDX |\
IWL_CALIB_CFG_TX_IQ_IDX |\
IWL_CALIB_CFG_SENSITIVITY_IDX)
/*
* Sets the calibrations trigger values that will be sent to the FW for runtime
* and init calibrations.
* The ones given in the FW TLV are not correct.
*/
static void iwl_set_default_calib_trigger(struct iwl_mvm *mvm)
{
struct iwl_tlv_calib_ctrl default_calib;
/*
* WkP FW TLV calib bits are wrong, overwrite them.
* This defines the dynamic calibrations which are implemented in the
* uCode both for init(flow) calculation and event driven calibs.
*/
/* Init Image */
default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_INIT);
default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_INIT);
if (default_calib.event_trigger !=
mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger)
IWL_ERR(mvm,
"Updating the event calib for INIT image: 0x%x -> 0x%x\n",
mvm->fw->default_calib[IWL_UCODE_INIT].event_trigger,
default_calib.event_trigger);
if (default_calib.flow_trigger !=
mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger)
IWL_ERR(mvm,
"Updating the flow calib for INIT image: 0x%x -> 0x%x\n",
mvm->fw->default_calib[IWL_UCODE_INIT].flow_trigger,
default_calib.flow_trigger);
memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_INIT],
&default_calib, sizeof(struct iwl_tlv_calib_ctrl));
IWL_ERR(mvm,
"Setting uCode init calibrations event 0x%x, trigger 0x%x\n",
default_calib.event_trigger,
default_calib.flow_trigger);
/* Run time image */
default_calib.event_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_EVENT_RUN);
default_calib.flow_trigger = cpu_to_le32(IWL_CALIB_DEFAULT_FLOW_RUN);
if (default_calib.event_trigger !=
mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger)
IWL_ERR(mvm,
"Updating the event calib for RT image: 0x%x -> 0x%x\n",
mvm->fw->default_calib[IWL_UCODE_REGULAR].event_trigger,
default_calib.event_trigger);
if (default_calib.flow_trigger !=
mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger)
IWL_ERR(mvm,
"Updating the flow calib for RT image: 0x%x -> 0x%x\n",
mvm->fw->default_calib[IWL_UCODE_REGULAR].flow_trigger,
default_calib.flow_trigger);
memcpy((void *)&mvm->fw->default_calib[IWL_UCODE_REGULAR],
&default_calib, sizeof(struct iwl_tlv_calib_ctrl));
IWL_ERR(mvm,
"Setting uCode runtime calibs event 0x%x, trigger 0x%x\n",
default_calib.event_trigger,
default_calib.flow_trigger);
}
static int iwl_set_default_calibrations(struct iwl_mvm *mvm)
{
u8 cmd_raw[16]; /* holds the variable size commands */
@ -434,6 +309,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
goto error;
}
ret = iwl_send_bt_prio_tbl(mvm);
if (ret)
goto error;
if (read_nvm) {
/* Read nvm */
ret = iwl_nvm_init(mvm);
@ -446,8 +325,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);
WARN_ON(ret);
/* Override the calibrations from TLV and the const of fw */
iwl_set_default_calib_trigger(mvm);
/* Send TX valid antennas before triggering calibrations */
ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
if (ret)
goto error;
/* WkP doesn't have all calibrations, need to set default values */
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
@ -537,6 +418,14 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret)
goto error;
ret = iwl_send_bt_prio_tbl(mvm);
if (ret)
goto error;
ret = iwl_send_bt_init_conf(mvm);
if (ret)
goto error;
/* Send phy db control command and then phy db calibration*/
ret = iwl_send_phy_db_data(mvm->phy_db);
if (ret)

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -553,9 +553,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
if (vif->bss_conf.qos)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
/* Don't use cts to self as the fw doesn't support it currently. */
if (vif->bss_conf.use_cts_prot)
cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT |
MAC_PROT_FLG_SELF_CTS_EN);
cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
/*
* I think that we should enable these 2 flags regardless the HT PROT
@ -651,6 +651,13 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
/* Allow beacons to pass through as long as we are not associated,or we
* do not have dtim period information */
if (!vif->bss_conf.assoc || !vif->bss_conf.dtim_period)
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
else
cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON);
/* Fill the data specific for station mode */
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta);
@ -714,7 +721,9 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROMISC);
/* Override the filter flags to accept only probe requests */
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
/*
* This flag should be set to true when the P2P Device is
@ -846,10 +855,10 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
*/
static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_data_ap *ctxt_ap)
struct iwl_mac_data_ap *ctxt_ap,
bool add)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 curr_dev_time;
ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
ctxt_ap->bi_reciprocal =
@ -861,10 +870,19 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
vif->bss_conf.dtim_period));
ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue);
curr_dev_time = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
ctxt_ap->beacon_time = cpu_to_le32(curr_dev_time);
ctxt_ap->beacon_tsf = cpu_to_le64(curr_dev_time);
/*
* Only read the system time when the MAC is being added, when we
* just modify the MAC then we should keep the time -- the firmware
* can otherwise have a "jumping" TBTT.
*/
if (add)
mvmvif->ap_beacon_time =
iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
ctxt_ap->beacon_time = cpu_to_le32(mvmvif->ap_beacon_time);
ctxt_ap->beacon_tsf = 0; /* unused */
/* TODO: Assume that the beacon id == mac context id */
ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id);
@ -881,8 +899,12 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
/* Also enable probe requests to pass */
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
/* 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.ap,
action == FW_CTXT_ACTION_ADD);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@ -899,7 +921,8 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, 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.go.ap,
action == FW_CTXT_ACTION_ADD);
cmd.go.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow);
cmd.go.opp_ps_enabled = cpu_to_le32(!!vif->bss_conf.p2p_oppps);

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -65,7 +65,9 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <net/mac80211.h>
#include <net/tcp.h>
#include "iwl-op-mode.h"
#include "iwl-io.h"
@ -102,10 +104,33 @@ static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
},
};
#ifdef CONFIG_PM_SLEEP
static const struct nl80211_wowlan_tcp_data_token_feature
iwl_mvm_wowlan_tcp_token_feature = {
.min_len = 0,
.max_len = 255,
.bufsize = IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS,
};
static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = {
.tok = &iwl_mvm_wowlan_tcp_token_feature,
.data_payload_max = IWL_WOWLAN_TCP_MAX_PACKET_LEN -
sizeof(struct ethhdr) -
sizeof(struct iphdr) -
sizeof(struct tcphdr),
.data_interval_max = 65535, /* __le16 in API */
.wake_payload_max = IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN -
sizeof(struct ethhdr) -
sizeof(struct iphdr) -
sizeof(struct tcphdr),
.seq = true,
};
#endif
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
{
struct ieee80211_hw *hw = mvm->hw;
int num_mac, ret;
int num_mac, ret, i;
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
@ -156,11 +181,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
hw->wiphy->addresses = mvm->addresses;
hw->wiphy->n_addresses = 1;
num_mac = mvm->nvm_data->n_hw_addrs;
if (num_mac > 1) {
memcpy(mvm->addresses[1].addr, mvm->addresses[0].addr,
/* Extract additional MAC addresses if available */
num_mac = (mvm->nvm_data->n_hw_addrs > 1) ?
min(IWL_MVM_MAX_ADDRESSES, mvm->nvm_data->n_hw_addrs) : 1;
for (i = 1; i < num_mac; i++) {
memcpy(mvm->addresses[i].addr, mvm->addresses[i-1].addr,
ETH_ALEN);
mvm->addresses[1].addr[5]++;
mvm->addresses[i].addr[5]++;
hw->wiphy->n_addresses++;
}
@ -206,6 +235,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
hw->wiphy->wowlan.tcp = &iwl_mvm_wowlan_tcp_support;
}
#endif
@ -273,12 +303,18 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
break;
case IEEE80211_AMPDU_TX_START:
if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) {
ret = -EINVAL;
break;
}
ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn);
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size);
@ -557,11 +593,9 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
return ret;
}
static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 tfd_msk = 0, ac;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
@ -594,12 +628,21 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
*/
flush_work(&mvm->sta_drained_wk);
}
}
static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
iwl_mvm_prepare_mac_removal(mvm, vif);
mutex_lock(&mvm->mutex);
/*
* For AP/GO interface, the tear down of the resources allocated to the
* interface should be handled as part of the bss_info_changed flow.
* interface is be handled as part of the stop_ap flow.
*/
if (vif->type == NL80211_IFTYPE_AP) {
iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
@ -763,6 +806,8 @@ static void iwl_mvm_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
iwl_mvm_prepare_mac_removal(mvm, vif);
mutex_lock(&mvm->mutex);
mvmvif->ap_active = false;

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -79,8 +79,9 @@
#include "fw-api.h"
#define IWL_INVALID_MAC80211_QUEUE 0xff
#define IWL_MVM_MAX_ADDRESSES 2
#define IWL_RSSI_OFFSET 44
#define IWL_MVM_MAX_ADDRESSES 5
/* RSSI offset for WkP */
#define IWL_RSSI_OFFSET 50
enum iwl_mvm_tx_fifo {
IWL_MVM_TX_FIFO_BK = 0,
@ -173,6 +174,8 @@ struct iwl_mvm_vif {
bool uploaded;
bool ap_active;
u32 ap_beacon_time;
enum iwl_tsf_id tsf_id;
/*
@ -327,6 +330,14 @@ struct iwl_mvm {
struct led_classdev led;
struct ieee80211_vif *p2p_device_vif;
#ifdef CONFIG_PM_SLEEP
int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
#endif
/* BT-Coex */
u8 bt_kill_msk;
struct iwl_bt_coex_profile_notif last_bt_notif;
};
/* Extract MVM priv from op_mode and _hw */
@ -497,4 +508,11 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int idx);
/* BT Coex */
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
int iwl_send_bt_init_conf(struct iwl_mvm *mvm);
int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
#endif /* __IWL_MVM_H__ */

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -74,6 +74,9 @@ static const int nvm_to_read[] = {
NVM_SECTION_TYPE_PRODUCTION,
};
/* Default NVM size to read */
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024);
/* used to simplify the shared operations on NCM_ACCESS_CMD versions */
union iwl_nvm_access_cmd {
struct iwl_nvm_access_cmd_ver1 ver1;
@ -193,9 +196,9 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
int ret;
bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000;
length = (iwlwifi_mod_params.amsdu_size_8K ? (8 * 1024) : (4 * 1024))
- sizeof(union iwl_nvm_access_cmd)
- sizeof(struct iwl_rx_packet);
/* Set nvm section read length */
length = IWL_NVM_DEFAULT_CHUNK_SIZE;
/*
* if length is greater than EEPROM size, truncate it because uCode
* doesn't check it by itself, and exit the loop when reached.

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -230,6 +230,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
@ -293,6 +295,11 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(NET_DETECT_PROFILES_CMD),
CMD(NET_DETECT_HOTSPOTS_CMD),
CMD(NET_DETECT_HOTSPOTS_QUERY_CMD),
CMD(CARD_STATE_NOTIFICATION),
CMD(BT_COEX_PRIO_TABLE),
CMD(BT_COEX_PROT_ENV),
CMD(BT_PROFILE_NOTIFICATION),
CMD(BT_CONFIG),
};
#undef CMD
@ -363,8 +370,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
/* TODO: this should really be a TLV */
if (cfg->device_family == IWL_DEVICE_FAMILY_7000)
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)
trans_cfg.bc_table_dword = true;
if (!iwlwifi_mod_params.wd_disable)
@ -624,12 +630,8 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
ieee80211_free_txskb(mvm->hw, skb);
}
static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
iwl_mvm_dump_nic_error_log(mvm);
iwl_abort_notification_waits(&mvm->notif_wait);
/*
@ -663,9 +665,21 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
}
}
static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
iwl_mvm_dump_nic_error_log(mvm);
iwl_mvm_nic_restart(mvm);
}
static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
WARN_ON(1);
iwl_mvm_nic_restart(mvm);
}
static const struct iwl_op_mode_ops iwl_mvm_ops = {

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -680,12 +680,14 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
*/
static bool rs_use_green(struct ieee80211_sta *sta)
{
struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
bool use_green = !(sta_priv->vif->bss_conf.ht_operation_mode &
IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && use_green;
/*
* There's a bug somewhere in this code that causes the
* scaling to get stuck because GF+SGI can't be combined
* in SISO rates. Until we find that bug, disable GF, it
* has only limited benefit and we still interoperate with
* GF APs since we can always receive GF transmissions.
*/
return false;
}
/**

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -131,33 +131,42 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
static int iwl_mvm_calc_rssi(struct iwl_mvm *mvm,
struct iwl_rx_phy_info *phy_info)
{
u32 rssi_a, rssi_b, rssi_c, max_rssi, agc_db;
int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm;
int rssi_all_band_a, rssi_all_band_b;
u32 agc_a, agc_b, max_agc;
u32 val;
/* Find max rssi among 3 possible receivers.
/* Find max rssi among 2 possible receivers.
* These values are measured by the Digital Signal Processor (DSP).
* They should stay fairly constant even as the signal strength varies,
* if the radio's Automatic Gain Control (AGC) is working right.
* AGC value (see below) will provide the "interesting" info.
*/
val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]);
agc_a = (val & IWL_OFDM_AGC_A_MSK) >> IWL_OFDM_AGC_A_POS;
agc_b = (val & IWL_OFDM_AGC_B_MSK) >> IWL_OFDM_AGC_B_POS;
max_agc = max_t(u32, agc_a, agc_b);
val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_AB_IDX]);
rssi_a = (val & IWL_OFDM_RSSI_INBAND_A_MSK) >> IWL_OFDM_RSSI_A_POS;
rssi_b = (val & IWL_OFDM_RSSI_INBAND_B_MSK) >> IWL_OFDM_RSSI_B_POS;
val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_RSSI_C_IDX]);
rssi_c = (val & IWL_OFDM_RSSI_INBAND_C_MSK) >> IWL_OFDM_RSSI_C_POS;
rssi_all_band_a = (val & IWL_OFDM_RSSI_ALLBAND_A_MSK) >>
IWL_OFDM_RSSI_ALLBAND_A_POS;
rssi_all_band_b = (val & IWL_OFDM_RSSI_ALLBAND_B_MSK) >>
IWL_OFDM_RSSI_ALLBAND_B_POS;
val = le32_to_cpu(phy_info->non_cfg_phy[IWL_RX_INFO_AGC_IDX]);
agc_db = (val & IWL_OFDM_AGC_DB_MSK) >> IWL_OFDM_AGC_DB_POS;
/*
* dBm = rssi dB - agc dB - constant.
* Higher AGC (higher radio gain) means lower signal.
*/
rssi_a_dbm = rssi_a - IWL_RSSI_OFFSET - agc_a;
rssi_b_dbm = rssi_b - IWL_RSSI_OFFSET - agc_b;
max_rssi_dbm = max_t(int, rssi_a_dbm, rssi_b_dbm);
max_rssi = max_t(u32, rssi_a, rssi_b);
max_rssi = max_t(u32, max_rssi, rssi_c);
IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d Max %d AGCA %d AGCB %d\n",
rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b);
IWL_DEBUG_STATS(mvm, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
rssi_a, rssi_b, rssi_c, max_rssi, agc_db);
/* dBm = max_rssi dB - agc dB - constant.
* Higher AGC (higher radio gain) means lower signal. */
return max_rssi - agc_db - IWL_RSSI_OFFSET;
return max_rssi_dbm;
}
/*

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -101,8 +101,55 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
add_sta_cmd.add_modify = update ? 1 : 0;
/* STA_FLG_FAT_EN_MSK ? */
/* STA_FLG_MIMO_EN_MSK ? */
add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_FAT_EN_MSK |
STA_FLG_MIMO_EN_MSK);
switch (sta->bandwidth) {
case IEEE80211_STA_RX_BW_160:
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_160MHZ);
/* fall through */
case IEEE80211_STA_RX_BW_80:
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_80MHZ);
/* fall through */
case IEEE80211_STA_RX_BW_40:
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_40MHZ);
/* fall through */
case IEEE80211_STA_RX_BW_20:
if (sta->ht_cap.ht_supported)
add_sta_cmd.station_flags |=
cpu_to_le32(STA_FLG_FAT_EN_20MHZ);
break;
}
switch (sta->rx_nss) {
case 1:
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO);
break;
case 2:
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO2);
break;
case 3 ... 8:
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO3);
break;
}
switch (sta->smps_mode) {
case IEEE80211_SMPS_AUTOMATIC:
case IEEE80211_SMPS_NUM_MODES:
WARN_ON(1);
break;
case IEEE80211_SMPS_STATIC:
/* override NSS */
add_sta_cmd.station_flags &= ~cpu_to_le32(STA_FLG_MIMO_EN_MSK);
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO);
break;
case IEEE80211_SMPS_DYNAMIC:
add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_RTS_MIMO_PROT);
break;
case IEEE80211_SMPS_OFF:
/* nothing */
break;
}
if (sta->ht_cap.ht_supported) {
add_sta_cmd.station_flags_msk |=
@ -340,6 +387,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
if (vif->type == NL80211_IFTYPE_STATION &&
mvmvif->ap_sta_id == mvm_sta->sta_id) {
/* flush its queues here since we are freeing mvm_sta */
ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
/*
* Put a non-NULL since the fw station isn't removed.
* It will be removed after the MAC will be set as
@ -348,9 +398,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
ERR_PTR(-EINVAL));
/* flush its queues here since we are freeing mvm_sta */
ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
/* if we are associated - we can't remove the AP STA now */
if (vif->bss_conf.assoc)
return ret;
@ -770,6 +817,16 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u16 txq_id;
int err;
/*
* If mac80211 is cleaning its state, then say that we finished since
* our state has been cleared anyway.
*/
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
return 0;
}
spin_lock_bh(&mvmsta->lock);
txq_id = tid_data->txq_id;
@ -824,6 +881,34 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return err;
}
int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid)
{
struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
u16 txq_id;
/*
* First set the agg state to OFF to avoid calling
* ieee80211_stop_tx_ba_cb in iwl_mvm_check_ratid_empty.
*/
spin_lock_bh(&mvmsta->lock);
txq_id = tid_data->txq_id;
IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
mvmsta->sta_id, tid, txq_id, tid_data->state);
tid_data->state = IWL_AGG_OFF;
spin_unlock_bh(&mvmsta->lock);
if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
mvm->queue_to_mac80211[tid_data->txq_id] =
IWL_INVALID_MAC80211_QUEUE;
return 0;
}
static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
{
int i;

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -348,6 +348,8 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u8 buf_size);
int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -607,12 +607,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
/* Single frame failure in an AMPDU queue => send BAR */
if (txq_id >= IWL_FIRST_AMPDU_QUEUE &&
!(info->flags & IEEE80211_TX_STAT_ACK)) {
/* there must be only one skb in the skb_list */
WARN_ON_ONCE(skb_freed > 1 ||
!skb_queue_empty(&skbs));
!(info->flags & IEEE80211_TX_STAT_ACK))
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
}
/* W/A FW bug: seq_ctl is wrong when the queue is flushed */
if (status == TX_STATUS_FAIL_FIFO_FLUSHED) {

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>

View File

@ -1,115 +0,0 @@
/******************************************************************************
*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#ifndef __iwl_pci_h__
#define __iwl_pci_h__
/*
* This file declares the config structures for all devices.
*/
extern const struct iwl_cfg iwl5300_agn_cfg;
extern const struct iwl_cfg iwl5100_agn_cfg;
extern const struct iwl_cfg iwl5350_agn_cfg;
extern const struct iwl_cfg iwl5100_bgn_cfg;
extern const struct iwl_cfg iwl5100_abg_cfg;
extern const struct iwl_cfg iwl5150_agn_cfg;
extern const struct iwl_cfg iwl5150_abg_cfg;
extern const struct iwl_cfg iwl6005_2agn_cfg;
extern const struct iwl_cfg iwl6005_2abg_cfg;
extern const struct iwl_cfg iwl6005_2bg_cfg;
extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
extern const struct iwl_cfg iwl6005_2agn_d_cfg;
extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
extern const struct iwl_cfg iwl1030_bgn_cfg;
extern const struct iwl_cfg iwl1030_bg_cfg;
extern const struct iwl_cfg iwl6030_2agn_cfg;
extern const struct iwl_cfg iwl6030_2abg_cfg;
extern const struct iwl_cfg iwl6030_2bgn_cfg;
extern const struct iwl_cfg iwl6030_2bg_cfg;
extern const struct iwl_cfg iwl6000i_2agn_cfg;
extern const struct iwl_cfg iwl6000i_2abg_cfg;
extern const struct iwl_cfg iwl6000i_2bg_cfg;
extern const struct iwl_cfg iwl6000_3agn_cfg;
extern const struct iwl_cfg iwl6050_2agn_cfg;
extern const struct iwl_cfg iwl6050_2abg_cfg;
extern const struct iwl_cfg iwl6150_bgn_cfg;
extern const struct iwl_cfg iwl6150_bg_cfg;
extern const struct iwl_cfg iwl1000_bgn_cfg;
extern const struct iwl_cfg iwl1000_bg_cfg;
extern const struct iwl_cfg iwl100_bgn_cfg;
extern const struct iwl_cfg iwl100_bg_cfg;
extern const struct iwl_cfg iwl130_bgn_cfg;
extern const struct iwl_cfg iwl130_bg_cfg;
extern const struct iwl_cfg iwl2000_2bgn_cfg;
extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
extern const struct iwl_cfg iwl2030_2bgn_cfg;
extern const struct iwl_cfg iwl6035_2agn_cfg;
extern const struct iwl_cfg iwl105_bgn_cfg;
extern const struct iwl_cfg iwl105_bgn_d_cfg;
extern const struct iwl_cfg iwl135_bgn_cfg;
extern const struct iwl_cfg iwl7260_2ac_cfg;
extern const struct iwl_cfg iwl3160_ac_cfg;
#endif /* __iwl_pci_h__ */

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -69,8 +69,6 @@
#include "iwl-trans.h"
#include "iwl-drv.h"
#include "cfg.h"
#include "internal.h"
#define IWL_PCI_DEVICE(dev, subdev, cfg) \

View File

@ -137,10 +137,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd)
struct iwl_cmd_meta {
/* only for SYNC commands, iff the reply skb is wanted */
struct iwl_host_cmd *source;
DEFINE_DMA_UNMAP_ADDR(mapping);
DEFINE_DMA_UNMAP_LEN(len);
u32 flags;
};
@ -182,19 +178,39 @@ struct iwl_queue {
#define TFD_TX_CMD_SLOTS 256
#define TFD_CMD_SLOTS 32
/*
* The FH will write back to the first TB only, so we need
* to copy some data into the buffer regardless of whether
* it should be mapped or not. This indicates how big the
* first TB must be to include the scratch buffer. Since
* the scratch is 4 bytes at offset 12, it's 16 now. If we
* make it bigger then allocations will be bigger and copy
* slower, so that's probably not useful.
*/
#define IWL_HCMD_SCRATCHBUF_SIZE 16
struct iwl_pcie_txq_entry {
struct iwl_device_cmd *cmd;
struct iwl_device_cmd *copy_cmd;
struct sk_buff *skb;
/* buffer to free after command completes */
const void *free_buf;
struct iwl_cmd_meta meta;
};
struct iwl_pcie_txq_scratch_buf {
struct iwl_cmd_header hdr;
u8 buf[8];
__le32 scratch;
};
/**
* struct iwl_txq - Tx Queue for DMA
* @q: generic Rx/Tx queue descriptor
* @tfds: transmit frame descriptors (DMA memory)
* @scratchbufs: start of command headers, including scratch buffers, for
* the writeback -- this is DMA memory and an array holding one buffer
* for each command on the queue
* @scratchbufs_dma: DMA address for the scratchbufs start
* @entries: transmit entries (driver state)
* @lock: queue lock
* @stuck_timer: timer that fires if queue gets stuck
@ -208,6 +224,8 @@ struct iwl_pcie_txq_entry {
struct iwl_txq {
struct iwl_queue q;
struct iwl_tfd *tfds;
struct iwl_pcie_txq_scratch_buf *scratchbufs;
dma_addr_t scratchbufs_dma;
struct iwl_pcie_txq_entry *entries;
spinlock_t lock;
struct timer_list stuck_timer;
@ -216,6 +234,13 @@ struct iwl_txq {
u8 active;
};
static inline dma_addr_t
iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
{
return txq->scratchbufs_dma +
sizeof(struct iwl_pcie_txq_scratch_buf) * idx;
}
/**
* struct iwl_trans_pcie - PCIe transport specific data
* @rxq: all the RX queue data

View File

@ -637,22 +637,14 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
index = SEQ_TO_INDEX(sequence);
cmd_index = get_cmd_index(&txq->q, index);
if (reclaim) {
struct iwl_pcie_txq_entry *ent;
ent = &txq->entries[cmd_index];
cmd = ent->copy_cmd;
WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD);
} else {
if (reclaim)
cmd = txq->entries[cmd_index].cmd;
else
cmd = NULL;
}
err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
if (reclaim) {
/* The original command isn't needed any more */
kfree(txq->entries[cmd_index].copy_cmd);
txq->entries[cmd_index].copy_cmd = NULL;
/* nor is the duplicated part of the command */
kfree(txq->entries[cmd_index].free_buf);
txq->entries[cmd_index].free_buf = NULL;
}

View File

@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@ -715,7 +715,8 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
static u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg)
{
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR,
((reg & 0x000FFFFF) | (3 << 24)));
return iwl_trans_pcie_read32(trans, HBUS_TARG_PRPH_RDAT);
}
@ -723,7 +724,7 @@ static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr,
u32 val)
{
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WADDR,
((addr & 0x0000FFFF) | (3 << 24)));
((addr & 0x000FFFFF) | (3 << 24)));
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val);
}
@ -1370,28 +1371,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
return ret;
}
static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_trans *trans = file->private_data;
if (!trans->op_mode)
return -EAGAIN;
local_bh_disable();
iwl_op_mode_nic_error(trans->op_mode);
local_bh_enable();
return count;
}
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
DEBUGFS_READ_FILE_OPS(fh_reg);
DEBUGFS_READ_FILE_OPS(rx_queue);
DEBUGFS_READ_FILE_OPS(tx_queue);
DEBUGFS_WRITE_FILE_OPS(csr);
DEBUGFS_WRITE_FILE_OPS(fw_restart);
/*
* Create the debugfs files and directories
@ -1405,7 +1389,6 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
return 0;
err:

View File

@ -191,12 +191,9 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
}
for (i = q->read_ptr; i != q->write_ptr;
i = iwl_queue_inc_wrap(i, q->n_bd)) {
struct iwl_tx_cmd *tx_cmd =
(struct iwl_tx_cmd *)txq->entries[i].cmd->payload;
i = iwl_queue_inc_wrap(i, q->n_bd))
IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
get_unaligned_le32(&tx_cmd->scratch));
}
le32_to_cpu(txq->scratchbufs[i].scratch));
iwl_op_mode_nic_error(trans->op_mode);
}
@ -367,8 +364,8 @@ static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_tfd *tfd)
}
static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
struct iwl_cmd_meta *meta, struct iwl_tfd *tfd,
enum dma_data_direction dma_dir)
struct iwl_cmd_meta *meta,
struct iwl_tfd *tfd)
{
int i;
int num_tbs;
@ -382,17 +379,12 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
return;
}
/* Unmap tx_cmd */
if (num_tbs)
dma_unmap_single(trans->dev,
dma_unmap_addr(meta, mapping),
dma_unmap_len(meta, len),
DMA_BIDIRECTIONAL);
/* first TB is never freed - it's the scratchbuf data */
/* Unmap chunks, if any. */
for (i = 1; i < num_tbs; i++)
dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i),
iwl_pcie_tfd_tb_get_len(tfd, i), dma_dir);
iwl_pcie_tfd_tb_get_len(tfd, i),
DMA_TO_DEVICE);
tfd->num_tbs = 0;
}
@ -406,8 +398,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
* Does NOT advance any TFD circular buffer read/write indexes
* Does NOT free the TFD itself (which is within circular buffer)
*/
static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq,
enum dma_data_direction dma_dir)
static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)
{
struct iwl_tfd *tfd_tmp = txq->tfds;
@ -418,8 +409,7 @@ static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq,
lockdep_assert_held(&txq->lock);
/* We have only q->n_window txq->entries, but we use q->n_bd tfds */
iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr],
dma_dir);
iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr]);
/* free SKB */
if (txq->entries) {
@ -479,6 +469,7 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
size_t scratchbuf_sz;
int i;
if (WARN_ON(txq->entries || txq->tfds))
@ -514,9 +505,25 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,
IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
goto error;
}
BUILD_BUG_ON(IWL_HCMD_SCRATCHBUF_SIZE != sizeof(*txq->scratchbufs));
BUILD_BUG_ON(offsetof(struct iwl_pcie_txq_scratch_buf, scratch) !=
sizeof(struct iwl_cmd_header) +
offsetof(struct iwl_tx_cmd, scratch));
scratchbuf_sz = sizeof(*txq->scratchbufs) * slots_num;
txq->scratchbufs = dma_alloc_coherent(trans->dev, scratchbuf_sz,
&txq->scratchbufs_dma,
GFP_KERNEL);
if (!txq->scratchbufs)
goto err_free_tfds;
txq->q.id = txq_id;
return 0;
err_free_tfds:
dma_free_coherent(trans->dev, tfd_sz, txq->tfds, txq->q.dma_addr);
error:
if (txq->entries && txq_id == trans_pcie->cmd_queue)
for (i = 0; i < slots_num; i++)
@ -565,22 +572,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_txq *txq = &trans_pcie->txq[txq_id];
struct iwl_queue *q = &txq->q;
enum dma_data_direction dma_dir;
if (!q->n_bd)
return;
/* In the command queue, all the TBs are mapped as BIDI
* so unmap them as such.
*/
if (txq_id == trans_pcie->cmd_queue)
dma_dir = DMA_BIDIRECTIONAL;
else
dma_dir = DMA_TO_DEVICE;
spin_lock_bh(&txq->lock);
while (q->write_ptr != q->read_ptr) {
iwl_pcie_txq_free_tfd(trans, txq, dma_dir);
iwl_pcie_txq_free_tfd(trans, txq);
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
}
spin_unlock_bh(&txq->lock);
@ -610,7 +608,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
if (txq_id == trans_pcie->cmd_queue)
for (i = 0; i < txq->q.n_window; i++) {
kfree(txq->entries[i].cmd);
kfree(txq->entries[i].copy_cmd);
kfree(txq->entries[i].free_buf);
}
@ -619,6 +616,10 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
dma_free_coherent(dev, sizeof(struct iwl_tfd) *
txq->q.n_bd, txq->tfds, txq->q.dma_addr);
txq->q.dma_addr = 0;
dma_free_coherent(dev,
sizeof(*txq->scratchbufs) * txq->q.n_window,
txq->scratchbufs, txq->scratchbufs_dma);
}
kfree(txq->entries);
@ -962,7 +963,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq);
iwl_pcie_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
iwl_pcie_txq_free_tfd(trans, txq);
}
iwl_pcie_txq_progress(trans_pcie, txq);
@ -1152,20 +1153,37 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
void *dup_buf = NULL;
dma_addr_t phys_addr;
int idx;
u16 copy_size, cmd_size;
u16 copy_size, cmd_size, scratch_size;
bool had_nocopy = false;
int i;
u32 cmd_pos;
const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];
u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];
copy_size = sizeof(out_cmd->hdr);
cmd_size = sizeof(out_cmd->hdr);
/* need one for the header if the first is NOCOPY */
BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
BUILD_BUG_ON(IWL_MAX_CMD_TBS_PER_TFD > IWL_NUM_OF_TBS - 1);
for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {
cmddata[i] = cmd->data[i];
cmdlen[i] = cmd->len[i];
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
if (!cmd->len[i])
continue;
/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */
if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) {
int copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size;
if (copy > cmdlen[i])
copy = cmdlen[i];
cmdlen[i] -= copy;
cmddata[i] += copy;
copy_size += copy;
}
if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
had_nocopy = true;
if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) {
@ -1185,7 +1203,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
goto free_dup_buf;
}
dup_buf = kmemdup(cmd->data[i], cmd->len[i],
dup_buf = kmemdup(cmddata[i], cmdlen[i],
GFP_ATOMIC);
if (!dup_buf)
return -ENOMEM;
@ -1195,7 +1213,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
idx = -EINVAL;
goto free_dup_buf;
}
copy_size += cmd->len[i];
copy_size += cmdlen[i];
}
cmd_size += cmd->len[i];
}
@ -1242,30 +1260,30 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
/* and copy the data that needs to be copied */
cmd_pos = offsetof(struct iwl_device_cmd, payload);
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
if (!cmd->len[i])
copy_size = sizeof(out_cmd->hdr);
for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {
int copy = 0;
if (!cmd->len)
continue;
if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |
IWL_HCMD_DFL_DUP))
break;
memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]);
cmd_pos += cmd->len[i];
}
WARN_ON_ONCE(txq->entries[idx].copy_cmd);
/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */
if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) {
copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size;
/*
* since out_cmd will be the source address of the FH, it will write
* the retry count there. So when the user needs to receivce the HCMD
* that corresponds to the response in the response handler, it needs
* to set CMD_WANT_HCMD.
*/
if (cmd->flags & CMD_WANT_HCMD) {
txq->entries[idx].copy_cmd =
kmemdup(out_cmd, cmd_pos, GFP_ATOMIC);
if (unlikely(!txq->entries[idx].copy_cmd)) {
idx = -ENOMEM;
goto out;
if (copy > cmd->len[i])
copy = cmd->len[i];
}
/* copy everything if not nocopy/dup */
if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |
IWL_HCMD_DFL_DUP)))
copy = cmd->len[i];
if (copy) {
memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], copy);
cmd_pos += copy;
copy_size += copy;
}
}
@ -1275,22 +1293,35 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);
phys_addr = dma_map_single(trans->dev, &out_cmd->hdr, copy_size,
DMA_BIDIRECTIONAL);
if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
idx = -ENOMEM;
goto out;
/* start the TFD with the scratchbuf */
scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE);
memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size);
iwl_pcie_txq_build_tfd(trans, txq,
iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr),
scratch_size, 1);
/* map first command fragment, if any remains */
if (copy_size > scratch_size) {
phys_addr = dma_map_single(trans->dev,
((u8 *)&out_cmd->hdr) + scratch_size,
copy_size - scratch_size,
DMA_TO_DEVICE);
if (dma_mapping_error(trans->dev, phys_addr)) {
iwl_pcie_tfd_unmap(trans, out_meta,
&txq->tfds[q->write_ptr]);
idx = -ENOMEM;
goto out;
}
iwl_pcie_txq_build_tfd(trans, txq, phys_addr,
copy_size - scratch_size, 0);
}
dma_unmap_addr_set(out_meta, mapping, phys_addr);
dma_unmap_len_set(out_meta, len, copy_size);
/* map the remaining (adjusted) nocopy/dup fragments */
for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {
const void *data = cmddata[i];
iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1);
for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
const void *data = cmd->data[i];
if (!cmd->len[i])
if (!cmdlen[i])
continue;
if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |
IWL_HCMD_DFL_DUP)))
@ -1298,16 +1329,15 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP)
data = dup_buf;
phys_addr = dma_map_single(trans->dev, (void *)data,
cmd->len[i], DMA_BIDIRECTIONAL);
cmdlen[i], DMA_TO_DEVICE);
if (dma_mapping_error(trans->dev, phys_addr)) {
iwl_pcie_tfd_unmap(trans, out_meta,
&txq->tfds[q->write_ptr],
DMA_BIDIRECTIONAL);
&txq->tfds[q->write_ptr]);
idx = -ENOMEM;
goto out;
}
iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0);
iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], 0);
}
out_meta->flags = cmd->flags;
@ -1317,8 +1347,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
txq->need_update = 1;
trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size,
&out_cmd->hdr, copy_size);
trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);
/* start timer if queue currently empty */
if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
@ -1377,7 +1406,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
cmd = txq->entries[cmd_index].cmd;
meta = &txq->entries[cmd_index].meta;
iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL);
iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index]);
/* Input error checking is done when commands are added to queue. */
if (meta->flags & CMD_WANT_SKB) {
@ -1556,10 +1585,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
struct iwl_cmd_meta *out_meta;
struct iwl_txq *txq;
struct iwl_queue *q;
dma_addr_t phys_addr = 0;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
u16 len, firstlen, secondlen;
dma_addr_t tb0_phys, tb1_phys, scratch_phys;
void *tb1_addr;
u16 len, tb1_len, tb2_len;
u8 wait_write_ptr = 0;
__le16 fc = hdr->frame_control;
u8 hdr_len = ieee80211_hdrlen(fc);
@ -1597,35 +1625,73 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
INDEX_TO_SEQ(q->write_ptr)));
tb0_phys = iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr);
scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) +
offsetof(struct iwl_tx_cmd, scratch);
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
/* Set up first empty entry in queue's array of Tx/cmd buffers */
out_meta = &txq->entries[q->write_ptr].meta;
/*
* Use the first empty entry in this queue's command buffer array
* to contain the Tx command and MAC header concatenated together
* (payload data will be in another buffer).
* Size of this varies, due to varying MAC header length.
* If end is not dword aligned, we'll have 2 extra bytes at the end
* of the MAC header (device reads on dword boundaries).
* We'll tell device about this padding later.
* The second TB (tb1) points to the remainder of the TX command
* and the 802.11 header - dword aligned size
* (This calculation modifies the TX command, so do it before the
* setup of the first TB)
*/
len = sizeof(struct iwl_tx_cmd) +
sizeof(struct iwl_cmd_header) + hdr_len;
firstlen = (len + 3) & ~3;
len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) +
hdr_len - IWL_HCMD_SCRATCHBUF_SIZE;
tb1_len = (len + 3) & ~3;
/* Tell NIC about any 2-byte padding after MAC header */
if (firstlen != len)
if (tb1_len != len)
tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
/* Physical address of this Tx command's header (not MAC header!),
* within command buffer array. */
txcmd_phys = dma_map_single(trans->dev,
&dev_cmd->hdr, firstlen,
DMA_BIDIRECTIONAL);
if (unlikely(dma_mapping_error(trans->dev, txcmd_phys)))
/* The first TB points to the scratchbuf data - min_copy bytes */
memcpy(&txq->scratchbufs[q->write_ptr], &dev_cmd->hdr,
IWL_HCMD_SCRATCHBUF_SIZE);
iwl_pcie_txq_build_tfd(trans, txq, tb0_phys,
IWL_HCMD_SCRATCHBUF_SIZE, 1);
/* there must be data left over for TB1 or this code must be changed */
BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_HCMD_SCRATCHBUF_SIZE);
/* map the data for TB1 */
tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_HCMD_SCRATCHBUF_SIZE;
tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, tb1_phys)))
goto out_err;
dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
dma_unmap_len_set(out_meta, len, firstlen);
iwl_pcie_txq_build_tfd(trans, txq, tb1_phys, tb1_len, 0);
/*
* Set up TFD's third entry to point directly to remainder
* of skb, if any (802.11 null frames have no payload).
*/
tb2_len = skb->len - hdr_len;
if (tb2_len > 0) {
dma_addr_t tb2_phys = dma_map_single(trans->dev,
skb->data + hdr_len,
tb2_len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, tb2_phys))) {
iwl_pcie_tfd_unmap(trans, out_meta,
&txq->tfds[q->write_ptr]);
goto out_err;
}
iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, 0);
}
/* Set up entry for this TFD in Tx byte-count array */
iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
trace_iwlwifi_dev_tx(trans->dev, skb,
&txq->tfds[txq->q.write_ptr],
sizeof(struct iwl_tfd),
&dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len,
skb->data + hdr_len, tb2_len);
trace_iwlwifi_dev_tx_data(trans->dev, skb,
skb->data + hdr_len, tb2_len);
if (!ieee80211_has_morefrags(fc)) {
txq->need_update = 1;
@ -1634,49 +1700,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
txq->need_update = 0;
}
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
secondlen = skb->len - hdr_len;
if (secondlen > 0) {
phys_addr = dma_map_single(trans->dev, skb->data + hdr_len,
secondlen, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
dma_unmap_single(trans->dev,
dma_unmap_addr(out_meta, mapping),
dma_unmap_len(out_meta, len),
DMA_BIDIRECTIONAL);
goto out_err;
}
}
/* Attach buffers to TFD */
iwl_pcie_txq_build_tfd(trans, txq, txcmd_phys, firstlen, 1);
if (secondlen > 0)
iwl_pcie_txq_build_tfd(trans, txq, phys_addr, secondlen, 0);
scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
offsetof(struct iwl_tx_cmd, scratch);
/* take back ownership of DMA buffer to enable update */
dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
DMA_BIDIRECTIONAL);
tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
/* Set up entry for this TFD in Tx byte-count array */
iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
DMA_BIDIRECTIONAL);
trace_iwlwifi_dev_tx(trans->dev, skb,
&txq->tfds[txq->q.write_ptr],
sizeof(struct iwl_tfd),
&dev_cmd->hdr, firstlen,
skb->data + hdr_len, secondlen);
trace_iwlwifi_dev_tx_data(trans->dev, skb,
skb->data + hdr_len, secondlen);
/* start timer if queue currently empty */
if (txq->need_update && q->read_ptr == q->write_ptr &&
trans_pcie->wd_timeout)