Commit 83368904 authored by Kalle Valo's avatar Kalle Valo

Merge tag 'iwlwifi-next-for-kalle-2017-06-06' of...

Merge tag 'iwlwifi-next-for-kalle-2017-06-06' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

First batch of iwlwifi driver patches 4.13

* Loads of FW API documentation improvements (for tools and htmldoc);
* Continued work for the new A000 family;
* Bumped the maximum supported FW API to 31;
* Improve the differentiation between 8000, 9000 and A000 families;
* A lot of fixes and cleanups here and there;

kvalo: There were conflicts iwl_mvm_stop_device() and
iwl_mvm_tcool_set_cur_state(). The former was easy but latter needed more
thought. Apparently the mutex was taken too late, so I fixed so that the mutex
is taken first and then check for iwl_mvm_firmware_running().
parents 63a2f310 0ae0bb3f
......@@ -70,8 +70,8 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 30
#define IWL8265_UCODE_API_MAX 30
#define IWL8000_UCODE_API_MAX 31
#define IWL8265_UCODE_API_MAX 31
/* Lowest firmware API version supported */
#define IWL8000_UCODE_API_MIN 22
......@@ -98,7 +98,6 @@
IWL8265_FW_PRE __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
#define DEFAULT_NVM_FILE_FAMILY_8000B "nvmData-8000B"
#define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C"
/* Max SDIO RX/TX aggregation sizes of the ADDBA request/response */
......@@ -162,10 +161,11 @@ static const struct iwl_tt_params iwl8000_tt_params = {
.dccm2_len = IWL8260_DCCM2_LEN, \
.smem_offset = IWL8260_SMEM_OFFSET, \
.smem_len = IWL8260_SMEM_LEN, \
.default_nvm_file_B_step = DEFAULT_NVM_FILE_FAMILY_8000B, \
.default_nvm_file_C_step = DEFAULT_NVM_FILE_FAMILY_8000C, \
.thermal_params = &iwl8000_tt_params, \
.apmg_not_supported = true
.apmg_not_supported = true, \
.ext_nvm = true, \
.dbgc_supported = true
#define IWL_DEVICE_8000 \
IWL_DEVICE_8000_COMMON, \
......
......@@ -55,7 +55,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL9000_UCODE_API_MAX 30
#define IWL9000_UCODE_API_MAX 31
/* Lowest firmware API version supported */
#define IWL9000_UCODE_API_MIN 30
......@@ -73,10 +73,13 @@
#define IWL9000_SMEM_LEN 0x68000
#define IWL9000_FW_PRE "iwlwifi-9000-pu-a0-jf-a0-"
#define IWL9000RFB_FW_PRE "iwlwifi-9000-pu-a0-jf-b0-"
#define IWL9260A_FW_PRE "iwlwifi-9260-th-a0-jf-a0-"
#define IWL9260B_FW_PRE "iwlwifi-9260-th-b0-jf-b0-"
#define IWL9000_MODULE_FIRMWARE(api) \
IWL9000_FW_PRE "-" __stringify(api) ".ucode"
#define IWL9000RFB_MODULE_FIRMWARE(api) \
IWL9000RFB_FW_PRE "-" __stringify(api) ".ucode"
#define IWL9260A_MODULE_FIRMWARE(api) \
IWL9260A_FW_PRE "-" __stringify(api) ".ucode"
#define IWL9260B_MODULE_FIRMWARE(api) \
......@@ -125,7 +128,7 @@ static const struct iwl_tt_params iwl9000_tt_params = {
#define IWL_DEVICE_9000 \
.ucode_api_max = IWL9000_UCODE_API_MAX, \
.ucode_api_min = IWL9000_UCODE_API_MIN, \
.device_family = IWL_DEVICE_FAMILY_8000, \
.device_family = IWL_DEVICE_FAMILY_9000, \
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl9000_base_params, \
......@@ -144,7 +147,9 @@ static const struct iwl_tt_params iwl9000_tt_params = {
.mq_rx_supported = true, \
.vht_mu_mimo_supported = true, \
.mac_addr_from_csr = true, \
.rf_id = true
.rf_id = true, \
.ext_nvm = true, \
.dbgc_supported = true
const struct iwl_cfg iwl9160_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9160",
......@@ -182,6 +187,7 @@ const struct iwl_cfg iwl9270_2ac_cfg = {
const struct iwl_cfg iwl9460_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9460",
.fw_name_pre = IWL9000_FW_PRE,
.fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
IWL_DEVICE_9000,
.ht_params = &iwl9000_ht_params,
.nvm_ver = IWL9000_NVM_VERSION,
......@@ -193,6 +199,7 @@ const struct iwl_cfg iwl9460_2ac_cfg = {
const struct iwl_cfg iwl9560_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9560",
.fw_name_pre = IWL9000_FW_PRE,
.fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
IWL_DEVICE_9000,
.ht_params = &iwl9000_ht_params,
.nvm_ver = IWL9000_NVM_VERSION,
......@@ -202,5 +209,6 @@ const struct iwl_cfg iwl9560_2ac_cfg = {
};
MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL9260A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL9260B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
......@@ -55,7 +55,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL_A000_UCODE_API_MAX 30
#define IWL_A000_UCODE_API_MAX 31
/* Lowest firmware API version supported */
#define IWL_A000_UCODE_API_MIN 24
......@@ -103,7 +103,7 @@ static const struct iwl_ht_params iwl_a000_ht_params = {
#define IWL_DEVICE_A000 \
.ucode_api_max = IWL_A000_UCODE_API_MAX, \
.ucode_api_min = IWL_A000_UCODE_API_MIN, \
.device_family = IWL_DEVICE_FAMILY_8000, \
.device_family = IWL_DEVICE_FAMILY_A000, \
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
.base_params = &iwl_a000_base_params, \
......@@ -123,7 +123,9 @@ static const struct iwl_ht_params iwl_a000_ht_params = {
.mac_addr_from_csr = true, \
.use_tfh = true, \
.rf_id = true, \
.gen2 = true
.gen2 = true, \
.ext_nvm = true, \
.dbgc_supported = true
const struct iwl_cfg iwla000_2ac_cfg_hr = {
.name = "Intel(R) Dual Band Wireless AC a000",
......
......@@ -88,6 +88,8 @@ enum iwl_device_family {
IWL_DEVICE_FAMILY_6150,
IWL_DEVICE_FAMILY_7000,
IWL_DEVICE_FAMILY_8000,
IWL_DEVICE_FAMILY_9000,
IWL_DEVICE_FAMILY_A000,
};
/*
......@@ -275,6 +277,8 @@ struct iwl_pwr_tx_backoff {
* filename is constructed as fw_name_pre<api>.ucode.
* @fw_name_pre_next_step: same as @fw_name_pre, only for next step
* (if supported)
* @fw_name_pre_rf_next_step: same as @fw_name_pre_next_step, only for rf next
* step. Supported only in integrated solutions.
* @ucode_api_max: Highest version of uCode API supported by driver.
* @ucode_api_min: Lowest version of uCode API supported by driver.
* @max_inst_size: The maximal length of the fw inst section
......@@ -315,6 +319,7 @@ struct iwl_pwr_tx_backoff {
* @integrated: discrete or integrated
* @gen2: a000 and on transport operation
* @cdb: CDB support
* @ext_nvm: extended NVM format
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
......@@ -325,13 +330,13 @@ struct iwl_cfg {
const char *name;
const char *fw_name_pre;
const char *fw_name_pre_next_step;
const char *fw_name_pre_rf_next_step;
/* params not likely to change within a device family */
const struct iwl_base_params *base_params;
/* params likely to change within a device family */
const struct iwl_ht_params *ht_params;
const struct iwl_eeprom_params *eeprom_params;
const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
const char *default_nvm_file_B_step;
const char *default_nvm_file_C_step;
const struct iwl_tt_params *thermal_params;
enum iwl_device_family device_family;
......@@ -362,7 +367,9 @@ struct iwl_cfg {
integrated:1,
use_tfh:1,
gen2:1,
cdb:1;
cdb:1,
ext_nvm:1,
dbgc_supported:1;
u8 valid_tx_ant;
u8 valid_rx_ant;
u8 non_shared_ant;
......
......@@ -316,6 +316,11 @@
#define CSR_HW_REV_DASH(_val) (((_val) & 0x0000003) >> 0)
#define CSR_HW_REV_STEP(_val) (((_val) & 0x000000C) >> 2)
/* HW RFID */
#define CSR_HW_RFID_FLAVOR(_val) (((_val) & 0x000000F) >> 0)
#define CSR_HW_RFID_DASH(_val) (((_val) & 0x00000F0) >> 4)
#define CSR_HW_RFID_STEP(_val) (((_val) & 0x0000F00) >> 8)
#define CSR_HW_RFID_TYPE(_val) (((_val) & 0x0FFF000) >> 12)
/**
* hw_rev values
......@@ -348,7 +353,8 @@ enum {
/* RF_ID value */
#define CSR_HW_RF_ID_TYPE_JF (0x00105000)
#define CSR_HW_RF_ID_TYPE_HR (0x00109000)
#define CSR_HW_RF_ID_TYPE_HR (0x0010A000)
#define CSR_HW_RF_ID_TYPE_HRCDB (0x00109000)
/* EEPROM REG */
#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
......
......@@ -215,9 +215,13 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
char tag[8];
const char *fw_pre_name;
if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_9000 &&
CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_B_STEP)
fw_pre_name = cfg->fw_name_pre_next_step;
else if (drv->trans->cfg->integrated &&
CSR_HW_RFID_STEP(drv->trans->hw_rf_id) == SILICON_B_STEP &&
cfg->fw_name_pre_rf_next_step)
fw_pre_name = cfg->fw_name_pre_rf_next_step;
else
fw_pre_name = cfg->fw_name_pre;
......
......@@ -79,12 +79,12 @@
#define NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
#define NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
#define NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(x) (x & 0xF)
#define NVM_RF_CFG_DASH_MSK_FAMILY_8000(x) ((x >> 4) & 0xF)
#define NVM_RF_CFG_STEP_MSK_FAMILY_8000(x) ((x >> 8) & 0xF)
#define NVM_RF_CFG_TYPE_MSK_FAMILY_8000(x) ((x >> 12) & 0xFFF)
#define NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(x) ((x >> 24) & 0xF)
#define NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(x) ((x >> 28) & 0xF)
#define EXT_NVM_RF_CFG_FLAVOR_MSK(x) ((x) & 0xF)
#define EXT_NVM_RF_CFG_DASH_MSK(x) (((x) >> 4) & 0xF)
#define EXT_NVM_RF_CFG_STEP_MSK(x) (((x) >> 8) & 0xF)
#define EXT_NVM_RF_CFG_TYPE_MSK(x) (((x) >> 12) & 0xFFF)
#define EXT_NVM_RF_CFG_TX_ANT_MSK(x) (((x) >> 24) & 0xF)
#define EXT_NVM_RF_CFG_RX_ANT_MSK(x) (((x) >> 28) & 0xF)
/**
* DOC: Driver system flows - drv component
......
......@@ -77,6 +77,8 @@
*/
#define FH_MEM_LOWER_BOUND (0x1000)
#define FH_MEM_UPPER_BOUND (0x2000)
#define FH_MEM_LOWER_BOUND_GEN2 (0xa06000)
#define FH_MEM_UPPER_BOUND_GEN2 (0xa08000)
/**
* Keep-Warm (KW) buffer base address.
......
/******************************************************************************
*
* 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 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* The full GNU General Public License is included in this distribution
* in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <linuxwifi@intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#ifndef __iwl_fw_api_h__
#define __iwl_fw_api_h__
/**
* DOC: Host command section
*
* A host command is a command issued by the upper layer to the fw. There are
* several versions of fw that have several APIs. The transport layer is
* completely agnostic to these differences.
* The transport does provide helper functionality (i.e. SYNC / ASYNC mode),
*/
#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f)
#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8)
#define SEQ_TO_INDEX(s) ((s) & 0xff)
#define INDEX_TO_SEQ(i) ((i) & 0xff)
#define SEQ_RX_FRAME cpu_to_le16(0x8000)
/*
* those functions retrieve specific information from
* the id field in the iwl_host_cmd struct which contains
* the command id, the group id and the version of the command
* and vice versa
*/
static inline u8 iwl_cmd_opcode(u32 cmdid)
{
return cmdid & 0xFF;
}
static inline u8 iwl_cmd_groupid(u32 cmdid)
{
return ((cmdid & 0xFF00) >> 8);
}
static inline u8 iwl_cmd_version(u32 cmdid)
{
return ((cmdid & 0xFF0000) >> 16);
}
static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version)
{
return opcode + (groupid << 8) + (version << 16);
}
/* make u16 wide id out of u8 group and opcode */
#define WIDE_ID(grp, opcode) (((grp) << 8) | (opcode))
#define DEF_ID(opcode) ((1 << 8) | (opcode))
/* due to the conversion, this group is special; new groups
* should be defined in the appropriate fw-api header files
*/
#define IWL_ALWAYS_LONG_GROUP 1
/**
* struct iwl_cmd_header
*
* This header format appears in the beginning of each command sent from the
* driver, and each response/notification received from uCode.
*/
struct iwl_cmd_header {
u8 cmd; /* Command ID: REPLY_RXON, etc. */
u8 group_id;
/*
* The driver sets up the sequence number to values of its choosing.
* uCode does not use this value, but passes it back to the driver
* when sending the response to each driver-originated command, so
* the driver can match the response to the command. Since the values
* don't get used by uCode, the driver may set up an arbitrary format.
*
* There is one exception: uCode sets bit 15 when it originates
* the response/notification, i.e. when the response/notification
* is not a direct response to a command sent by the driver. For
* example, uCode issues REPLY_RX when it sends a received frame
* to the driver; it is not a direct response to any driver command.
*
* The Linux driver uses the following format:
*
* 0:7 tfd index - position within TX queue
* 8:12 TX queue id
* 13:14 reserved
* 15 unsolicited RX or uCode-originated notification
*/
__le16 sequence;
} __packed;
/**
* struct iwl_cmd_header_wide
*
* This header format appears in the beginning of each command sent from the
* driver, and each response/notification received from uCode.
* this is the wide version that contains more information about the command
* like length, version and command type
*/
struct iwl_cmd_header_wide {
u8 cmd;
u8 group_id;
__le16 sequence;
__le16 length;
u8 reserved;
u8 version;
} __packed;
/**
* iwl_tx_queue_cfg_actions - TXQ config options
* @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue
* @TX_QUEUE_CFG_TFD_SHORT_FORMAT: use short TFD format
*/
enum iwl_tx_queue_cfg_actions {
TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0),
TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1),
};
/**
* struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command
* @sta_id: station id
* @tid: tid of the queue
* @flags: see &enum iwl_tx_queue_cfg_actions
* @cb_size: size of TFD cyclic buffer. Value is exponent - 3.
* Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs)
* @byte_cnt_addr: address of byte count table
* @tfdq_addr: address of TFD circular buffer
*/
struct iwl_tx_queue_cfg_cmd {
u8 sta_id;
u8 tid;
__le16 flags;
__le32 cb_size;
__le64 byte_cnt_addr;
__le64 tfdq_addr;
} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */
/**
* struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config
* @queue_number: queue number assigned to this RA -TID
* @flags: set on failure
* @write_pointer: initial value for write pointer
*/
struct iwl_tx_queue_cfg_rsp {
__le16 queue_number;
__le16 flags;
__le16 write_pointer;
__le16 reserved;
} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */
#endif /* __iwl_fw_api_h__*/
......@@ -116,7 +116,7 @@ enum iwl_fw_error_dump_type {
/**
* struct iwl_fw_error_dump_data - data for one type
* @type: %enum iwl_fw_error_dump_type
* @type: &enum iwl_fw_error_dump_type
* @len: the length starting from %data
* @data: the data itself
*/
......@@ -130,7 +130,7 @@ struct iwl_fw_error_dump_data {
* struct iwl_fw_error_dump_file - the layout of the header of the file
* @barker: must be %IWL_FW_ERROR_DUMP_BARKER
* @file_len: the length of all the file starting from %barker
* @data: array of %struct iwl_fw_error_dump_data
* @data: array of &struct iwl_fw_error_dump_data
*/
struct iwl_fw_error_dump_file {
__le32 barker;
......@@ -225,7 +225,7 @@ enum iwl_fw_error_dump_mem_type {
/**
* struct iwl_fw_error_dump_mem - chunk of memory
* @type: %enum iwl_fw_error_dump_mem_type
* @type: &enum iwl_fw_error_dump_mem_type
* @offset: the offset from which the memory was read
* @data: the content of the memory
*/
......@@ -324,7 +324,7 @@ enum iwl_fw_dbg_trigger {
/**
* struct iwl_fw_error_dump_trigger_desc - describes the trigger condition
* @type: %enum iwl_fw_dbg_trigger
* @type: &enum iwl_fw_dbg_trigger
* @data: raw data about what happened
*/
struct iwl_fw_error_dump_trigger_desc {
......
......@@ -244,6 +244,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
* @IWL_UCODE_TLV_API_TKIP_MIC_KEYS: This ucode supports version 2 of
* ADD_MODIFY_STA_KEY_API_S_VER_2.
* @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement.
* @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2
*
* @NUM_IWL_UCODE_TLV_API: number of bits used
*/
......@@ -255,6 +256,7 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_SCAN_TSF_REPORT = (__force iwl_ucode_tlv_api_t)28,
IWL_UCODE_TLV_API_TKIP_MIC_KEYS = (__force iwl_ucode_tlv_api_t)29,
IWL_UCODE_TLV_API_STA_TYPE = (__force iwl_ucode_tlv_api_t)30,
IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31,
NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__
......@@ -395,8 +397,8 @@ enum iwl_ucode_tlv_capa {
#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8)
#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF)
/*
* Calibration control struct.
/**
* struct iwl_tlv_calib_ctrl - Calibration control struct.
* Sent as part of the phy configuration command.
* @flow_trigger: bitmap for which calibrations to perform according to
* flow triggers.
......@@ -468,7 +470,7 @@ enum iwl_fw_dbg_reg_operator {
/**
* struct iwl_fw_dbg_reg_op - an operation on a register
*
* @op: %enum iwl_fw_dbg_reg_operator
* @op: &enum iwl_fw_dbg_reg_operator
* @addr: offset of the register
* @val: value
*/
......@@ -526,7 +528,7 @@ struct iwl_fw_dbg_mem_seg_tlv {
* struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data
*
* @version: version of the TLV - currently 0
* @monitor_mode: %enum iwl_fw_dbg_monitor_mode
* @monitor_mode: &enum iwl_fw_dbg_monitor_mode
* @size_power: buffer size will be 2^(size_power + 11)
* @base_reg: addr of the base addr register (PRPH)
* @end_reg: addr of the end addr register (PRPH)
......@@ -595,15 +597,15 @@ enum iwl_fw_dbg_trigger_vif_type {
/**
* struct iwl_fw_dbg_trigger_tlv - a TLV that describes the trigger
* @id: %enum iwl_fw_dbg_trigger
* @vif_type: %enum iwl_fw_dbg_trigger_vif_type
* @id: &enum iwl_fw_dbg_trigger
* @vif_type: &enum iwl_fw_dbg_trigger_vif_type
* @stop_conf_ids: bitmap of configurations this trigger relates to.
* if the mode is %IWL_FW_DBG_TRIGGER_STOP, then if the bit corresponding
* to the currently running configuration is set, the data should be
* collected.
* @stop_delay: how many milliseconds to wait before collecting the data
* after the STOP trigger fires.
* @mode: %enum iwl_fw_dbg_trigger_mode - can be stop / start of both
* @mode: &enum iwl_fw_dbg_trigger_mode - can be stop / start of both
* @start_conf_id: if mode is %IWL_FW_DBG_TRIGGER_START, this defines what
* configuration should be applied when the triggers kicks in.
* @occurrences: number of occurrences. 0 means the trigger will never fire.
......
......@@ -241,12 +241,12 @@ IWL_EXPORT_SYMBOL(iwl_clear_bits_prph);
void iwl_force_nmi(struct iwl_trans *trans)
{
if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) {
iwl_write_prph(trans, DEVICE_SET_NMI_REG,
DEVICE_SET_NMI_VAL_DRV);
iwl_write_prph(trans, DEVICE_SET_NMI_REG,
DEVICE_SET_NMI_VAL_HW);
} else if (trans->cfg->gen2) {
} else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_A000) {
iwl_write_prph(trans, UREG_NIC_SET_NMI_DRIVER,
DEVICE_SET_NMI_8000_VAL);
} else {
......
......@@ -114,7 +114,7 @@ enum iwl_uapsd_disable {
* @debug_level: levels are IWL_DL_*
* @ant_coupling: antenna coupling in dB, default = 0
* @nvm_file: specifies a external NVM file
* @uapsd_disable: disable U-APSD, see %enum iwl_uapsd_disable, default =
* @uapsd_disable: disable U-APSD, see &enum iwl_uapsd_disable, default =
* IWL_DISABLE_UAPSD_BSS | IWL_DISABLE_UAPSD_P2P_CLIENT
* @d0i3_disable: disable d0i3, default = 1,
* @d0i3_entry_delay: time to wait after no refs are taken before
......
......@@ -94,30 +94,21 @@ enum wkp_nvm_offsets {
XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
};
enum family_8000_nvm_offsets {
enum ext_nvm_offsets {
/* NVM HW-Section offset (in words) definitions */
HW_ADDR0_WFPM_FAMILY_8000 = 0x12,
HW_ADDR1_WFPM_FAMILY_8000 = 0x16,
HW_ADDR0_PCIE_FAMILY_8000 = 0x8A,
HW_ADDR1_PCIE_FAMILY_8000 = 0x8E,
MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1,
MAC_ADDRESS_OVERRIDE_EXT_NVM = 1,
/* NVM SW-Section offset (in words) definitions */
NVM_SW_SECTION_FAMILY_8000 = 0x1C0,
NVM_VERSION_FAMILY_8000 = 0,
RADIO_CFG_FAMILY_8000 = 0,
NVM_VERSION_EXT_NVM = 0,
RADIO_CFG_FAMILY_EXT_NVM = 0,
SKU_FAMILY_8000 = 2,
N_HW_ADDRS_FAMILY_8000 = 3,
/* NVM REGULATORY -Section offset (in words) definitions */
NVM_CHANNELS_FAMILY_8000 = 0,
NVM_LAR_OFFSET_FAMILY_8000_OLD = 0x4C7,
NVM_LAR_OFFSET_FAMILY_8000 = 0x507,
NVM_LAR_ENABLED_FAMILY_8000 = 0x7,
/* NVM calibration section offset (in words) definitions */
NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8,
XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000
NVM_CHANNELS_EXTENDED = 0,
NVM_LAR_OFFSET_OLD = 0x4C7,
NVM_LAR_OFFSET = 0x507,
NVM_LAR_ENABLED = 0x7,
};
/* SKU Capabilities (actual values from NVM definition) */
......@@ -141,7 +132,7 @@ static const u8 iwl_nvm_channels[] = {
149, 153, 157, 161, 165
};
static const u8 iwl_nvm_channels_family_8000[] = {
static const u8 iwl_ext_nvm_channels[] = {
/* 2.4 GHz */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
/* 5 GHz */
......@@ -151,9 +142,9 @@ static const u8 iwl_nvm_channels_family_8000[] = {
};
#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
#define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000)
#define IWL_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
#define NUM_2GHZ_CHANNELS 14
#define NUM_2GHZ_CHANNELS_FAMILY_8000 14
#define NUM_2GHZ_CHANNELS_EXT 14
#define FIRST_2GHZ_HT_MINUS 5
#define LAST_2GHZ_HT_PLUS 9
#define LAST_5GHZ_HT 165
......@@ -219,7 +210,7 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
u32 flags = IEEE80211_CHAN_NO_HT40;
u32 last_5ghz_ht = LAST_5GHZ_HT;
if (cfg->device_family == IWL_DEVICE_FAMILY_8000)
if (cfg->ext_nvm)
last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) {
......@@ -273,14 +264,14 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
int num_of_ch, num_2ghz_channels;
const u8 *nvm_chan;
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (!cfg->ext_nvm) {
num_of_ch = IWL_NUM_CHANNELS;
nvm_chan = &iwl_nvm_channels[0];
num_2ghz_channels = NUM_2GHZ_CHANNELS;
} else {
num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
nvm_chan = &iwl_nvm_channels_family_8000[0];
num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000;
num_of_ch = IWL_NUM_CHANNELS_EXT;
nvm_chan = &iwl_ext_nvm_channels[0];
num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT;
}
for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
......@@ -479,7 +470,7 @@ IWL_EXPORT_SYMBOL(iwl_init_sbands);
static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
const __le16 *phy_sku)
{
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
if (!cfg->ext_nvm)
return le16_to_cpup(nvm_sw + SKU);
return le32_to_cpup((__le32 *)(phy_sku + SKU_FAMILY_8000));
......@@ -487,20 +478,20 @@ static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw)
{
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
if (!cfg->ext_nvm)
return le16_to_cpup(nvm_sw + NVM_VERSION);
else
return le32_to_cpup((__le32 *)(nvm_sw +
NVM_VERSION_FAMILY_8000));
NVM_VERSION_EXT_NVM));
}
static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
const __le16 *phy_sku)
{
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
if (!cfg->ext_nvm)
return le16_to_cpup(nvm_sw + RADIO_CFG);
return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_8000));
return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_EXT_NVM));
}
......@@ -508,7 +499,7 @@ static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw)
{
int n_hw_addr;
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
if (!cfg->ext_nvm)
return le16_to_cpup(nvm_sw + N_HW_ADDRS);
n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000));
......@@ -520,7 +511,7 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
u32 radio_cfg)
{
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (!cfg->ext_nvm) {
data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
......@@ -529,12 +520,12 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
}
/* set the radio configuration for family 8000 */
data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg);
data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg);
data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
data->radio_cfg_type = EXT_NVM_RF_CFG_TYPE_MSK(radio_cfg);
data->radio_cfg_step = EXT_NVM_RF_CFG_STEP_MSK(radio_cfg);
data->radio_cfg_dash = EXT_NVM_RF_CFG_DASH_MSK(radio_cfg);
data->radio_cfg_pnum = EXT_NVM_RF_CFG_FLAVOR_MSK(radio_cfg);
data->valid_tx_ant = EXT_NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
data->valid_rx_ant = EXT_NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
}
static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest)
......@@ -587,7 +578,7 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
};
hw_addr = (const u8 *)(mac_override +
MAC_ADDRESS_OVERRIDE_FAMILY_8000);
MAC_ADDRESS_OVERRIDE_EXT_NVM);
/*
* Store the MAC address from MAO section.
......@@ -629,7 +620,7 @@ static int iwl_set_hw_address(struct iwl_trans *trans,
{
if (cfg->mac_addr_from_csr) {
iwl_set_hw_address_from_csr(trans, data);
} else if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
} else if (!cfg->ext_nvm) {
const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR);
/* The byte order is little endian 16 bit, meaning 214365 */
......@@ -666,7 +657,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
u16 lar_config;
const __le16 *ch_section;
if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
if (!cfg->ext_nvm)
data = kzalloc(sizeof(*data) +
sizeof(struct ieee80211_channel) *
IWL_NUM_CHANNELS,
......@@ -674,7 +665,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
else
data = kzalloc(sizeof(*data) +
sizeof(struct ieee80211_channel) *
IWL_NUM_CHANNELS_FAMILY_8000,
IWL_NUM_CHANNELS_EXT,
GFP_KERNEL);
if (!data)
return NULL;
......@@ -700,7 +691,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (!cfg->ext_nvm) {
/* Checking for required sections */
if (!nvm_calib) {
IWL_ERR(trans,
......@@ -715,14 +706,14 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
ch_section = &nvm_sw[NVM_CHANNELS];
} else {
u16 lar_offset = data->nvm_version < 0xE39 ?
NVM_LAR_OFFSET_FAMILY_8000_OLD :
NVM_LAR_OFFSET_FAMILY_8000;
NVM_LAR_OFFSET_OLD :
NVM_LAR_OFFSET;
lar_config = le16_to_cpup(regulatory + lar_offset);
data->lar_enabled = !!(lar_config &
NVM_LAR_ENABLED_FAMILY_8000);
NVM_LAR_ENABLED);
lar_enabled = data->lar_enabled;
ch_section = &regulatory[NVM_CHANNELS_FAMILY_8000];
ch_section = &regulatory[NVM_CHANNELS_EXTENDED];
}
/* If no valid mac address was found - bail out */
......@@ -746,7 +737,7 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
u32 flags = NL80211_RRF_NO_HT40;
u32 last_5ghz_ht = LAST_5GHZ_HT;
if (cfg->device_family == IWL_DEVICE_FAMILY_8000)
if (cfg->ext_nvm)
last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
if (ch_idx < NUM_2GHZ_CHANNELS &&
......@@ -793,8 +784,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
{
int ch_idx;
u16 ch_flags, prev_ch_flags = 0;
const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ?
iwl_nvm_channels_family_8000 : iwl_nvm_channels;
const u8 *nvm_chan = cfg->ext_nvm ?
iwl_ext_nvm_channels : iwl_nvm_channels;
struct ieee80211_regdomain *regd;
int size_of_regd;
struct ieee80211_reg_rule *rule;
......@@ -802,8 +793,8 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
int center_freq, prev_center_freq = 0;
int valid_rules = 0;
bool new_rule;
int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ?
IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS;
int max_num_ch = cfg->ext_nvm ?
IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS;
if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
return ERR_PTR(-EINVAL);
......
......@@ -102,6 +102,8 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
if (!trans->dev_cmd_pool)
return NULL;
WARN_ON(!ops->wait_txq_empty && !ops->wait_tx_queues_empty);
return trans;
}
......
......@@ -76,6 +76,7 @@
#include "iwl-config.h"
#include "iwl-fw.h"
#include "iwl-op-mode.h"
#include "iwl-fw-api.h"
/**
* DOC: Transport layer - what is it ?
......@@ -111,104 +112,6 @@
* 6) Eventually, the free function will be called.
*/
/**
* DOC: Host command section
*
* A host command is a command issued by the upper layer to the fw. There are
* several versions of fw that have several APIs. The transport layer is
* completely agnostic to these differences.
* The transport does provide helper functionality (i.e. SYNC / ASYNC mode),
*/
#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f)
#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8)
#define SEQ_TO_INDEX(s) ((s) & 0xff)
#define INDEX_TO_SEQ(i) ((i) & 0xff)
#define SEQ_RX_FRAME cpu_to_le16(0x8000)
/*
* those functions retrieve specific information from
* the id field in the iwl_host_cmd struct which contains
* the command id, the group id and the version of the command
* and vice versa
*/
static inline u8 iwl_cmd_opcode(u32 cmdid)
{
return cmdid & 0xFF;
}
static inline u8 iwl_cmd_groupid(u32 cmdid)
{
return ((cmdid & 0xFF00) >> 8);
}
static inline u8 iwl_cmd_version(u32 cmdid)
{
return ((cmdid & 0xFF0000) >> 16);
}
static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version)
{
return opcode + (groupid << 8) + (version << 16);
}
/* make u16 wide id out of u8 group and opcode */
#define WIDE_ID(grp, opcode) ((grp << 8) | opcode)
#define DEF_ID(opcode) ((1 << 8) | (opcode))
/* due to the conversion, this group is special; new groups
* should be defined in the appropriate fw-api header files
*/
#define IWL_ALWAYS_LONG_GROUP 1
/**
* struct iwl_cmd_header
*
* This header format appears in the beginning of each command sent from the
* driver, and each response/notification received from uCode.
*/
struct iwl_cmd_header {
u8 cmd; /* Command ID: REPLY_RXON, etc. */
u8 group_id;
/*
* The driver sets up the sequence number to values of its choosing.
* uCode does not use this value, but passes it back to the driver
* when sending the response to each driver-originated command, so
* the driver can match the response to the command. Since the values
* don't get used by uCode, the driver may set up an arbitrary format.
*
* There is one exception: uCode sets bit 15 when it originates
* the response/notification, i.e. when the response/notification
* is not a direct response to a command sent by the driver. For
* example, uCode issues REPLY_RX when it sends a received frame
* to the driver; it is not a direct response to any driver command.
*
* The Linux driver uses the following format:
*
* 0:7 tfd index - position within TX queue
* 8:12 TX queue id
* 13:14 reserved
* 15 unsolicited RX or uCode-originated notification
*/
__le16 sequence;
} __packed;
/**
* struct iwl_cmd_header_wide
*
* This header format appears in the beginning of each command sent from the
* driver, and each response/notification received from uCode.
* this is the wide version that contains more information about the command
* like length, version and command type
*/
struct iwl_cmd_header_wide {
u8 cmd;
u8 group_id;
__le16 sequence;
__le16 length;
u8 reserved;
u8 version;
} __packed;
#define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */
#define FH_RSCSR_FRAME_INVALID 0x55550000
#define FH_RSCSR_FRAME_ALIGN 0x40
......@@ -308,7 +211,7 @@ struct iwl_device_cmd {
#define IWL_MAX_CMD_TBS_PER_TFD 2
/**
* struct iwl_hcmd_dataflag - flag for each one of the chunks of the command
* enum iwl_hcmd_dataflag - flag for each one of the chunks of the command
*
* @IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's
* ring. The transport layer doesn't map the command's buffer to DMA, but
......@@ -533,44 +436,6 @@ struct iwl_trans_txq_scd_cfg {
int frame_limit;
};
/* Available options for &struct iwl_tx_queue_cfg_cmd */
enum iwl_tx_queue_cfg_actions {
TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0),
TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1),
};
/**
* struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command
* @sta_id: station id
* @tid: tid of the queue
* @flags: Bit 0 - on enable, off - disable, Bit 1 - short TFD format
* @cb_size: size of TFD cyclic buffer. Value is exponent - 3.
* Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs)
* @byte_cnt_addr: address of byte count table
* @tfdq_addr: address of TFD circular buffer
*/
struct iwl_tx_queue_cfg_cmd {
u8 sta_id;
u8 tid;
__le16 flags;
__le32 cb_size;
__le64 byte_cnt_addr;
__le64 tfdq_addr;
} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */
/**
* struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config
* @queue_number: queue number assigned to this RA -TID
* @flags: set on failure
* @write_pointer: initial value for write pointer
*/
struct iwl_tx_queue_cfg_rsp {
__le16 queue_number;
__le16 flags;
__le16 write_pointer;
__le16 reserved;
} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */
/**
* struct iwl_trans_ops - transport specific operations
*
......@@ -619,7 +484,8 @@ struct iwl_tx_queue_cfg_rsp {
* @txq_disable: de-configure a Tx queue to send AMPDUs
* Must be atomic
* @txq_set_shared_mode: change Tx queue shared/unshared marking
* @wait_tx_queue_empty: wait until tx queues are empty. May sleep.
* @wait_tx_queues_empty: wait until tx queues are empty. May sleep.
* @wait_txq_empty: wait until specific tx queue is empty. May sleep.
* @freeze_txq_timer: prevents the timer of the queue from firing until the
* queue is set to awake. Must be atomic.
* @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note
......@@ -692,6 +558,7 @@ struct iwl_trans_ops {
bool shared);
int (*wait_tx_queues_empty)(struct iwl_trans *trans, u32 txq_bm);
int (*wait_txq_empty)(struct iwl_trans *trans, int queue);
void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs,
bool freeze);
void (*block_txq_ptrs)(struct iwl_trans *trans, bool block);
......@@ -1041,13 +908,7 @@ iwl_trans_dump_data(struct iwl_trans *trans,
static inline struct iwl_device_cmd *
iwl_trans_alloc_tx_cmd(struct iwl_trans *trans)
{
struct iwl_device_cmd *dev_cmd_ptr =
kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC);
if (unlikely(dev_cmd_ptr == NULL))
return NULL;
return dev_cmd_ptr;
return kmem_cache_alloc(trans->dev_cmd_pool, GFP_ATOMIC);
}
int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
......@@ -1198,6 +1059,9 @@ static inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans,
static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans,
u32 txqs)
{
if (WARN_ON_ONCE(!trans->ops->wait_tx_queues_empty))
return -ENOTSUPP;
if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
return -EIO;
......@@ -1206,6 +1070,19 @@ static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans,
return trans->ops->wait_tx_queues_empty(trans, txqs);
}
static inline int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue)
{
if (WARN_ON_ONCE(!trans->ops->wait_txq_empty))
return -ENOTSUPP;
if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
return -EIO;
}
return trans->ops->wait_txq_empty(trans, queue);
}
static inline void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val)
{
trans->ops->write8(trans, ofs, val);
......
......@@ -914,7 +914,8 @@ void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
u32 ant_isolation = le32_to_cpup((void *)pkt->data);
struct iwl_mvm_antenna_coupling_notif *notif = (void *)pkt->data;
u32 ant_isolation = le32_to_cpu(notif->isolation);
struct iwl_bt_coex_corun_lut_update_cmd cmd = {};
u8 __maybe_unused lower_bound, upper_bound;
u8 lut;
......
......@@ -110,6 +110,7 @@
#define IWL_MVM_TOF_IS_RESPONDER 0
#define IWL_MVM_SW_TX_CSUM_OFFLOAD 0
#define IWL_MVM_HW_CSUM_DISABLE 0
#define IWL_MVM_PARSE_NVM 0
#define IWL_MVM_COLLECT_FW_ERR_DUMP 1
#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1
#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2
......
......@@ -7,7 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
......@@ -34,6 +34,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -82,7 +83,8 @@ static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file,
char buf[16];
int pos, budget;
if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
if (!iwl_mvm_firmware_running(mvm) ||
mvm->cur_ucode != IWL_UCODE_REGULAR)
return -EIO;
mutex_lock(&mvm->mutex);
......@@ -102,7 +104,8 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf,
{
int ret;
if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
if (!iwl_mvm_firmware_running(mvm) ||
mvm->cur_ucode != IWL_UCODE_REGULAR)
return -EIO;
mutex_lock(&mvm->mutex);
......@@ -118,7 +121,8 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf,
int ret;
u32 scd_q_msk;
if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
if (!iwl_mvm_firmware_running(mvm) ||
mvm->cur_ucode != IWL_UCODE_REGULAR)
return -EIO;
if (sscanf(buf, "%x", &scd_q_msk) != 1)
......@@ -139,7 +143,8 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
struct iwl_mvm_sta *mvmsta;
int sta_id, drain, ret;
if (!mvm->ucode_loaded || mvm->cur_ucode != IWL_UCODE_REGULAR)
if (!iwl_mvm_firmware_running(mvm) ||
mvm->cur_ucode != IWL_UCODE_REGULAR)
return -EIO;
if (sscanf(buf, "%d %d", &sta_id, &drain) != 2)
......@@ -172,7 +177,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
size_t ret;
u8 *ptr;
if (!mvm->ucode_loaded)
if (!iwl_mvm_firmware_running(mvm))
return -EINVAL;
/* default is to dump the entire data segment */
......@@ -205,7 +210,7 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
u32 offset, len;
u32 img_offset, img_len;
if (!mvm->ucode_loaded)
if (!iwl_mvm_firmware_running(mvm))
return -EINVAL;
img = &mvm->fw->img[mvm->cur_ucode];
......@@ -258,7 +263,7 @@ static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
{
int temperature;
if (!mvm->ucode_loaded && !mvm->temperature_test)
if (!iwl_mvm_firmware_running(mvm) && !mvm->temperature_test)
return -EIO;
if (kstrtoint(buf, 10, &temperature))
......@@ -305,7 +310,7 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file,
int pos, ret;
s32 temp;
if (!mvm->ucode_loaded)
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
mutex_lock(&mvm->mutex);
......@@ -371,7 +376,7 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf,
{
int ret, val;
if (!mvm->ucode_loaded)
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
if (!strncmp("disable_power_off_d0=", buf, 21)) {
......@@ -583,7 +588,11 @@ iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf,
mvm->bt_force_ant_mode = bt_force_ant_mode;
IWL_DEBUG_COEX(mvm, "Force mode: %s\n",
modes_str[mvm->bt_force_ant_mode]);
ret = iwl_send_bt_init_conf(mvm);
if (iwl_mvm_firmware_running(mvm))
ret = iwl_send_bt_init_conf(mvm);
else
ret = 0;
out:
mutex_unlock(&mvm->mutex);
......@@ -800,6 +809,9 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
{
int __maybe_unused ret;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
mutex_lock(&mvm->mutex);
/* allow one more restart that we're provoking here */
......@@ -817,7 +829,12 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf,
static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf,
size_t count, loff_t *ppos)
{
int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI);
int ret;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_NMI);
if (ret)
return ret;
......@@ -857,6 +874,9 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
{
u8 scan_rx_ant;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
if (sscanf(buf, "%hhx", &scan_rx_ant) != 1)
return -EINVAL;
if (scan_rx_ant > ANT_ABC)
......@@ -911,7 +931,11 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key));
mutex_lock(&mvm->mutex);
ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
if (iwl_mvm_firmware_running(mvm))
ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0,
sizeof(cmd), &cmd);
else
ret = 0;
mutex_unlock(&mvm->mutex);
return ret ?: count;
......@@ -931,6 +955,9 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm,
int bin_len = count / 2;
int ret = -EINVAL;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
/* supporting only 9000 descriptor */
if (!mvm->trans->cfg->mq_rx_supported)
return -ENOTSUPP;
......@@ -1004,11 +1031,14 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
struct iwl_continuous_record_cmd cont_rec = {};
int ret, rec_mode;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
if (!dest)
return -EOPNOTSUPP;
if (dest->monitor_mode != SMEM_MODE ||
trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)
return -EOPNOTSUPP;
ret = kstrtoint(buf, 0, &rec_mode);
......@@ -1034,6 +1064,9 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
unsigned int conf_id;
int ret;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
ret = kstrtouint(buf, 0, &conf_id);
if (ret)
return ret;
......@@ -1052,8 +1085,12 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
char *buf, size_t count,
loff_t *ppos)
{
int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
int ret;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
if (ret)
return ret;
if (count == 0)
......@@ -1184,7 +1221,8 @@ static ssize_t iwl_dbgfs_bcast_filters_write(struct iwl_mvm *mvm, char *buf,
&filter, sizeof(filter));
/* send updated bcast filtering configuration */
if (mvm->dbgfs_bcast_filtering.override &&
if (iwl_mvm_firmware_running(mvm) &&
mvm->dbgfs_bcast_filtering.override &&
iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
sizeof(cmd), &cmd);
......@@ -1256,7 +1294,8 @@ static ssize_t iwl_dbgfs_bcast_filters_macs_write(struct iwl_mvm *mvm,
&mac, sizeof(mac));
/* send updated bcast filtering configuration */
if (mvm->dbgfs_bcast_filtering.override &&
if (iwl_mvm_firmware_running(mvm) &&
mvm->dbgfs_bcast_filtering.override &&
iwl_mvm_bcast_filter_build_cmd(mvm, &cmd))
err = iwl_mvm_send_cmd_pdu(mvm, BCAST_FILTER_CMD, 0,
sizeof(cmd), &cmd);
......@@ -1473,6 +1512,9 @@ iwl_dbgfs_send_echo_cmd_write(struct iwl_mvm *mvm, char *buf,
{
int ret;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
mutex_lock(&mvm->mutex);
ret = iwl_mvm_send_cmd_pdu(mvm, ECHO_CMD, 0, 0, NULL);
mutex_unlock(&mvm->mutex);
......@@ -1534,6 +1576,9 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
size_t delta;
ssize_t ret, len;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
DEBUG_GROUP, 0);
cmd.op = cpu_to_le32(DEBUG_MEM_OP_READ);
......@@ -1586,6 +1631,9 @@ static ssize_t iwl_dbgfs_mem_write(struct file *file,
u32 op, len;
ssize_t ret;
if (!iwl_mvm_firmware_running(mvm))
return -EIO;
hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
DEBUG_GROUP, 0);
......
......@@ -99,8 +99,8 @@ enum iwl_bt_coex_enabled_modules {
/**
* struct iwl_bt_coex_cmd - bt coex configuration command
* @mode: enum %iwl_bt_coex_mode
* @enabled_modules: enum %iwl_bt_coex_enabled_modules
* @mode: &enum iwl_bt_coex_mode
* @enabled_modules: &enum iwl_bt_coex_enabled_modules
*
* The structure is used for the BT_COEX command.
*/
......@@ -234,9 +234,9 @@ enum iwl_bt_ci_compliance {
* @mbox_msg: message from BT to WiFi
* @msg_idx: the index of the message
* @bt_ci_compliance: enum %iwl_bt_ci_compliance
* @primary_ch_lut: LUT used for primary channel enum %iwl_bt_coex_lut_type
* @secondary_ch_lut: LUT used for secondary channel enume %iwl_bt_coex_lut_type
* @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading
* @primary_ch_lut: LUT used for primary channel &enum iwl_bt_coex_lut_type
* @secondary_ch_lut: LUT used for secondary channel &enum iwl_bt_coex_lut_type
* @bt_activity_grading: the activity of BT &enum iwl_bt_activity_grading
* @ttc_rrc_status: is TTC or RRC enabled - one bit per PHY
*/
struct iwl_bt_coex_profile_notif {
......
......@@ -7,7 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
......@@ -34,6 +34,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -254,6 +255,17 @@ enum iwl_wowlan_flags {
ENABLE_STORE_BEACON = BIT(4),
};
/**
* struct iwl_wowlan_config_cmd - WoWLAN configuration
* @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters
* @non_qos_seq: non-QoS sequence counter to use next
* @qos_seq: QoS sequence counters to use next
* @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down
* @is_11n_connection: indicates HT connection
* @offloading_tid: TID reserved for firmware use
* @flags: extra flags, see &enum iwl_wowlan_flags
* @reserved: reserved
*/
struct iwl_wowlan_config_cmd {
__le32 wakeup_filter;
__le16 non_qos_seq;
......@@ -370,6 +382,21 @@ struct iwl_wowlan_gtk_status {
struct iwl_wowlan_rsc_tsc_params_cmd rsc;
} __packed; /* WOWLAN_GTK_MATERIAL_VER_1 */
/**
* struct iwl_wowlan_status - WoWLAN status
* @gtk: GTK data
* @replay_ctr: GTK rekey replay counter
* @pattern_number: number of the matched pattern
* @non_qos_seq_ctr: non-QoS sequence counter to use next
* @qos_seq_ctr: QoS sequence counters to use next
* @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason
* @num_of_gtk_rekeys: number of GTK rekeys
* @transmitted_ndps: number of transmitted neighbor discovery packets
* @received_beacons: number of received beacons
* @wake_packet_length: wakeup packet length
* @wake_packet_bufsize: wakeup packet buffer size
* @wake_packet: wakeup packet
*/
struct iwl_wowlan_status {
struct iwl_wowlan_gtk_status gtk;
__le64 replay_ctr;
......
......@@ -329,17 +329,17 @@ struct iwl_ac_qos {
* ( MAC_CONTEXT_CMD = 0x28 )
* @id_and_color: ID and color of the MAC
* @action: action to perform, one of FW_CTXT_ACTION_*
* @mac_type: one of FW_MAC_TYPE_*
* @tsd_id: TSF HW timer, one of TSF_ID_*
* @mac_type: one of &enum iwl_mac_types
* @tsd_id: TSF HW timer, one of &enum iwl_tsf_id
* @node_addr: MAC address
* @bssid_addr: BSSID
* @cck_rates: basic rates available for CCK
* @ofdm_rates: basic rates available for OFDM
* @protection_flags: combination of MAC_PROT_FLG_FLAG_*
* @protection_flags: combination of &enum iwl_mac_protection_flags
* @cck_short_preamble: 0x20 for enabling short preamble, 0 otherwise
* @short_slot: 0x10 for enabling short slots, 0 otherwise
* @filter_flags: combination of MAC_FILTER_*
* @qos_flags: from MAC_QOS_FLG_*
* @filter_flags: combination of &enum iwl_mac_filter_flags
* @qos_flags: from &enum iwl_mac_qos_flags
* @ac: one iwl_mac_qos configuration for each AC
* @mac_specific: one of struct iwl_mac_data_*, according to mac_type
*/
......
......@@ -82,6 +82,8 @@
* @LTR_CFG_FLAG_SW_SET_SHORT: fixed static short LTR register
* @LTR_CFG_FLAG_SW_SET_LONG: fixed static short LONG register
* @LTR_CFG_FLAG_DENIE_C10_ON_PD: allow going into C10 on PD
* @LTR_CFG_FLAG_UPDATE_VALUES: update config values and short
* idle timeout
*/
enum iwl_ltr_config_flags {
LTR_CFG_FLAG_FEATURE_ENABLE = BIT(0),
......@@ -91,11 +93,14 @@ enum iwl_ltr_config_flags {
LTR_CFG_FLAG_SW_SET_SHORT = BIT(4),
LTR_CFG_FLAG_SW_SET_LONG = BIT(5),
LTR_CFG_FLAG_DENIE_C10_ON_PD = BIT(6),
LTR_CFG_FLAG_UPDATE_VALUES = BIT(7),
};
/**
* struct iwl_ltr_config_cmd_v1 - configures the LTR
* @flags: See %enum iwl_ltr_config_flags
* @flags: See &enum iwl_ltr_config_flags
* @static_long: static LTR Long register value.
* @static_short: static LTR Short register value.
*/
struct iwl_ltr_config_cmd_v1 {
__le32 flags;
......@@ -107,11 +112,14 @@ struct iwl_ltr_config_cmd_v1 {
/**
* struct iwl_ltr_config_cmd - configures the LTR
* @flags: See %enum iwl_ltr_config_flags
* @static_long:
* @static_short:
* @ltr_cfg_values:
* @ltr_short_idle_timeout:
* @flags: See &enum iwl_ltr_config_flags
* @static_long: static LTR Long register value.
* @static_short: static LTR Short register value.
* @ltr_cfg_values: LTR parameters table values (in usec) in folowing order:
* TX, RX, Short Idle, Long Idle. Used only if %LTR_CFG_FLAG_UPDATE_VALUES
* is set.
* @ltr_short_idle_timeout: LTR Short Idle timeout (in usec). Used only if
* %LTR_CFG_FLAG_UPDATE_VALUES is set.
*/
struct iwl_ltr_config_cmd {
__le32 flags;
......@@ -140,7 +148,7 @@ struct iwl_ltr_config_cmd {
* PBW Snoozing enabled
* @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
* @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
* @POWER_FLAGS_AP_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving
* @POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK: AP/GO's uAPSD misbehaving
* detection enablement
*/
enum iwl_power_flags {
......@@ -166,6 +174,7 @@ enum iwl_power_flags {
* Minimum allowed:- 3 * DTIM. Keep alive period must be
* set regardless of power scheme or current power state.
* FW use this value also when PM is disabled.
* @debug_flags: debug flags
* @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to
* PSM transition - legacy PM
* @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to
......@@ -191,7 +200,8 @@ struct iwl_powertable_cmd {
/**
* enum iwl_device_power_flags - masks for device power command flags
* @DEVIC_POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
* @DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK:
* '1' Allow to save power by turning off
* receiver and transmitter. '0' - does not allow.
*/
enum iwl_device_power_flags {
......@@ -202,7 +212,8 @@ enum iwl_device_power_flags {
* struct iwl_device_power_cmd - device wide power command.
* DEVICE_POWER_CMD = 0x77 (command, has simple generic response)
*
* @flags: Power table command flags from DEVICE_POWER_FLAGS_*
* @flags: Power table command flags from &enum iwl_device_power_flags
* @reserved: reserved (padding)
*/
struct iwl_device_power_cmd {
/* PM_POWER_TABLE_CMD_API_S_VER_6 */
......@@ -213,7 +224,7 @@ struct iwl_device_power_cmd {
/**
* struct iwl_mac_power_cmd - New power command containing uAPSD support
* MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response)
* @id_and_color: MAC contex identifier
* @id_and_color: MAC contex identifier, &enum iwl_mvm_id_and_color
* @flags: Power table command flags from POWER_FLAGS_*
* @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec.
* Minimum allowed:- 3 * DTIM. Keep alive period must be
......@@ -223,7 +234,6 @@ struct iwl_device_power_cmd {
* PSM transition - legacy PM
* @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to
* PSM transition - legacy PM
* @sleep_interval: not in use
* @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag
* is set. For example, if it is required to skip over
* one DTIM, this value need to be set to 2 (DTIM periods).
......@@ -233,7 +243,6 @@ struct iwl_device_power_cmd {
* PSM transition - uAPSD
* @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled.
* Default: 80dbm
* @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set
* @snooze_interval: Maximum time between attempts to retrieve buffered data
* from the AP [msec]
* @snooze_window: A window of time in which PBW snoozing insures that all
......@@ -251,8 +260,9 @@ struct iwl_device_power_cmd {
* @heavy_rx_thld_packets: RX threshold measured in number of packets
* @heavy_tx_thld_percentage: TX threshold measured in load's percentage
* @heavy_rx_thld_percentage: RX threshold measured in load's percentage
* @limited_ps_threshold:
*/
* @limited_ps_threshold: (unused)
* @reserved: reserved (padding)
*/
struct iwl_mac_power_cmd {
/* CONTEXT_DESC_API_T_VER_1 */
__le32 id_and_color;
......@@ -343,6 +353,7 @@ struct iwl_dev_tx_power_cmd_v3 {
* @v3: version 3 of the command, embedded here for easier software handling
* @enable_ack_reduction: enable or disable close range ack TX power
* reduction.
* @reserved: reserved (padding)
*/
struct iwl_dev_tx_power_cmd {
/* v4 is just an extension of v3 - keep this here */
......@@ -393,7 +404,6 @@ struct iwl_geo_tx_power_profiles_cmd {
/**
* struct iwl_beacon_filter_cmd
* REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
* @id_and_color: MAC contex identifier
* @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon
* to driver if delta in Energy values calculated for this and last
* passed beacon is greater than this threshold. Zero value means that
......@@ -411,7 +421,7 @@ struct iwl_geo_tx_power_profiles_cmd {
* Threshold. Typical energy threshold is -72dBm.
* @bf_temp_threshold: This threshold determines the type of temperature
* filtering (Slow or Fast) that is selected (Units are in Celsuis):
* If the current temperature is above this threshold - Fast filter
* If the current temperature is above this threshold - Fast filter
* will be used, If the current temperature is below this threshold -
* Slow filter will be used.
* @bf_temp_fast_filter: Send Beacon to driver if delta in temperature values
......@@ -425,7 +435,8 @@ struct iwl_geo_tx_power_profiles_cmd {
* beacon filtering; beacons will not be forced to be sent to driver
* regardless of whether its temerature has been changed.
* @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled.
* @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed
* @bf_debug_flag: beacon filtering debug configuration
* @bf_escape_timer: Send beacons to to driver if no beacons were passed
* for a specific period of time. Units: Beacons.
* @ba_escape_timer: Fully receive and parse beacon if no beacons were passed
* for a longer period of time then this escape-timeout. Units: Beacons.
......
......@@ -392,7 +392,7 @@ enum {
struct iwl_lq_cmd {
u8 sta_id;
u8 reduced_tpc;
u16 control;
__le16 control;
/* LINK_QUAL_GENERAL_PARAMS_API_S_VER_1 */
u8 flags;
u8 mimo_delim;
......
......@@ -7,7 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
......@@ -34,7 +34,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -147,7 +147,8 @@ enum iwl_csum_rx_assist_info {
/**
* struct iwl_rx_mpdu_res_start - phy info
* @assist: see CSUM_RX_ASSIST_ above
* @byte_count: byte count of the frame
* @assist: see &enum iwl_csum_rx_assist_info
*/
struct iwl_rx_mpdu_res_start {
__le16 byte_count;
......@@ -348,35 +349,106 @@ enum iwl_rx_mpdu_mac_info {
IWL_RX_MPDU_PHY_PHY_INDEX_MASK = 0xf0,
};
/**
* struct iwl_rx_mpdu_desc - RX MPDU descriptor
*/
struct iwl_rx_mpdu_desc {
/* DW2 */
/**
* @mpdu_len: MPDU length
*/
__le16 mpdu_len;
/**
* @mac_flags1: &enum iwl_rx_mpdu_mac_flags1
*/
u8 mac_flags1;
/**
* @mac_flags2: &enum iwl_rx_mpdu_mac_flags2
*/
u8 mac_flags2;
/* DW3 */
/**
* @amsdu_info: &enum iwl_rx_mpdu_amsdu_info
*/
u8 amsdu_info;
/**
* @phy_info: &enum iwl_rx_mpdu_phy_info
*/
__le16 phy_info;
/**
* @mac_phy_idx: MAC/PHY index
*/
u8 mac_phy_idx;
/* DW4 - carries csum data only when rpa_en == 1 */
__le16 raw_csum; /* alledgedly unreliable */
/**
* @raw_csum: raw checksum (alledgedly unreliable)
*/
__le16 raw_csum;
/**
* @l3l4_flags: &enum iwl_rx_l3l4_flags
*/
__le16 l3l4_flags;
/* DW5 */
/**
* @status: &enum iwl_rx_mpdu_status
*/
__le16 status;
/**
* @hash_filter: hash filter value
*/
u8 hash_filter;
/**
* @sta_id_flags: &enum iwl_rx_mpdu_sta_id_flags
*/
u8 sta_id_flags;
/* DW6 */
/**
* @reorder_data: &enum iwl_rx_mpdu_reorder_data
*/
__le32 reorder_data;
/* DW7 - carries rss_hash only when rpa_en == 1 */
/**
* @rss_hash: RSS hash value
*/
__le32 rss_hash;
/* DW8 - carries filter_match only when rpa_en == 1 */
/**
* @filter_match: filter match value
*/
__le32 filter_match;
/* DW9 */
/**
* @rate_n_flags: RX rate/flags encoding
*/
__le32 rate_n_flags;
/* DW10 */
u8 energy_a, energy_b, channel, mac_context;
/**
* @energy_a: energy chain A
*/
u8 energy_a;
/**
* @energy_b: energy chain B
*/
u8 energy_b;
/**
* @channel: channel number
*/
u8 channel;
/**
* @mac_context: MAC context mask
*/
u8 mac_context;
/* DW11 */
/**
* @gp2_on_air_rise: GP2 timer value on air rise (INA)
*/
__le32 gp2_on_air_rise;
/* DW12 & DW13 - carries TSF only TSF_OVERLOAD bit == 0 */
/* DW12 & DW13 */
/**
* @tsf_on_air_rise:
* TSF value on air rise (INA), only valid if
* %IWL_RX_MPDU_PHY_TSF_OVERLOAD isn't set
*/
__le64 tsf_on_air_rise;
} __packed;
......@@ -447,7 +519,7 @@ struct iwl_rxq_sync_notification {
} __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */
/**
* Internal message identifier
* enum iwl_mvm_rxq_notif_type - Internal message identifier
*
* @IWL_MVM_RXQ_EMPTY: empty sync notification
* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
......@@ -491,7 +563,7 @@ enum iwl_mvm_pm_event {
/**
* struct iwl_mvm_pm_state_notification - station PM state notification
* @sta_id: station ID of the station changing state
* @type: the new powersave state, see IWL_MVM_PM_EVENT_ above
* @type: the new powersave state, see &enum iwl_mvm_pm_event
*/
struct iwl_mvm_pm_state_notification {
u8 sta_id;
......
......@@ -7,7 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
......@@ -34,6 +34,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -67,8 +68,6 @@
#ifndef __fw_api_scan_h__
#define __fw_api_scan_h__
#include "fw-api.h"
/* Scan Commands, Responses, Notifications */
/* Max number of IEs for direct SSID scans in a command */
......@@ -111,7 +110,7 @@ enum scan_framework_client {
};
/**
* iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S
* struct iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S
* @ssid: MAC address to filter out
* @reported_rssi: AP rssi reported to the host
* @client_bitmap: clients ignore this entry - enum scan_framework_client
......@@ -135,7 +134,7 @@ enum iwl_scan_offload_band_selection {
};
/**
* iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S
* struct iwl_scan_offload_profile - SCAN_OFFLOAD_PROFILE_S
* @ssid_index: index to ssid list in fixed part
* @unicast_cipher: encryption algorithm to match - bitmap
* @aut_alg: authentication algorithm to match - bitmap
......@@ -154,8 +153,7 @@ struct iwl_scan_offload_profile {
} __packed;
/**
* iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1
* @blaclist: AP list to filter off from scan results
* struct iwl_scan_offload_profile_cfg - SCAN_OFFLOAD_PROFILES_CFG_API_S_VER_1
* @profiles: profiles to search for match
* @blacklist_len: length of blacklist
* @num_profiles: num of profiles in the list
......@@ -176,7 +174,7 @@ struct iwl_scan_offload_profile_cfg {
} __packed;
/**
* iwl_scan_schedule_lmac - schedule of scan offload
* struct iwl_scan_schedule_lmac - schedule of scan offload
* @delay: delay between iterations, in seconds.
* @iterations: num of scan iterations
* @full_scan_mul: number of partial scans before each full scan
......@@ -200,7 +198,7 @@ enum iwl_scan_ebs_status {
};
/**
* iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S
* struct iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S
* @tx_flags: combination of TX_CMD_FLG_*
* @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is
* cleared. Combination of RATE_MCS_*
......@@ -220,7 +218,7 @@ enum iwl_scan_channel_flags_lmac {
};
/**
* iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2
* struct iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2
* @flags: bits 1-20: directed scan to i'th ssid
* other bits &enum iwl_scan_channel_flags_lmac
* @channel_number: channel number 1-13 etc
......@@ -235,7 +233,7 @@ struct iwl_scan_channel_cfg_lmac {
} __packed;
/*
* iwl_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1
* struct iwl_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1
* @offset: offset in the data block
* @len: length of the segment
*/
......@@ -263,7 +261,7 @@ enum iwl_scan_channel_flags {
IWL_SCAN_CHANNEL_FLAG_CACHE_ADD = BIT(2),
};
/* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S
/* struct iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S
* @flags: enum iwl_scan_channel_flags
* @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is
* involved.
......@@ -276,7 +274,7 @@ struct iwl_scan_channel_opt {
} __packed;
/**
* iwl_mvm_lmac_scan_flags
* enum iwl_mvm_lmac_scan_flags - LMAC scan flags
* @IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL: pass all beacons and probe responses
* without filtering.
* @IWL_MVM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels
......@@ -320,7 +318,7 @@ enum iwl_scan_priority_ext {
};
/**
* iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1
* struct iwl_scan_req_lmac - SCAN_REQUEST_CMD_API_S_VER_1
* @reserved1: for alignment and future use
* @channel_num: num of channels to scan
* @active-dwell: dwell time for active channels
......@@ -410,7 +408,7 @@ struct iwl_lmac_scan_complete_notif {
} __packed;
/**
* iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2
* struct iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2
* @last_schedule_line: last schedule line executed (fast or regular)
* @last_schedule_iteration: last scan iteration executed before scan abort
* @status: enum iwl_scan_offload_complete_status
......@@ -547,12 +545,12 @@ struct iwl_scan_config {
} __packed; /* SCAN_CONFIG_DB_CMD_API_S_3 */
/**
* iwl_umac_scan_flags
*@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request
* enum iwl_umac_scan_flags - UMAC scan flags
* @IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request
* can be preempted by other scan requests with higher priority.
* The low priority scan will be resumed when the higher proirity scan is
* completed.
*@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver
* @IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver
* when scan starts.
*/
enum iwl_umac_scan_flags {
......
......@@ -197,7 +197,15 @@ enum iwl_sta_modify_flag {
STA_MODIFY_QUEUES = BIT(7),
};
#define STA_MODE_MODIFY 1
/**
* enum iwl_sta_mode - station command mode
* @STA_MODE_ADD: add new station
* @STA_MODE_MODIFY: modify the station
*/
enum iwl_sta_mode {
STA_MODE_ADD = 0,
STA_MODE_MODIFY = 1,
};
/**
* enum iwl_sta_sleep_flag - type of sleep of the station
......@@ -223,7 +231,7 @@ enum iwl_sta_sleep_flag {
/**
* struct iwl_mvm_keyinfo - key information
* @key_flags: type %iwl_sta_key_flag
* @key_flags: type &enum iwl_sta_key_flag
* @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection
* @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx
* @key_offset: key offset in the fw's key table
......@@ -253,17 +261,19 @@ struct iwl_mvm_keyinfo {
/**
* struct iwl_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table.
* ( REPLY_ADD_STA = 0x18 )
* @add_modify: 1: modify existing, 0: add new station
* @add_modify: see &enum iwl_sta_mode
* @awake_acs:
* @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
* AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field.
* @mac_id_n_color: the Mac context this station belongs to
* @addr[ETH_ALEN]: station's MAC address
* @mac_id_n_color: the Mac context this station belongs to,
* see &enum iwl_mvm_id_and_color
* @addr: station's MAC address
* @sta_id: index of station in uCode's station table
* @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave
* alone. 1 - modify, 0 - don't change.
* @station_flags: look at %iwl_sta_flags
* @station_flags_msk: what of %station_flags have changed
* @station_flags: look at &enum iwl_sta_flags
* @station_flags_msk: what of %station_flags have changed,
* also &enum iwl_sta_flags
* @add_immediate_ba_tid: tid for which to add block-ack support (Rx)
* Set %STA_MODIFY_ADD_BA_TID to use this field, and also set
* add_immediate_ba_ssn.
......@@ -274,7 +284,7 @@ struct iwl_mvm_keyinfo {
* @sleep_tx_count: number of packets to transmit to station even though it is
* asleep. Used to synchronise PS-poll and u-APSD responses while ucode
* keeps track of STA sleep state.
* @sleep_state_flags: Look at %iwl_sta_sleep_flag.
* @sleep_state_flags: Look at &enum iwl_sta_sleep_flag.
* @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP
* mac-addr.
* @beamform_flags: beam forming controls
......@@ -330,17 +340,19 @@ enum iwl_sta_type {
/**
* struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table.
* ( REPLY_ADD_STA = 0x18 )
* @add_modify: 1: modify existing, 0: add new station
* @add_modify: see &enum iwl_sta_mode
* @awake_acs:
* @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
* AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field.
* @mac_id_n_color: the Mac context this station belongs to
* @addr[ETH_ALEN]: station's MAC address
* @mac_id_n_color: the Mac context this station belongs to,
* see &enum iwl_mvm_id_and_color
* @addr: station's MAC address
* @sta_id: index of station in uCode's station table
* @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave
* alone. 1 - modify, 0 - don't change.
* @station_flags: look at %iwl_sta_flags
* @station_flags_msk: what of %station_flags have changed
* @station_flags: look at &enum iwl_sta_flags
* @station_flags_msk: what of %station_flags have changed,
* also &enum iwl_sta_flags
* @add_immediate_ba_tid: tid for which to add block-ack support (Rx)
* Set %STA_MODIFY_ADD_BA_TID to use this field, and also set
* add_immediate_ba_ssn.
......@@ -352,7 +364,7 @@ enum iwl_sta_type {
* asleep. Used to synchronise PS-poll and u-APSD responses while ucode
* keeps track of STA sleep state.
* @station_type: type of this station. See &enum iwl_sta_type.
* @sleep_state_flags: Look at %iwl_sta_sleep_flag.
* @sleep_state_flags: Look at &enum iwl_sta_sleep_flag.
* @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP
* mac-addr.
* @beamform_flags: beam forming controls
......@@ -401,7 +413,7 @@ struct iwl_mvm_add_sta_cmd {
* ( REPLY_ADD_STA_KEY = 0x17 )
* @sta_id: index of station in uCode's station table
* @key_offset: key offset in key storage
* @key_flags: type %iwl_sta_key_flag
* @key_flags: type &enum iwl_sta_key_flag
* @key: key material data
* @rx_secur_seq_cnt: RX security sequence counter for the key
*/
......@@ -468,7 +480,7 @@ struct iwl_mvm_rm_sta_cmd {
/**
* struct iwl_mvm_mgmt_mcast_key_cmd_v1
* ( MGMT_MCAST_KEY = 0x1f )
* @ctrl_flags: %iwl_sta_key_flag
* @ctrl_flags: &enum iwl_sta_key_flag
* @igtk:
* @k1: unused
* @k2: unused
......@@ -489,7 +501,7 @@ struct iwl_mvm_mgmt_mcast_key_cmd_v1 {
/**
* struct iwl_mvm_mgmt_mcast_key_cmd
* ( MGMT_MCAST_KEY = 0x1f )
* @ctrl_flags: %iwl_sta_key_flag
* @ctrl_flags: &enum iwl_sta_key_flag
* @igtk: IGTK master key
* @sta_id: station ID that support IGTK
* @key_id:
......
......@@ -7,7 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
......@@ -72,7 +72,7 @@ struct mvm_statistics_dbg {
__le32 burst_check;
__le32 burst_count;
__le32 wait_for_silence_timeout_cnt;
__le32 reserved[3];
u8 reserved[12];
} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */
struct mvm_statistics_div {
......@@ -323,9 +323,30 @@ struct iwl_notif_statistics_cdb {
struct mvm_statistics_load_cdb load_stats;
} __packed; /* STATISTICS_NTFY_API_S_VER_12 */
#define IWL_STATISTICS_FLG_CLEAR 0x1
#define IWL_STATISTICS_FLG_DISABLE_NOTIF 0x2
/**
* enum iwl_statistics_notif_flags - flags used in statistics notification
* @IWL_STATISTICS_REPLY_FLG_CLEAR: statistics were cleared after this report
*/
enum iwl_statistics_notif_flags {
IWL_STATISTICS_REPLY_FLG_CLEAR = 0x1,
};
/**
* enum iwl_statistics_cmd_flags - flags used in statistics command
* @IWL_STATISTICS_FLG_CLEAR: request to clear statistics after the report
* that's sent after this command
* @IWL_STATISTICS_FLG_DISABLE_NOTIF: disable unilateral statistics
* notifications
*/
enum iwl_statistics_cmd_flags {
IWL_STATISTICS_FLG_CLEAR = 0x1,
IWL_STATISTICS_FLG_DISABLE_NOTIF = 0x2,
};
/**
* struct iwl_statistics_cmd - statistics config command
* @flags: flags from &enum iwl_statistics_cmd_flags
*/
struct iwl_statistics_cmd {
__le32 flags;
} __packed; /* STATISTICS_CMD_API_S_VER_1 */
......
......@@ -63,8 +63,6 @@
#ifndef __fw_api_tof_h__
#define __fw_api_tof_h__
#include "fw-api.h"
/* ToF sub-group command IDs */
enum iwl_mvm_tof_sub_grp_ids {
TOF_RANGE_REQ_CMD = 0x1,
......@@ -118,11 +116,17 @@ struct iwl_tof_config_cmd {
* @bandwidth: current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz
* @rate: current AP rate
* @ctrl_ch_position: coding of the control channel position relative to
* the center frequency.
* 40MHz 0 below center, 1 above center
* 80MHz bits [0..1]: 0 the near 20MHz to the center,
* 1 the far 20MHz to the center
* bit[2] as above 40MHz
* the center frequency:
*
* 40 MHz
* 0 below center, 1 above center
*
* 80 MHz
* bits [0..1]
* * 0 the near 20MHz to the center,
* * 1 the far 20MHz to the center
* bit[2]
* as above 40MHz
* @ftm_per_burst: FTMs per Burst
* @ftm_resp_ts_avail: '0' - we don't measure over the Initial FTM Response,
* '1' - we measure over the Initial FTM Response
......
......@@ -74,6 +74,7 @@
* Otherwise, use rate_n_flags from the TX command
* @TX_CMD_FLG_BAR: this frame is a BA request, immediate BAR is expected
* Must set TX_CMD_FLG_ACK with this flag.
* @TX_CMD_FLG_TXOP_PROT: TXOP protection requested
* @TX_CMD_FLG_VHT_NDPA: mark frame is NDPA for VHT beamformer sequence
* @TX_CMD_FLG_HT_NDPA: mark frame is NDPA for HT beamformer sequence
* @TX_CMD_FLG_CSI_FDBK2HOST: mark to send feedback to host (only if good CRC)
......@@ -177,29 +178,6 @@ enum iwl_tx_cmd_sec_ctrl {
TX_CMD_SEC_KEY_FROM_TABLE = 0x10,
};
/* TODO: how does these values are OK with only 16 bit variable??? */
/*
* TX command next frame info
*
* bits 0:2 - security control (TX_CMD_SEC_*)
* bit 3 - immediate ACK required
* bit 4 - rate is taken from STA table
* bit 5 - frame belongs to BA stream
* bit 6 - immediate BA response expected
* bit 7 - unused
* bits 8:15 - Station ID
* bits 16:31 - rate
*/
#define TX_CMD_NEXT_FRAME_ACK_MSK (0x8)
#define TX_CMD_NEXT_FRAME_STA_RATE_MSK (0x10)
#define TX_CMD_NEXT_FRAME_BA_MSK (0x20)
#define TX_CMD_NEXT_FRAME_IMM_BA_RSP_MSK (0x40)
#define TX_CMD_NEXT_FRAME_FLAGS_MSK (0xf8)
#define TX_CMD_NEXT_FRAME_STA_ID_MSK (0xff00)
#define TX_CMD_NEXT_FRAME_STA_ID_POS (8)
#define TX_CMD_NEXT_FRAME_RATE_MSK (0xffff0000)
#define TX_CMD_NEXT_FRAME_RATE_POS (16)
/*
* TX command Frame life time in us - to be written in pm_frame_timeout
*/
......@@ -224,7 +202,7 @@ enum iwl_tx_cmd_sec_ctrl {
/**
* enum iwl_tx_offload_assist_flags_pos - set %iwl_tx_cmd offload_assist values
* @TX_CMD_OFFLD_IP_HDR_OFFSET: offset to start of IP header (in words)
* @TX_CMD_OFFLD_IP_HDR: offset to start of IP header (in words)
* from mac header end. For normal case it is 4 words for SNAP.
* note: tx_cmd, mac header and pad are not counted in the offset.
* This is used to help the offload in case there is tunneling such as
......@@ -258,22 +236,27 @@ enum iwl_tx_offload_assist_flags_pos {
* @len: in bytes of the payload, see below for details
* @offload_assist: TX offload configuration
* @tx_flags: combination of TX_CMD_FLG_*
* @scratch: scratch buffer used by the device
* @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is
* cleared. Combination of RATE_MCS_*
* @sta_id: index of destination station in FW station table
* @sec_ctl: security control, TX_CMD_SEC_*
* @initial_rate_index: index into the the rate table for initial TX attempt.
* Applied if TX_CMD_FLG_STA_RATE_MSK is set, normally 0 for data frames.
* @reserved2: reserved
* @key: security key
* @next_frame_flags: TX_CMD_SEC_* and TX_CMD_NEXT_FRAME_*
* @reserved3: reserved
* @life_time: frame life time (usecs??)
* @dram_lsb_ptr: Physical address of scratch area in the command (try_cnt +
* btkill_cnd + reserved), first 32 bits. "0" disables usage.
* @dram_msb_ptr: upper bits of the scratch physical address
* @rts_retry_limit: max attempts for RTS
* @data_retry_limit: max attempts to send the data packet
* @tid_spec: TID/tspec
* @tid_tspec: TID/tspec
* @pm_frame_timeout: PM TX frame timeout
* @reserved4: reserved
* @payload: payload (same as @hdr)
* @hdr: 802.11 header (same as @payload)
*
* The byte count (both len and next_frame_len) includes MAC header
* (24/26/30/32 bytes)
......@@ -327,10 +310,11 @@ struct iwl_dram_sec_info {
* ( TX_CMD = 0x1c )
* @len: in bytes of the payload, see below for details
* @offload_assist: TX offload configuration
* @tx_flags: combination of &iwl_tx_cmd_flags
* @flags: combination of &enum iwl_tx_cmd_flags
* @dram_info: FW internal DRAM storage
* @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is
* cleared. Combination of RATE_MCS_*
* @hdr: 802.11 header
*/
struct iwl_tx_cmd_gen2 {
__le16 len;
......@@ -545,6 +529,8 @@ struct agg_tx_status {
* @pa_integ_res_b: tx power info
* @pa_integ_res_c: tx power info
* @measurement_req_id: tx power info
* @reduced_tpc: transmit power reduction used
* @reserved: reserved
* @tfd_info: TFD information set by the FH
* @seq_ctl: sequence control from the Tx cmd
* @byte_cnt: byte count from the Tx cmd
......@@ -597,11 +583,11 @@ struct iwl_mvm_tx_resp {
/**
* struct iwl_mvm_ba_notif - notifies about reception of BA
* ( BA_NOTIF = 0xc5 )
* @sta_addr_lo32: lower 32 bits of the MAC address
* @sta_addr_hi16: upper 16 bits of the MAC address
* @sta_addr: MAC address
* @reserved: reserved
* @sta_id: Index of recipient (BA-sending) station in fw's station table
* @tid: tid of the session
* @seq_ctl:
* @seq_ctl: sequence control field
* @bitmap: the bitmap of the BA notification as seen in the air
* @scd_flow: the tx queue this BA relates to
* @scd_ssn: the index of the last contiguously sent packet
......@@ -610,10 +596,10 @@ struct iwl_mvm_tx_resp {
* @reduced_txp: power reduced according to TPC. This is the actual value and
* not a copy from the LQ command. Thus, if not the first rate was used
* for Tx-ing then this value will be set to 0 by FW.
* @reserved1: reserved
*/
struct iwl_mvm_ba_notif {
__le32 sta_addr_lo32;
__le16 sta_addr_hi16;
u8 sta_addr[ETH_ALEN];
__le16 reserved;
u8 sta_id;
......@@ -633,13 +619,13 @@ struct iwl_mvm_ba_notif {
* @q_num: TFD queue number
* @tfd_index: Index of first un-acked frame in the TFD queue
* @scd_queue: For debug only - the physical queue the TFD queue is bound to
* @reserved: reserved for alignment
*/
struct iwl_mvm_compressed_ba_tfd {
__le16 q_num;
__le16 tfd_index;
u8 scd_queue;
u8 reserved;
__le16 reserved2;
u8 reserved[3];
} __packed; /* COMPRESSED_BA_TFD_API_S_VER_1 */
/**
......@@ -687,11 +673,12 @@ enum iwl_mvm_ba_resp_flags {
* @query_frame_cnt: SCD query frame count
* @txed: number of frames sent in the aggregation (all-TIDs)
* @done: number of frames that were Acked by the BA (all-TIDs)
* @reserved: reserved (for alignment)
* @wireless_time: Wireless-media time
* @tx_rate: the rate the aggregation was sent at
* @tfd_cnt: number of TFD-Q elements
* @ra_tid_cnt: number of RATID-Q elements
* @ba_tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd
* @tfd: array of TFD queue status updates. See &iwl_mvm_compressed_ba_tfd
* for details.
* @ra_tid: array of RA-TID queue status updates. For debug purposes only. See
* &iwl_mvm_compressed_ba_ratid for more details.
......@@ -765,6 +752,7 @@ struct iwl_mac_beacon_cmd_v7 {
* struct iwl_mac_beacon_cmd - beacon template command with offloaded CSA
* @byte_cnt: byte count of the beacon frame
* @flags: for future use
* @reserved: reserved
* @data: see &iwl_mac_beacon_cmd_data
*/
struct iwl_mac_beacon_cmd {
......@@ -824,16 +812,17 @@ enum iwl_scd_cfg_actions {
/**
* struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command
* @token:
* @token: unused
* @sta_id: station id
* @tid:
* @tid: TID
* @scd_queue: scheduler queue to confiug
* @action: 1 queue enable, 0 queue disable, 2 change txq's tid owner
* Value is one of %iwl_scd_cfg_actions options
* Value is one of &enum iwl_scd_cfg_actions options
* @aggregate: 1 aggregated queue, 0 otherwise
* @tx_fifo: %enum iwl_mvm_tx_fifo
* @tx_fifo: &enum iwl_mvm_tx_fifo
* @window: BA window size
* @ssn: SSN for the BA agreement
* @reserved: reserved
*/
struct iwl_scd_txq_cfg_cmd {
u8 token;
......
......@@ -640,18 +640,21 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
}
/* Make room for PRPH registers */
for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); i++) {
/* The range includes both boundaries */
int num_bytes_in_chunk =
iwl_prph_dump_addr_comm[i].end -
iwl_prph_dump_addr_comm[i].start + 4;
prph_len += sizeof(*dump_data) +
sizeof(struct iwl_fw_error_dump_prph) +
num_bytes_in_chunk;
if (!mvm->trans->cfg->gen2) {
for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm);
i++) {
/* The range includes both boundaries */
int num_bytes_in_chunk =
iwl_prph_dump_addr_comm[i].end -
iwl_prph_dump_addr_comm[i].start + 4;
prph_len += sizeof(*dump_data) +
sizeof(struct iwl_fw_error_dump_prph) +
num_bytes_in_chunk;
}
}
if (mvm->cfg->mq_rx_supported) {
if (!mvm->trans->cfg->gen2 && mvm->cfg->mq_rx_supported) {
for (i = 0; i <
ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) {
/* The range includes both boundaries */
......@@ -691,7 +694,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
}
/* Make room for fw's virtual image pages, if it exists */
if (mvm->fw->img[mvm->cur_ucode].paging_mem_size &&
if (!mvm->trans->cfg->gen2 &&
mvm->fw->img[mvm->cur_ucode].paging_mem_size &&
mvm->fw_paging_db[0].fw_paging_block)
file_len += mvm->num_of_paging_blk *
(sizeof(*dump_data) +
......@@ -704,14 +708,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sizeof(*dump_info);
}
/*
* In 8000 HW family B-step include the ICCM (which resides separately)
*/
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP)
file_len += sizeof(*dump_data) + sizeof(*dump_mem) +
IWL8260_ICCM_LEN;
if (mvm->fw_dump_desc)
file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
mvm->fw_dump_desc->len;
......@@ -836,21 +832,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
dump_data = iwl_fw_error_next_data(dump_data);
}
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP) {
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
dump_data->len = cpu_to_le32(IWL8260_ICCM_LEN +
sizeof(*dump_mem));
dump_mem = (void *)dump_data->data;
dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
dump_mem->offset = cpu_to_le32(IWL8260_ICCM_OFFSET);
iwl_trans_read_mem_bytes(mvm->trans, IWL8260_ICCM_OFFSET,
dump_mem->data, IWL8260_ICCM_LEN);
dump_data = iwl_fw_error_next_data(dump_data);
}
/* Dump fw's virtual image */
if (mvm->fw->img[mvm->cur_ucode].paging_mem_size &&
if (!mvm->trans->cfg->gen2 &&
mvm->fw->img[mvm->cur_ucode].paging_mem_size &&
mvm->fw_paging_db[0].fw_paging_block) {
for (i = 1; i < mvm->num_of_paging_blk + 1; i++) {
struct iwl_fw_error_dump_paging *paging;
......@@ -943,7 +927,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
mvm->fw_dump_desc = desc;
mvm->fw_dump_trig = trigger;
queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay);
schedule_delayed_work(&mvm->fw_dump_wk, delay);
return 0;
}
......
......@@ -384,20 +384,23 @@ static int iwl_save_fw_paging(struct iwl_mvm *mvm,
/* send paging cmd to FW in case CPU2 has paging image */
static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw)
{
struct iwl_fw_paging_cmd paging_cmd = {
.flags =
union {
struct iwl_fw_paging_cmd v2;
struct iwl_fw_paging_cmd_v1 v1;
} paging_cmd = {
.v2.flags =
cpu_to_le32(PAGING_CMD_IS_SECURED |
PAGING_CMD_IS_ENABLED |
(mvm->num_of_pages_in_last_blk <<
PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)),
.block_size = cpu_to_le32(BLOCK_2_EXP_SIZE),
.block_num = cpu_to_le32(mvm->num_of_paging_blk),
.v2.block_size = cpu_to_le32(BLOCK_2_EXP_SIZE),
.v2.block_num = cpu_to_le32(mvm->num_of_paging_blk),
};
int blk_idx, size = sizeof(paging_cmd);
int blk_idx, size = sizeof(paging_cmd.v2);
/* A bit hard coded - but this is the old API and will be deprecated */
if (!iwl_mvm_has_new_tx_api(mvm))
size -= NUM_OF_FW_PAGING_BLOCKS * 4;
size = sizeof(paging_cmd.v1);
/* loop for for all paging blocks + CSS block */
for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) {
......@@ -408,11 +411,11 @@ static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw)
if (iwl_mvm_has_new_tx_api(mvm)) {
__le64 phy_addr = cpu_to_le64(addr);
paging_cmd.device_phy_addr.addr64[blk_idx] = phy_addr;
paging_cmd.v2.device_phy_addr[blk_idx] = phy_addr;
} else {
__le32 phy_addr = cpu_to_le32(addr);
paging_cmd.device_phy_addr.addr32[blk_idx] = phy_addr;
paging_cmd.v1.device_phy_addr[blk_idx] = phy_addr;
}
}
......@@ -619,7 +622,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
if (WARN_ON(!fw))
return -EINVAL;
mvm->cur_ucode = ucode_type;
mvm->ucode_loaded = false;
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
iwl_init_notification_wait(&mvm->notif_wait, &alive_wait,
alive_cmd, ARRAY_SIZE(alive_cmd),
......@@ -641,12 +644,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
if (ret) {
struct iwl_trans *trans = mvm->trans;
if (trans->cfg->gen2)
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_A000)
IWL_ERR(mvm,
"SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n",
iwl_read_prph(trans, UMAG_SB_CPU_1_STATUS),
iwl_read_prph(trans, UMAG_SB_CPU_2_STATUS));
else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
else if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
IWL_ERR(mvm,
"SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n",
iwl_read_prph(trans, SB_CPU_1_STATUS),
......@@ -693,7 +696,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
atomic_set(&mvm->mac80211_queue_stop_count[i], 0);
mvm->ucode_loaded = true;
set_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
return 0;
}
......@@ -738,9 +741,13 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
goto error;
}
/* Read the NVM only at driver load time, no need to do this twice */
if (read_nvm) {
/* Read nvm */
/* Load NVM to NIC if needed */
if (mvm->nvm_file_name) {
iwl_mvm_read_external_nvm(mvm);
iwl_mvm_load_nvm_to_nic(mvm);
}
if (IWL_MVM_PARSE_NVM && read_nvm) {
ret = iwl_nvm_init(mvm, true);
if (ret) {
IWL_ERR(mvm, "Failed to read NVM: %d\n", ret);
......@@ -748,14 +755,6 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
}
}
/* In case we read the NVM from external file, load it to the NIC */
if (mvm->nvm_file_name)
iwl_mvm_load_nvm_to_nic(mvm);
ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans);
if (WARN_ON(ret))
goto error;
ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP,
NVM_ACCESS_COMPLETE), 0,
sizeof(nvm_complete), &nvm_complete);
......@@ -766,8 +765,21 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
}
/* We wait for the INIT complete notification */
return iwl_wait_notification(&mvm->notif_wait, &init_wait,
MVM_UCODE_ALIVE_TIMEOUT);
ret = iwl_wait_notification(&mvm->notif_wait, &init_wait,
MVM_UCODE_ALIVE_TIMEOUT);
if (ret)
return ret;
/* Read the NVM only at driver load time, no need to do this twice */
if (!IWL_MVM_PARSE_NVM && read_nvm) {
ret = iwl_mvm_nvm_get_from_fw(mvm);
if (ret) {
IWL_ERR(mvm, "Failed to read NVM: %d\n", ret);
return ret;
}
}
return 0;
error:
iwl_remove_notification(&mvm->notif_wait, &init_wait);
......@@ -1627,7 +1639,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
return 0;
error:
iwl_mvm_stop_device(mvm);
if (!iwlmvm_mod_params.init_dbg)
iwl_mvm_stop_device(mvm);
return ret;
}
......
......@@ -123,14 +123,17 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
return ret;
}
mvm->init_status |= IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;
return 0;
}
void iwl_mvm_leds_exit(struct iwl_mvm *mvm)
{
if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE)
if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE ||
!(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE))
return;
led_classdev_unregister(&mvm->led);
kfree(mvm->led.name);
mvm->init_status &= ~IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE;
}
......@@ -1632,9 +1632,9 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n");
queue_delayed_work(system_wq, &mvm->cs_tx_unblock_dwork,
msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT *
csa_vif->bss_conf.beacon_int));
schedule_delayed_work(&mvm->cs_tx_unblock_dwork,
msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT *
csa_vif->bss_conf.beacon_int));
ieee80211_csa_finish(csa_vif);
......
......@@ -735,6 +735,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
ret = ieee80211_register_hw(mvm->hw);
if (ret)
iwl_mvm_leds_exit(mvm);
mvm->init_status |= IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;
if (mvm->cfg->vht_mu_mimo_supported)
wiphy_ext_feature_set(hw->wiphy,
......@@ -1243,6 +1244,17 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
flush_work(&mvm->d0i3_exit_work);
flush_work(&mvm->async_handlers_wk);
flush_work(&mvm->add_stream_wk);
/*
* Lock and clear the firmware running bit here already, so that
* new commands coming in elsewhere, e.g. from debugfs, will not
* be able to proceed. This is important here because one of those
* debugfs files causes the fw_dump_wk to be triggered, and if we
* don't stop debugfs accesses before canceling that it could be
* retriggered after we flush it but before we've cleared the bit.
*/
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
cancel_delayed_work_sync(&mvm->fw_dump_wk);
cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork);
cancel_delayed_work_sync(&mvm->scan_timeout_dwork);
......@@ -1451,7 +1463,7 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
{
u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif);
if (tfd_msk) {
if (tfd_msk && !iwl_mvm_is_dqa_supported(mvm)) {
/*
* mac80211 first removes all the stations of the vif and
* then removes the vif. When it removes a station it also
......@@ -1460,6 +1472,8 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
* of these AMPDU sessions are properly closed.
* We still need to take care of the shared queues of the vif.
* Flush them here.
* For DQA mode there is no need - broacast and multicast queue
* are flushed separately.
*/
mutex_lock(&mvm->mutex);
iwl_mvm_flush_tx_path(mvm, tfd_msk, 0);
......@@ -3988,21 +4002,23 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
/* make sure only TDLS peers or the AP are flushed */
WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls);
msk |= mvmsta->tfd_queue_msk;
if (drop) {
if (iwl_mvm_flush_sta(mvm, mvmsta, false, 0))
IWL_ERR(mvm, "flush request fail\n");
} else {
msk |= mvmsta->tfd_queue_msk;
if (iwl_mvm_has_new_tx_api(mvm))
iwl_mvm_wait_sta_queues_empty(mvm, mvmsta);
}
}
if (drop) {
if (iwl_mvm_flush_tx_path(mvm, msk, 0))
IWL_ERR(mvm, "flush request fail\n");
mutex_unlock(&mvm->mutex);
} else {
mutex_unlock(&mvm->mutex);
mutex_unlock(&mvm->mutex);
/* this can take a while, and we may need/want other operations
* to succeed while doing this, so do it without the mutex held
*/
/* this can take a while, and we may need/want other operations
* to succeed while doing this, so do it without the mutex held
*/
if (!drop && !iwl_mvm_has_new_tx_api(mvm))
iwl_trans_wait_tx_queues_empty(mvm->trans, msk);
}
}
static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
......@@ -4023,7 +4039,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
mutex_lock(&mvm->mutex);
if (mvm->ucode_loaded) {
if (iwl_mvm_firmware_running(mvm)) {
ret = iwl_mvm_request_statistics(mvm, false);
if (ret)
goto out;
......
......@@ -754,6 +754,8 @@ struct iwl_mvm {
struct work_struct roc_done_wk;
unsigned long init_status;
unsigned long status;
u32 queue_sync_cookie;
......@@ -765,7 +767,6 @@ struct iwl_mvm {
struct iwl_mvm_vif *bf_allowed_vif;
enum iwl_ucode_type cur_ucode;
bool ucode_loaded;
bool hw_registered;
bool calibrating;
u32 error_event_table[2];
......@@ -1086,6 +1087,15 @@ enum iwl_mvm_status {
IWL_MVM_STATUS_ROC_AUX_RUNNING,
IWL_MVM_STATUS_D3_RECONFIG,
IWL_MVM_STATUS_DUMPING_FW_LOG,
IWL_MVM_STATUS_FIRMWARE_RUNNING,
};
/* Keep track of completed init configuration */
enum iwl_mvm_init_status {
IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE = BIT(0),
IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE = BIT(1),
IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE = BIT(2),
IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE = BIT(3),
};
static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
......@@ -1099,6 +1109,11 @@ static inline bool iwl_mvm_is_radio_hw_killed(struct iwl_mvm *mvm)
return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
}
static inline bool iwl_mvm_firmware_running(struct iwl_mvm *mvm)
{
return test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
}
/* Must be called with rcu_read_lock() held and it can only be
* released when mvmsta is not needed anymore.
*/
......@@ -1188,7 +1203,7 @@ static inline bool iwl_mvm_is_lar_supported(struct iwl_mvm *mvm)
* Enable LAR only if it is supported by the FW (TLV) &&
* enabled in the NVM
*/
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000)
if (mvm->cfg->ext_nvm)
return nvm_lar && tlv_lar;
else
return tlv_lar;
......@@ -1355,6 +1370,8 @@ const char *iwl_mvm_get_tx_fail_reason(u32 status);
static inline const char *iwl_mvm_get_tx_fail_reason(u32 status) { return ""; }
#endif
int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags);
int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool int_sta, u32 flags);
void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm);
static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info,
......@@ -1381,7 +1398,9 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm);
/* NVM */
int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic);
int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm);
int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm);
int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm);
static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm)
{
......@@ -1755,7 +1774,7 @@ static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
{
if (!iwl_mvm_has_new_tx_api(mvm))
iwl_free_fw_paging(mvm);
mvm->ucode_loaded = false;
clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
mvm->fw_dbg_conf = FW_DBG_INVALID;
iwl_trans_stop_device(mvm->trans);
}
......
......@@ -77,7 +77,7 @@
/* Default NVM size to read */
#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024)
#define IWL_MAX_NVM_SECTION_SIZE 0x1b58
#define IWL_MAX_NVM_8000_SECTION_SIZE 0x1ffc
#define IWL_MAX_EXT_NVM_SECTION_SIZE 0x1ffc
#define NVM_WRITE_OPCODE 1
#define NVM_READ_OPCODE 0
......@@ -300,7 +300,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
bool lar_enabled;
/* Checking for required sections */
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (!mvm->trans->cfg->ext_nvm) {
if (!mvm->nvm_sections[NVM_SECTION_TYPE_SW].data ||
!mvm->nvm_sections[mvm->cfg->nvm_hw_section_num].data) {
IWL_ERR(mvm, "Can't parse empty OTP/NVM sections\n");
......@@ -374,7 +374,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
*
* 4. save as "iNVM_xxx.bin" under /lib/firmware
*/
static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
{
int ret, section_size;
u16 section_id;
......@@ -391,19 +391,19 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
#define NVM_WORD1_LEN(x) (8 * (x & 0x03FF))
#define NVM_WORD2_ID(x) (x >> 12)
#define NVM_WORD2_LEN_FAMILY_8000(x) (2 * ((x & 0xFF) << 8 | x >> 8))
#define NVM_WORD1_ID_FAMILY_8000(x) (x >> 4)
#define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8))
#define EXT_NVM_WORD1_ID(x) ((x) >> 4)
#define NVM_HEADER_0 (0x2A504C54)
#define NVM_HEADER_1 (0x4E564D2A)
#define NVM_HEADER_SIZE (4 * sizeof(u32))
IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from external NVM\n");
/* Maximal size depends on HW family and step */
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
/* Maximal size depends on NVM version */
if (!mvm->trans->cfg->ext_nvm)
max_section_size = IWL_MAX_NVM_SECTION_SIZE;
else
max_section_size = IWL_MAX_NVM_8000_SECTION_SIZE;
max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE;
/*
* Obtain NVM image via request_firmware. Since we already used
......@@ -447,10 +447,9 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
le32_to_cpu(dword_buff[3]));
/* nvm file validation, dword_buff[2] holds the file version */
if ((CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP &&
le32_to_cpu(dword_buff[2]) < 0xE4A) ||
(CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_B_STEP &&
le32_to_cpu(dword_buff[2]) >= 0xE4A)) {
if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_C_STEP &&
le32_to_cpu(dword_buff[2]) < 0xE4A) {
ret = -EFAULT;
goto out;
}
......@@ -472,14 +471,14 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
break;
}
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
if (!mvm->trans->cfg->ext_nvm) {
section_size =
2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1));
section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2));
} else {
section_size = 2 * NVM_WORD2_LEN_FAMILY_8000(
section_size = 2 * EXT_NVM_WORD2_LEN(
le16_to_cpu(file_sec->word2));
section_id = NVM_WORD1_ID_FAMILY_8000(
section_id = EXT_NVM_WORD1_ID(
le16_to_cpu(file_sec->word1));
}
......@@ -551,12 +550,99 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm)
return ret;
}
int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm)
{
struct iwl_nvm_get_info cmd = {};
struct iwl_nvm_get_info_rsp *rsp;
struct iwl_trans *trans = mvm->trans;
struct iwl_host_cmd hcmd = {
.flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL,
.data = { &cmd, },
.len = { sizeof(cmd) },
.id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO)
};
int ret;
bool lar_fw_supported = !iwlwifi_mod_params.lar_disable &&
fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
lockdep_assert_held(&mvm->mutex);
ret = iwl_mvm_send_cmd(mvm, &hcmd);
if (ret)
return ret;
if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp),
"Invalid payload len in NVM response from FW %d",
iwl_rx_packet_payload_len(hcmd.resp_pkt))) {
ret = -EINVAL;
goto out;
}
rsp = (void *)hcmd.resp_pkt->data;
if (le32_to_cpu(rsp->general.flags)) {
IWL_ERR(mvm, "Invalid NVM data from FW\n");
ret = -EINVAL;
goto out;
}
mvm->nvm_data = kzalloc(sizeof(*mvm->nvm_data) +
sizeof(struct ieee80211_channel) *
IWL_NUM_CHANNELS, GFP_KERNEL);
if (!mvm->nvm_data) {
ret = -ENOMEM;
goto out;
}
iwl_set_hw_address_from_csr(trans, mvm->nvm_data);
/* TODO: if platform NVM has MAC address - override it here */
if (!is_valid_ether_addr(mvm->nvm_data->hw_addr)) {
IWL_ERR(trans, "no valid mac address was found\n");
ret = -EINVAL;
goto out;
}
/* Initialize general data */
mvm->nvm_data->nvm_version = le16_to_cpu(rsp->general.nvm_version);
/* Initialize MAC sku data */
mvm->nvm_data->sku_cap_11ac_enable =
le32_to_cpu(rsp->mac_sku.enable_11ac);
mvm->nvm_data->sku_cap_11n_enable =
le32_to_cpu(rsp->mac_sku.enable_11n);
mvm->nvm_data->sku_cap_band_24GHz_enable =
le32_to_cpu(rsp->mac_sku.enable_24g);
mvm->nvm_data->sku_cap_band_52GHz_enable =
le32_to_cpu(rsp->mac_sku.enable_5g);
mvm->nvm_data->sku_cap_mimo_disabled =
le32_to_cpu(rsp->mac_sku.mimo_disable);
/* Initialize PHY sku data */
mvm->nvm_data->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains);
mvm->nvm_data->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains);
/* Initialize regulatory data */
mvm->nvm_data->lar_enabled =
le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported;
iwl_init_sbands(trans->dev, trans->cfg, mvm->nvm_data,
rsp->regulatory.channel_profile,
mvm->nvm_data->valid_tx_ant & mvm->fw->valid_tx_ant,
mvm->nvm_data->valid_rx_ant & mvm->fw->valid_rx_ant,
rsp->regulatory.lar_enabled && lar_fw_supported);
ret = 0;
out:
iwl_free_resp(&hcmd);
return ret;
}
int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
{
int ret, section;
u32 size_read = 0;
u8 *nvm_buffer, *temp;
const char *nvm_file_B = mvm->cfg->default_nvm_file_B_step;
const char *nvm_file_C = mvm->cfg->default_nvm_file_C_step;
if (WARN_ON_ONCE(mvm->cfg->nvm_hw_section_num >= NVM_MAX_NUM_SECTIONS))
......@@ -626,14 +712,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
/* read External NVM file from the mod param */
ret = iwl_mvm_read_external_nvm(mvm);
if (ret) {
/* choose the nvm_file name according to the
* HW step
*/
if (CSR_HW_REV_STEP(mvm->trans->hw_rev) ==
SILICON_B_STEP)
mvm->nvm_file_name = nvm_file_B;
else
mvm->nvm_file_name = nvm_file_C;
mvm->nvm_file_name = nvm_file_C;
if ((ret == -EFAULT || ret == -ENOENT) &&
mvm->nvm_file_name) {
......@@ -758,7 +837,7 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm)
struct ieee80211_regdomain *regd;
char mcc[3];
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
if (mvm->cfg->ext_nvm) {
tlv_lar = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT);
nvm_lar = mvm->nvm_data->lar_enabled;
......@@ -825,8 +904,8 @@ void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm,
if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm)))
return;
mcc[0] = notif->mcc >> 8;
mcc[1] = notif->mcc & 0xff;
mcc[0] = le16_to_cpu(notif->mcc) >> 8;
mcc[1] = le16_to_cpu(notif->mcc) & 0xff;
mcc[2] = '\0';
src = notif->source_id;
......
......@@ -7,6 +7,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*
* 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
......@@ -33,7 +34,7 @@
*
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -172,13 +173,14 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE);
/*
* TODO: Bits 7-8 of CSR in 8000 HW family set the ADC sampling, and
* shouldn't be set to any non-zero value. The same is supposed to be
* true of the other HW, but unsetting them (such as the 7260) causes
* automatic tests to fail on seemingly unrelated errors. Need to
* further investigate this, but for now we'll separate cases.
* TODO: Bits 7-8 of CSR in 8000 HW family and higher set the ADC
* sampling, and shouldn't be set to any non-zero value.
* The same is supposed to be true of the other HW, but unsetting
* them (such as the 7260) causes automatic tests to fail on seemingly
* unrelated errors. Need to further investigate this, but for now
* we'll separate cases.
*/
if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
if (mvm->trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)
reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI;
iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG,
......@@ -483,6 +485,7 @@ static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = {
*/
static const struct iwl_hcmd_names iwl_mvm_regulatory_and_nvm_names[] = {
HCMD_NAME(NVM_ACCESS_COMPLETE),
HCMD_NAME(NVM_GET_INFO),
};
static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
......@@ -588,6 +591,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->fw = fw;
mvm->hw = hw;
mvm->init_status = 0;
if (iwl_mvm_has_new_rx_api(mvm)) {
op_mode->ops = &iwl_mvm_ops_mq;
trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc);
......@@ -752,7 +757,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);
mutex_unlock(&mvm->mutex);
/* returns 0 if successful, 1 if success but in rfkill */
if (err < 0 && !iwlmvm_mod_params.init_dbg) {
if (err < 0) {
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
goto out_free;
}
......@@ -790,12 +795,18 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
return op_mode;
out_unregister:
if (iwlmvm_mod_params.init_dbg)
return op_mode;
ieee80211_unregister_hw(mvm->hw);
mvm->hw_registered = false;
iwl_mvm_leds_exit(mvm);
iwl_mvm_thermal_exit(mvm);
out_free:
flush_delayed_work(&mvm->fw_dump_wk);
if (iwlmvm_mod_params.init_dbg)
return op_mode;
iwl_phy_db_free(mvm->phy_db);
kfree(mvm->scan_cmd);
iwl_trans_op_mode_leave(trans);
......@@ -820,7 +831,10 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
iwl_mvm_thermal_exit(mvm);
ieee80211_unregister_hw(mvm->hw);
if (mvm->init_status & IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE) {
ieee80211_unregister_hw(mvm->hw);
mvm->init_status &= ~IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;
}
kfree(mvm->scan_cmd);
kfree(mvm->mcast_filter_cmd);
......
......@@ -1421,8 +1421,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvm->scan_vif = iwl_mvm_vif_from_mac80211(vif);
iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
queue_delayed_work(system_wq, &mvm->scan_timeout_dwork,
msecs_to_jiffies(SCAN_TIMEOUT));
schedule_delayed_work(&mvm->scan_timeout_dwork,
msecs_to_jiffies(SCAN_TIMEOUT));
return 0;
}
......
......@@ -1590,6 +1590,29 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm,
}
}
int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta)
{
int i, ret;
for (i = 0; i < ARRAY_SIZE(mvm_sta->tid_data); i++) {
u16 txq_id;
spin_lock_bh(&mvm_sta->lock);
txq_id = mvm_sta->tid_data[i].txq_id;
spin_unlock_bh(&mvm_sta->lock);
if (txq_id == IWL_MVM_INVALID_QUEUE)
continue;
ret = iwl_trans_wait_txq_empty(mvm->trans, txq_id);
if (ret)
break;
}
return ret;
}
int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
......@@ -1611,11 +1634,17 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
if (ret)
return ret;
/* flush its queues here since we are freeing mvm_sta */
ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, 0);
ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0);
if (ret)
return ret;
ret = iwl_trans_wait_tx_queues_empty(mvm->trans,
mvm_sta->tfd_queue_msk);
if (iwl_mvm_has_new_tx_api(mvm)) {
ret = iwl_mvm_wait_sta_queues_empty(mvm, mvm_sta);
} else {
u32 q_mask = mvm_sta->tfd_queue_msk;
ret = iwl_trans_wait_tx_queues_empty(mvm->trans,
q_mask);
}
if (ret)
return ret;
ret = iwl_mvm_drain_sta(mvm, mvm_sta, false);
......@@ -1978,6 +2007,8 @@ static void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
iwl_mvm_flush_sta(mvm, &mvmvif->bcast_sta, true, 0);
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC)
iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue,
......@@ -2187,6 +2218,8 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (!iwl_mvm_is_dqa_supported(mvm))
return 0;
iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0);
iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue,
IWL_MAX_TID_COUNT, 0);
......@@ -2857,8 +2890,13 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_drain_sta(mvm, mvmsta, true);
if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), 0))
IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
iwl_trans_wait_tx_queues_empty(mvm->trans,
mvmsta->tfd_queue_msk);
if (iwl_mvm_has_new_tx_api(mvm))
iwl_trans_wait_txq_empty(mvm->trans, txq_id);
else
iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(txq_id));
iwl_mvm_drain_sta(mvm, mvmsta, false);
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
......
......@@ -489,6 +489,8 @@ static inline int iwl_mvm_update_sta(struct iwl_mvm *mvm,
return iwl_mvm_sta_send_to_fw(mvm, sta, true, 0);
}
int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta);
int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
......
......@@ -551,8 +551,7 @@ void iwl_mvm_tdls_ch_switch_work(struct work_struct *work)
/* retry after a DTIM if we failed sending now */
delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int);
queue_delayed_work(system_wq, &mvm->tdls_cs.dwork,
msecs_to_jiffies(delay));
schedule_delayed_work(&mvm->tdls_cs.dwork, msecs_to_jiffies(delay));
out:
mutex_unlock(&mvm->mutex);
}
......
......@@ -130,7 +130,10 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
* issue as it will have to complete before the next command is
* executed, and a new time event means a new command.
*/
iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC);
if (iwl_mvm_is_dqa_supported(mvm))
iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC);
else
iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC);
}
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
......
......@@ -93,17 +93,21 @@ void iwl_mvm_tof_init(struct iwl_mvm *mvm)
cpu_to_le32(TOF_RANGE_REQ_EXT_CMD);
mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
mvm->init_status |= IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE;
}
void iwl_mvm_tof_clean(struct iwl_mvm *mvm)
{
struct iwl_mvm_tof_data *tof_data = &mvm->tof_data;
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT))
if (!fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_TOF_SUPPORT) ||
!(mvm->init_status & IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE))
return;
memset(tof_data, 0, sizeof(*tof_data));
mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID;
mvm->init_status &= ~IWL_MVM_INIT_STATUS_TOF_INIT_COMPLETE;
}
static void iwl_tof_iterator(void *_data, u8 *mac,
......
......@@ -628,7 +628,8 @@ static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device,
mutex_lock(&mvm->mutex);
if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
if (!iwl_mvm_firmware_running(mvm) ||
mvm->cur_ucode != IWL_UCODE_REGULAR) {
ret = -EIO;
goto out;
}
......@@ -678,7 +679,8 @@ static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
mutex_lock(&mvm->mutex);
if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
if (!iwl_mvm_firmware_running(mvm) ||
mvm->cur_ucode != IWL_UCODE_REGULAR) {
ret = -EIO;
goto out;
}
......@@ -792,7 +794,8 @@ static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,
mutex_lock(&mvm->mutex);
if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
if (!iwl_mvm_firmware_running(mvm) ||
mvm->cur_ucode != IWL_UCODE_REGULAR) {
ret = -EIO;
goto unlock;
}
......@@ -884,10 +887,14 @@ void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)
iwl_mvm_cooling_device_register(mvm);
iwl_mvm_thermal_zone_register(mvm);
#endif
mvm->init_status |= IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE;
}
void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
{
if (!(mvm->init_status & IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE))
return;
cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
......@@ -895,4 +902,5 @@ void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
iwl_mvm_cooling_device_unregister(mvm);
iwl_mvm_thermal_zone_unregister(mvm);
#endif
mvm->init_status &= ~IWL_MVM_INIT_STATUS_THERMAL_INIT_COMPLETE;
}
......@@ -480,8 +480,14 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload;
u16 offload_assist = iwl_mvm_tx_csum(mvm, skb, hdr, info);
if (ieee80211_is_data_qos(hdr->frame_control)) {
u8 *qc = ieee80211_get_qos_ctl(hdr);
if (*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
offload_assist |= BIT(TX_CMD_OFFLD_AMSDU);
}
/* padding is inserted later in transport */
/* FIXME - check for AMSDU may need to be removed */
if (ieee80211_hdrlen(hdr->frame_control) % 4 &&
!(offload_assist & BIT(TX_CMD_OFFLD_AMSDU)))
offload_assist |= BIT(TX_CMD_OFFLD_PAD);
......@@ -1860,7 +1866,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
IWL_DEBUG_TX_REPLY(mvm,
"BA_NOTIFICATION Received from %pM, sta_id = %d\n",
(u8 *)&ba_notif->sta_addr_lo32, ba_notif->sta_id);
ba_notif->sta_addr, ba_notif->sta_id);
IWL_DEBUG_TX_REPLY(mvm,
"TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
......@@ -1894,3 +1900,20 @@ int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk, u32 flags)
IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret);
return ret;
}
int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool int_sta, u32 flags)
{
u32 mask;
if (int_sta) {
struct iwl_mvm_int_sta *int_sta = sta;
mask = int_sta->tfd_queue_msk;
} else {
struct iwl_mvm_sta *mvm_sta = sta;
mask = mvm_sta->tfd_queue_msk;
}
return iwl_mvm_flush_tx_path(mvm, mask, flags);
}
......@@ -538,7 +538,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
/* a000 Series */
{IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg_hr_cdb)},
{IWL_PCI_DEVICE(0x2722, 0x0A10, iwla000_2ac_cfg_hr)},
{IWL_PCI_DEVICE(0x34F0, 0x0310, iwla000_2ac_cfg_jf)},
#endif /* CONFIG_IWLMVM */
{0}
......@@ -672,10 +672,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
iwl_trans->cfg = cfg_7265d;
}
if (iwl_trans->cfg->rf_id &&
(cfg == &iwla000_2ac_cfg_hr || cfg == &iwla000_2ac_cfg_hr_cdb) &&
iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF) {
cfg = &iwla000_2ac_cfg_jf;
if (iwl_trans->cfg->rf_id && cfg == &iwla000_2ac_cfg_hr_cdb) {
if (iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF)
cfg = &iwla000_2ac_cfg_jf;
else if (iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_HR)
cfg = &iwla000_2ac_cfg_hr;
iwl_trans->cfg = cfg;
}
#endif
......
......@@ -779,6 +779,9 @@ int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans,
struct iwl_dma_ptr *ptr, size_t size);
void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr);
void iwl_pcie_apply_destination(struct iwl_trans *trans);
#ifdef CONFIG_INET
struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len);
#endif
/* transport gen 2 exported functions */
int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
......
......@@ -245,7 +245,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans)
*/
/* Disable L0S exit timer (platform NMI Work/Around) */
if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)
iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
......@@ -478,7 +478,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000)
iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_WAKE_ME);
else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
else if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) {
iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
CSR_RESET_LINK_PWR_MGMT_DISABLED);
iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
......@@ -892,7 +892,7 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans)
if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) {
iwl_write_prph(trans, le32_to_cpu(dest->base_reg),
trans_pcie->fw_mon_phys >> dest->base_shift);
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
iwl_write_prph(trans, le32_to_cpu(dest->end_reg),
(trans_pcie->fw_mon_phys +
trans_pcie->fw_mon_size - 256) >>
......@@ -1318,7 +1318,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
/* Load the given image to the HW */
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
ret = iwl_pcie_load_given_ucode_8000(trans, fw);
else
ret = iwl_pcie_load_given_ucode(trans, fw);
......@@ -1435,7 +1435,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
udelay(2);
ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
......@@ -1822,7 +1822,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans,
/* this bit wakes up the NIC */
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000)
udelay(2);
/*
......@@ -2045,17 +2045,52 @@ void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq)
iwl_read_direct32(trans, FH_TX_TRB_REG(fifo)));
}
static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_txq *txq;
int cnt;
unsigned long now = jiffies;
u8 wr_ptr;
if (!test_bit(txq_idx, trans_pcie->queue_used))
return -EINVAL;
IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", txq_idx);
txq = trans_pcie->txq[txq_idx];
wr_ptr = ACCESS_ONCE(txq->write_ptr);
while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) &&
!time_after(jiffies,
now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) {
u8 write_ptr = ACCESS_ONCE(txq->write_ptr);
if (WARN_ONCE(wr_ptr != write_ptr,
"WR pointer moved while flushing %d -> %d\n",
wr_ptr, write_ptr))
return -ETIMEDOUT;
usleep_range(1000, 2000);
}
if (txq->read_ptr != txq->write_ptr) {
IWL_ERR(trans,
"fail to flush all tx fifo queues Q %d\n", txq_idx);
iwl_trans_pcie_log_scd_error(trans, txq);
return -ETIMEDOUT;
}
IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", txq_idx);
return 0;
}
static int iwl_trans_pcie_wait_txqs_empty(struct iwl_trans *trans, u32 txq_bm)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int cnt;
int ret = 0;
/* waiting for all the tx frames complete might take a while */
for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
u8 wr_ptr;
if (cnt == trans_pcie->cmd_queue)
continue;
......@@ -2064,34 +2099,11 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
if (!(BIT(cnt) & txq_bm))
continue;
IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt);
txq = trans_pcie->txq[cnt];
wr_ptr = ACCESS_ONCE(txq->write_ptr);
while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) &&
!time_after(jiffies,
now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) {
u8 write_ptr = ACCESS_ONCE(txq->write_ptr);
if (WARN_ONCE(wr_ptr != write_ptr,
"WR pointer moved while flushing %d -> %d\n",
wr_ptr, write_ptr))
return -ETIMEDOUT;
usleep_range(1000, 2000);
}
if (txq->read_ptr != txq->write_ptr) {
IWL_ERR(trans,
"fail to flush all tx fifo queues Q %d\n", cnt);
ret = -ETIMEDOUT;
ret = iwl_trans_pcie_wait_txq_empty(trans, cnt);
if (ret)
break;
}
IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt);
}
if (ret)
iwl_trans_pcie_log_scd_error(trans, txq);
return ret;
}
......@@ -2563,8 +2575,15 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans,
(*data)->len = cpu_to_le32(fh_regs_len);
val = (void *)(*data)->data;
for (i = FH_MEM_LOWER_BOUND; i < FH_MEM_UPPER_BOUND; i += sizeof(u32))
*val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i));
if (!trans->cfg->gen2)
for (i = FH_MEM_LOWER_BOUND; i < FH_MEM_UPPER_BOUND;
i += sizeof(u32))
*val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i));
else
for (i = FH_MEM_LOWER_BOUND_GEN2; i < FH_MEM_UPPER_BOUND_GEN2;
i += sizeof(u32))
*val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans,
i));
iwl_trans_release_nic_access(trans, &flags);
......@@ -2714,7 +2733,7 @@ static struct iwl_trans_dump_data
trans->dbg_dest_tlv->end_shift;
/* Make "end" point to the actual end */
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 ||
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000 ||
trans->dbg_dest_tlv->monitor_mode == MARBH_MODE)
end += (1 << trans->dbg_dest_tlv->end_shift);
monitor_len = end - base;
......@@ -2740,7 +2759,12 @@ static struct iwl_trans_dump_data
len += sizeof(*data) + IWL_CSR_TO_DUMP;
/* FH registers */
len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND);
if (trans->cfg->gen2)
len += sizeof(*data) +
(FH_MEM_UPPER_BOUND_GEN2 - FH_MEM_LOWER_BOUND_GEN2);
else
len += sizeof(*data) +
(FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND);
if (dump_rbs) {
/* Dump RBs is supported only for pre-9000 devices (1 queue) */
......@@ -2754,6 +2778,13 @@ static struct iwl_trans_dump_data
(PAGE_SIZE << trans_pcie->rx_page_order));
}
/* Paged memory for gen2 HW */
if (trans->cfg->gen2)
for (i = 0; i < trans_pcie->init_dram.paging_cnt; i++)
len += sizeof(*data) +
sizeof(struct iwl_fw_error_dump_paging) +
trans_pcie->init_dram.paging[i].size;
dump_data = vzalloc(len);
if (!dump_data)
return NULL;
......@@ -2793,6 +2824,28 @@ static struct iwl_trans_dump_data
if (dump_rbs)
len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs);
/* Paged memory for gen2 HW */
if (trans->cfg->gen2) {
for (i = 0; i < trans_pcie->init_dram.paging_cnt; i++) {
struct iwl_fw_error_dump_paging *paging;
dma_addr_t addr =
trans_pcie->init_dram.paging[i].physical;
u32 page_len = trans_pcie->init_dram.paging[i].size;
data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
data->len = cpu_to_le32(sizeof(*paging) + page_len);
paging = (void *)data->data;
paging->index = cpu_to_le32(i);
dma_sync_single_for_cpu(trans->dev, addr, page_len,
DMA_BIDIRECTIONAL);
memcpy(paging->data,
trans_pcie->init_dram.paging[i].block, page_len);
data = iwl_fw_error_next_data(data);
len += sizeof(*data) + sizeof(*paging) + page_len;
}
}
len += iwl_trans_pcie_dump_monitor(trans, &data, monitor_len);
dump_data->len = len;
......@@ -2835,7 +2888,6 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans)
.ref = iwl_trans_pcie_ref, \
.unref = iwl_trans_pcie_unref, \
.dump_data = iwl_trans_pcie_dump_data, \
.wait_tx_queues_empty = iwl_trans_pcie_wait_txq_empty, \
.d3_suspend = iwl_trans_pcie_d3_suspend, \
.d3_resume = iwl_trans_pcie_d3_resume
......@@ -2865,6 +2917,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode,
.wait_tx_queues_empty = iwl_trans_pcie_wait_txqs_empty,
.freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer,
.block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs,
};
......@@ -2884,6 +2938,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = {
.txq_alloc = iwl_trans_pcie_dyn_txq_alloc,
.txq_free = iwl_trans_pcie_dyn_txq_free,
.wait_txq_empty = iwl_trans_pcie_wait_txq_empty,
};
struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
......@@ -2988,7 +3043,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
* "dash" value). To keep hw_rev backwards compatible - we'll store it
* in the old format.
*/
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_8000) {
unsigned long flags;
trans->hw_rev = (trans->hw_rev & 0xfff0) |
......
......@@ -49,6 +49,7 @@
*
*****************************************************************************/
#include <linux/pm_runtime.h>
#include <net/tso.h>
#include "iwl-debug.h"
#include "iwl-csr.h"
......@@ -226,6 +227,143 @@ static int iwl_pcie_gen2_set_tb(struct iwl_trans *trans,
return idx;
}
static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans,
struct sk_buff *skb,
struct iwl_tfh_tfd *tfd, int start_len,
u8 hdr_len, struct iwl_device_cmd *dev_cmd)
{
#ifdef CONFIG_INET
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload;
struct ieee80211_hdr *hdr = (void *)skb->data;
unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
unsigned int mss = skb_shinfo(skb)->gso_size;
u16 length, iv_len, amsdu_pad;
u8 *start_hdr;
struct iwl_tso_hdr_page *hdr_page;
struct page **page_ptr;
struct tso_t tso;
/* if the packet is protected, then it must be CCMP or GCMP */
iv_len = ieee80211_has_protected(hdr->frame_control) ?
IEEE80211_CCMP_HDR_LEN : 0;
trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd),
&dev_cmd->hdr, start_len, NULL, 0);
ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb);
snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb);
total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len - iv_len;
amsdu_pad = 0;
/* total amount of header we may need for this A-MSDU */
hdr_room = DIV_ROUND_UP(total_len, mss) *
(3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len;
/* Our device supports 9 segments at most, it will fit in 1 page */
hdr_page = get_page_hdr(trans, hdr_room);
if (!hdr_page)
return -ENOMEM;
get_page(hdr_page->page);
start_hdr = hdr_page->pos;
page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs);
*page_ptr = hdr_page->page;
memcpy(hdr_page->pos, skb->data + hdr_len, iv_len);
hdr_page->pos += iv_len;
/*
* Pull the ieee80211 header + IV to be able to use TSO core,
* we will restore it for the tx_status flow.
*/
skb_pull(skb, hdr_len + iv_len);
/*
* Remove the length of all the headers that we don't actually
* have in the MPDU by themselves, but that we duplicate into
* all the different MSDUs inside the A-MSDU.
*/
le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen);
tso_start(skb, &tso);
while (total_len) {
/* this is the data left for this subframe */
unsigned int data_left = min_t(unsigned int, mss, total_len);
struct sk_buff *csum_skb = NULL;
unsigned int tb_len;
dma_addr_t tb_phys;
struct tcphdr *tcph;
u8 *iph, *subf_hdrs_start = hdr_page->pos;
total_len -= data_left;
memset(hdr_page->pos, 0, amsdu_pad);
hdr_page->pos += amsdu_pad;
amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen +
data_left)) & 0x3;
ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr));
hdr_page->pos += ETH_ALEN;
ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr));
hdr_page->pos += ETH_ALEN;
length = snap_ip_tcp_hdrlen + data_left;
*((__be16 *)hdr_page->pos) = cpu_to_be16(length);
hdr_page->pos += sizeof(length);
/*
* This will copy the SNAP as well which will be considered
* as MAC header.
*/
tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len);
iph = hdr_page->pos + 8;
tcph = (void *)(iph + ip_hdrlen);
hdr_page->pos += snap_ip_tcp_hdrlen;
tb_len = hdr_page->pos - start_hdr;
tb_phys = dma_map_single(trans->dev, start_hdr,
tb_len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, tb_phys))) {
dev_kfree_skb(csum_skb);
goto out_err;
}
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len);
trace_iwlwifi_dev_tx_tso_chunk(trans->dev, start_hdr, tb_len);
/* add this subframe's headers' length to the tx_cmd */
le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start);
/* prepare the start_hdr for the next subframe */
start_hdr = hdr_page->pos;
/* put the payload */
while (data_left) {
tb_len = min_t(unsigned int, tso.size, data_left);
tb_phys = dma_map_single(trans->dev, tso.data,
tb_len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(trans->dev, tb_phys))) {
dev_kfree_skb(csum_skb);
goto out_err;
}
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len);
trace_iwlwifi_dev_tx_tso_chunk(trans->dev, tso.data,
tb_len);
data_left -= tb_len;
tso_build_data(skb, &tso, tb_len);
}
}
/* re -add the WiFi header and IV */
skb_push(skb, hdr_len + iv_len);
return 0;
out_err:
#endif
return -EINVAL;
}
static
struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans,
struct iwl_txq *txq,
......@@ -238,15 +376,21 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans,
struct iwl_tfh_tfd *tfd =
iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr);
dma_addr_t tb_phys;
bool amsdu;
int i, len, tb1_len, tb2_len, hdr_len;
void *tb1_addr;
memset(tfd, 0, sizeof(*tfd));
amsdu = ieee80211_is_data_qos(hdr->frame_control) &&
(*ieee80211_get_qos_ctl(hdr) &
IEEE80211_QOS_CTL_A_MSDU_PRESENT);
tb_phys = iwl_pcie_get_first_tb_dma(txq, txq->write_ptr);
/* The first TB points to bi-directional DMA data */
memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr,
IWL_FIRST_TB_SIZE);
if (!amsdu)
memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr,
IWL_FIRST_TB_SIZE);
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, IWL_FIRST_TB_SIZE);
......@@ -262,7 +406,11 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans,
len = sizeof(struct iwl_tx_cmd_gen2) + sizeof(struct iwl_cmd_header) +
ieee80211_hdrlen(hdr->frame_control) - IWL_FIRST_TB_SIZE;
tb1_len = ALIGN(len, 4);
/* do not align A-MSDU to dword as the subframe header aligns it */
if (amsdu)
tb1_len = len;
else
tb1_len = ALIGN(len, 4);
/* map the data for TB1 */
tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE;
......@@ -271,8 +419,24 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans,
goto out_err;
iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb1_len);
/* set up TFD's third entry to point to remainder of skb's head */
hdr_len = ieee80211_hdrlen(hdr->frame_control);
if (amsdu) {
if (!iwl_pcie_gen2_build_amsdu(trans, skb, tfd,
tb1_len + IWL_FIRST_TB_SIZE,
hdr_len, dev_cmd))
goto out_err;
/*
* building the A-MSDU might have changed this data, so memcpy
* it now
*/
memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr,
IWL_FIRST_TB_SIZE);
return tfd;
}
/* set up TFD's third entry to point to remainder of skb's head */
tb2_len = skb_headlen(skb) - hdr_len;
if (tb2_len > 0) {
......
......@@ -762,7 +762,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
/* Enable L1-Active */
if (trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000)
iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
}
......@@ -1987,8 +1987,7 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
}
#ifdef CONFIG_INET
static struct iwl_tso_hdr_page *
get_page_hdr(struct iwl_trans *trans, size_t len)
struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_tso_hdr_page *p = this_cpu_ptr(trans_pcie->tso_hdr_page);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment