Commit a08e61d2 authored by Kalle Valo's avatar Kalle Valo

Merge tag 'iwlwifi-next-for-kalle-2017-12-20' of...

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

Third batch of updates for v4.16

* Small cleanups in the new rate-scaling code;
* Some improvements in debugging;
* New FW API changes;
* Fix a bug where we got a false-positive warning;
* Fix forced quota debugfs functionality;
parents a9f89463 4243edb4
......@@ -15,6 +15,7 @@ iwlwifi-objs += fw/notif-wait.o
iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o fw/dbg.o
iwlwifi-$(CONFIG_IWLMVM) += fw/common_rx.o fw/nvm.o
iwlwifi-$(CONFIG_ACPI) += fw/acpi.o
iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o
iwlwifi-objs += $(iwlwifi-m)
......
......@@ -250,10 +250,12 @@ struct iwl_mfu_assert_dump_notif {
* The ids for different type of markers to insert into the usniffer logs
*
* @MARKER_ID_TX_FRAME_LATENCY: TX latency marker
* @MARKER_ID_SYNC_CLOCK: sync FW time and systime
*/
enum iwl_mvm_marker_id {
MARKER_ID_TX_FRAME_LATENCY = 1,
}; /* MARKER_ID_API_E_VER_1 */
MARKER_ID_SYNC_CLOCK = 2,
}; /* MARKER_ID_API_E_VER_2 */
/**
* struct iwl_mvm_marker - mark info into the usniffer logs
......
......@@ -67,6 +67,10 @@
* enum iwl_mac_conf_subcmd_ids - mac configuration command IDs
*/
enum iwl_mac_conf_subcmd_ids {
/**
* @LOW_LATENCY_CMD: &struct iwl_mac_low_latency_cmd
*/
LOW_LATENCY_CMD = 0x3,
/**
* @CHANNEL_SWITCH_NOA_NOTIF: &struct iwl_channel_switch_noa_notif
*/
......@@ -82,4 +86,19 @@ struct iwl_channel_switch_noa_notif {
__le32 id_and_color;
} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */
/**
* struct iwl_mac_low_latency_cmd - set/clear mac to 'low-latency mode'
*
* @mac_id: MAC ID to whom to apply the low-latency configurations
* @low_latency_rx: 1/0 to set/clear Rx low latency direction
* @low_latency_tx: 1/0 to set/clear Tx low latency direction
* @reserved: reserved for alignment purposes
*/
struct iwl_mac_low_latency_cmd {
__le32 mac_id;
u8 low_latency_rx;
u8 low_latency_tx;
__le16 reserved;
} __packed; /* MAC_LOW_LATENCY_API_S_VER_1 */
#endif /* __iwl_fw_api_mac_cfg_h__ */
......@@ -71,7 +71,7 @@
* @IWL_TLC_MNG_CFG_FLAGS_BF_MSK: enable BFER
* @IWL_TLC_MNG_CFG_FLAGS_DCM_MSK: enable DCM
*/
enum iwl_tlc_mng_cfg_flags_enum {
enum iwl_tlc_mng_cfg_flags {
IWL_TLC_MNG_CFG_FLAGS_CCK_MSK = BIT(0),
IWL_TLC_MNG_CFG_FLAGS_DD_MSK = BIT(1),
IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(2),
......@@ -81,14 +81,14 @@ enum iwl_tlc_mng_cfg_flags_enum {
};
/**
* enum iwl_tlc_mng_cfg_cw_enum - channel width options
* enum iwl_tlc_mng_cfg_cw - channel width options
* @IWL_TLC_MNG_MAX_CH_WIDTH_20MHZ: 20MHZ channel
* @IWL_TLC_MNG_MAX_CH_WIDTH_40MHZ: 40MHZ channel
* @IWL_TLC_MNG_MAX_CH_WIDTH_80MHZ: 80MHZ channel
* @IWL_TLC_MNG_MAX_CH_WIDTH_160MHZ: 160MHZ channel
* @IWL_TLC_MNG_MAX_CH_WIDTH_LAST: maximum value
*/
enum iwl_tlc_mng_cfg_cw_enum {
enum iwl_tlc_mng_cfg_cw {
IWL_TLC_MNG_MAX_CH_WIDTH_20MHZ,
IWL_TLC_MNG_MAX_CH_WIDTH_40MHZ,
IWL_TLC_MNG_MAX_CH_WIDTH_80MHZ,
......@@ -97,25 +97,25 @@ enum iwl_tlc_mng_cfg_cw_enum {
};
/**
* enum iwl_tlc_mng_cfg_chains_enum - possible chains
* enum iwl_tlc_mng_cfg_chains - possible chains
* @IWL_TLC_MNG_CHAIN_A_MSK: chain A
* @IWL_TLC_MNG_CHAIN_B_MSK: chain B
* @IWL_TLC_MNG_CHAIN_C_MSK: chain C
*/
enum iwl_tlc_mng_cfg_chains_enum {
enum iwl_tlc_mng_cfg_chains {
IWL_TLC_MNG_CHAIN_A_MSK = BIT(0),
IWL_TLC_MNG_CHAIN_B_MSK = BIT(1),
IWL_TLC_MNG_CHAIN_C_MSK = BIT(2),
};
/**
* enum iwl_tlc_mng_cfg_gi_enum - guard interval options
* enum iwl_tlc_mng_cfg_gi - guard interval options
* @IWL_TLC_MNG_SGI_20MHZ_MSK: enable short GI for 20MHZ
* @IWL_TLC_MNG_SGI_40MHZ_MSK: enable short GI for 40MHZ
* @IWL_TLC_MNG_SGI_80MHZ_MSK: enable short GI for 80MHZ
* @IWL_TLC_MNG_SGI_160MHZ_MSK: enable short GI for 160MHZ
*/
enum iwl_tlc_mng_cfg_gi_enum {
enum iwl_tlc_mng_cfg_gi {
IWL_TLC_MNG_SGI_20MHZ_MSK = BIT(0),
IWL_TLC_MNG_SGI_40MHZ_MSK = BIT(1),
IWL_TLC_MNG_SGI_80MHZ_MSK = BIT(2),
......@@ -123,7 +123,7 @@ enum iwl_tlc_mng_cfg_gi_enum {
};
/**
* enum iwl_tlc_mng_cfg_mode_enum - supported modes
* enum iwl_tlc_mng_cfg_mode - supported modes
* @IWL_TLC_MNG_MODE_CCK: enable CCK
* @IWL_TLC_MNG_MODE_OFDM_NON_HT: enable OFDM (non HT)
* @IWL_TLC_MNG_MODE_NON_HT: enable non HT
......@@ -133,7 +133,7 @@ enum iwl_tlc_mng_cfg_gi_enum {
* @IWL_TLC_MNG_MODE_INVALID: invalid value
* @IWL_TLC_MNG_MODE_NUM: a count of possible modes
*/
enum iwl_tlc_mng_cfg_mode_enum {
enum iwl_tlc_mng_cfg_mode {
IWL_TLC_MNG_MODE_CCK = 0,
IWL_TLC_MNG_MODE_OFDM_NON_HT = IWL_TLC_MNG_MODE_CCK,
IWL_TLC_MNG_MODE_NON_HT = IWL_TLC_MNG_MODE_CCK,
......@@ -145,14 +145,14 @@ enum iwl_tlc_mng_cfg_mode_enum {
};
/**
* enum iwl_tlc_mng_vht_he_types_enum - VHT HE types
* enum iwl_tlc_mng_vht_he_types - VHT HE types
* @IWL_TLC_MNG_VALID_VHT_HE_TYPES_SU: VHT HT single user
* @IWL_TLC_MNG_VALID_VHT_HE_TYPES_SU_EXT: VHT HT single user extended
* @IWL_TLC_MNG_VALID_VHT_HE_TYPES_MU: VHT HT multiple users
* @IWL_TLC_MNG_VALID_VHT_HE_TYPES_TRIG_BASED: trigger based
* @IWL_TLC_MNG_VALID_VHT_HE_TYPES_NUM: a count of possible types
*/
enum iwl_tlc_mng_vht_he_types_enum {
enum iwl_tlc_mng_vht_he_types {
IWL_TLC_MNG_VALID_VHT_HE_TYPES_SU = 0,
IWL_TLC_MNG_VALID_VHT_HE_TYPES_SU_EXT,
IWL_TLC_MNG_VALID_VHT_HE_TYPES_MU,
......@@ -163,7 +163,7 @@ enum iwl_tlc_mng_vht_he_types_enum {
};
/**
* enum iwl_tlc_mng_ht_rates_enum - HT/VHT rates
* enum iwl_tlc_mng_ht_rates - HT/VHT rates
* @IWL_TLC_MNG_HT_RATE_MCS0: index of MCS0
* @IWL_TLC_MNG_HT_RATE_MCS1: index of MCS1
* @IWL_TLC_MNG_HT_RATE_MCS2: index of MCS2
......@@ -176,7 +176,7 @@ enum iwl_tlc_mng_vht_he_types_enum {
* @IWL_TLC_MNG_HT_RATE_MCS9: index of MCS9
* @IWL_TLC_MNG_HT_RATE_MAX: maximal rate for HT/VHT
*/
enum iwl_tlc_mng_ht_rates_enum {
enum iwl_tlc_mng_ht_rates {
IWL_TLC_MNG_HT_RATE_MCS0 = 0,
IWL_TLC_MNG_HT_RATE_MCS1,
IWL_TLC_MNG_HT_RATE_MCS2,
......@@ -198,13 +198,13 @@ enum iwl_tlc_mng_ht_rates_enum {
* @sta_id: station id
* @reserved1: reserved
* @max_supp_ch_width: channel width
* @flags: bitmask of %IWL_TLC_MNG_CONFIG_FLAGS_ENABLE_\*
* @chains: bitmask of %IWL_TLC_MNG_CHAIN_\*
* @flags: bitmask of &enum iwl_tlc_mng_cfg_flags
* @chains: bitmask of &enum iwl_tlc_mng_cfg_chains
* @max_supp_ss: valid values are 0-3, 0 - spatial streams are not supported
* @valid_vht_he_types: bitmap of %IWL_TLC_MNG_VALID_VHT_HE_TYPES_\*
* @valid_vht_he_types: bitmap of &enum iwl_tlc_mng_vht_he_types
* @non_ht_supp_rates: bitmap of supported legacy rates
* @ht_supp_rates: bitmap of supported HT/VHT rates, valid bits are 0-9
* @mode: modulation type %IWL_TLC_MNG_MODE_\*
* @mode: &enum iwl_tlc_mng_cfg_mode
* @reserved2: reserved
* @he_supp_rates: bitmap of supported HE rates
* @sgi_ch_width_supp: bitmap of SGI support per channel width
......
/******************************************************************************
*
* 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) 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.
*
* 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) 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
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include "api/commands.h"
#include "debugfs.h"
#define FWRT_DEBUGFS_READ_FILE_OPS(name) \
static ssize_t iwl_dbgfs_##name##_read(struct iwl_fw_runtime *fwrt, \
char *buf, size_t count, \
loff_t *ppos); \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \
static ssize_t iwl_dbgfs_##name##_write(struct iwl_fw_runtime *fwrt, \
char *buf, size_t count, \
loff_t *ppos); \
static ssize_t _iwl_dbgfs_##name##_write(struct file *file, \
const char __user *user_buf, \
size_t count, loff_t *ppos) \
{ \
struct iwl_fw_runtime *fwrt = file->private_data; \
char buf[buflen] = {}; \
size_t buf_size = min(count, sizeof(buf) - 1); \
\
if (copy_from_user(buf, user_buf, buf_size)) \
return -EFAULT; \
\
return iwl_dbgfs_##name##_write(fwrt, buf, buf_size, ppos); \
}
#define FWRT_DEBUGFS_READ_WRITE_FILE_OPS(name, buflen) \
FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = _iwl_dbgfs_##name##_write, \
.read = iwl_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define FWRT_DEBUGFS_WRITE_FILE_OPS(name, buflen) \
FWRT_DEBUGFS_WRITE_WRAPPER(name, buflen) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = _iwl_dbgfs_##name##_write, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define FWRT_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode) do { \
if (!debugfs_create_file(alias, mode, parent, fwrt, \
&iwl_dbgfs_##name##_ops)) \
goto err; \
} while (0)
#define FWRT_DEBUGFS_ADD_FILE(name, parent, mode) \
FWRT_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
static int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt)
{
struct iwl_mvm_marker marker = {
.dw_len = sizeof(struct iwl_mvm_marker) / 4,
.marker_id = MARKER_ID_SYNC_CLOCK,
/* the real timestamp is taken from the ftrace clock
* this is for finding the match between fw and kernel logs
*/
.timestamp = cpu_to_le64(fwrt->timestamp.seq++),
};
struct iwl_host_cmd hcmd = {
.id = MARKER_CMD,
.flags = CMD_ASYNC,
.data[0] = &marker,
.len[0] = sizeof(marker),
};
return iwl_trans_send_cmd(fwrt->trans, &hcmd);
}
static void iwl_fw_timestamp_marker_wk(struct work_struct *work)
{
int ret;
struct iwl_fw_runtime *fwrt =
container_of(work, struct iwl_fw_runtime, timestamp.wk.work);
unsigned long delay = fwrt->timestamp.delay;
ret = iwl_fw_send_timestamp_marker_cmd(fwrt);
if (!ret && delay)
schedule_delayed_work(&fwrt->timestamp.wk,
round_jiffies_relative(delay));
else
IWL_INFO(fwrt,
"stopping timestamp_marker, ret: %d, delay: %u\n",
ret, jiffies_to_msecs(delay) / 1000);
}
static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt,
char *buf, size_t count,
loff_t *ppos)
{
int ret;
u32 delay;
ret = kstrtou32(buf, 10, &delay);
if (ret < 0)
return ret;
IWL_INFO(fwrt,
"starting timestamp_marker trigger with delay: %us\n",
delay);
iwl_fw_cancel_timestamp(fwrt);
fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000);
schedule_delayed_work(&fwrt->timestamp.wk,
round_jiffies_relative(fwrt->timestamp.delay));
return count;
}
FWRT_DEBUGFS_WRITE_FILE_OPS(timestamp_marker, 10);
int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
struct dentry *dbgfs_dir)
{
INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk);
FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, S_IWUSR);
return 0;
err:
IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n");
return -ENOMEM;
}
/******************************************************************************
*
* 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) 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.
*
* 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) 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
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#include "runtime.h"
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
struct dentry *dbgfs_dir);
static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt)
{
fwrt->timestamp.delay = 0;
cancel_delayed_work_sync(&fwrt->timestamp.wk);
}
#else
static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
struct dentry *dbgfs_dir)
{
return 0;
}
static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {}
#endif /* CONFIG_IWLWIFI_DEBUGFS */
......@@ -7,7 +7,7 @@
*
* Copyright(c) 2008 - 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,7 +34,7 @@
*
* Copyright(c) 2005 - 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
......@@ -248,6 +248,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
* @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used
* @IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY: Quota command includes a field
* indicating low latency direction.
* @IWL_UCODE_TLV_API_DEPRECATE_TTAK: RX status flag TTAK ok (bit 7) is
* deprecated.
*
* @NUM_IWL_UCODE_TLV_API: number of bits used
*/
......@@ -266,6 +268,7 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE = (__force iwl_ucode_tlv_api_t)34,
IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35,
IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY = (__force iwl_ucode_tlv_api_t)38,
IWL_UCODE_TLV_API_DEPRECATE_TTAK = (__force iwl_ucode_tlv_api_t)41,
NUM_IWL_UCODE_TLV_API
#ifdef __CHECKER__
......@@ -311,6 +314,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
* @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan
* @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification
* @IWL_UCODE_TLV_CAPA_TLC_OFFLOAD: firmware implements rate scaling algorithm
* @IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA: firmware implements quota related
* @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
* @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
* @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
......@@ -366,6 +370,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)40,
IWL_UCODE_TLV_CAPA_D0I3_END_FIRST = (__force iwl_ucode_tlv_capa_t)41,
IWL_UCODE_TLV_CAPA_TLC_OFFLOAD = (__force iwl_ucode_tlv_capa_t)43,
IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA = (__force iwl_ucode_tlv_capa_t)44,
IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64,
IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65,
IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67,
......@@ -540,7 +545,7 @@ struct iwl_fw_dbg_mem_seg_tlv {
} __packed;
/**
* struct iwl_fw_dbg_dest_tlv - configures the destination of the debug data
* struct iwl_fw_dbg_dest_tlv_v1 - configures the destination of the debug data
*
* @version: version of the TLV - currently 0
* @monitor_mode: &enum iwl_fw_dbg_monitor_mode
......@@ -555,7 +560,7 @@ struct iwl_fw_dbg_mem_seg_tlv {
*
* This parses IWL_UCODE_TLV_FW_DBG_DEST
*/
struct iwl_fw_dbg_dest_tlv {
struct iwl_fw_dbg_dest_tlv_v1 {
u8 version;
u8 monitor_mode;
u8 size_power;
......@@ -569,6 +574,26 @@ struct iwl_fw_dbg_dest_tlv {
struct iwl_fw_dbg_reg_op reg_ops[0];
} __packed;
/* Mask of the register for defining the LDBG MAC2SMEM buffer SMEM size */
#define IWL_LDBG_M2S_BUF_SIZE_MSK 0x0fff0000
/* Mask of the register for defining the LDBG MAC2SMEM SMEM base address */
#define IWL_LDBG_M2S_BUF_BA_MSK 0x00000fff
/* The smem buffer chunks are in units of 256 bits */
#define IWL_M2S_UNIT_SIZE 0x100
struct iwl_fw_dbg_dest_tlv {
u8 version;
u8 monitor_mode;
u8 size_power;
u8 reserved;
__le32 cfg_reg;
__le32 write_ptr_reg;
__le32 wrap_count;
u8 base_shift;
u8 size_shift;
struct iwl_fw_dbg_reg_op reg_ops[0];
} __packed;
struct iwl_fw_dbg_conf_hcmd {
u8 id;
u8 reserved;
......
......@@ -284,7 +284,7 @@ struct iwl_fw {
struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS];
u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
......
......@@ -58,10 +58,12 @@
#include "iwl-drv.h"
#include "runtime.h"
#include "dbg.h"
#include "debugfs.h"
void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
const struct iwl_fw *fw,
const struct iwl_fw_runtime_ops *ops, void *ops_ctx)
const struct iwl_fw *fw,
const struct iwl_fw_runtime_ops *ops, void *ops_ctx,
struct dentry *dbgfs_dir)
{
memset(fwrt, 0, sizeof(*fwrt));
fwrt->trans = trans;
......@@ -71,5 +73,12 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
fwrt->ops = ops;
fwrt->ops_ctx = ops_ctx;
INIT_DELAYED_WORK(&fwrt->dump.wk, iwl_fw_error_dump_wk);
iwl_fwrt_dbgfs_register(fwrt, dbgfs_dir);
}
IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);
void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt)
{
iwl_fw_cancel_timestamp(fwrt);
}
IWL_EXPORT_SYMBOL(iwl_fw_runtime_exit);
......@@ -134,11 +134,21 @@ struct iwl_fw_runtime {
/* ts of the beginning of a non-collect fw dbg data period */
unsigned long non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1];
} dump;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct {
struct delayed_work wk;
u32 delay;
u64 seq;
} timestamp;
#endif /* CONFIG_IWLWIFI_DEBUGFS */
};
void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
const struct iwl_fw *fw,
const struct iwl_fw_runtime_ops *ops, void *ops_ctx);
const struct iwl_fw *fw,
const struct iwl_fw_runtime_ops *ops, void *ops_ctx,
struct dentry *dbgfs_dir);
void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt);
static inline void iwl_fw_set_current_image(struct iwl_fw_runtime *fwrt,
enum iwl_ucode_type cur_fw_img)
......
......@@ -95,7 +95,7 @@ TRACE_EVENT(iwlwifi_dev_tx,
TP_ARGS(dev, skb, tfd, tfdlen, buf0, buf0_len, hdr_len),
TP_STRUCT__entry(
DEV_ENTRY
__field(void *, skbaddr)
__field(size_t, framelen)
__dynamic_array(u8, tfd, tfdlen)
......@@ -110,6 +110,7 @@ TRACE_EVENT(iwlwifi_dev_tx,
),
TP_fast_assign(
DEV_ASSIGN;
__entry->skbaddr = skb;
__entry->framelen = buf0_len;
if (hdr_len > 0)
__entry->framelen += skb->len - hdr_len;
......@@ -120,9 +121,9 @@ TRACE_EVENT(iwlwifi_dev_tx,
__get_dynamic_array(buf1),
skb->len - hdr_len);
),
TP_printk("[%s] TX %.2x (%zu bytes)",
TP_printk("[%s] TX %.2x (%zu bytes) skbaddr=%p",
__get_str(dev), ((u8 *)__get_dynamic_array(buf0))[0],
__entry->framelen)
__entry->framelen, __entry->skbaddr)
);
TRACE_EVENT(iwlwifi_dev_ucode_error,
......
......@@ -296,7 +296,12 @@ struct iwl_firmware_pieces {
u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
/* FW debug data parsed for driver usage */
struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
bool dbg_dest_tlv_init;
u8 *dbg_dest_ver;
union {
struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv_v1;
};
struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
size_t dbg_conf_tlv_len[FW_DBG_CONF_MAX];
struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX];
......@@ -930,21 +935,49 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
break;
}
case IWL_UCODE_TLV_FW_DBG_DEST: {
struct iwl_fw_dbg_dest_tlv *dest = (void *)tlv_data;
struct iwl_fw_dbg_dest_tlv *dest = NULL;
struct iwl_fw_dbg_dest_tlv_v1 *dest_v1 = NULL;
u8 mon_mode;
pieces->dbg_dest_ver = (u8 *)tlv_data;
if (*pieces->dbg_dest_ver == 1) {
dest = (void *)tlv_data;
} else if (*pieces->dbg_dest_ver == 0) {
dest_v1 = (void *)tlv_data;
} else {
IWL_ERR(drv,
"The version is %d, and it is invalid\n",
*pieces->dbg_dest_ver);
break;
}
if (pieces->dbg_dest_tlv) {
if (pieces->dbg_dest_tlv_init) {
IWL_ERR(drv,
"dbg destination ignored, already exists\n");
break;
}
pieces->dbg_dest_tlv = dest;
pieces->dbg_dest_tlv_init = true;
if (dest_v1) {
pieces->dbg_dest_tlv_v1 = dest_v1;
mon_mode = dest_v1->monitor_mode;
} else {
pieces->dbg_dest_tlv = dest;
mon_mode = dest->monitor_mode;
}
IWL_INFO(drv, "Found debug destination: %s\n",
get_fw_dbg_mode_string(dest->monitor_mode));
get_fw_dbg_mode_string(mon_mode));
drv->fw.dbg_dest_reg_num = (dest_v1) ?
tlv_len -
offsetof(struct iwl_fw_dbg_dest_tlv_v1,
reg_ops) :
tlv_len -
offsetof(struct iwl_fw_dbg_dest_tlv,
reg_ops);
drv->fw.dbg_dest_reg_num =
tlv_len - offsetof(struct iwl_fw_dbg_dest_tlv,
reg_ops);
drv->fw.dbg_dest_reg_num /=
sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]);
......@@ -953,7 +986,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
case IWL_UCODE_TLV_FW_DBG_CONF: {
struct iwl_fw_dbg_conf_tlv *conf = (void *)tlv_data;
if (!pieces->dbg_dest_tlv) {
if (!pieces->dbg_dest_tlv_init) {
IWL_ERR(drv,
"Ignore dbg config %d - no destination configured\n",
conf->id);
......@@ -1340,15 +1373,51 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
if (iwl_alloc_ucode(drv, pieces, i))
goto out_free_fw;
if (pieces->dbg_dest_tlv) {
drv->fw.dbg_dest_tlv =
kmemdup(pieces->dbg_dest_tlv,
sizeof(*pieces->dbg_dest_tlv) +
sizeof(pieces->dbg_dest_tlv->reg_ops[0]) *
drv->fw.dbg_dest_reg_num, GFP_KERNEL);
if (pieces->dbg_dest_tlv_init) {
size_t dbg_dest_size = sizeof(*drv->fw.dbg_dest_tlv) +
sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
drv->fw.dbg_dest_reg_num;
drv->fw.dbg_dest_tlv = kmalloc(dbg_dest_size, GFP_KERNEL);
if (!drv->fw.dbg_dest_tlv)
goto out_free_fw;
if (*pieces->dbg_dest_ver == 0) {
memcpy(drv->fw.dbg_dest_tlv, pieces->dbg_dest_tlv_v1,
dbg_dest_size);
} else {
struct iwl_fw_dbg_dest_tlv_v1 *dest_tlv =
drv->fw.dbg_dest_tlv;
dest_tlv->version = pieces->dbg_dest_tlv->version;
dest_tlv->monitor_mode =
pieces->dbg_dest_tlv->monitor_mode;
dest_tlv->size_power =
pieces->dbg_dest_tlv->size_power;
dest_tlv->wrap_count =
pieces->dbg_dest_tlv->wrap_count;
dest_tlv->write_ptr_reg =
pieces->dbg_dest_tlv->write_ptr_reg;
dest_tlv->base_shift =
pieces->dbg_dest_tlv->base_shift;
memcpy(dest_tlv->reg_ops,
pieces->dbg_dest_tlv->reg_ops,
sizeof(drv->fw.dbg_dest_tlv->reg_ops[0]) *
drv->fw.dbg_dest_reg_num);
/* In version 1 of the destination tlv, which is
* relevant for internal buffer exclusively,
* the base address is part of given with the length
* of the buffer, and the size shift is give instead of
* end shift. We now store these values in base_reg,
* and end shift, and when dumping the data we'll
* manipulate it for extracting both the length and
* base address */
dest_tlv->base_reg = pieces->dbg_dest_tlv->cfg_reg;
dest_tlv->end_shift =
pieces->dbg_dest_tlv->size_shift;
}
}
for (i = 0; i < ARRAY_SIZE(drv->fw.dbg_conf_tlv); i++) {
......
......@@ -579,6 +579,7 @@ struct iwl_trans_ops {
void (*configure)(struct iwl_trans *trans,
const struct iwl_trans_config *trans_cfg);
void (*set_pmi)(struct iwl_trans *trans, bool state);
void (*sw_reset)(struct iwl_trans *trans);
bool (*grab_nic_access)(struct iwl_trans *trans, unsigned long *flags);
void (*release_nic_access)(struct iwl_trans *trans,
unsigned long *flags);
......@@ -744,7 +745,7 @@ struct iwl_trans {
struct lockdep_map sync_cmd_lockdep_map;
#endif
const struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
const struct iwl_fw_dbg_dest_tlv_v1 *dbg_dest_tlv;
const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_CONF_MAX];
struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv;
u8 dbg_dest_reg_num;
......@@ -1124,6 +1125,12 @@ static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state)
trans->ops->set_pmi(trans, state);
}
static inline void iwl_trans_sw_reset(struct iwl_trans *trans)
{
if (trans->ops->sw_reset)
trans->ops->sw_reset(trans);
}
static inline void
iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value)
{
......
......@@ -1221,7 +1221,7 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
loff_t *ppos)
{
struct iwl_trans *trans = mvm->trans;
const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv;
const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
struct iwl_continuous_record_cmd cont_rec = {};
int ret, rec_mode;
......@@ -1914,7 +1914,7 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TLC_OFFLOAD))
if (iwl_mvm_has_tlc_offload(mvm))
MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, S_IRUSR);
return;
......
......@@ -421,7 +421,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TLC_OFFLOAD)) {
if (iwl_mvm_has_tlc_offload(mvm)) {
ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
}
......@@ -460,7 +460,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
/* this is the case for CCK frames, it's better (only 8) for OFDM */
hw->radiotap_timestamp.accuracy = 22;
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TLC_OFFLOAD))
if (!iwl_mvm_has_tlc_offload(mvm))
hw->rate_control_algorithm = RS_NAME;
hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
......@@ -3801,7 +3801,7 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm,
mvm->noa_duration = noa_duration;
mvm->noa_vif = vif;
return iwl_mvm_update_quotas(mvm, false, NULL);
return iwl_mvm_update_quotas(mvm, true, NULL);
case IWL_MVM_TM_CMD_SET_BEACON_FILTER:
/* must be associated client vif - ignore authorized */
if (!vif || vif->type != NL80211_IFTYPE_STATION ||
......
......@@ -1278,6 +1278,12 @@ static inline bool iwl_mvm_has_quota_low_latency(struct iwl_mvm *mvm)
IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY);
}
static inline bool iwl_mvm_has_tlc_offload(const struct iwl_mvm *mvm)
{
return fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_TLC_OFFLOAD);
}
static inline struct agg_tx_status *
iwl_mvm_get_agg_status(struct iwl_mvm *mvm, void *tx_resp)
{
......
......@@ -602,7 +602,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mvm->fw = fw;
mvm->hw = hw;
iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm);
iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm,
dbgfs_dir);
mvm->init_status = 0;
......@@ -801,6 +802,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_mvm_leds_exit(mvm);
iwl_mvm_thermal_exit(mvm);
out_free:
iwl_fw_runtime_exit(&mvm->fwrt);
iwl_fw_flush_dump(&mvm->fwrt);
if (iwlmvm_mod_params.init_dbg)
......@@ -841,7 +843,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
kfree(mvm->d3_resume_sram);
#endif
iwl_fw_runtime_exit(&mvm->fwrt);
iwl_trans_op_mode_leave(mvm->trans);
iwl_phy_db_free(mvm->phy_db);
......
......@@ -202,6 +202,10 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA))
return 0;
/* update all upon completion */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
return 0;
......
......@@ -4052,7 +4052,7 @@ static const struct rate_control_ops rs_mvm_ops_drv = {
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
enum nl80211_band band, bool init)
{
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TLC_OFFLOAD))
if (iwl_mvm_has_tlc_offload(mvm))
rs_fw_rate_init(mvm, sta, band);
else
rs_drv_rate_init(mvm, sta, band, init);
......@@ -4096,7 +4096,7 @@ static int rs_drv_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool enable)
{
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TLC_OFFLOAD))
if (iwl_mvm_has_tlc_offload(mvm))
return rs_fw_tx_protection(mvm, mvmsta, enable);
else
return rs_drv_tx_protection(mvm, mvmsta, enable);
......
......@@ -222,7 +222,9 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
case RX_MPDU_RES_STATUS_SEC_TKIP_ENC:
/* Don't drop the frame and decrypt it in SW */
if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK))
if (!fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_DEPRECATE_TTAK) &&
!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK))
return 0;
*crypt_len = IEEE80211_TKIP_IV_LEN;
/* fall through if TTAK OK */
......
......@@ -261,7 +261,9 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
return 0;
case IWL_RX_MPDU_STATUS_SEC_TKIP:
/* Don't drop the frame and decrypt it in SW */
if (!(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK))
if (!fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_DEPRECATE_TTAK) &&
!(status & IWL_RX_MPDU_RES_STATUS_TTAK_OK))
return 0;
*crypt_len = IEEE80211_TKIP_IV_LEN;
......
......@@ -1443,7 +1443,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
* if rs is registered with mac80211, then "add station" will be handled
* via the corresponding ops, otherwise need to notify rate scaling here
*/
if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TLC_OFFLOAD))
if (iwl_mvm_has_tlc_offload(mvm))
iwl_mvm_rs_add_sta(mvm, mvm_sta);
update_fw:
......@@ -2586,8 +2586,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* When FW supports TLC_OFFLOAD, it also implements Tx aggregation
* manager, so this function should never be called in this case.
*/
if (WARN_ON_ONCE(fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_TLC_OFFLOAD)))
if (WARN_ON_ONCE(iwl_mvm_has_tlc_offload(mvm)))
return -EINVAL;
BUILD_BUG_ON((sizeof(mvmsta->agg_tids) * BITS_PER_BYTE)
......
......@@ -888,10 +888,9 @@ static void iwl_mvm_tx_add_stream(struct iwl_mvm *mvm,
/*
* The first deferred frame should've stopped the MAC queues, so we
* should never get a second deferred frame for the RA/TID.
* In case of GSO the first packet may have been split, so don't warn.
*/
if (!WARN(skb_queue_len(deferred_tx_frames) != 1,
"RATID %d/%d has %d deferred frames\n", mvm_sta->sta_id, tid,
skb_queue_len(deferred_tx_frames))) {
if (skb_queue_len(deferred_tx_frames) == 1) {
iwl_mvm_stop_mac_queues(mvm, BIT(mac_queue));
schedule_work(&mvm->add_stream_wk);
}
......@@ -1719,8 +1718,7 @@ static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,
ba_info->band = chanctx_conf->def.chan->band;
iwl_mvm_hwrate_to_tx_status(rate, ba_info);
if (!fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_TLC_OFFLOAD)) {
if (!iwl_mvm_has_tlc_offload(mvm)) {
IWL_DEBUG_TX_REPLY(mvm,
"No reclaim. Update rs directly\n");
iwl_mvm_rs_tx_status(mvm, sta, tid, ba_info, false);
......
......@@ -516,8 +516,7 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base)
IWL_ERR(trans, "HW error, resetting before reading\n");
/* reset the device */
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
usleep_range(5000, 6000);
iwl_trans_sw_reset(trans);
/* set INIT_DONE flag */
iwl_set_bit(trans, CSR_GP_CNTRL,
......@@ -913,8 +912,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init)
};
if (WARN_ON(lq->sta_id == IWL_MVM_INVALID_STA ||
fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_TLC_OFFLOAD)))
iwl_mvm_has_tlc_offload(mvm)))
return -EINVAL;
return iwl_mvm_send_cmd(mvm, &cmd);
......@@ -1033,12 +1031,34 @@ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int res;
bool low_latency;
lockdep_assert_held(&mvm->mutex);
if (iwl_mvm_vif_low_latency(mvmvif) == prev)
low_latency = iwl_mvm_vif_low_latency(mvmvif);
if (low_latency == prev)
return 0;
if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_DYNAMIC_QUOTA)) {
struct iwl_mac_low_latency_cmd cmd = {
.mac_id = cpu_to_le32(mvmvif->id)
};
if (low_latency) {
/* currently we don't care about the direction */
cmd.low_latency_rx = 1;
cmd.low_latency_tx = 1;
}
res = iwl_mvm_send_cmd_pdu(mvm,
iwl_cmd_id(LOW_LATENCY_CMD,
MAC_CONF_GROUP, 0),
0, sizeof(cmd), &cmd);
if (res)
IWL_ERR(mvm, "Failed to send low latency command\n");
}
res = iwl_mvm_update_quotas(mvm, false, NULL);
if (res)
return res;
......
......@@ -658,13 +658,6 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans)
}
}
static inline void iwl_pcie_sw_reset(struct iwl_trans *trans)
{
/* Reset entire device - do controller reset (results in SHRD_HW_RST) */
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
usleep_range(5000, 6000);
}
static inline u8 iwl_pcie_get_cmd_index(struct iwl_txq *q, u32 index)
{
return index & (q->n_window - 1);
......
......@@ -137,7 +137,7 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
/* Stop device's DMA activity */
iwl_pcie_apm_stop_master(trans);
iwl_pcie_sw_reset(trans);
iwl_trans_sw_reset(trans);
/*
* Clear "initialization complete" bit to move adapter from
......@@ -192,7 +192,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans, bool low_power)
/* Stop the device, and put it in low power state */
iwl_pcie_gen2_apm_stop(trans, false);
iwl_pcie_sw_reset(trans);
iwl_trans_sw_reset(trans);
/*
* Upon stop, the IVAR table gets erased, so msi-x won't
......
......@@ -176,6 +176,13 @@ static void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
kfree(buf);
}
static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans)
{
/* Reset entire device - do controller reset (results in SHRD_HW_RST) */
iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
usleep_range(5000, 6000);
}
static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
......@@ -446,7 +453,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
iwl_pcie_sw_reset(trans);
iwl_trans_pcie_sw_reset(trans);
/*
* Set "initialization complete" bit to move adapter from
......@@ -487,7 +494,7 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
apmg_xtal_cfg_reg |
SHR_APMG_XTAL_CFG_XTAL_ON_REQ);
iwl_pcie_sw_reset(trans);
iwl_trans_pcie_sw_reset(trans);
/* Enable LP XTAL by indirect access through CSR */
apmg_gp1_reg = iwl_trans_pcie_read_shr(trans, SHR_APMG_GP1_REG);
......@@ -580,7 +587,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
return;
}
iwl_pcie_sw_reset(trans);
iwl_trans_pcie_sw_reset(trans);
/*
* Clear "initialization complete" bit to move adapter from
......@@ -915,14 +922,9 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
void iwl_pcie_apply_destination(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
const struct iwl_fw_dbg_dest_tlv *dest = trans->dbg_dest_tlv;
const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg_dest_tlv;
int i;
if (dest->version)
IWL_ERR(trans,
"DBG DEST version is %d - expect issues\n",
dest->version);
IWL_INFO(trans, "Applying debug destination %s\n",
get_fw_dbg_mode_string(dest->monitor_mode));
......@@ -1270,7 +1272,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
/* Stop the device, and put it in low power state */
iwl_pcie_apm_stop(trans, false);
iwl_pcie_sw_reset(trans);
iwl_trans_pcie_sw_reset(trans);
/*
* Upon stop, the IVAR table gets erased, so msi-x won't
......@@ -1744,7 +1746,7 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
return err;
}
iwl_pcie_sw_reset(trans);
iwl_trans_pcie_sw_reset(trans);
err = iwl_pcie_apm_init(trans);
if (err)
......@@ -2816,8 +2818,17 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans,
* Update pointers to reflect actual values after
* shifting
*/
base = iwl_read_prph(trans, base) <<
trans->dbg_dest_tlv->base_shift;
if (trans->dbg_dest_tlv->version) {
base = (iwl_read_prph(trans, base) &
IWL_LDBG_M2S_BUF_BA_MSK) <<
trans->dbg_dest_tlv->base_shift;
base *= IWL_M2S_UNIT_SIZE;
base += trans->cfg->smem_offset;
} else {
base = iwl_read_prph(trans, base) <<
trans->dbg_dest_tlv->base_shift;
}
iwl_trans_read_mem(trans, base, fw_mon_data->data,
monitor_len / sizeof(u32));
} else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) {
......@@ -2865,21 +2876,36 @@ static struct iwl_trans_dump_data
trans_pcie->fw_mon_size;
monitor_len = trans_pcie->fw_mon_size;
} else if (trans->dbg_dest_tlv) {
u32 base, end;
u32 base, end, cfg_reg;
base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
end = le32_to_cpu(trans->dbg_dest_tlv->end_reg);
if (trans->dbg_dest_tlv->version == 1) {
cfg_reg = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
cfg_reg = iwl_read_prph(trans, cfg_reg);
base = (cfg_reg & IWL_LDBG_M2S_BUF_BA_MSK) <<
trans->dbg_dest_tlv->base_shift;
base *= IWL_M2S_UNIT_SIZE;
base += trans->cfg->smem_offset;
base = iwl_read_prph(trans, base) <<
trans->dbg_dest_tlv->base_shift;
end = iwl_read_prph(trans, end) <<
trans->dbg_dest_tlv->end_shift;
monitor_len =
(cfg_reg & IWL_LDBG_M2S_BUF_SIZE_MSK) >>
trans->dbg_dest_tlv->end_shift;
monitor_len *= IWL_M2S_UNIT_SIZE;
} else {
base = le32_to_cpu(trans->dbg_dest_tlv->base_reg);
end = le32_to_cpu(trans->dbg_dest_tlv->end_reg);
/* Make "end" point to the actual end */
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;
base = iwl_read_prph(trans, base) <<
trans->dbg_dest_tlv->base_shift;
end = iwl_read_prph(trans, end) <<
trans->dbg_dest_tlv->end_shift;
/* Make "end" point to the actual end */
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;
}
len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) +
monitor_len;
} else {
......@@ -3025,6 +3051,7 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans)
.write_mem = iwl_trans_pcie_write_mem, \
.configure = iwl_trans_pcie_configure, \
.set_pmi = iwl_trans_pcie_set_pmi, \
.sw_reset = iwl_trans_pcie_sw_reset, \
.grab_nic_access = iwl_trans_pcie_grab_nic_access, \
.release_nic_access = iwl_trans_pcie_release_nic_access, \
.set_bits_mask = iwl_trans_pcie_set_bits_mask, \
......
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