aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/fw
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/fw')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/config.h13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h401
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac.h41
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/rx.h239
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.c706
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.h80
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/error-dump.h20
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/img.h26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/runtime.h8
11 files changed, 1359 insertions, 187 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h
index 7f645b62804e..5e88fa2e6fb7 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h
@@ -8,6 +8,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
+ * Copyright (C) 2018 Intel Corporation
*
* 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
@@ -30,6 +31,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
+ * Copyright (C) 2018 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -127,17 +129,6 @@ struct iwl_phy_cfg_cmd {
struct iwl_calib_ctrl calib_control;
} __packed;
-#define PHY_CFG_RADIO_TYPE (BIT(0) | BIT(1))
-#define PHY_CFG_RADIO_STEP (BIT(2) | BIT(3))
-#define PHY_CFG_RADIO_DASH (BIT(4) | BIT(5))
-#define PHY_CFG_PRODUCT_NUMBER (BIT(6) | BIT(7))
-#define PHY_CFG_TX_CHAIN_A BIT(8)
-#define PHY_CFG_TX_CHAIN_B BIT(9)
-#define PHY_CFG_TX_CHAIN_C BIT(10)
-#define PHY_CFG_RX_CHAIN_A BIT(12)
-#define PHY_CFG_RX_CHAIN_B BIT(13)
-#define PHY_CFG_RX_CHAIN_C BIT(14)
-
/*
* enum iwl_dc2dc_config_id - flag ids
*
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
index eff3249af48a..fdc54a5dc9de 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
@@ -105,6 +105,11 @@ enum iwl_data_path_subcmd_ids {
HE_AIR_SNIFFER_CONFIG_CMD = 0x13,
/**
+ * @RX_NO_DATA_NOTIF: &struct iwl_rx_no_data
+ */
+ RX_NO_DATA_NOTIF = 0xF5,
+
+ /**
* @TLC_MNG_UPDATE_NOTIF: &struct iwl_tlc_update_notif
*/
TLC_MNG_UPDATE_NOTIF = 0xF7,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
new file mode 100644
index 000000000000..ab82b7a67967
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h
@@ -0,0 +1,401 @@
+/******************************************************************************
+ *
+ * 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) 2018 Intel Corporation
+ *
+ * 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) 2018 Intel Corporation
+ * 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_dbg_tlv_h__
+#define __iwl_fw_dbg_tlv_h__
+
+#include <linux/bitops.h>
+
+/*
+ * struct iwl_fw_ini_header: Common Header for all debug group TLV's structures
+ * @tlv_version: version info
+ * @apply_point: &enum iwl_fw_ini_apply_point
+ * @data: TLV data followed
+ **/
+struct iwl_fw_ini_header {
+ __le32 tlv_version;
+ __le32 apply_point;
+ u8 data[];
+} __packed; /* FW_INI_HEADER_TLV_S */
+
+/**
+ * struct iwl_fw_ini_allocation_tlv - (IWL_FW_INI_TLV_TYPE_BUFFER_ALLOCATION)
+ * buffer allocation TLV - for debug
+ *
+ * @iwl_fw_ini_header: header
+ * @allocation_id: &enum iwl_fw_ini_allocation_id - to bind allocation and hcmd
+ * if needed (DBGC1/DBGC2/SDFX/...)
+ * @buffer_location: type of iwl_fw_ini_buffer_location
+ * @size: size in bytes
+ * @max_fragments: the maximum allowed fragmentation in the desired memory
+ * allocation above
+ * @min_frag_size: the minimum allowed fragmentation size in bytes
+*/
+struct iwl_fw_ini_allocation_tlv {
+ struct iwl_fw_ini_header header;
+ __le32 allocation_id;
+ __le32 buffer_location;
+ __le32 size;
+ __le32 max_fragments;
+ __le32 min_frag_size;
+} __packed; /* FW_INI_BUFFER_ALLOCATION_TLV_S_VER_1 */
+
+/**
+ * struct iwl_fw_ini_hcmd (IWL_FW_INI_TLV_TYPE_HCMD)
+ * Generic Host command pass through TLV
+ *
+ * @id: the debug configuration command type for instance: 0xf6 / 0xf5 / DHC
+ * @group: the desired cmd group
+ * @padding: all zeros for dword alignment
+ * @data: all of the relevant command (0xf6/0xf5) to be sent
+*/
+struct iwl_fw_ini_hcmd {
+ u8 id;
+ u8 group;
+ __le16 padding;
+ u8 data[0];
+} __packed; /* FW_INI_HCMD_S */
+
+/**
+ * struct iwl_fw_ini_hcmd_tlv
+ * @header: header
+ * @hcmd: a variable length host-command to be sent to apply the configuration.
+ */
+struct iwl_fw_ini_hcmd_tlv {
+ struct iwl_fw_ini_header header;
+ struct iwl_fw_ini_hcmd hcmd;
+} __packed; /* FW_INI_HCMD_TLV_S_VER_1 */
+
+/*
+ * struct iwl_fw_ini_debug_flow_tlv (IWL_FW_INI_TLV_TYPE_DEBUG_FLOW)
+ *
+ * @header: header
+ * @debug_flow_cfg: &enum iwl_fw_ini_debug_flow
+ */
+struct iwl_fw_ini_debug_flow_tlv {
+ struct iwl_fw_ini_header header;
+ __le32 debug_flow_cfg;
+} __packed; /* FW_INI_DEBUG_FLOW_TLV_S_VER_1 */
+
+#define IWL_FW_INI_MAX_REGION_ID 20
+#define IWL_FW_INI_MAX_NAME 32
+/**
+ * struct iwl_fw_ini_region_cfg
+ * @region_id: ID of this dump configuration
+ * @region_type: &enum iwl_fw_ini_region_type
+ * @num_regions: amount of regions in the address array.
+ * @allocation_id: For DRAM type field substitutes for allocation_id.
+ * @name_len: name length
+ * @name: file name to use for this region
+ * @size: size of the data, in bytes.(unused for IWL_FW_INI_REGION_DRAM_BUFFER)
+ * @start_addr: array of addresses. (unused for IWL_FW_INI_REGION_DRAM_BUFFER)
+ */
+struct iwl_fw_ini_region_cfg {
+ __le32 region_id;
+ __le32 region_type;
+ __le32 name_len;
+ u8 name[IWL_FW_INI_MAX_NAME];
+ union {
+ __le32 num_regions;
+ __le32 allocation_id;
+ };
+ __le32 size;
+ __le32 start_addr[];
+} __packed; /* FW_INI_REGION_CONFIG_S */
+
+/**
+ * struct iwl_fw_ini_region_tlv - (IWL_FW_INI_TLV_TYPE_REGION_CFG)
+ * DUMP sections define IDs and triggers that use those IDs TLV
+ * @header: header
+ * @num_regions: how many different region section and IDs are coming next
+ * @iwl_fw_ini_dump dump_config: list of dump configurations
+ */
+struct iwl_fw_ini_region_tlv {
+ struct iwl_fw_ini_header header;
+ __le32 num_regions;
+ struct iwl_fw_ini_region_cfg region_config[];
+} __packed; /* FW_INI_REGION_CFG_S */
+
+/**
+ * struct iwl_fw_ini_trigger - (IWL_FW_INI_TLV_TYPE_DUMP_CFG)
+ * Region sections define IDs and triggers that use those IDs TLV
+ *
+ * @trigger_id: enum &iwl_fw_ini_tigger_id
+ * @ignore_default: override FW TLV with binary TLV
+ * @dump_delay: delay from trigger fire to dump, in usec
+ * @occurrences: max amount of times to be fired
+ * @ignore_consec: ignore consecutive triggers, in usec
+ * @force_restart: force FW restart
+ * @multi_dut: initiate debug dump data on several DUTs
+ * @trigger_data: generic data to be utilized per trigger
+ * @num_regions: number of dump regions defined for this trigger
+ * @data: region IDs
+ */
+struct iwl_fw_ini_trigger {
+ __le32 trigger_id;
+ __le32 ignore_default;
+ __le32 dump_delay;
+ __le32 occurrences;
+ __le32 ignore_consec;
+ __le32 force_restart;
+ __le32 multi_dut;
+ __le32 trigger_data;
+ __le32 num_regions;
+ __le32 data[];
+} __packed; /* FW_INI_TRIGGER_CONFIG_S */
+
+/**
+ * struct iwl_fw_ini_trigger_tlv - (IWL_FW_INI_TLV_TYPE_TRIGGERS_CFG)
+ * DUMP sections define IDs and triggers that use those IDs TLV
+ *
+ * @header: header
+ * @num_triggers: how many different triggers section and IDs are coming next
+ * @trigger_config: list of trigger configurations
+ */
+struct iwl_fw_ini_trigger_tlv {
+ struct iwl_fw_ini_header header;
+ __le32 num_triggers;
+ struct iwl_fw_ini_trigger trigger_config[];
+} __packed; /* FW_INI_TRIGGER_CFG_S */
+
+/**
+ * enum iwl_fw_ini_trigger_id
+ * @IWL_FW_TRIGGER_ID_FW_ASSERT: FW assert
+ * @IWL_FW_TRIGGER_ID_FW_TFD_Q_HANG: TFD queue hang
+ * @IWL_FW_TRIGGER_ID_FW_HW_ERROR: HW assert
+ * @IWL_FW_TRIGGER_ID_FW_TRIGGER_ERROR: FW error notification
+ * @IWL_FW_TRIGGER_ID_FW_TRIGGER_WARNING: FW warning notification
+ * @IWL_FW_TRIGGER_ID_FW_TRIGGER_INFO: FW info notification
+ * @IWL_FW_TRIGGER_ID_FW_TRIGGER_DEBUG: FW debug notification
+ * @IWL_FW_TRIGGER_ID_USER_TRIGGER: User trigger
+ * @IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_INACTIVITY: peer inactivity
+ * @FW_DEBUG_TLV_TRIGGER_ID_HOST_DID_INITIATED_EVENT: undefined
+ * @IWL_FW_TRIGGER_ID_HOST_TX_LATENCY_THRESHOLD_CROSSED: TX latency
+ * threshold was crossed
+ * @IWL_FW_TRIGGER_ID_HOST_TX_RESPONSE_STATUS_FAILED: TX failed
+ * @IWL_FW_TRIGGER_ID_HOST_OS_REQ_DEAUTH_PEER: Deauth initiated by host
+ * @IWL_FW_TRIGGER_ID_HOST_STOP_GO_REQUEST: stop GO request
+ * @IWL_FW_TRIGGER_ID_HOST_START_GO_REQUEST: start GO request
+ * @IWL_FW_TRIGGER_ID_HOST_JOIN_GROUP_REQUEST: join P2P group request
+ * @IWL_FW_TRIGGER_ID_HOST_SCAN_START: scan started event
+ * @IWL_FW_TRIGGER_ID_HOST_SCAN_SUBMITTED: undefined
+ * @IWL_FW_TRIGGER_ID_HOST_SCAN_PARAMS: undefined
+ * @IWL_FW_TRIGGER_ID_HOST_CHECK_FOR_HANG: undefined
+ * @IWL_FW_TRIGGER_ID_HOST_BAR_RECEIVED: BAR frame was received
+ * @IWL_FW_TRIGGER_ID_HOST_AGG_TX_RESPONSE_STATUS_FAILED: agg TX failed
+ * @IWL_FW_TRIGGER_ID_HOST_EAPOL_TX_RESPONSE_FAILED: EAPOL TX failed
+ * @IWL_FW_TRIGGER_ID_HOST_FAKE_TX_RESPONSE_SUSPECTED: suspicious TX response
+ * @IWL_FW_TRIGGER_ID_HOST_AUTH_REQ_FROM_ASSOC_CLIENT: received suspicious auth
+ * @IWL_FW_TRIGGER_ID_HOST_ROAM_COMPLETE: roaming was completed
+ * @IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAST_FAILED: fast assoc failed
+ * @IWL_FW_TRIGGER_ID_HOST_D3_START: D3 start
+ * @IWL_FW_TRIGGER_ID_HOST_D3_END: D3 end
+ * @IWL_FW_TRIGGER_ID_HOST_BSS_MISSED_BEACONS: missed beacon events
+ * @IWL_FW_TRIGGER_ID_HOST_P2P_CLIENT_MISSED_BEACONS: P2P missed beacon events
+ * @IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_TX_FAILURES: undefined
+ * @IWL_FW_TRIGGER_ID_HOST_TX_WFD_ACTION_FRAME_FAILED: undefined
+ * @IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAILED: authentication / association
+ * failed
+ * @IWL_FW_TRIGGER_ID_HOST_SCAN_COMPLETE: scan complete event
+ * @IWL_FW_TRIGGER_ID_HOST_SCAN_ABORT: scan abort complete
+ * @IWL_FW_TRIGGER_ID_HOST_NIC_ALIVE: nic alive message was received
+ * @IWL_FW_TRIGGER_ID_HOST_CHANNEL_SWITCH_COMPLETE: CSA was completed
+ * @IWL_FW_TRIGGER_ID_NUM: number of trigger IDs
+ */
+enum iwl_fw_ini_trigger_id {
+ /* Errors triggers */
+ IWL_FW_TRIGGER_ID_FW_ASSERT = 1,
+ IWL_FW_TRIGGER_ID_FW_TFD_Q_HANG = 2,
+ IWL_FW_TRIGGER_ID_FW_HW_ERROR = 3,
+ /* Generic triggers */
+ IWL_FW_TRIGGER_ID_FW_TRIGGER_ERROR = 4,
+ IWL_FW_TRIGGER_ID_FW_TRIGGER_WARNING = 5,
+ IWL_FW_TRIGGER_ID_FW_TRIGGER_INFO = 6,
+ IWL_FW_TRIGGER_ID_FW_TRIGGER_DEBUG = 7,
+ /* User Trigger */
+ IWL_FW_TRIGGER_ID_USER_TRIGGER = 8,
+ /* Host triggers */
+ IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_INACTIVITY = 9,
+ IWL_FW_TRIGGER_ID_HOST_DID_INITIATED_EVENT = 10,
+ IWL_FW_TRIGGER_ID_HOST_TX_LATENCY_THRESHOLD_CROSSED = 11,
+ IWL_FW_TRIGGER_ID_HOST_TX_RESPONSE_STATUS_FAILED = 12,
+ IWL_FW_TRIGGER_ID_HOST_OS_REQ_DEAUTH_PEER = 13,
+ IWL_FW_TRIGGER_ID_HOST_STOP_GO_REQUEST = 14,
+ IWL_FW_TRIGGER_ID_HOST_START_GO_REQUEST = 15,
+ IWL_FW_TRIGGER_ID_HOST_JOIN_GROUP_REQUEST = 16,
+ IWL_FW_TRIGGER_ID_HOST_SCAN_START = 17,
+ IWL_FW_TRIGGER_ID_HOST_SCAN_SUBITTED = 18,
+ IWL_FW_TRIGGER_ID_HOST_SCAN_PARAMS = 19,
+ IWL_FW_TRIGGER_ID_HOST_CHECK_FOR_HANG = 20,
+ IWL_FW_TRIGGER_ID_HOST_BAR_RECEIVED = 21,
+ IWL_FW_TRIGGER_ID_HOST_AGG_TX_RESPONSE_STATUS_FAILED = 22,
+ IWL_FW_TRIGGER_ID_HOST_EAPOL_TX_RESPONSE_FAILED = 23,
+ IWL_FW_TRIGGER_ID_HOST_FAKE_TX_RESPONSE_SUSPECTED = 24,
+ IWL_FW_TRIGGER_ID_HOST_AUTH_REQ_FROM_ASSOC_CLIENT = 25,
+ IWL_FW_TRIGGER_ID_HOST_ROAM_COMPLETE = 26,
+ IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAST_FAILED = 27,
+ IWL_FW_TRIGGER_ID_HOST_D3_START = 28,
+ IWL_FW_TRIGGER_ID_HOST_D3_END = 29,
+ IWL_FW_TRIGGER_ID_HOST_BSS_MISSED_BEACONS = 30,
+ IWL_FW_TRIGGER_ID_HOST_P2P_CLIENT_MISSED_BEACONS = 31,
+ IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_TX_FAILURES = 32,
+ IWL_FW_TRIGGER_ID_HOST_TX_WFD_ACTION_FRAME_FAILED = 33,
+ IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAILED = 34,
+ IWL_FW_TRIGGER_ID_HOST_SCAN_COMPLETE = 35,
+ IWL_FW_TRIGGER_ID_HOST_SCAN_ABORT = 36,
+ IWL_FW_TRIGGER_ID_HOST_NIC_ALIVE = 37,
+ IWL_FW_TRIGGER_ID_HOST_CHANNEL_SWITCH_COMPLETE = 38,
+ IWL_FW_TRIGGER_ID_NUM,
+}; /* FW_INI_TRIGGER_ID_E_VER_1 */
+
+/**
+ * enum iwl_fw_ini_apply_point
+ * @IWL_FW_INI_APPLY_INVALID: invalid
+ * @IWL_FW_INI_APPLY_EARLY: pre loading FW
+ * @IWL_FW_INI_APPLY_AFTER_ALIVE: first cmd from host after alive
+ * @IWL_FW_INI_APPLY_POST_INIT: last cmd in initialization sequence
+ * @IWL_FW_INI_APPLY_MISSED_BEACONS: missed beacons notification
+ * @IWL_FW_INI_APPLY_SCAN_COMPLETE: scan completed
+ * @IWL_FW_INI_APPLY_NUM: number of apply points
+*/
+enum iwl_fw_ini_apply_point {
+ IWL_FW_INI_APPLY_INVALID,
+ IWL_FW_INI_APPLY_EARLY,
+ IWL_FW_INI_APPLY_AFTER_ALIVE,
+ IWL_FW_INI_APPLY_POST_INIT,
+ IWL_FW_INI_APPLY_MISSED_BEACONS,
+ IWL_FW_INI_APPLY_SCAN_COMPLETE,
+ IWL_FW_INI_APPLY_NUM,
+}; /* FW_INI_APPLY_POINT_E_VER_1 */
+
+/**
+ * enum iwl_fw_ini_allocation_id
+ * @IWL_FW_INI_ALLOCATION_INVALID: invalid
+ * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration
+ * @IWL_FW_INI_ALLOCATION_ID_DBGC2: allocation meant for DBGC2 configuration
+ * @IWL_FW_INI_ALLOCATION_ID_DBGC3: allocation meant for DBGC3 configuration
+ * @IWL_FW_INI_ALLOCATION_ID_SDFX: for SDFX module
+ * @IWL_FW_INI_ALLOCATION_ID_FW_DUMP: used for crash and runtime dumps
+ * @IWL_FW_INI_ALLOCATION_ID_USER_DEFINED: for future user scenarios
+*/
+enum iwl_fw_ini_allocation_id {
+ IWL_FW_INI_ALLOCATION_INVALID,
+ IWL_FW_INI_ALLOCATION_ID_DBGC1,
+ IWL_FW_INI_ALLOCATION_ID_DBGC2,
+ IWL_FW_INI_ALLOCATION_ID_DBGC3,
+ IWL_FW_INI_ALLOCATION_ID_SDFX,
+ IWL_FW_INI_ALLOCATION_ID_FW_DUMP,
+ IWL_FW_INI_ALLOCATION_ID_USER_DEFINED,
+}; /* FW_INI_ALLOCATION_ID_E_VER_1 */
+
+/**
+ * enum iwl_fw_ini_buffer_location
+ * @IWL_FW_INI_LOCATION_INVALID: invalid
+ * @IWL_FW_INI_LOCATION_SRAM_PATH: SRAM location
+ * @IWL_FW_INI_LOCATION_DRAM_PATH: DRAM location
+ */
+enum iwl_fw_ini_buffer_location {
+ IWL_FW_INI_LOCATION_SRAM_INVALID,
+ IWL_FW_INI_LOCATION_SRAM_PATH,
+ IWL_FW_INI_LOCATION_DRAM_PATH,
+}; /* FW_INI_BUFFER_LOCATION_E_VER_1 */
+
+/**
+ * enum iwl_fw_ini_debug_flow
+ * @IWL_FW_INI_DEBUG_INVALID: invalid
+ * @IWL_FW_INI_DEBUG_DBTR_FLOW: undefined
+ * @IWL_FW_INI_DEBUG_TB2DTF_FLOW: undefined
+ */
+enum iwl_fw_ini_debug_flow {
+ IWL_FW_INI_DEBUG_INVALID,
+ IWL_FW_INI_DEBUG_DBTR_FLOW,
+ IWL_FW_INI_DEBUG_TB2DTF_FLOW,
+}; /* FW_INI_DEBUG_FLOW_E_VER_1 */
+
+/**
+ * enum iwl_fw_ini_region_type
+ * @IWL_FW_INI_REGION_INVALID: invalid
+ * @IWL_FW_INI_REGION_DEVICE_MEMORY: device internal memory
+ * @IWL_FW_INI_REGION_PERIPHERY_MAC: periphery registers of MAC
+ * @IWL_FW_INI_REGION_PERIPHERY_PHY: periphery registers of PHY
+ * @IWL_FW_INI_REGION_PERIPHERY_AUX: periphery registers of AUX
+ * @IWL_FW_INI_REGION_DRAM_BUFFER: DRAM buffer
+ * @IWL_FW_INI_REGION_DRAM_IMR: IMR memory
+ * @IWL_FW_INI_REGION_INTERNAL_BUFFER: undefined
+ * @IWL_FW_INI_REGION_TXF: TX fifos
+ * @IWL_FW_INI_REGION_RXF: RX fifo
+ * @IWL_FW_INI_REGION_PAGING: paging memory
+ * @IWL_FW_INI_REGION_CSR: CSR registers
+ * @IWL_FW_INI_REGION_NUM: number of region types
+ */
+enum iwl_fw_ini_region_type {
+ IWL_FW_INI_REGION_INVALID,
+ IWL_FW_INI_REGION_DEVICE_MEMORY,
+ IWL_FW_INI_REGION_PERIPHERY_MAC,
+ IWL_FW_INI_REGION_PERIPHERY_PHY,
+ IWL_FW_INI_REGION_PERIPHERY_AUX,
+ IWL_FW_INI_REGION_DRAM_BUFFER,
+ IWL_FW_INI_REGION_DRAM_IMR,
+ IWL_FW_INI_REGION_INTERNAL_BUFFER,
+ IWL_FW_INI_REGION_TXF,
+ IWL_FW_INI_REGION_RXF,
+ IWL_FW_INI_REGION_PAGING,
+ IWL_FW_INI_REGION_CSR,
+ IWL_FW_INI_REGION_NUM
+}; /* FW_INI_REGION_TYPE_E_VER_1*/
+
+#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
index 1dd23f846fb9..7a3f7b7e6358 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h
@@ -151,9 +151,9 @@ enum iwl_tsf_id {
* @beacon_time: beacon transmit time in system time
* @beacon_tsf: beacon transmit time in TSF
* @bi: beacon interval in TU
- * @bi_reciprocal: 2^32 / bi
+ * @reserved1: reserved
* @dtim_interval: dtim transmit time in TU
- * @dtim_reciprocal: 2^32 / dtim_interval
+ * @reserved2: reserved
* @mcast_qid: queue ID for multicast traffic.
* NOTE: obsolete from VER2 and on
* @beacon_template: beacon template ID
@@ -162,9 +162,9 @@ struct iwl_mac_data_ap {
__le32 beacon_time;
__le64 beacon_tsf;
__le32 bi;
- __le32 bi_reciprocal;
+ __le32 reserved1;
__le32 dtim_interval;
- __le32 dtim_reciprocal;
+ __le32 reserved2;
__le32 mcast_qid;
__le32 beacon_template;
} __packed; /* AP_MAC_DATA_API_S_VER_2 */
@@ -174,26 +174,34 @@ struct iwl_mac_data_ap {
* @beacon_time: beacon transmit time in system time
* @beacon_tsf: beacon transmit time in TSF
* @bi: beacon interval in TU
- * @bi_reciprocal: 2^32 / bi
+ * @reserved: reserved
* @beacon_template: beacon template ID
*/
struct iwl_mac_data_ibss {
__le32 beacon_time;
__le64 beacon_tsf;
__le32 bi;
- __le32 bi_reciprocal;
+ __le32 reserved;
__le32 beacon_template;
} __packed; /* IBSS_MAC_DATA_API_S_VER_1 */
/**
+ * enum iwl_mac_data_policy - policy of the data path for this MAC
+ * @TWT_SUPPORTED: twt is supported
+ */
+enum iwl_mac_data_policy {
+ TWT_SUPPORTED = BIT(0),
+};
+
+/**
* struct iwl_mac_data_sta - configuration data for station MAC context
* @is_assoc: 1 for associated state, 0 otherwise
* @dtim_time: DTIM arrival time in system time
* @dtim_tsf: DTIM arrival time in TSF
* @bi: beacon interval in TU, applicable only when associated
- * @bi_reciprocal: 2^32 / bi , applicable only when associated
+ * @reserved1: reserved
* @dtim_interval: DTIM interval in TU, applicable only when associated
- * @dtim_reciprocal: 2^32 / dtim_interval , applicable only when associated
+ * @data_policy: see &enum iwl_mac_data_policy
* @listen_interval: in beacon intervals, applicable only when associated
* @assoc_id: unique ID assigned by the AP during association
* @assoc_beacon_arrive_time: TSF of first beacon after association
@@ -203,13 +211,13 @@ struct iwl_mac_data_sta {
__le32 dtim_time;
__le64 dtim_tsf;
__le32 bi;
- __le32 bi_reciprocal;
+ __le32 reserved1;
__le32 dtim_interval;
- __le32 dtim_reciprocal;
+ __le32 data_policy;
__le32 listen_interval;
__le32 assoc_id;
__le32 assoc_beacon_arrive_time;
-} __packed; /* STA_MAC_DATA_API_S_VER_1 */
+} __packed; /* STA_MAC_DATA_API_S_VER_2 */
/**
* struct iwl_mac_data_go - configuration data for P2P GO MAC context
@@ -233,7 +241,7 @@ struct iwl_mac_data_go {
struct iwl_mac_data_p2p_sta {
struct iwl_mac_data_sta sta;
__le32 ctwin;
-} __packed; /* P2P_STA_MAC_DATA_API_S_VER_1 */
+} __packed; /* P2P_STA_MAC_DATA_API_S_VER_2 */
/**
* struct iwl_mac_data_pibss - Pseudo IBSS config data
@@ -378,13 +386,6 @@ struct iwl_mac_ctx_cmd {
};
} __packed; /* MAC_CONTEXT_CMD_API_S_VER_1 */
-static inline u32 iwl_mvm_reciprocal(u32 v)
-{
- if (!v)
- return 0;
- return 0xFFFFFFFF / v;
-}
-
#define IWL_NONQOS_SEQ_GET 0x1
#define IWL_NONQOS_SEQ_SET 0x2
struct iwl_nonqos_seq_query_cmd {
@@ -442,7 +443,7 @@ struct iwl_he_backoff_conf {
* Support for Nss x BW (or RU) matrix:
* (0=SISO, 1=MIMO2) x (0-20MHz, 1-40MHz, 2-80MHz, 3-160MHz)
* Each entry contains 2 QAM thresholds for 8us and 16us:
- * 0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6/7=RES
+ * 0=BPSK, 1=QPSK, 2=16QAM, 3=64QAM, 4=256QAM, 5=1024QAM, 6=RES, 7=NONE
* i.e. QAM_th1 < QAM_th2 such if TX uses QAM_tx:
* QAM_tx < QAM_th1 --> PPE=0us
* QAM_th1 <= QAM_tx < QAM_th2 --> PPE=8us
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
index 0537496b6eb1..0791a854fc8f 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
@@ -345,66 +345,98 @@ enum iwl_rx_mpdu_mac_info {
IWL_RX_MPDU_PHY_PHY_INDEX_MASK = 0xf0,
};
-/*
- * enum iwl_rx_he_phy - HE PHY data
- */
-enum iwl_rx_he_phy {
- IWL_RX_HE_PHY_BEAM_CHNG = BIT(0),
- IWL_RX_HE_PHY_UPLINK = BIT(1),
- IWL_RX_HE_PHY_BSS_COLOR_MASK = 0xfc,
- IWL_RX_HE_PHY_SPATIAL_REUSE_MASK = 0xf00,
- IWL_RX_HE_PHY_SU_EXT_BW10 = BIT(12),
- IWL_RX_HE_PHY_TXOP_DUR_MASK = 0xfe000,
- IWL_RX_HE_PHY_LDPC_EXT_SYM = BIT(20),
- IWL_RX_HE_PHY_PRE_FEC_PAD_MASK = 0x600000,
- IWL_RX_HE_PHY_PE_DISAMBIG = BIT(23),
- IWL_RX_HE_PHY_DOPPLER = BIT(24),
+/* TSF overload low dword */
+enum iwl_rx_phy_data0 {
+ /* info type: HE any */
+ IWL_RX_PHY_DATA0_HE_BEAM_CHNG = 0x00000001,
+ IWL_RX_PHY_DATA0_HE_UPLINK = 0x00000002,
+ IWL_RX_PHY_DATA0_HE_BSS_COLOR_MASK = 0x000000fc,
+ IWL_RX_PHY_DATA0_HE_SPATIAL_REUSE_MASK = 0x00000f00,
+ /* 1 bit reserved */
+ IWL_RX_PHY_DATA0_HE_TXOP_DUR_MASK = 0x000fe000,
+ IWL_RX_PHY_DATA0_HE_LDPC_EXT_SYM = 0x00100000,
+ IWL_RX_PHY_DATA0_HE_PRE_FEC_PAD_MASK = 0x00600000,
+ IWL_RX_PHY_DATA0_HE_PE_DISAMBIG = 0x00800000,
+ IWL_RX_PHY_DATA0_HE_DOPPLER = 0x01000000,
/* 6 bits reserved */
- IWL_RX_HE_PHY_DELIM_EOF = BIT(31),
+ IWL_RX_PHY_DATA0_HE_DELIM_EOF = 0x80000000,
+};
+
+enum iwl_rx_phy_info_type {
+ IWL_RX_PHY_INFO_TYPE_NONE = 0,
+ IWL_RX_PHY_INFO_TYPE_CCK = 1,
+ IWL_RX_PHY_INFO_TYPE_OFDM_LGCY = 2,
+ IWL_RX_PHY_INFO_TYPE_HT = 3,
+ IWL_RX_PHY_INFO_TYPE_VHT_SU = 4,
+ IWL_RX_PHY_INFO_TYPE_VHT_MU = 5,
+ IWL_RX_PHY_INFO_TYPE_HE_SU = 6,
+ IWL_RX_PHY_INFO_TYPE_HE_MU = 7,
+ IWL_RX_PHY_INFO_TYPE_HE_TB = 8,
+ IWL_RX_PHY_INFO_TYPE_HE_MU_EXT = 9,
+ IWL_RX_PHY_INFO_TYPE_HE_TB_EXT = 10,
+};
- /* second dword - common data */
- IWL_RX_HE_PHY_HE_LTF_NUM_MASK = 0xe000000000ULL,
- IWL_RX_HE_PHY_RU_ALLOC_SEC80 = BIT_ULL(32 + 8),
+/* TSF overload high dword */
+enum iwl_rx_phy_data1 {
+ /*
+ * check this first - if TSF overload is set,
+ * see &enum iwl_rx_phy_info_type
+ */
+ IWL_RX_PHY_DATA1_INFO_TYPE_MASK = 0xf0000000,
+
+ /* info type: HT/VHT/HE any */
+ IWL_RX_PHY_DATA1_LSIG_LEN_MASK = 0x0fff0000,
+
+ /* info type: HE MU/MU-EXT */
+ IWL_RX_PHY_DATA1_HE_MU_SIGB_COMPRESSION = 0x00000001,
+ IWL_RX_PHY_DATA1_HE_MU_SIBG_SYM_OR_USER_NUM_MASK = 0x0000001e,
+
+ /* info type: HE any */
+ IWL_RX_PHY_DATA1_HE_LTF_NUM_MASK = 0x000000e0,
+ IWL_RX_PHY_DATA1_HE_RU_ALLOC_SEC80 = 0x00000100,
/* trigger encoded */
- IWL_RX_HE_PHY_RU_ALLOC_MASK = 0xfe0000000000ULL,
- IWL_RX_HE_PHY_INFO_TYPE_MASK = 0xf000000000000000ULL,
- IWL_RX_HE_PHY_INFO_TYPE_SU = 0x0, /* TSF low valid (first DW) */
- IWL_RX_HE_PHY_INFO_TYPE_MU = 0x1, /* TSF low/high valid (both DWs) */
- IWL_RX_HE_PHY_INFO_TYPE_MU_EXT_INFO = 0x2, /* same + SIGB-common0/1/2 valid */
- IWL_RX_HE_PHY_INFO_TYPE_TB = 0x3, /* TSF low/high valid (both DWs) */
-
- /* second dword - MU data */
- IWL_RX_HE_PHY_MU_SIGB_COMPRESSION = BIT_ULL(32 + 0),
- IWL_RX_HE_PHY_MU_SIBG_SYM_OR_USER_NUM_MASK = 0x1e00000000ULL,
- IWL_RX_HE_PHY_MU_SIGB_MCS_MASK = 0xf000000000000ULL,
- IWL_RX_HE_PHY_MU_SIGB_DCM = BIT_ULL(32 + 21),
- IWL_RX_HE_PHY_MU_PREAMBLE_PUNC_TYPE_MASK = 0xc0000000000000ULL,
-
- /* second dword - TB data */
- IWL_RX_HE_PHY_TB_PILOT_TYPE = BIT_ULL(32 + 0),
- IWL_RX_HE_PHY_TB_LOW_SS_MASK = 0xe00000000ULL
+ IWL_RX_PHY_DATA1_HE_RU_ALLOC_MASK = 0x0000fe00,
+
+ /* info type: HE TB/TX-EXT */
+ IWL_RX_PHY_DATA1_HE_TB_PILOT_TYPE = 0x00000001,
+ IWL_RX_PHY_DATA1_HE_TB_LOW_SS_MASK = 0x0000000e,
};
-enum iwl_rx_he_sigb_common0 {
+/* goes into Metadata DW 7 */
+enum iwl_rx_phy_data2 {
+ /* info type: HE MU-EXT */
/* the a1/a2/... is what the PHY/firmware calls the values */
- IWL_RX_HE_SIGB_COMMON0_CH1_RU0 = 0x000000ff, /* a1 */
- IWL_RX_HE_SIGB_COMMON0_CH1_RU2 = 0x0000ff00, /* a2 */
- IWL_RX_HE_SIGB_COMMON0_CH2_RU0 = 0x00ff0000, /* b1 */
- IWL_RX_HE_SIGB_COMMON0_CH2_RU2 = 0xff000000, /* b2 */
+ IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU0 = 0x000000ff, /* a1 */
+ IWL_RX_PHY_DATA2_HE_MU_EXT_CH1_RU2 = 0x0000ff00, /* a2 */
+ IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU0 = 0x00ff0000, /* b1 */
+ IWL_RX_PHY_DATA2_HE_MU_EXT_CH2_RU2 = 0xff000000, /* b2 */
+
+ /* info type: HE TB-EXT */
+ IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE1 = 0x0000000f,
+ IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE2 = 0x000000f0,
+ IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE3 = 0x00000f00,
+ IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE4 = 0x0000f000,
};
-enum iwl_rx_he_sigb_common1 {
- IWL_RX_HE_SIGB_COMMON1_CH1_RU1 = 0x000000ff, /* c1 */
- IWL_RX_HE_SIGB_COMMON1_CH1_RU3 = 0x0000ff00, /* c2 */
- IWL_RX_HE_SIGB_COMMON1_CH2_RU1 = 0x00ff0000, /* d1 */
- IWL_RX_HE_SIGB_COMMON1_CH2_RU3 = 0xff000000, /* d2 */
+/* goes into Metadata DW 8 */
+enum iwl_rx_phy_data3 {
+ /* info type: HE MU-EXT */
+ IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU1 = 0x000000ff, /* c1 */
+ IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU3 = 0x0000ff00, /* c2 */
+ IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU1 = 0x00ff0000, /* d1 */
+ IWL_RX_PHY_DATA3_HE_MU_EXT_CH2_RU3 = 0xff000000, /* d2 */
};
-enum iwl_rx_he_sigb_common2 {
- IWL_RX_HE_SIGB_COMMON2_CH1_CTR_RU = 0x0001,
- IWL_RX_HE_SIGB_COMMON2_CH2_CTR_RU = 0x0002,
- IWL_RX_HE_SIGB_COMMON2_CH1_CRC_OK = 0x0004,
- IWL_RX_HE_SIGB_COMMON2_CH2_CRC_OK = 0x0008,
+/* goes into Metadata DW 4 high 16 bits */
+enum iwl_rx_phy_data4 {
+ /* info type: HE MU-EXT */
+ IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CTR_RU = 0x0001,
+ IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CTR_RU = 0x0002,
+ IWL_RX_PHY_DATA4_HE_MU_EXT_CH1_CRC_OK = 0x0004,
+ IWL_RX_PHY_DATA4_HE_MU_EXT_CH2_CRC_OK = 0x0008,
+ IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_MCS_MASK = 0x00f0,
+ IWL_RX_PHY_DATA4_HE_MU_EXT_SIGB_DCM = 0x0100,
+ IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK = 0x0600,
};
/**
@@ -419,9 +451,9 @@ struct iwl_rx_mpdu_desc_v1 {
__le32 rss_hash;
/**
- * @sigb_common0: for HE sniffer, HE-SIG-B common part 0
+ * @phy_data2: depends on info type (see @phy_data1)
*/
- __le32 sigb_common0;
+ __le32 phy_data2;
};
/* DW8 - carries filter_match only when rpa_en == 1 */
@@ -432,9 +464,9 @@ struct iwl_rx_mpdu_desc_v1 {
__le32 filter_match;
/**
- * @sigb_common1: for HE sniffer, HE-SIG-B common part 1
+ * @phy_data3: depends on info type (see @phy_data1)
*/
- __le32 sigb_common1;
+ __le32 phy_data3;
};
/* DW9 */
@@ -472,12 +504,19 @@ struct iwl_rx_mpdu_desc_v1 {
* %IWL_RX_MPDU_PHY_TSF_OVERLOAD isn't set
*/
__le64 tsf_on_air_rise;
- /**
- * @he_phy_data:
- * HE PHY data, see &enum iwl_rx_he_phy, valid
- * only if %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set
- */
- __le64 he_phy_data;
+
+ struct {
+ /**
+ * @phy_data0: depends on info_type, see @phy_data1
+ */
+ __le32 phy_data0;
+ /**
+ * @phy_data1: valid only if
+ * %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set,
+ * see &enum iwl_rx_phy_data1.
+ */
+ __le32 phy_data1;
+ };
};
} __packed;
@@ -493,9 +532,9 @@ struct iwl_rx_mpdu_desc_v3 {
__le32 filter_match;
/**
- * @sigb_common0: for HE sniffer, HE-SIG-B common part 0
+ * @phy_data2: depends on info type (see @phy_data1)
*/
- __le32 sigb_common0;
+ __le32 phy_data2;
};
/* DW8 - carries rss_hash only when rpa_en == 1 */
@@ -506,9 +545,9 @@ struct iwl_rx_mpdu_desc_v3 {
__le32 rss_hash;
/**
- * @sigb_common1: for HE sniffer, HE-SIG-B common part 1
+ * @phy_data3: depends on info type (see @phy_data1)
*/
- __le32 sigb_common1;
+ __le32 phy_data3;
};
/* DW9 */
/**
@@ -556,12 +595,19 @@ struct iwl_rx_mpdu_desc_v3 {
* %IWL_RX_MPDU_PHY_TSF_OVERLOAD isn't set
*/
__le64 tsf_on_air_rise;
- /**
- * @he_phy_data:
- * HE PHY data, see &enum iwl_rx_he_phy, valid
- * only if %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set
- */
- __le64 he_phy_data;
+
+ struct {
+ /**
+ * @phy_data0: depends on info_type, see @phy_data1
+ */
+ __le32 phy_data0;
+ /**
+ * @phy_data1: valid only if
+ * %IWL_RX_MPDU_PHY_TSF_OVERLOAD is set,
+ * see &enum iwl_rx_phy_data1.
+ */
+ __le32 phy_data1;
+ };
};
/* DW16 & DW17 */
/**
@@ -613,9 +659,9 @@ struct iwl_rx_mpdu_desc {
__le16 l3l4_flags;
/**
- * @sigb_common2: for HE sniffer, HE-SIG-B common part 2
+ * @phy_data4: depends on info type, see phy_data1
*/
- __le16 sigb_common2;
+ __le16 phy_data4;
};
/* DW5 */
/**
@@ -651,6 +697,55 @@ struct iwl_rx_mpdu_desc {
#define IWL_CD_STTS_WIFI_STATUS_POS 4
#define IWL_CD_STTS_WIFI_STATUS_MSK 0xF0
+#define RX_NO_DATA_CHAIN_A_POS 0
+#define RX_NO_DATA_CHAIN_A_MSK (0xff << RX_NO_DATA_CHAIN_A_POS)
+#define RX_NO_DATA_CHAIN_B_POS 8
+#define RX_NO_DATA_CHAIN_B_MSK (0xff << RX_NO_DATA_CHAIN_B_POS)
+#define RX_NO_DATA_CHANNEL_POS 16
+#define RX_NO_DATA_CHANNEL_MSK (0xff << RX_NO_DATA_CHANNEL_POS)
+
+#define RX_NO_DATA_INFO_TYPE_POS 0
+#define RX_NO_DATA_INFO_TYPE_MSK (0xff << RX_NO_DATA_INFO_TYPE_POS)
+#define RX_NO_DATA_INFO_TYPE_NONE 0
+#define RX_NO_DATA_INFO_TYPE_RX_ERR 1
+#define RX_NO_DATA_INFO_TYPE_NDP 2
+#define RX_NO_DATA_INFO_TYPE_MU_UNMATCHED 3
+#define RX_NO_DATA_INFO_TYPE_HE_TB_UNMATCHED 4
+
+#define RX_NO_DATA_INFO_ERR_POS 8
+#define RX_NO_DATA_INFO_ERR_MSK (0xff << RX_NO_DATA_INFO_ERR_POS)
+#define RX_NO_DATA_INFO_ERR_NONE 0
+#define RX_NO_DATA_INFO_ERR_BAD_PLCP 1
+#define RX_NO_DATA_INFO_ERR_UNSUPPORTED_RATE 2
+#define RX_NO_DATA_INFO_ERR_NO_DELIM 3
+#define RX_NO_DATA_INFO_ERR_BAD_MAC_HDR 4
+
+#define RX_NO_DATA_FRAME_TIME_POS 0
+#define RX_NO_DATA_FRAME_TIME_MSK (0xfffff << RX_NO_DATA_FRAME_TIME_POS)
+
+/**
+ * struct iwl_rx_no_data - RX no data descriptor
+ * @info: 7:0 frame type, 15:8 RX error type
+ * @rssi: 7:0 energy chain-A,
+ * 15:8 chain-B, measured at FINA time (FINA_ENERGY), 16:23 channel
+ * @on_air_rise_time: GP2 during on air rise
+ * @fr_time: frame time
+ * @rate: rate/mcs of frame
+ * @phy_info: &enum iwl_rx_phy_data0 and &enum iwl_rx_phy_info_type
+ * @rx_vec: DW-12:9 raw RX vectors from DSP according to modulation type.
+ * for VHT: OFDM_RX_VECTOR_SIGA1_OUT, OFDM_RX_VECTOR_SIGA2_OUT
+ * for HE: OFDM_RX_VECTOR_HE_SIGA1_OUT, OFDM_RX_VECTOR_HE_SIGA2_OUT
+ */
+struct iwl_rx_no_data {
+ __le32 info;
+ __le32 rssi;
+ __le32 on_air_rise_time;
+ __le32 fr_time;
+ __le32 rate;
+ __le32 phy_info[2];
+ __le32 rx_vec[3];
+} __packed; /* RX_NO_DATA_NTFY_API_S_VER_1 */
+
/**
* enum iwl_completion_desc_transfer_status - transfer status (bits 1-3)
* @IWL_CD_STTS_UNUSED: unused
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index c16757051f16..2a19b178c5e8 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -225,22 +225,18 @@ static void iwl_fwrt_dump_txf(struct iwl_fw_runtime *fwrt,
*dump_data = iwl_fw_error_next_data(*dump_data);
}
-static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
- struct iwl_fw_error_dump_data **dump_data)
+static void iwl_fw_dump_rxf(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_error_dump_data **dump_data)
{
- struct iwl_fw_error_dump_fifo *fifo_hdr;
struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
- u32 *fifo_data;
- u32 fifo_len;
unsigned long flags;
- int i, j;
- IWL_DEBUG_INFO(fwrt, "WRT FIFO dump\n");
+ IWL_DEBUG_INFO(fwrt, "WRT RX FIFO dump\n");
if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
return;
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)) {
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RXF)) {
/* Pull RXF1 */
iwl_fwrt_dump_rxf(fwrt, dump_data,
cfg->lmac[0].rxfifo1_size, 0, 0);
@@ -254,7 +250,25 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
LMAC2_PRPH_OFFSET, 2);
}
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)) {
+ iwl_trans_release_nic_access(fwrt->trans, &flags);
+}
+
+static void iwl_fw_dump_txf(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_error_dump_data **dump_data)
+{
+ struct iwl_fw_error_dump_fifo *fifo_hdr;
+ struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg;
+ u32 *fifo_data;
+ u32 fifo_len;
+ unsigned long flags;
+ int i, j;
+
+ IWL_DEBUG_INFO(fwrt, "WRT TX FIFO dump\n");
+
+ if (!iwl_trans_grab_nic_access(fwrt->trans, &flags))
+ return;
+
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_TXF)) {
/* Pull TXF data from LMAC1 */
for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) {
/* Mark the number of TXF we're pulling now */
@@ -279,7 +293,7 @@ static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt,
}
}
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) {
/* Pull UMAC internal TXF data from all TXFs */
@@ -591,20 +605,42 @@ static void iwl_fw_dump_mem(struct iwl_fw_runtime *fwrt,
IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type);
}
+static void iwl_fw_dump_named_mem(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_error_dump_data **dump_data,
+ u32 len, u32 ofs, u8 *name, u8 name_len)
+{
+ struct iwl_fw_error_dump_named_mem *dump_mem;
+
+ if (!len)
+ return;
+
+ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+ (*dump_data)->len = cpu_to_le32(len + sizeof(*dump_mem));
+ dump_mem = (void *)(*dump_data)->data;
+ dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_NAMED_MEM);
+ dump_mem->offset = cpu_to_le32(ofs);
+ dump_mem->name_len = name_len;
+ memcpy(dump_mem->name, name, name_len);
+ iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len);
+ *dump_data = iwl_fw_error_next_data(*dump_data);
+
+ IWL_DEBUG_INFO(fwrt, "WRT memory dump. Type=%u\n", dump_mem->type);
+}
+
#define ADD_LEN(len, item_len, const_len) \
do {size_t item = item_len; len += (!!item) * const_len + item; } \
while (0)
-static int iwl_fw_fifo_len(struct iwl_fw_runtime *fwrt,
- struct iwl_fwrt_shared_mem_cfg *mem_cfg)
+static int iwl_fw_rxf_len(struct iwl_fw_runtime *fwrt,
+ struct iwl_fwrt_shared_mem_cfg *mem_cfg)
{
size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) +
sizeof(struct iwl_fw_error_dump_fifo);
u32 fifo_len = 0;
int i;
- if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RXF)))
- goto dump_txf;
+ if (!iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RXF))
+ return 0;
/* Count RXF2 size */
ADD_LEN(fifo_len, mem_cfg->rxfifo2_size, hdr_len);
@@ -613,8 +649,18 @@ static int iwl_fw_fifo_len(struct iwl_fw_runtime *fwrt,
for (i = 0; i < mem_cfg->num_lmacs; i++)
ADD_LEN(fifo_len, mem_cfg->lmac[i].rxfifo1_size, hdr_len);
-dump_txf:
- if (!(fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_TXF)))
+ return fifo_len;
+}
+
+static int iwl_fw_txf_len(struct iwl_fw_runtime *fwrt,
+ struct iwl_fwrt_shared_mem_cfg *mem_cfg)
+{
+ size_t hdr_len = sizeof(struct iwl_fw_error_dump_data) +
+ sizeof(struct iwl_fw_error_dump_fifo);
+ u32 fifo_len = 0;
+ int i;
+
+ if (!iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_TXF))
goto dump_internal_txf;
/* Count TXF sizes */
@@ -627,7 +673,7 @@ dump_txf:
}
dump_internal_txf:
- if (!((fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_INTERNAL_TXF)) &&
+ if (!(iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_INTERNAL_TXF) &&
fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)))
goto out;
@@ -639,6 +685,32 @@ out:
return fifo_len;
}
+static void iwl_dump_paging(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_error_dump_data **data)
+{
+ int i;
+
+ IWL_DEBUG_INFO(fwrt, "WRT paging dump\n");
+ for (i = 1; i < fwrt->num_of_paging_blk + 1; i++) {
+ struct iwl_fw_error_dump_paging *paging;
+ struct page *pages =
+ fwrt->fw_paging_db[i].fw_paging_block;
+ dma_addr_t addr = fwrt->fw_paging_db[i].fw_paging_phys;
+
+ (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
+ (*data)->len = cpu_to_le32(sizeof(*paging) +
+ PAGING_BLOCK_SIZE);
+ paging = (void *)(*data)->data;
+ paging->index = cpu_to_le32(i);
+ dma_sync_single_for_cpu(fwrt->trans->dev, addr,
+ PAGING_BLOCK_SIZE,
+ DMA_BIDIRECTIONAL);
+ memcpy(paging->data, page_address(pages),
+ PAGING_BLOCK_SIZE);
+ (*data) = iwl_fw_error_next_data(*data);
+ }
+}
+
static struct iwl_fw_error_dump_file *
_iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
struct iwl_fw_dump_ptrs *fw_error_dump)
@@ -655,13 +727,8 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
u32 smem_len = fwrt->fw->dbg.n_mem_tlv ? 0 : fwrt->trans->cfg->smem_len;
u32 sram2_len = fwrt->fw->dbg.n_mem_tlv ?
0 : fwrt->trans->cfg->dccm2_len;
- bool monitor_dump_only = false;
int i;
- if (fwrt->dump.trig &&
- fwrt->dump.trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)
- monitor_dump_only = true;
-
/* SRAM - include stack CCM if driver knows the values for it */
if (!fwrt->trans->cfg->dccm_offset || !fwrt->trans->cfg->dccm_len) {
const struct fw_img *img;
@@ -676,26 +743,27 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
/* reading RXF/TXF sizes */
if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) {
- fifo_len = iwl_fw_fifo_len(fwrt, mem_cfg);
+ fifo_len = iwl_fw_rxf_len(fwrt, mem_cfg);
+ fifo_len += iwl_fw_txf_len(fwrt, mem_cfg);
/* Make room for PRPH registers */
if (!fwrt->trans->cfg->gen2 &&
- fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PRPH))
+ iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_PRPH))
prph_len += iwl_fw_get_prph_len(fwrt);
if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 &&
- fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_RADIO_REG))
+ iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_RADIO_REG))
radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ;
}
file_len = sizeof(*dump_file) + fifo_len + prph_len + radio_len;
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO))
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_DEV_FW_INFO))
file_len += sizeof(*dump_data) + sizeof(*dump_info);
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG))
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM_CFG))
file_len += sizeof(*dump_data) + sizeof(*dump_smem_cfg);
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM)) {
size_t hdr_len = sizeof(*dump_data) +
sizeof(struct iwl_fw_error_dump_mem);
@@ -712,10 +780,7 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
}
/* Make room for fw's virtual image pages, if it exists */
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
- !fwrt->trans->cfg->gen2 &&
- fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
- fwrt->fw_paging_db[0].fw_paging_block)
+ if (iwl_fw_dbg_is_paging_enabled(fwrt))
file_len += fwrt->num_of_paging_blk *
(sizeof(*dump_data) +
sizeof(struct iwl_fw_error_dump_paging) +
@@ -727,12 +792,12 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
}
/* If we only want a monitor dump, reset the file length */
- if (monitor_dump_only) {
+ if (fwrt->dump.monitor_only) {
file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 +
sizeof(*dump_info) + sizeof(*dump_smem_cfg);
}
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_ERROR_INFO) &&
fwrt->dump.desc)
file_len += sizeof(*dump_data) + sizeof(*dump_trig) +
fwrt->dump.desc->len;
@@ -746,7 +811,7 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
dump_data = (void *)dump_file->data;
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_DEV_FW_INFO)) {
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
dump_data->len = cpu_to_le32(sizeof(*dump_info));
dump_info = (void *)dump_data->data;
@@ -763,11 +828,12 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
sizeof(dump_info->dev_human_readable) - 1);
strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name,
sizeof(dump_info->bus_human_readable) - 1);
+ dump_info->rt_status = cpu_to_le32(fwrt->dump.rt_status);
dump_data = iwl_fw_error_next_data(dump_data);
}
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM_CFG)) {
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM_CFG)) {
/* Dump shared memory configuration */
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG);
dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg));
@@ -799,12 +865,13 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
/* We only dump the FIFOs if the FW is in error state */
if (fifo_len) {
- iwl_fw_dump_fifos(fwrt, &dump_data);
+ iwl_fw_dump_rxf(fwrt, &dump_data);
+ iwl_fw_dump_txf(fwrt, &dump_data);
if (radio_len)
iwl_read_radio_regs(fwrt, &dump_data);
}
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_ERROR_INFO) &&
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_ERROR_INFO) &&
fwrt->dump.desc) {
dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO);
dump_data->len = cpu_to_le32(sizeof(*dump_trig) +
@@ -817,10 +884,10 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
}
/* In case we only want monitor dump, skip to dump trasport data */
- if (monitor_dump_only)
+ if (fwrt->dump.monitor_only)
goto out;
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_MEM)) {
+ if (iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_MEM)) {
const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem =
fwrt->fw->dbg.mem_tlv;
@@ -865,30 +932,8 @@ _iwl_fw_error_dump(struct iwl_fw_runtime *fwrt,
}
/* Dump fw's virtual image */
- if (fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_PAGING) &&
- !fwrt->trans->cfg->gen2 &&
- fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
- fwrt->fw_paging_db[0].fw_paging_block) {
- IWL_DEBUG_INFO(fwrt, "WRT paging dump\n");
- for (i = 1; i < fwrt->num_of_paging_blk + 1; i++) {
- struct iwl_fw_error_dump_paging *paging;
- struct page *pages =
- fwrt->fw_paging_db[i].fw_paging_block;
- dma_addr_t addr = fwrt->fw_paging_db[i].fw_paging_phys;
-
- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
- dump_data->len = cpu_to_le32(sizeof(*paging) +
- PAGING_BLOCK_SIZE);
- paging = (void *)dump_data->data;
- paging->index = cpu_to_le32(i);
- dma_sync_single_for_cpu(fwrt->trans->dev, addr,
- PAGING_BLOCK_SIZE,
- DMA_BIDIRECTIONAL);
- memcpy(paging->data, page_address(pages),
- PAGING_BLOCK_SIZE);
- dump_data = iwl_fw_error_next_data(dump_data);
- }
- }
+ if (iwl_fw_dbg_is_paging_enabled(fwrt))
+ iwl_dump_paging(fwrt, &dump_data);
if (prph_len) {
iwl_dump_prph(fwrt->trans, &dump_data,
@@ -906,12 +951,245 @@ out:
return dump_file;
}
+static void iwl_dump_prph_ini(struct iwl_trans *trans,
+ struct iwl_fw_error_dump_data **data,
+ struct iwl_fw_ini_region_cfg *reg)
+{
+ struct iwl_fw_error_dump_prph *prph;
+ unsigned long flags;
+ u32 i, size = le32_to_cpu(reg->num_regions);
+
+ IWL_DEBUG_INFO(trans, "WRT PRPH dump\n");
+
+ if (!iwl_trans_grab_nic_access(trans, &flags))
+ return;
+
+ for (i = 0; i < size; i++) {
+ (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PRPH);
+ (*data)->len = cpu_to_le32(le32_to_cpu(reg->size) +
+ sizeof(*prph));
+ prph = (void *)(*data)->data;
+ prph->prph_start = reg->start_addr[i];
+ prph->data[0] = cpu_to_le32(iwl_read_prph_no_grab(trans,
+ le32_to_cpu(prph->prph_start)));
+ *data = iwl_fw_error_next_data(*data);
+ }
+ iwl_trans_release_nic_access(trans, &flags);
+}
+
+static void iwl_dump_csr_ini(struct iwl_trans *trans,
+ struct iwl_fw_error_dump_data **data,
+ struct iwl_fw_ini_region_cfg *reg)
+{
+ int i, num = le32_to_cpu(reg->num_regions);
+ u32 size = le32_to_cpu(reg->size);
+
+ IWL_DEBUG_INFO(trans, "WRT CSR dump\n");
+
+ for (i = 0; i < num; i++) {
+ u32 add = le32_to_cpu(reg->start_addr[i]);
+ __le32 *val;
+ int j;
+
+ (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_CSR);
+ (*data)->len = cpu_to_le32(size);
+ val = (void *)(*data)->data;
+
+ for (j = 0; j < size; j += 4)
+ *val++ = cpu_to_le32(iwl_trans_read32(trans, j + add));
+
+ *data = iwl_fw_error_next_data(*data);
+ }
+}
+
+static int iwl_fw_ini_get_trigger_len(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_ini_trigger *trigger)
+{
+ int i, num, size = 0, hdr_len = sizeof(struct iwl_fw_error_dump_data);
+
+ if (!trigger || !trigger->num_regions)
+ return 0;
+
+ num = le32_to_cpu(trigger->num_regions);
+ for (i = 0; i < num; i++) {
+ u32 reg_id = le32_to_cpu(trigger->data[i]);
+ struct iwl_fw_ini_region_cfg *reg;
+ enum iwl_fw_ini_region_type type;
+ u32 num_entries;
+
+ if (WARN_ON(reg_id >= ARRAY_SIZE(fwrt->dump.active_regs)))
+ continue;
+
+ reg = fwrt->dump.active_regs[reg_id].reg;
+ if (WARN(!reg, "Unassigned region %d\n", reg_id))
+ continue;
+
+ type = le32_to_cpu(reg->region_type);
+ num_entries = le32_to_cpu(reg->num_regions);
+
+ switch (type) {
+ case IWL_FW_INI_REGION_DEVICE_MEMORY:
+ size += hdr_len +
+ sizeof(struct iwl_fw_error_dump_named_mem) +
+ le32_to_cpu(reg->size);
+ break;
+ case IWL_FW_INI_REGION_PERIPHERY_MAC:
+ case IWL_FW_INI_REGION_PERIPHERY_PHY:
+ case IWL_FW_INI_REGION_PERIPHERY_AUX:
+ size += num_entries *
+ (hdr_len +
+ sizeof(struct iwl_fw_error_dump_prph) +
+ sizeof(u32));
+ break;
+ case IWL_FW_INI_REGION_TXF:
+ size += iwl_fw_txf_len(fwrt, &fwrt->smem_cfg);
+ break;
+ case IWL_FW_INI_REGION_RXF:
+ size += iwl_fw_rxf_len(fwrt, &fwrt->smem_cfg);
+ break;
+ case IWL_FW_INI_REGION_PAGING:
+ if (!iwl_fw_dbg_is_paging_enabled(fwrt))
+ break;
+ size += fwrt->num_of_paging_blk *
+ (hdr_len +
+ sizeof(struct iwl_fw_error_dump_paging) +
+ PAGING_BLOCK_SIZE);
+ break;
+ case IWL_FW_INI_REGION_CSR:
+ size += num_entries *
+ (hdr_len + le32_to_cpu(reg->size));
+ break;
+ case IWL_FW_INI_REGION_DRAM_BUFFER:
+ /* Transport takes care of DRAM dumping */
+ case IWL_FW_INI_REGION_INTERNAL_BUFFER:
+ case IWL_FW_INI_REGION_DRAM_IMR:
+ /* Undefined yet */
+ default:
+ break;
+ }
+ }
+ return size;
+}
+
+static void iwl_fw_ini_dump_trigger(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_ini_trigger *trigger,
+ struct iwl_fw_error_dump_data **data,
+ u32 *dump_mask)
+{
+ int i, num = le32_to_cpu(trigger->num_regions);
+
+ for (i = 0; i < num; i++) {
+ u32 reg_id = le32_to_cpu(trigger->data[i]);
+ enum iwl_fw_ini_region_type type;
+ struct iwl_fw_ini_region_cfg *reg;
+
+ if (reg_id >= ARRAY_SIZE(fwrt->dump.active_regs))
+ continue;
+
+ reg = fwrt->dump.active_regs[reg_id].reg;
+ /* Don't warn, get_trigger_len already warned */
+ if (!reg)
+ continue;
+
+ type = le32_to_cpu(reg->region_type);
+ switch (type) {
+ case IWL_FW_INI_REGION_DEVICE_MEMORY:
+ if (WARN_ON(le32_to_cpu(reg->num_regions) > 1))
+ continue;
+ iwl_fw_dump_named_mem(fwrt, data,
+ le32_to_cpu(reg->size),
+ le32_to_cpu(reg->start_addr[0]),
+ reg->name,
+ le32_to_cpu(reg->name_len));
+ break;
+ case IWL_FW_INI_REGION_PERIPHERY_MAC:
+ case IWL_FW_INI_REGION_PERIPHERY_PHY:
+ case IWL_FW_INI_REGION_PERIPHERY_AUX:
+ iwl_dump_prph_ini(fwrt->trans, data, reg);
+ break;
+ case IWL_FW_INI_REGION_DRAM_BUFFER:
+ *dump_mask |= IWL_FW_ERROR_DUMP_FW_MONITOR;
+ break;
+ case IWL_FW_INI_REGION_PAGING:
+ if (iwl_fw_dbg_is_paging_enabled(fwrt))
+ iwl_dump_paging(fwrt, data);
+ else
+ *dump_mask |= IWL_FW_ERROR_DUMP_PAGING;
+ break;
+ case IWL_FW_INI_REGION_TXF:
+ iwl_fw_dump_txf(fwrt, data);
+ break;
+ case IWL_FW_INI_REGION_RXF:
+ iwl_fw_dump_rxf(fwrt, data);
+ break;
+ case IWL_FW_INI_REGION_CSR:
+ iwl_dump_csr_ini(fwrt->trans, data, reg);
+ break;
+ case IWL_FW_INI_REGION_DRAM_IMR:
+ case IWL_FW_INI_REGION_INTERNAL_BUFFER:
+ /* This is undefined yet */
+ default:
+ break;
+ }
+ }
+}
+
+static struct iwl_fw_error_dump_file *
+_iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_dump_ptrs *fw_error_dump,
+ u32 *dump_mask)
+{
+ int size, id = le32_to_cpu(fwrt->dump.desc->trig_desc.type);
+ struct iwl_fw_error_dump_data *dump_data;
+ struct iwl_fw_error_dump_file *dump_file;
+ struct iwl_fw_ini_trigger *trigger, *ext;
+
+ if (id == FW_DBG_TRIGGER_FW_ASSERT)
+ id = IWL_FW_TRIGGER_ID_FW_ASSERT;
+ else if (id == FW_DBG_TRIGGER_USER)
+ id = IWL_FW_TRIGGER_ID_USER_TRIGGER;
+ else if (id < FW_DBG_TRIGGER_MAX)
+ return NULL;
+
+ if (WARN_ON(id >= ARRAY_SIZE(fwrt->dump.active_trigs)))
+ return NULL;
+
+ trigger = fwrt->dump.active_trigs[id].conf;
+ ext = fwrt->dump.active_trigs[id].conf_ext;
+
+ size = sizeof(*dump_file);
+ size += iwl_fw_ini_get_trigger_len(fwrt, trigger);
+ size += iwl_fw_ini_get_trigger_len(fwrt, ext);
+
+ if (!size)
+ return NULL;
+
+ dump_file = vzalloc(size);
+ if (!dump_file)
+ return NULL;
+
+ fw_error_dump->fwrt_ptr = dump_file;
+
+ dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
+ dump_data = (void *)dump_file->data;
+ dump_file->file_len = cpu_to_le32(size);
+
+ *dump_mask = 0;
+ if (trigger)
+ iwl_fw_ini_dump_trigger(fwrt, trigger, &dump_data, dump_mask);
+ if (ext)
+ iwl_fw_ini_dump_trigger(fwrt, ext, &dump_data, dump_mask);
+
+ return dump_file;
+}
+
void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
{
struct iwl_fw_dump_ptrs *fw_error_dump;
struct iwl_fw_error_dump_file *dump_file;
struct scatterlist *sg_dump_data;
u32 file_len;
+ u32 dump_mask = fwrt->fw->dbg.dump_mask;
IWL_DEBUG_INFO(fwrt, "WRT dump start\n");
@@ -925,14 +1203,21 @@ void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt)
if (!fw_error_dump)
goto out;
- dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump);
+ if (fwrt->trans->ini_valid)
+ dump_file = _iwl_fw_error_ini_dump(fwrt, fw_error_dump,
+ &dump_mask);
+ else
+ dump_file = _iwl_fw_error_dump(fwrt, fw_error_dump);
+
if (!dump_file) {
kfree(fw_error_dump);
goto out;
}
- fw_error_dump->trans_ptr = iwl_trans_dump_data(fwrt->trans,
- fwrt->dump.trig);
+ if (!fwrt->trans->ini_valid && fwrt->dump.monitor_only)
+ dump_mask &= IWL_FW_ERROR_DUMP_FW_MONITOR;
+
+ fw_error_dump->trans_ptr = iwl_trans_dump_data(fwrt->trans, dump_mask);
file_len = le32_to_cpu(dump_file->file_len);
fw_error_dump->fwrt_len = file_len;
if (fw_error_dump->trans_ptr) {
@@ -973,6 +1258,14 @@ const struct iwl_fw_dump_desc iwl_dump_desc_assert = {
};
IWL_EXPORT_SYMBOL(iwl_dump_desc_assert);
+void iwl_fw_assert_error_dump(struct iwl_fw_runtime *fwrt)
+{
+ IWL_INFO(fwrt, "error dump due to fw assert\n");
+ fwrt->dump.desc = &iwl_dump_desc_assert;
+ iwl_fw_error_dump(fwrt);
+}
+IWL_EXPORT_SYMBOL(iwl_fw_assert_error_dump);
+
void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt)
{
struct iwl_fw_dump_desc *iwl_dump_desc_no_alive =
@@ -998,7 +1291,8 @@ void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt)
IWL_EXPORT_SYMBOL(iwl_fw_alive_error_dump);
int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
- const struct iwl_fw_dump_desc *desc, void *trigger,
+ const struct iwl_fw_dump_desc *desc,
+ bool monitor_only,
unsigned int delay)
{
/*
@@ -1028,7 +1322,7 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
le32_to_cpu(desc->trig_desc.type));
fwrt->dump.desc = desc;
- fwrt->dump.trig = trigger;
+ fwrt->dump.monitor_only = monitor_only;
schedule_delayed_work(&fwrt->dump.wk, delay);
@@ -1036,13 +1330,14 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc);
-int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
- enum iwl_fw_dbg_trigger trig,
- const char *str, size_t len,
- struct iwl_fw_dbg_trigger_tlv *trigger)
+int _iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
+ enum iwl_fw_dbg_trigger trig,
+ const char *str, size_t len,
+ struct iwl_fw_dbg_trigger_tlv *trigger)
{
struct iwl_fw_dump_desc *desc;
unsigned int delay = 0;
+ bool monitor_only = false;
if (trigger) {
u16 occurrences = le16_to_cpu(trigger->occurrences) - 1;
@@ -1059,6 +1354,7 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
trigger->occurrences = cpu_to_le16(occurrences);
delay = le16_to_cpu(trigger->trig_dis_ms);
+ monitor_only = trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY;
}
desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC);
@@ -1070,7 +1366,48 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
desc->trig_desc.type = cpu_to_le32(trig);
memcpy(desc->trig_desc.data, str, len);
- return iwl_fw_dbg_collect_desc(fwrt, desc, trigger, delay);
+ return iwl_fw_dbg_collect_desc(fwrt, desc, monitor_only, delay);
+}
+IWL_EXPORT_SYMBOL(_iwl_fw_dbg_collect);
+
+int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
+ u32 id, const char *str, size_t len)
+{
+ struct iwl_fw_dump_desc *desc;
+ u32 occur, delay;
+
+ if (!fwrt->trans->ini_valid)
+ return _iwl_fw_dbg_collect(fwrt, id, str, len, NULL);
+
+ if (id == FW_DBG_TRIGGER_USER)
+ id = IWL_FW_TRIGGER_ID_USER_TRIGGER;
+
+ if (WARN_ON(!fwrt->dump.active_trigs[id].active))
+ return -EINVAL;
+
+ delay = le32_to_cpu(fwrt->dump.active_trigs[id].conf->ignore_consec);
+ occur = le32_to_cpu(fwrt->dump.active_trigs[id].conf->occurrences);
+ if (!occur)
+ return 0;
+
+ if (le32_to_cpu(fwrt->dump.active_trigs[id].conf->force_restart)) {
+ IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", id);
+ iwl_force_nmi(fwrt->trans);
+ return 0;
+ }
+
+ desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC);
+ if (!desc)
+ return -ENOMEM;
+
+ occur--;
+ fwrt->dump.active_trigs[id].conf->occurrences = cpu_to_le32(occur);
+
+ desc->len = len;
+ desc->trig_desc.type = cpu_to_le32(id);
+ memcpy(desc->trig_desc.data, str, len);
+
+ return iwl_fw_dbg_collect_desc(fwrt, desc, true, delay);
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect);
@@ -1081,6 +1418,9 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
int ret, len = 0;
char buf[64];
+ if (fwrt->trans->ini_valid)
+ return 0;
+
if (fmt) {
va_list ap;
@@ -1097,8 +1437,8 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
len = strlen(buf) + 1;
}
- ret = iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len,
- trigger);
+ ret = _iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len,
+ trigger);
if (ret)
return ret;
@@ -1224,3 +1564,217 @@ void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt)
cfg->d3_debug_data_length);
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_read_d3_debug_data);
+
+static void
+iwl_fw_dbg_buffer_allocation(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_ini_allocation_tlv *alloc)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ struct iwl_continuous_record_cmd cont_rec = {};
+ struct iwl_buffer_allocation_cmd *cmd = (void *)&cont_rec.pad[0];
+ struct iwl_host_cmd hcmd = {
+ .id = LDBG_CONFIG_CMD,
+ .flags = CMD_ASYNC,
+ .data[0] = &cont_rec,
+ .len[0] = sizeof(cont_rec),
+ };
+ void *virtual_addr = NULL;
+ u32 size = le32_to_cpu(alloc->size);
+ dma_addr_t phys_addr;
+
+ cont_rec.record_mode.enable_recording = cpu_to_le16(BUFFER_ALLOCATION);
+
+ if (!trans->num_blocks &&
+ le32_to_cpu(alloc->buffer_location) !=
+ IWL_FW_INI_LOCATION_DRAM_PATH)
+ return;
+
+ virtual_addr = dma_alloc_coherent(fwrt->trans->dev, size,
+ &phys_addr, GFP_KERNEL);
+
+ /* TODO: alloc fragments if needed */
+ if (!virtual_addr)
+ IWL_ERR(fwrt, "Failed to allocate debug memory\n");
+
+ if (WARN_ON_ONCE(trans->num_blocks == ARRAY_SIZE(trans->fw_mon)))
+ return;
+
+ trans->fw_mon[trans->num_blocks].block = virtual_addr;
+ trans->fw_mon[trans->num_blocks].physical = phys_addr;
+ trans->fw_mon[trans->num_blocks].size = size;
+ trans->num_blocks++;
+
+ IWL_DEBUG_FW(trans, "Allocated debug block of size %d\n", size);
+
+ /* First block is assigned via registers / context info */
+ if (trans->num_blocks == 1)
+ return;
+
+ cmd->num_frags = cpu_to_le32(1);
+ cmd->fragments[0].address = cpu_to_le64(phys_addr);
+ cmd->fragments[0].size = alloc->size;
+ cmd->allocation_id = alloc->allocation_id;
+ cmd->buffer_location = alloc->buffer_location;
+
+ iwl_trans_send_cmd(trans, &hcmd);
+}
+
+static void iwl_fw_dbg_send_hcmd(struct iwl_fw_runtime *fwrt,
+ struct iwl_ucode_tlv *tlv)
+{
+ struct iwl_fw_ini_hcmd_tlv *hcmd_tlv = (void *)&tlv->data[0];
+ struct iwl_fw_ini_hcmd *data = &hcmd_tlv->hcmd;
+ u16 len = le32_to_cpu(tlv->length) - sizeof(*hcmd_tlv);
+
+ struct iwl_host_cmd hcmd = {
+ .id = WIDE_ID(data->group, data->id),
+ .len = { len, },
+ .data = { data->data, },
+ };
+
+ iwl_trans_send_cmd(fwrt->trans, &hcmd);
+}
+
+static void iwl_fw_dbg_update_regions(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_ini_region_tlv *tlv,
+ bool ext, enum iwl_fw_ini_apply_point pnt)
+{
+ void *iter = (void *)tlv->region_config;
+ int i, size = le32_to_cpu(tlv->num_regions);
+
+ for (i = 0; i < size; i++) {
+ struct iwl_fw_ini_region_cfg *reg = iter;
+ int id = le32_to_cpu(reg->region_id);
+ struct iwl_fw_ini_active_regs *active;
+
+ if (WARN(id >= ARRAY_SIZE(fwrt->dump.active_regs),
+ "Invalid region id %d for apply point %d\n", id, pnt))
+ break;
+
+ active = &fwrt->dump.active_regs[id];
+
+ if (ext && active->apply_point == pnt)
+ IWL_WARN(fwrt->trans,
+ "External region TLV overrides FW default %x\n",
+ id);
+
+ IWL_DEBUG_FW(fwrt,
+ "%s: apply point %d, activating region ID %d\n",
+ __func__, pnt, id);
+
+ active->reg = reg;
+ active->apply_point = pnt;
+
+ if (le32_to_cpu(reg->region_type) !=
+ IWL_FW_INI_REGION_DRAM_BUFFER)
+ iter += le32_to_cpu(reg->num_regions) * sizeof(__le32);
+
+ iter += sizeof(*reg);
+ }
+}
+
+static void iwl_fw_dbg_update_triggers(struct iwl_fw_runtime *fwrt,
+ struct iwl_fw_ini_trigger_tlv *tlv,
+ bool ext,
+ enum iwl_fw_ini_apply_point apply_point)
+{
+ int i, size = le32_to_cpu(tlv->num_triggers);
+ void *iter = (void *)tlv->trigger_config;
+
+ for (i = 0; i < size; i++) {
+ struct iwl_fw_ini_trigger *trig = iter;
+ struct iwl_fw_ini_active_triggers *active;
+ int id = le32_to_cpu(trig->trigger_id);
+ u32 num;
+
+ if (WARN_ON(id >= ARRAY_SIZE(fwrt->dump.active_trigs)))
+ break;
+
+ active = &fwrt->dump.active_trigs[id];
+
+ if (active->apply_point != apply_point) {
+ active->conf = NULL;
+ active->conf_ext = NULL;
+ }
+
+ num = le32_to_cpu(trig->num_regions);
+
+ if (ext && active->apply_point == apply_point) {
+ num += le32_to_cpu(active->conf->num_regions);
+ if (trig->ignore_default) {
+ active->conf_ext = active->conf;
+ active->conf = trig;
+ } else {
+ active->conf_ext = trig;
+ }
+ } else {
+ active->conf = trig;
+ }
+
+ /* Since zero means infinity - just set to -1 */
+ if (!le32_to_cpu(trig->occurrences))
+ trig->occurrences = cpu_to_le32(-1);
+ if (!le32_to_cpu(trig->ignore_consec))
+ trig->ignore_consec = cpu_to_le32(-1);
+
+ iter += sizeof(*trig) +
+ le32_to_cpu(trig->num_regions) * sizeof(__le32);
+
+ active->active = num;
+ active->apply_point = apply_point;
+ }
+}
+
+static void _iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
+ struct iwl_apply_point_data *data,
+ enum iwl_fw_ini_apply_point pnt,
+ bool ext)
+{
+ void *iter = data->data;
+
+ while (iter && iter < data->data + data->size) {
+ struct iwl_ucode_tlv *tlv = iter;
+ void *ini_tlv = (void *)tlv->data;
+ u32 type = le32_to_cpu(tlv->type);
+
+ switch (type) {
+ case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
+ iwl_fw_dbg_buffer_allocation(fwrt, ini_tlv);
+ break;
+ case IWL_UCODE_TLV_TYPE_HCMD:
+ if (pnt < IWL_FW_INI_APPLY_AFTER_ALIVE) {
+ IWL_ERR(fwrt,
+ "Invalid apply point %x for host command\n",
+ pnt);
+ goto next;
+ }
+ iwl_fw_dbg_send_hcmd(fwrt, tlv);
+ break;
+ case IWL_UCODE_TLV_TYPE_REGIONS:
+ iwl_fw_dbg_update_regions(fwrt, ini_tlv, ext, pnt);
+ break;
+ case IWL_UCODE_TLV_TYPE_TRIGGERS:
+ iwl_fw_dbg_update_triggers(fwrt, ini_tlv, ext, pnt);
+ break;
+ case IWL_UCODE_TLV_TYPE_DEBUG_FLOW:
+ break;
+ default:
+ WARN_ONCE(1, "Invalid TLV %x for apply point\n", type);
+ break;
+ }
+next:
+ iter += sizeof(*tlv) + le32_to_cpu(tlv->length);
+ }
+}
+
+void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
+ enum iwl_fw_ini_apply_point apply_point)
+{
+ void *data = &fwrt->trans->apply_points[apply_point];
+
+ _iwl_fw_dbg_apply_point(fwrt, data, apply_point, false);
+
+ data = &fwrt->trans->apply_points_ext[apply_point];
+ _iwl_fw_dbg_apply_point(fwrt, data, apply_point, true);
+}
+IWL_EXPORT_SYMBOL(iwl_fw_dbg_apply_point);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
index 6f8d3256f7b0..6aabbdd72326 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
@@ -72,6 +72,7 @@
#include "file.h"
#include "error-dump.h"
#include "api/commands.h"
+#include "api/dbg-tlv.h"
/**
* struct iwl_fw_dump_desc - describes the dump
@@ -101,17 +102,19 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt)
if (fwrt->dump.desc != &iwl_dump_desc_assert)
kfree(fwrt->dump.desc);
fwrt->dump.desc = NULL;
- fwrt->dump.trig = NULL;
+ fwrt->dump.rt_status = 0;
}
void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt);
int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
const struct iwl_fw_dump_desc *desc,
- void *trigger, unsigned int delay);
+ bool monitor_only, unsigned int delay);
+int _iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
+ enum iwl_fw_dbg_trigger trig,
+ const char *str, size_t len,
+ struct iwl_fw_dbg_trigger_tlv *trigger);
int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
- enum iwl_fw_dbg_trigger trig,
- const char *str, size_t len,
- struct iwl_fw_dbg_trigger_tlv *trigger);
+ u32 id, const char *str, size_t len);
int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
struct iwl_fw_dbg_trigger_tlv *trigger,
const char *fmt, ...) __printf(3, 4);
@@ -193,6 +196,9 @@ _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt,
{
struct iwl_fw_dbg_trigger_tlv *trig;
+ if (fwrt->trans->ini_valid)
+ return NULL;
+
if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id))
return NULL;
@@ -210,6 +216,37 @@ _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt,
_iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \
})
+static inline bool
+_iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt,
+ const enum iwl_fw_dbg_trigger id)
+{
+ struct iwl_fw_ini_active_triggers *trig = &fwrt->dump.active_trigs[id];
+ u32 ms;
+
+ if (!fwrt->trans->ini_valid)
+ return false;
+
+ if (!trig || !trig->active)
+ return false;
+
+ ms = le32_to_cpu(trig->conf->ignore_consec);
+ if (ms)
+ ms /= USEC_PER_MSEC;
+
+ if (iwl_fw_dbg_no_trig_window(fwrt, id, ms)) {
+ IWL_WARN(fwrt, "Trigger %d fired in no-collect window\n", id);
+ return false;
+ }
+
+ return true;
+}
+
+#define iwl_fw_ini_trigger_on(fwrt, wdev, id) ({ \
+ BUILD_BUG_ON(!__builtin_constant_p(id)); \
+ BUILD_BUG_ON((id) >= IWL_FW_TRIGGER_ID_NUM); \
+ _iwl_fw_ini_trigger_on((fwrt), (wdev), (id)); \
+})
+
static inline void
_iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
struct wireless_dev *wdev,
@@ -263,6 +300,9 @@ _iwl_fw_dbg_stop_recording(struct iwl_trans *trans,
iwl_write_prph(trans, DBGC_IN_SAMPLE, 0);
udelay(100);
iwl_write_prph(trans, DBGC_OUT_CTRL, 0);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ trans->dbg_rec_on = false;
+#endif
}
static inline void
@@ -293,6 +333,14 @@ _iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
}
}
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+static inline void iwl_fw_set_dbg_rec_on(struct iwl_fw_runtime *fwrt)
+{
+ if (fwrt->fw->dbg.dest_tlv && fwrt->cur_fw_img == IWL_UCODE_REGULAR)
+ fwrt->trans->dbg_rec_on = true;
+}
+#endif
+
static inline void
iwl_fw_dbg_restart_recording(struct iwl_fw_runtime *fwrt,
struct iwl_fw_dbg_params *params)
@@ -301,6 +349,9 @@ iwl_fw_dbg_restart_recording(struct iwl_fw_runtime *fwrt,
_iwl_fw_dbg_restart_recording(fwrt->trans, params);
else
iwl_fw_dbg_start_stop_hcmd(fwrt, true);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ iwl_fw_set_dbg_rec_on(fwrt);
+#endif
}
static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)
@@ -310,12 +361,25 @@ static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)
void iwl_fw_error_dump_wk(struct work_struct *work);
+static inline bool iwl_fw_dbg_type_on(struct iwl_fw_runtime *fwrt, u32 type)
+{
+ return (fwrt->fw->dbg.dump_mask & BIT(type) || fwrt->trans->ini_valid);
+}
+
static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt)
{
return fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_D3_DEBUG) &&
fwrt->trans->cfg->d3_debug_data_length &&
- fwrt->fw->dbg.dump_mask & BIT(IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
+ iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
+}
+
+static inline bool iwl_fw_dbg_is_paging_enabled(struct iwl_fw_runtime *fwrt)
+{
+ return iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_PAGING) &&
+ !fwrt->trans->cfg->gen2 &&
+ fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
+ fwrt->fw_paging_db[0].fw_paging_block;
}
void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt);
@@ -366,6 +430,10 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
#endif /* CONFIG_IWLWIFI_DEBUGFS */
+void iwl_fw_assert_error_dump(struct iwl_fw_runtime *fwrt);
void iwl_fw_alive_error_dump(struct iwl_fw_runtime *fwrt);
void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt);
+void iwl_fw_dbg_apply_point(struct iwl_fw_runtime *fwrt,
+ enum iwl_fw_ini_apply_point apply_point);
+
#endif /* __iwl_fw_dbg_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
index 6fede174c664..65faecf552cd 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
@@ -187,6 +187,8 @@ enum iwl_fw_error_dump_family {
* @fw_human_readable: human readable FW version
* @dev_human_readable: name of the device
* @bus_human_readable: name of the bus used
+ * @rt_status: the error_id/rt_status that that triggered the latest dump
+ * if the dump collection was not initiated by an assert, the value is 0
*/
struct iwl_fw_error_dump_info {
__le32 device_family;
@@ -194,6 +196,7 @@ struct iwl_fw_error_dump_info {
u8 fw_human_readable[FW_VER_HUMAN_READABLE_SZ];
u8 dev_human_readable[64];
u8 bus_human_readable[8];
+ __le32 rt_status;
} __packed;
/**
@@ -249,6 +252,7 @@ struct iwl_fw_error_dump_prph {
enum iwl_fw_error_dump_mem_type {
IWL_FW_ERROR_DUMP_MEM_SRAM,
IWL_FW_ERROR_DUMP_MEM_SMEM,
+ IWL_FW_ERROR_DUMP_MEM_NAMED_MEM = 10,
};
/**
@@ -264,6 +268,22 @@ struct iwl_fw_error_dump_mem {
};
/**
+ * struct iwl_fw_error_dump_named_mem - chunk of memory
+ * @type: &enum iwl_fw_error_dump_mem_type
+ * @offset: the offset from which the memory was read
+ * @name_len: name length
+ * @name: file name
+ * @data: the content of the memory
+ */
+struct iwl_fw_error_dump_named_mem {
+ __le32 type;
+ __le32 offset;
+ u8 name_len;
+ u8 name[32];
+ u8 data[];
+};
+
+/**
* struct iwl_fw_error_dump_rb - content of an Receive Buffer
* @index: the index of the Receive Buffer in the Rx queue
* @rxq: the RB's Rx queue
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index 6005a41c53d1..81f557c0b58d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -91,6 +91,8 @@ struct iwl_ucode_header {
} u;
};
+#define IWL_UCODE_INI_TLV_GROUP BIT(24)
+
/*
* new TLV uCode file layout
*
@@ -141,6 +143,11 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_FW_GSCAN_CAPA = 50,
IWL_UCODE_TLV_FW_MEM_SEG = 51,
IWL_UCODE_TLV_IML = 52,
+ IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_INI_TLV_GROUP | 0x1,
+ IWL_UCODE_TLV_TYPE_HCMD = IWL_UCODE_INI_TLV_GROUP | 0x2,
+ IWL_UCODE_TLV_TYPE_REGIONS = IWL_UCODE_INI_TLV_GROUP | 0x3,
+ IWL_UCODE_TLV_TYPE_TRIGGERS = IWL_UCODE_INI_TLV_GROUP | 0x4,
+ IWL_UCODE_TLV_TYPE_DEBUG_FLOW = IWL_UCODE_INI_TLV_GROUP | 0x5,
/* TLVs 0x1000-0x2000 are for internal driver usage */
IWL_UCODE_TLV_FW_DBG_DUMP_LST = 0x1000,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h
index 54dbbd998abf..12333167ea23 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/img.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h
@@ -65,6 +65,8 @@
#define __iwl_fw_img_h__
#include <linux/types.h>
+#include "api/dbg-tlv.h"
+
#include "file.h"
#include "error-dump.h"
@@ -221,6 +223,30 @@ struct iwl_fw_dbg {
};
/**
+ * struct iwl_fw_ini_active_triggers
+ * @active: is this trigger active
+ * @apply_point: last apply point that updated this trigger
+ * @conf: active trigger
+ * @conf_ext: second trigger, contains extra regions to dump
+ */
+struct iwl_fw_ini_active_triggers {
+ bool active;
+ enum iwl_fw_ini_apply_point apply_point;
+ struct iwl_fw_ini_trigger *conf;
+ struct iwl_fw_ini_trigger *conf_ext;
+};
+
+/**
+ * struct iwl_fw_ini_active_regs
+ * @reg: active region from TLV
+ * @apply_point: apply point where it became active
+ */
+struct iwl_fw_ini_active_regs {
+ struct iwl_fw_ini_region_cfg *reg;
+ enum iwl_fw_ini_apply_point apply_point;
+};
+
+/**
* struct iwl_fw - variables associated with the firmware
*
* @ucode_ver: ucode version from the ucode file
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
index 2b8b50a77990..4f7090f88cb0 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
@@ -64,6 +64,7 @@
#include "iwl-trans.h"
#include "img.h"
#include "fw/api/debug.h"
+#include "fw/api/dbg-tlv.h"
#include "fw/api/paging.h"
#include "iwl-eeprom-parse.h"
@@ -131,14 +132,17 @@ struct iwl_fw_runtime {
/* debug */
struct {
const struct iwl_fw_dump_desc *desc;
- const struct iwl_fw_dbg_trigger_tlv *trig;
+ bool monitor_only;
struct delayed_work wk;
u8 conf;
/* ts of the beginning of a non-collect fw dbg data period */
- unsigned long non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1];
+ unsigned long non_collect_ts_start[IWL_FW_TRIGGER_ID_NUM - 1];
u32 *d3_debug_data;
+ struct iwl_fw_ini_active_regs active_regs[IWL_FW_INI_MAX_REGION_ID];
+ struct iwl_fw_ini_active_triggers active_trigs[IWL_FW_TRIGGER_ID_NUM];
+ u32 rt_status;
} dump;
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct {