2021-06-21 07:38:15

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 0/9] iwlwifi: updates intended for v5.14 2021-06-21

From: Luca Coelho <[email protected]>

Hi,

Here's the fourth set of patches intended for v5.14. It's the usual
development, new features, cleanups and bugfixes.

The changes are:

* Updates in the WoWLAN FW commands;
* Add one new device to the PCI ID lists;
* Support reading PNVM from a UEFI variable;
* Bump the supported FW API version;
* Some other small fixes, clean-ups and improvements.

As usual, I'm pushing this to a pending branch, for kbuild bot, and
will send a pull-request later.

Please review.

Cheers,
Luca.


Emmanuel Grumbach (3):
iwlwifi: mvm: update iwl_wowlan_patterns_cmd
iwlwifi: mvm: introduce iwl_wowlan_kek_kck_material_cmd_v4
iwlwifi: mvm: introduce iwl_wowlan_get_status_cmd

Johannes Berg (2):
iwlwifi: move error dump to fw utils
iwlwifi: fw: dump TCM error table if present

Luca Coelho (3):
iwlwifi: move UEFI code to a separate file
iwlwifi: support loading the reduced power table from UEFI
iwlwifi: bump FW API to 64 for AX devices

ybaruch (1):
iwlwifi: add 9560 killer device

drivers/net/wireless/intel/iwlwifi/Makefile | 3 +-
.../net/wireless/intel/iwlwifi/cfg/22000.c | 4 +-
drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 6 +-
.../net/wireless/intel/iwlwifi/fw/api/d3.h | 31 +-
drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 38 --
drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 4 +-
drivers/net/wireless/intel/iwlwifi/fw/dump.c | 418 ++++++++++++++++++
drivers/net/wireless/intel/iwlwifi/fw/file.h | 8 +-
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 120 ++---
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 262 +++++++++++
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 42 ++
.../net/wireless/intel/iwlwifi/iwl-config.h | 2 +
.../intel/iwlwifi/iwl-context-info-gen3.h | 16 +-
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 11 +
.../net/wireless/intel/iwlwifi/iwl-trans.h | 20 +
drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 74 +++-
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 +-
.../net/wireless/intel/iwlwifi/mvm/utils.c | 310 -------------
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 34 ++
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 +
.../wireless/intel/iwlwifi/pcie/internal.h | 1 +
.../net/wireless/intel/iwlwifi/pcie/trans.c | 7 +
22 files changed, 962 insertions(+), 459 deletions(-)
create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/dump.c
create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/uefi.c
create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/uefi.h

--
2.32.0


2021-06-21 07:38:24

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 1/9] iwlwifi: mvm: update iwl_wowlan_patterns_cmd

From: Emmanuel Grumbach <[email protected]>

We need to pass the station id to tell the firmware
on which station we want to configure the patterns.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/api/d3.h | 14 ++++++++++++--
drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 13 ++++++++++---
2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
index a9e8f30ef91d..4dbf24128a98 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
@@ -318,13 +318,23 @@ struct iwl_wowlan_patterns_cmd {
/**
* @n_patterns: number of patterns
*/
- __le32 n_patterns;
+ u8 n_patterns;
+
+ /**
+ * @n_patterns: sta_id
+ */
+ u8 sta_id;
+
+ /**
+ * @reserved: reserved for alignment
+ */
+ __le16 reserved;

/**
* @patterns: the patterns, array length in @n_patterns
*/
struct iwl_wowlan_pattern_v2 patterns[];
-} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_2 */
+} __packed; /* WOWLAN_PATTERN_ARRAY_API_S_VER_3 */

enum iwl_wowlan_wakeup_filters {
IWL_WOWLAN_WAKEUP_MAGIC_PACKET = BIT(0),
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 7b13c4fc1b58..8e5814a3b178 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -393,14 +393,19 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm,
}

static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
struct cfg80211_wowlan *wowlan)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_wowlan_patterns_cmd *pattern_cmd;
struct iwl_host_cmd cmd = {
.id = WOWLAN_PATTERNS,
.dataflags[0] = IWL_HCMD_DFL_NOCOPY,
};
int i, err;
+ int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ WOWLAN_PATTERNS,
+ IWL_FW_CMD_VER_UNKNOWN);

if (!wowlan->n_patterns)
return 0;
@@ -408,11 +413,13 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
cmd.len[0] = sizeof(*pattern_cmd) +
wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern_v2);

- pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+ pattern_cmd = kzalloc(cmd.len[0], GFP_KERNEL);
if (!pattern_cmd)
return -ENOMEM;

- pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+ pattern_cmd->n_patterns = wowlan->n_patterns;
+ if (ver >= 3)
+ pattern_cmd->sta_id = mvmvif->ap_sta_id;

for (i = 0; i < wowlan->n_patterns; i++) {
int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
@@ -887,7 +894,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,

if (fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE))
- ret = iwl_mvm_send_patterns(mvm, wowlan);
+ ret = iwl_mvm_send_patterns(mvm, vif, wowlan);
else
ret = iwl_mvm_send_patterns_v1(mvm, wowlan);
if (ret)
--
2.32.0

2021-06-21 07:38:49

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 3/9] iwlwifi: mvm: introduce iwl_wowlan_get_status_cmd

From: Emmanuel Grumbach <[email protected]>

We need to pass the station id to teach the firmware on which
station id we want to get the status.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
.../net/wireless/intel/iwlwifi/fw/api/d3.h | 4 +++
drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 31 ++++++++++++++-----
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 -
3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
index ea2bd34e32a3..b2e7ef3ddc88 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
@@ -496,6 +496,10 @@ struct iwl_wowlan_kek_kck_material_cmd_v4 {
__le32 bigtk_cipher;
} __packed; /* KEK_KCK_MATERIAL_API_S_VER_4 */

+struct iwl_wowlan_get_status_cmd {
+ __le32 sta_id;
+} __packed; /* WOWLAN_GET_STATUSES_CMD_API_S_VER_1 */
+
#define RF_KILL_INDICATOR_FOR_WOWLAN 0x87

enum iwl_wowlan_rekey_status {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 0777a709740b..6a259d867d90 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1612,15 +1612,27 @@ iwl_mvm_parse_wowlan_status_common(v6)
iwl_mvm_parse_wowlan_status_common(v7)
iwl_mvm_parse_wowlan_status_common(v9)

-struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm)
+static struct iwl_wowlan_status *
+iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
{
struct iwl_wowlan_status *status;
+ struct iwl_wowlan_get_status_cmd get_status_cmd = {
+ .sta_id = cpu_to_le32(sta_id),
+ };
struct iwl_host_cmd cmd = {
.id = WOWLAN_GET_STATUSES,
.flags = CMD_WANT_SKB,
+ .data = { &get_status_cmd, },
+ .len = { sizeof(get_status_cmd), },
};
int ret, len;
u8 notif_ver;
+ u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ WOWLAN_GET_STATUSES,
+ IWL_FW_CMD_VER_UNKNOWN);
+
+ if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN)
+ cmd.len[0] = 0;

lockdep_assert_held(&mvm->mutex);

@@ -1708,32 +1720,37 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm)
}

static struct iwl_wowlan_status *
-iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm)
+iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, u8 sta_id)
{
- int ret;
+ u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP,
+ OFFLOADS_QUERY_CMD,
+ IWL_FW_CMD_VER_UNKNOWN);
+ __le32 station_id = cpu_to_le32(sta_id);
+ u32 cmd_size = cmd_ver != IWL_FW_CMD_VER_UNKNOWN ? sizeof(station_id) : 0;

if (!mvm->net_detect) {
/* only for tracing for now */
int ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0,
- 0, NULL);
+ cmd_size, &station_id);
if (ret)
IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret);
}

- return iwl_mvm_send_wowlan_get_status(mvm);
+ return iwl_mvm_send_wowlan_get_status(mvm, sta_id);
}

/* releases the MVM mutex */
static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
struct ieee80211_vif *vif)
{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_wowlan_status_data status;
struct iwl_wowlan_status *fw_status;
int i;
bool keep;
struct iwl_mvm_sta *mvm_ap_sta;

- fw_status = iwl_mvm_get_wakeup_status(mvm);
+ fw_status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id);
if (IS_ERR_OR_NULL(fw_status))
goto out_unlock;

@@ -1911,7 +1928,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm,
u32 reasons = 0;
int i, n_matches, ret;

- fw_status = iwl_mvm_get_wakeup_status(mvm);
+ fw_status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA);
if (!IS_ERR_OR_NULL(fw_status)) {
reasons = le32_to_cpu(fw_status->wakeup_reasons);
kfree(fw_status);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index b0223f1c52f2..7be747738016 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1795,7 +1795,6 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int idx);
extern const struct file_operations iwl_dbgfs_d3_test_ops;
-struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm);
#ifdef CONFIG_PM
void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
--
2.32.0

2021-06-21 07:39:09

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 2/9] iwlwifi: mvm: introduce iwl_wowlan_kek_kck_material_cmd_v4

From: Emmanuel Grumbach <[email protected]>

We need to pass the station id to teach the firmware on which
station id we want to configure the key material.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
.../net/wireless/intel/iwlwifi/fw/api/d3.h | 13 ++++++++
drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 30 +++++++++++++------
2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
index 4dbf24128a98..ea2bd34e32a3 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
@@ -483,6 +483,19 @@ struct iwl_wowlan_kek_kck_material_cmd_v3 {
__le32 bigtk_cipher;
} __packed; /* KEK_KCK_MATERIAL_API_S_VER_3 */

+struct iwl_wowlan_kek_kck_material_cmd_v4 {
+ __le32 sta_id;
+ u8 kck[IWL_KCK_MAX_SIZE];
+ u8 kek[IWL_KEK_MAX_SIZE];
+ __le16 kck_len;
+ __le16 kek_len;
+ __le64 replay_ctr;
+ __le32 akm;
+ __le32 gtk_cipher;
+ __le32 igtk_cipher;
+ __le32 bigtk_cipher;
+} __packed; /* KEK_KCK_MATERIAL_API_S_VER_4 */
+
#define RF_KILL_INDICATOR_FOR_WOWLAN 0x87

enum iwl_wowlan_rekey_status {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 8e5814a3b178..0777a709740b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -104,7 +104,7 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key,
struct wowlan_key_data {
struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
struct iwl_wowlan_tkip_params_cmd *tkip;
- struct iwl_wowlan_kek_kck_material_cmd_v3 *kek_kck_cmd;
+ struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd;
bool error, use_rsc_tsc, use_tkip, configure_keys;
int wep_key_idx;
};
@@ -716,7 +716,8 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
u32 cmd_flags)
{
- struct iwl_wowlan_kek_kck_material_cmd_v3 kek_kck_cmd = {};
+ struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {};
+ struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd;
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
bool unified = fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
@@ -725,7 +726,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
.use_rsc_tsc = false,
.tkip = &tkip_cmd,
.use_tkip = false,
- .kek_kck_cmd = &kek_kck_cmd,
+ .kek_kck_cmd = _kek_kck_cmd,
};
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
@@ -819,13 +820,9 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
IWL_ALWAYS_LONG_GROUP,
WOWLAN_KEK_KCK_MATERIAL,
IWL_FW_CMD_VER_UNKNOWN);
- if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 &&
+ if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && cmd_ver != 4 &&
cmd_ver != IWL_FW_CMD_VER_UNKNOWN))
return -EINVAL;
- if (cmd_ver == 3)
- cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3);
- else
- cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2);

memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck,
mvmvif->rekey_data.kck_len);
@@ -835,6 +832,21 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len);
kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr;
kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm);
+ kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->ap_sta_id);
+
+ if (cmd_ver == 4) {
+ cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4);
+ } else {
+ if (cmd_ver == 3)
+ cmd_size =
+ sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3);
+ else
+ cmd_size =
+ sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2);
+ /* skip the sta_id at the beginning */
+ _kek_kck_cmd = (void *)
+ ((u8 *)_kek_kck_cmd) + sizeof(kek_kck_cmd.sta_id);
+ }

IWL_DEBUG_WOWLAN(mvm, "setting akm %d\n",
mvmvif->rekey_data.akm);
@@ -842,7 +854,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
ret = iwl_mvm_send_cmd_pdu(mvm,
WOWLAN_KEK_KCK_MATERIAL, cmd_flags,
cmd_size,
- &kek_kck_cmd);
+ _kek_kck_cmd);
if (ret)
goto out;
}
--
2.32.0

2021-06-21 07:41:02

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 4/9] iwlwifi: move UEFI code to a separate file

From: Luca Coelho <[email protected]>

We are going to read more variables from UEFI, so it's cleaner to have
all the code that handles UEFI variables in a separate file.

Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/Makefile | 1 +
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 105 +++++--------------
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 64 +++++++++++
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 25 +++++
4 files changed, 114 insertions(+), 81 deletions(-)
create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/uefi.c
create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/uefi.h

diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile
index c033caa0eaa9..12ce156c2e9d 100644
--- a/drivers/net/wireless/intel/iwlwifi/Makefile
+++ b/drivers/net/wireless/intel/iwlwifi/Makefile
@@ -19,6 +19,7 @@ iwlwifi-objs += fw/img.o fw/notif-wait.o
iwlwifi-objs += fw/dbg.o fw/pnvm.o
iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o
iwlwifi-$(CONFIG_ACPI) += fw/acpi.o
+iwlwifi-$(CONFIG_EFI) += fw/uefi.o
iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o

iwlwifi-objs += $(iwlwifi-m)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
index 40f2109a097f..565c19475155 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
@@ -10,13 +10,22 @@
#include "fw/api/commands.h"
#include "fw/api/nvm-reg.h"
#include "fw/api/alive.h"
-#include <linux/efi.h>
+#include "fw/uefi.h"

struct iwl_pnvm_section {
__le32 offset;
const u8 data[];
} __packed;

+struct pnvm_sku_package {
+ u8 rev;
+ u8 reserved1[3];
+ u32 total_size;
+ u8 n_skus;
+ u8 reserved2[11];
+ u8 data[];
+};
+
static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait,
struct iwl_rx_packet *pkt, void *data)
{
@@ -220,83 +229,6 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
return -ENOENT;
}

-#if defined(CONFIG_EFI)
-
-#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \
- 0xb2, 0xec, 0xf5, 0xa3, \
- 0x59, 0x4f, 0x4a, 0xea)
-
-#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm"
-
-#define IWL_HARDCODED_PNVM_SIZE 4096
-
-struct pnvm_sku_package {
- u8 rev;
- u8 reserved1[3];
- u32 total_size;
- u8 n_skus;
- u8 reserved2[11];
- u8 data[];
-};
-
-static int iwl_pnvm_get_from_efi(struct iwl_trans *trans,
- u8 **data, size_t *len)
-{
- struct efivar_entry *pnvm_efivar;
- struct pnvm_sku_package *package;
- unsigned long package_size;
- int err;
-
- pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL);
- if (!pnvm_efivar)
- return -ENOMEM;
-
- memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME,
- sizeof(IWL_UEFI_OEM_PNVM_NAME));
- pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
-
- /*
- * TODO: we hardcode a maximum length here, because reading
- * from the UEFI is not working. To implement this properly,
- * we have to call efivar_entry_size().
- */
- package_size = IWL_HARDCODED_PNVM_SIZE;
-
- package = kmalloc(package_size, GFP_KERNEL);
- if (!package) {
- err = -ENOMEM;
- goto out;
- }
-
- err = efivar_entry_get(pnvm_efivar, NULL, &package_size, package);
- if (err) {
- IWL_DEBUG_FW(trans,
- "PNVM UEFI variable not found %d (len %lu)\n",
- err, package_size);
- goto out;
- }
-
- IWL_DEBUG_FW(trans, "Read PNVM fro UEFI with size %lu\n", package_size);
-
- *data = kmemdup(package->data, *len, GFP_KERNEL);
- if (!*data)
- err = -ENOMEM;
- *len = package_size - sizeof(*package);
-
-out:
- kfree(package);
- kfree(pnvm_efivar);
-
- return err;
-}
-#else /* CONFIG_EFI */
-static inline int iwl_pnvm_get_from_efi(struct iwl_trans *trans,
- u8 **data, size_t *len)
-{
- return -EOPNOTSUPP;
-}
-#endif /* CONFIG_EFI */
-
static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len)
{
const struct firmware *pnvm;
@@ -335,6 +267,7 @@ int iwl_pnvm_load(struct iwl_trans *trans,
{
u8 *data;
size_t len;
+ struct pnvm_sku_package *package;
struct iwl_notification_wait pnvm_wait;
static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
PNVM_INIT_COMPLETE_NTFY) };
@@ -356,9 +289,19 @@ int iwl_pnvm_load(struct iwl_trans *trans,
}

/* First attempt to get the PNVM from BIOS */
- ret = iwl_pnvm_get_from_efi(trans, &data, &len);
- if (!ret)
- goto parse;
+ package = iwl_uefi_get_pnvm(trans, &len);
+ if (!IS_ERR_OR_NULL(package)) {
+ data = kmemdup(package->data, len, GFP_KERNEL);
+
+ /* free package regardless of whether kmemdup succeeded */
+ kfree(package);
+
+ if (data) {
+ /* we need only the data size */
+ len -= sizeof(*package);
+ goto parse;
+ }
+ }

/* If it's not available, try from the filesystem */
ret = iwl_pnvm_get_from_fs(trans, &data, &len);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
new file mode 100644
index 000000000000..bdcdca178eda
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright(c) 2021 Intel Corporation
+ */
+
+#include "iwl-drv.h"
+#include "pnvm.h"
+#include "iwl-prph.h"
+#include "iwl-io.h"
+
+#include "fw/uefi.h"
+#include <linux/efi.h>
+
+#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \
+ 0xb2, 0xec, 0xf5, 0xa3, \
+ 0x59, 0x4f, 0x4a, 0xea)
+
+void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
+{
+ struct efivar_entry *pnvm_efivar;
+ void *data;
+ unsigned long package_size;
+ int err;
+
+ pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL);
+ if (!pnvm_efivar)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME,
+ sizeof(IWL_UEFI_OEM_PNVM_NAME));
+ pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
+
+ /*
+ * TODO: we hardcode a maximum length here, because reading
+ * from the UEFI is not working. To implement this properly,
+ * we have to call efivar_entry_size().
+ */
+ package_size = IWL_HARDCODED_PNVM_SIZE;
+
+ data = kmalloc(package_size, GFP_KERNEL);
+ if (!data) {
+ data = ERR_PTR(-ENOMEM);
+ *len = 0;
+ goto out;
+ }
+
+ err = efivar_entry_get(pnvm_efivar, NULL, &package_size, data);
+ if (err) {
+ IWL_DEBUG_FW(trans,
+ "PNVM UEFI variable not found %d (len %zd)\n",
+ err, package_size);
+ kfree(data);
+ data = ERR_PTR(err);
+ goto out;
+ }
+
+ IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %zd\n", package_size);
+ *len = package_size;
+
+out:
+ kfree(pnvm_efivar);
+
+ return data;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
new file mode 100644
index 000000000000..48f1b54e3e76
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright(c) 2021 Intel Corporation
+ */
+
+
+#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm"
+
+/*
+ * TODO: we have these hardcoded values that the caller must pass,
+ * because reading from the UEFI is not working. To implement this
+ * properly, we have to change iwl_pnvm_get_from_uefi() to call
+ * efivar_entry_size() and return the value to the caller instead.
+ */
+#define IWL_HARDCODED_PNVM_SIZE 4096
+
+#ifdef CONFIG_EFI
+void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len);
+#else /* CONFIG_EFI */
+static inline
+void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+#endif /* CONFIG_EFI */
--
2.32.0

2021-06-21 07:41:03

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 5/9] iwlwifi: support loading the reduced power table from UEFI

From: Luca Coelho <[email protected]>

This new feature allows OEMs to set a special reduced power table in a
UEFI variable, which we use to tell the firmware to change the TX
power tables.

Read the variable and store it in a dram block to pass it to the
firmware. We do this as part of the PNVM loading flow.

Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 +-
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 33 ++-
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 200 +++++++++++++++++-
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 21 +-
.../intel/iwlwifi/iwl-context-info-gen3.h | 16 +-
.../net/wireless/intel/iwlwifi/iwl-trans.h | 17 ++
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 34 +++
.../wireless/intel/iwlwifi/pcie/internal.h | 1 +
.../net/wireless/intel/iwlwifi/pcie/trans.c | 7 +
9 files changed, 318 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index ef1a24504c8b..74e25a6ecc3d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -52,7 +52,8 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_INIT_DATA = 4,
IWL_UCODE_TLV_BOOT = 5,
IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */
- IWL_UCODE_TLV_PAN = 7,
+ IWL_UCODE_TLV_PAN = 7, /* deprecated -- only used in DVM */
+ IWL_UCODE_TLV_MEM_DESC = 7, /* replaces PAN in non-DVM */
IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8,
IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9,
IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
index 565c19475155..2403490cbc26 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
@@ -17,15 +17,6 @@ struct iwl_pnvm_section {
const u8 data[];
} __packed;

-struct pnvm_sku_package {
- u8 rev;
- u8 reserved1[3];
- u32 total_size;
- u8 n_skus;
- u8 reserved2[11];
- u8 data[];
-};
-
static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait,
struct iwl_rx_packet *pkt, void *data)
{
@@ -322,6 +313,30 @@ int iwl_pnvm_load(struct iwl_trans *trans,
kfree(data);

skip_parse:
+ data = NULL;
+ /* now try to get the reduce power table, if not loaded yet */
+ if (!trans->reduce_power_loaded) {
+ data = iwl_uefi_get_reduced_power(trans, &len);
+ if (IS_ERR_OR_NULL(data)) {
+ /*
+ * Pretend we've loaded it - at least we've tried and
+ * couldn't load it at all, so there's no point in
+ * trying again over and over.
+ */
+ trans->reduce_power_loaded = true;
+
+ goto skip_reduce_power;
+ }
+ }
+
+ ret = iwl_trans_set_reduce_power(trans, data, len);
+ if (ret)
+ IWL_DEBUG_FW(trans,
+ "Failed to set reduce power table %d\n",
+ ret);
+ kfree(data);
+
+skip_reduce_power:
iwl_init_notification_wait(notif_wait, &pnvm_wait,
ntf_cmds, ARRAY_SIZE(ntf_cmds),
iwl_pnvm_complete_fn, trans);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index bdcdca178eda..a7c79d814aa4 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -9,6 +9,7 @@
#include "iwl-io.h"

#include "fw/uefi.h"
+#include "fw/api/alive.h"
#include <linux/efi.h>

#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \
@@ -22,6 +23,8 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
unsigned long package_size;
int err;

+ *len = 0;
+
pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL);
if (!pnvm_efivar)
return ERR_PTR(-ENOMEM);
@@ -40,7 +43,6 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
data = kmalloc(package_size, GFP_KERNEL);
if (!data) {
data = ERR_PTR(-ENOMEM);
- *len = 0;
goto out;
}

@@ -62,3 +64,199 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)

return data;
}
+
+static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
+ const u8 *data, size_t len)
+{
+ struct iwl_ucode_tlv *tlv;
+ u8 *reduce_power_data = NULL, *tmp;
+ u32 size = 0;
+
+ IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n");
+
+ while (len >= sizeof(*tlv)) {
+ u32 tlv_len, tlv_type;
+
+ len -= sizeof(*tlv);
+ tlv = (void *)data;
+
+ tlv_len = le32_to_cpu(tlv->length);
+ tlv_type = le32_to_cpu(tlv->type);
+
+ if (len < tlv_len) {
+ IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
+ len, tlv_len);
+ reduce_power_data = ERR_PTR(-EINVAL);
+ goto out;
+ }
+
+ data += sizeof(*tlv);
+
+ switch (tlv_type) {
+ case IWL_UCODE_TLV_MEM_DESC: {
+ IWL_DEBUG_FW(trans,
+ "Got IWL_UCODE_TLV_MEM_DESC len %d\n",
+ tlv_len);
+
+ IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len);
+
+ tmp = krealloc(reduce_power_data, size + tlv_len, GFP_KERNEL);
+ if (!tmp) {
+ IWL_DEBUG_FW(trans,
+ "Couldn't allocate (more) reduce_power_data\n");
+
+ reduce_power_data = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ reduce_power_data = tmp;
+
+ memcpy(reduce_power_data + size, data, tlv_len);
+
+ size += tlv_len;
+
+ break;
+ }
+ case IWL_UCODE_TLV_PNVM_SKU:
+ IWL_DEBUG_FW(trans,
+ "New REDUCE_POWER section started, stop parsing.\n");
+ goto done;
+ default:
+ IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n",
+ tlv_type, tlv_len);
+ break;
+ }
+
+ len -= ALIGN(tlv_len, 4);
+ data += ALIGN(tlv_len, 4);
+ }
+
+done:
+ if (!size) {
+ IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n");
+ reduce_power_data = ERR_PTR(-ENOENT);
+ goto out;
+ }
+
+ IWL_INFO(trans, "loaded REDUCE_POWER\n");
+
+out:
+ return reduce_power_data;
+}
+
+static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
+ const u8 *data, size_t len)
+{
+ struct iwl_ucode_tlv *tlv;
+ void *sec_data;
+
+ IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n");
+
+ while (len >= sizeof(*tlv)) {
+ u32 tlv_len, tlv_type;
+
+ len -= sizeof(*tlv);
+ tlv = (void *)data;
+
+ tlv_len = le32_to_cpu(tlv->length);
+ tlv_type = le32_to_cpu(tlv->type);
+
+ if (len < tlv_len) {
+ IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
+ len, tlv_len);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) {
+ struct iwl_sku_id *sku_id =
+ (void *)(data + sizeof(*tlv));
+
+ IWL_DEBUG_FW(trans,
+ "Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
+ tlv_len);
+ IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
+ le32_to_cpu(sku_id->data[0]),
+ le32_to_cpu(sku_id->data[1]),
+ le32_to_cpu(sku_id->data[2]));
+
+ data += sizeof(*tlv) + ALIGN(tlv_len, 4);
+ len -= ALIGN(tlv_len, 4);
+
+ if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) &&
+ trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) &&
+ trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) {
+ sec_data = iwl_uefi_reduce_power_section(trans,
+ data,
+ len);
+ if (!IS_ERR(sec_data))
+ return sec_data;
+ } else {
+ IWL_DEBUG_FW(trans, "SKU ID didn't match!\n");
+ }
+ } else {
+ data += sizeof(*tlv) + ALIGN(tlv_len, 4);
+ len -= ALIGN(tlv_len, 4);
+ }
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
+{
+ struct efivar_entry *reduce_power_efivar;
+ struct pnvm_sku_package *package;
+ void *data = NULL;
+ unsigned long package_size;
+ int err;
+
+ *len = 0;
+
+ reduce_power_efivar = kzalloc(sizeof(*reduce_power_efivar), GFP_KERNEL);
+ if (!reduce_power_efivar)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(&reduce_power_efivar->var.VariableName, IWL_UEFI_REDUCED_POWER_NAME,
+ sizeof(IWL_UEFI_REDUCED_POWER_NAME));
+ reduce_power_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
+
+ /*
+ * TODO: we hardcode a maximum length here, because reading
+ * from the UEFI is not working. To implement this properly,
+ * we have to call efivar_entry_size().
+ */
+ package_size = IWL_HARDCODED_REDUCE_POWER_SIZE;
+
+ package = kmalloc(package_size, GFP_KERNEL);
+ if (!package) {
+ package = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ err = efivar_entry_get(reduce_power_efivar, NULL, &package_size, package);
+ if (err) {
+ IWL_DEBUG_FW(trans,
+ "Reduced Power UEFI variable not found %d (len %lu)\n",
+ err, package_size);
+ kfree(package);
+ data = ERR_PTR(err);
+ goto out;
+ }
+
+ IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n",
+ package_size);
+ *len = package_size;
+
+ IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n",
+ package->rev, package->total_size, package->n_skus);
+
+ data = iwl_uefi_reduce_power_parse(trans, package->data,
+ *len - sizeof(*package));
+
+ kfree(package);
+
+out:
+ kfree(reduce_power_efivar);
+
+ return data;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 48f1b54e3e76..45d0b36d79b5 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -4,7 +4,8 @@
*/


-#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm"
+#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm"
+#define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower"

/*
* TODO: we have these hardcoded values that the caller must pass,
@@ -12,14 +13,30 @@
* properly, we have to change iwl_pnvm_get_from_uefi() to call
* efivar_entry_size() and return the value to the caller instead.
*/
-#define IWL_HARDCODED_PNVM_SIZE 4096
+#define IWL_HARDCODED_PNVM_SIZE 4096
+#define IWL_HARDCODED_REDUCE_POWER_SIZE 32768
+
+struct pnvm_sku_package {
+ u8 rev;
+ u32 total_size;
+ u8 n_skus;
+ u32 reserved[2];
+ u8 data[];
+} __packed;

#ifdef CONFIG_EFI
void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len);
+void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len);
#else /* CONFIG_EFI */
static inline
void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
{
return ERR_PTR(-EOPNOTSUPP);
}
+
+static inline
+void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
#endif /* CONFIG_EFI */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index 518a1bc79584..e1fec23ac07f 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -127,6 +127,17 @@ struct iwl_prph_scratch_rbd_cfg {
__le32 reserved;
} __packed; /* PERIPH_SCRATCH_RBD_CFG_S */

+/*
+ * struct iwl_prph_scratch_uefi_cfg - prph scratch reduce power table
+ * @base_addr: reduce power table address
+ * @size: table size in dwords
+ */
+struct iwl_prph_scratch_uefi_cfg {
+ __le64 base_addr;
+ __le32 size;
+ __le32 reserved;
+} __packed; /* PERIPH_SCRATCH_UEFI_CFG_S */
+
/*
* struct iwl_prph_scratch_ctrl_cfg - prph scratch ctrl and config
* @version: version information of context info and HW
@@ -141,6 +152,7 @@ struct iwl_prph_scratch_ctrl_cfg {
struct iwl_prph_scratch_pnvm_cfg pnvm_cfg;
struct iwl_prph_scratch_hwm_cfg hwm_cfg;
struct iwl_prph_scratch_rbd_cfg rbd_cfg;
+ struct iwl_prph_scratch_uefi_cfg reduce_power_cfg;
} __packed; /* PERIPH_SCRATCH_CTRL_CFG_S */

/*
@@ -151,7 +163,7 @@ struct iwl_prph_scratch_ctrl_cfg {
*/
struct iwl_prph_scratch {
struct iwl_prph_scratch_ctrl_cfg ctrl_cfg;
- __le32 reserved[16];
+ __le32 reserved[12];
struct iwl_context_info_dram dram;
} __packed; /* PERIPH_SCRATCH_S */

@@ -249,5 +261,7 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive);

int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
const void *data, u32 len);
+int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
+ const void *data, u32 len);

#endif /* __iwl_context_info_file_gen3_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index a642f5920146..81868d92ef66 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -589,6 +589,8 @@ struct iwl_trans_ops {
void (*debugfs_cleanup)(struct iwl_trans *trans);
void (*sync_nmi)(struct iwl_trans *trans);
int (*set_pnvm)(struct iwl_trans *trans, const void *data, u32 len);
+ int (*set_reduce_power)(struct iwl_trans *trans,
+ const void *data, u32 len);
void (*interrupts)(struct iwl_trans *trans, bool enable);
};

@@ -959,6 +961,7 @@ struct iwl_trans {
bool pm_support;
bool ltr_enabled;
u8 pnvm_loaded:1;
+ u8 reduce_power_loaded:1;

const struct iwl_hcmd_arr *command_groups;
int command_groups_size;
@@ -1422,6 +1425,20 @@ static inline int iwl_trans_set_pnvm(struct iwl_trans *trans,
return 0;
}

+static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans,
+ const void *data, u32 len)
+{
+ if (trans->ops->set_reduce_power) {
+ int ret = trans->ops->set_reduce_power(trans, data, len);
+
+ if (ret)
+ return ret;
+ }
+
+ trans->reduce_power_loaded = true;
+ return 0;
+}
+
static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans)
{
return trans->dbg.internal_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED ||
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index c69a1541e678..239a722cd79d 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -302,3 +302,37 @@ int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,

return 0;
}
+
+int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
+ const void *data, u32 len)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
+ &trans_pcie->prph_scratch->ctrl_cfg;
+ int ret;
+
+ if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
+ return 0;
+
+ /* only allocate the DRAM if not allocated yet */
+ if (!trans->reduce_power_loaded) {
+ if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size))
+ return -EBUSY;
+
+ ret = iwl_pcie_ctxt_info_alloc_dma(trans, data, len,
+ &trans_pcie->reduce_power_dram);
+ if (ret < 0) {
+ IWL_DEBUG_FW(trans,
+ "Failed to allocate reduce power DMA %d.\n",
+ ret);
+ return ret;
+ }
+ }
+
+ prph_sc_ctrl->reduce_power_cfg.base_addr =
+ cpu_to_le64(trans_pcie->reduce_power_dram.physical);
+ prph_sc_ctrl->reduce_power_cfg.size =
+ cpu_to_le32(trans_pcie->reduce_power_dram.size);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index 69289e9f8d7e..cc550f6ef957 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -349,6 +349,7 @@ struct iwl_trans_pcie {
struct iwl_dma_ptr kw;

struct iwl_dram_data pnvm_dram;
+ struct iwl_dram_data reduce_power_dram;

struct iwl_txq *txq_memory;

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index a4d6988b50a6..86a8448ce86a 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1955,6 +1955,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
trans_pcie->pnvm_dram.block,
trans_pcie->pnvm_dram.physical);

+ if (trans_pcie->reduce_power_dram.size)
+ dma_free_coherent(trans->dev,
+ trans_pcie->reduce_power_dram.size,
+ trans_pcie->reduce_power_dram.block,
+ trans_pcie->reduce_power_dram.physical);
+
mutex_destroy(&trans_pcie->mutex);
iwl_trans_free(trans);
}
@@ -3430,6 +3436,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = {
.wait_txq_empty = iwl_trans_pcie_wait_txq_empty,
.rxq_dma_data = iwl_trans_pcie_rxq_dma_data,
.set_pnvm = iwl_trans_pcie_ctx_info_gen3_set_pnvm,
+ .set_reduce_power = iwl_trans_pcie_ctx_info_gen3_set_reduce_power,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup,
#endif
--
2.32.0

2021-06-21 07:41:07

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 8/9] iwlwifi: fw: dump TCM error table if present

From: Johannes Berg <[email protected]>

If the TCM is present in the hardware (as advertised in the firmware
file TLV data), dump its error log table during firmware error dumps.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/dump.c | 60 +++++++++++++++++++
drivers/net/wireless/intel/iwlwifi/fw/file.h | 5 ++
drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 11 ++++
.../net/wireless/intel/iwlwifi/iwl-trans.h | 3 +
4 files changed, 79 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
index 66f86d2a7cca..a1842205e86a 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
@@ -271,6 +271,65 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu
IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler);
}

+/*
+ * TCM error struct.
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_tcm_error_event_table {
+ u32 valid;
+ u32 error_id;
+ u32 blink2;
+ u32 ilink1;
+ u32 ilink2;
+ u32 data1, data2, data3;
+ u32 logpc;
+ u32 frame_pointer;
+ u32 stack_pointer;
+ u32 msgid;
+ u32 isr;
+ u32 hw_status[5];
+ u32 sw_status[1];
+ u32 reserved[4];
+} __packed; /* TCM_LOG_ERROR_TABLE_API_S_VER_1 */
+
+static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ struct iwl_tcm_error_event_table table = {};
+ u32 base = fwrt->trans->dbg.tcm_error_event_table;
+ int i;
+
+ if (!base ||
+ !(fwrt->trans->dbg.error_event_table_tlv_status &
+ IWL_ERROR_EVENT_TABLE_TCM))
+ return;
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ IWL_ERR(fwrt, "TCM status:\n");
+ IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id);
+ IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2);
+ IWL_ERR(fwrt, "0x%08X | tcm interruptlink1\n", table.ilink1);
+ IWL_ERR(fwrt, "0x%08X | tcm interruptlink2\n", table.ilink2);
+ IWL_ERR(fwrt, "0x%08X | tcm data1\n", table.data1);
+ IWL_ERR(fwrt, "0x%08X | tcm data2\n", table.data2);
+ IWL_ERR(fwrt, "0x%08X | tcm data3\n", table.data3);
+ IWL_ERR(fwrt, "0x%08X | tcm log PC\n", table.logpc);
+ IWL_ERR(fwrt, "0x%08X | tcm frame pointer\n", table.frame_pointer);
+ IWL_ERR(fwrt, "0x%08X | tcm stack pointer\n", table.stack_pointer);
+ IWL_ERR(fwrt, "0x%08X | tcm msg ID\n", table.msgid);
+ IWL_ERR(fwrt, "0x%08X | tcm ISR status\n", table.isr);
+ for (i = 0; i < ARRAY_SIZE(table.hw_status); i++)
+ IWL_ERR(fwrt, "0x%08X | tcm HW status[%d]\n",
+ table.hw_status[i], i);
+ for (i = 0; i < ARRAY_SIZE(table.sw_status); i++)
+ IWL_ERR(fwrt, "0x%08X | tcm SW status[%d]\n",
+ table.sw_status[i], i);
+}
+
static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt)
{
struct iwl_trans *trans = fwrt->trans;
@@ -352,6 +411,7 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
if (fwrt->trans->dbg.lmac_error_event_table[1])
iwl_fwrt_dump_lmac_error_log(fwrt, 1);
iwl_fwrt_dump_umac_error_log(fwrt);
+ iwl_fwrt_dump_tcm_error_log(fwrt);
iwl_fwrt_dump_iml_error_log(fwrt);
iwl_fwrt_dump_fseq_regs(fwrt);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index 74e25a6ecc3d..9a8c7b7a0816 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -98,6 +98,7 @@ enum iwl_ucode_tlv_type {

IWL_UCODE_TLV_PNVM_VERSION = 62,
IWL_UCODE_TLV_PNVM_SKU = 64,
+ IWL_UCODE_TLV_TCM_DEBUG_ADDRS = 65,

IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0,

@@ -950,6 +951,10 @@ struct iwl_fw_cmd_version {
u8 notif_ver;
} __packed;

+struct iwl_fw_tcm_error_addr {
+ __le32 addr;
+}; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */
+
static inline size_t _iwl_tlv_array_len(const struct iwl_ucode_tlv *tlv,
size_t fixed_size, size_t var_size)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index 884750bf7840..977dce686bdb 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1117,6 +1117,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
IWL_ERROR_EVENT_TABLE_LMAC1;
break;
}
+ case IWL_UCODE_TLV_TCM_DEBUG_ADDRS: {
+ struct iwl_fw_tcm_error_addr *ptr = (void *)tlv_data;
+
+ if (tlv_len != sizeof(*ptr))
+ goto invalid_tlv_len;
+ drv->trans->dbg.tcm_error_event_table =
+ le32_to_cpu(ptr->addr) & ~FW_ADDR_CACHE_CONTROL;
+ drv->trans->dbg.error_event_table_tlv_status |=
+ IWL_ERROR_EVENT_TABLE_TCM;
+ break;
+ }
case IWL_UCODE_TLV_TYPE_DEBUG_INFO:
case IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION:
case IWL_UCODE_TLV_TYPE_HCMD:
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 81868d92ef66..942c6f3f8d3f 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -193,6 +193,7 @@ enum iwl_error_event_table_status {
IWL_ERROR_EVENT_TABLE_LMAC1 = BIT(0),
IWL_ERROR_EVENT_TABLE_LMAC2 = BIT(1),
IWL_ERROR_EVENT_TABLE_UMAC = BIT(2),
+ IWL_ERROR_EVENT_TABLE_TCM = BIT(3),
};

/**
@@ -708,6 +709,7 @@ struct iwl_self_init_dram {
* @trigger_tlv: array of pointers to triggers TLVs for debug
* @lmac_error_event_table: addrs of lmacs error tables
* @umac_error_event_table: addr of umac error table
+ * @tcm_error_event_table: address of TCM error table
* @error_event_table_tlv_status: bitmap that indicates what error table
* pointers was recevied via TLV. uses enum &iwl_error_event_table_status
* @internal_ini_cfg: internal debug cfg state. Uses &enum iwl_ini_cfg_state
@@ -734,6 +736,7 @@ struct iwl_trans_debug {

u32 lmac_error_event_table[2];
u32 umac_error_event_table;
+ u32 tcm_error_event_table;
unsigned int error_event_table_tlv_status;

enum iwl_ini_cfg_state internal_ini_cfg;
--
2.32.0

2021-06-21 07:41:08

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 7/9] iwlwifi: add 9560 killer device

From: ybaruch <[email protected]>

add new killer devices configurations.

Signed-off-by: ybaruch <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 6 +++++-
drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 ++
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 ++
3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
index df1297358379..871533beff30 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*/
#include <linux/module.h>
#include <linux/stringify.h>
@@ -171,8 +171,12 @@ const char iwl9260_killer_1550_name[] =
"Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW) 160MHz";
const char iwl9560_killer_1550i_name[] =
"Killer (R) Wireless-AC 1550i Wireless Network Adapter (9560NGW)";
+const char iwl9560_killer_1550i_160_name[] =
+ "Killer(R) Wireless-AC 1550i Wireless Network Adapter (9560NGW) 160MHz";
const char iwl9560_killer_1550s_name[] =
"Killer (R) Wireless-AC 1550s Wireless Network Adapter (9560NGW)";
+const char iwl9560_killer_1550s_160_name[] =
+ "Killer(R) Wireless-AC 1550s Wireless Network Adapter (9560D2W) 160MHz";

const struct iwl_cfg iwl9260_2ac_cfg = {
.fw_name_pre = IWL9260_FW_PRE,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index 3e4c6a809595..bf6ee56d4d96 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -506,6 +506,8 @@ extern const char iwl_ax201_killer_1650s_name[];
extern const char iwl_ax201_killer_1650i_name[];
extern const char iwl_ax210_killer_1675w_name[];
extern const char iwl_ax210_killer_1675x_name[];
+extern const char iwl9560_killer_1550i_160_name[];
+extern const char iwl9560_killer_1550s_160_name[];
extern const char iwl_ax211_name[];
extern const char iwl_ax221_name[];
extern const char iwl_ax231_name[];
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index d7106a51e8bf..863c10e602d5 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -532,6 +532,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
IWL_DEV_INFO(0x31DC, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_name),
IWL_DEV_INFO(0xA370, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_name),
IWL_DEV_INFO(0xA370, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_name),
+ IWL_DEV_INFO(0x51F0, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_160_name),
+ IWL_DEV_INFO(0x51F0, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_160_name),

IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name),

--
2.32.0

2021-06-21 07:41:14

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 9/9] iwlwifi: bump FW API to 64 for AX devices

From: Luca Coelho <[email protected]>

Start supporting API version 64 for AX devices.

Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index 0256d0042f71..7f1faa9d97b4 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2021 Intel Corporation
*/
#include <linux/module.h>
#include <linux/stringify.h>
@@ -9,7 +9,7 @@
#include "iwl-prph.h"

/* Highest firmware API version supported */
-#define IWL_22000_UCODE_API_MAX 63
+#define IWL_22000_UCODE_API_MAX 64

/* Lowest firmware API version supported */
#define IWL_22000_UCODE_API_MIN 39
--
2.32.0

2021-06-21 07:41:24

by Luca Coelho

[permalink] [raw]
Subject: [PATCH 6/9] iwlwifi: move error dump to fw utils

From: Johannes Berg <[email protected]>

Conceptually, this belongs more into the firmware utils
rather than the mvm opmode, so move the collection and
output there.

Note that this slightly changes the format of the Status
line.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/Makefile | 2 +-
drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 38 --
drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 4 +-
drivers/net/wireless/intel/iwlwifi/fw/dump.c | 358 ++++++++++++++++++
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 7 +-
.../net/wireless/intel/iwlwifi/mvm/utils.c | 310 ---------------
6 files changed, 368 insertions(+), 351 deletions(-)
create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/dump.c

diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile
index 12ce156c2e9d..dab41f0fdea7 100644
--- a/drivers/net/wireless/intel/iwlwifi/Makefile
+++ b/drivers/net/wireless/intel/iwlwifi/Makefile
@@ -16,7 +16,7 @@ iwlwifi-objs += iwl-trans.o
iwlwifi-objs += queue/tx.o

iwlwifi-objs += fw/img.o fw/notif-wait.o
-iwlwifi-objs += fw/dbg.o fw/pnvm.o
+iwlwifi-objs += fw/dbg.o fw/pnvm.o fw/dump.o
iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o
iwlwifi-$(CONFIG_ACPI) += fw/acpi.o
iwlwifi-$(CONFIG_EFI) += fw/uefi.o
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index 5a534d70f253..df7c55e06f54 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -2759,44 +2759,6 @@ void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt)
}
IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_sync);

-#define FSEQ_REG(x) { .addr = (x), .str = #x, }
-
-void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt)
-{
- struct iwl_trans *trans = fwrt->trans;
- int i;
- struct {
- u32 addr;
- const char *str;
- } fseq_regs[] = {
- FSEQ_REG(FSEQ_ERROR_CODE),
- FSEQ_REG(FSEQ_TOP_INIT_VERSION),
- FSEQ_REG(FSEQ_CNVIO_INIT_VERSION),
- FSEQ_REG(FSEQ_OTP_VERSION),
- FSEQ_REG(FSEQ_TOP_CONTENT_VERSION),
- FSEQ_REG(FSEQ_ALIVE_TOKEN),
- FSEQ_REG(FSEQ_CNVI_ID),
- FSEQ_REG(FSEQ_CNVR_ID),
- FSEQ_REG(CNVI_AUX_MISC_CHIP),
- FSEQ_REG(CNVR_AUX_MISC_CHIP),
- FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM),
- FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR),
- };
-
- if (!iwl_trans_grab_nic_access(trans))
- return;
-
- IWL_ERR(fwrt, "Fseq Registers:\n");
-
- for (i = 0; i < ARRAY_SIZE(fseq_regs); i++)
- IWL_ERR(fwrt, "0x%08X | %s\n",
- iwl_read_prph_no_grab(trans, fseq_regs[i].addr),
- fseq_regs[i].str);
-
- iwl_trans_release_nic_access(trans);
-}
-IWL_EXPORT_SYMBOL(iwl_fw_error_print_fseq_regs);
-
static int iwl_fw_dbg_suspend_resume_hcmd(struct iwl_trans *trans, bool suspend)
{
struct iwl_dbg_suspend_resume_cmd cmd = {
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
index 49fa2f5f8c7e..c0e84ef84f5d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2018-2019 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2019, 2021 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -321,4 +321,6 @@ static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt,
fwrt->dump.fw_ver.umac_minor = le32_to_cpu(umac->umac_minor);
}
}
+
+void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt);
#endif /* __iwl_fw_dbg_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
new file mode 100644
index 000000000000..66f86d2a7cca
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
+ * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (C) 2015-2017 Intel Deutschland GmbH
+ */
+#include <linux/devcoredump.h>
+#include "iwl-drv.h"
+#include "runtime.h"
+#include "dbg.h"
+#include "debugfs.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+#include "iwl-csr.h"
+
+/*
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_error_event_table_v1 {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 pc; /* program counter */
+ u32 blink1; /* branch link */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 data3; /* error-specific data */
+ u32 bcon_time; /* beacon timer */
+ u32 tsf_low; /* network timestamp function timer */
+ u32 tsf_hi; /* network timestamp function timer */
+ u32 gp1; /* GP1 timer register */
+ u32 gp2; /* GP2 timer register */
+ u32 gp3; /* GP3 timer register */
+ u32 ucode_ver; /* uCode version */
+ u32 hw_ver; /* HW Silicon version */
+ u32 brd_ver; /* HW board version */
+ u32 log_pc; /* log program counter */
+ u32 frame_ptr; /* frame pointer */
+ u32 stack_ptr; /* stack pointer */
+ u32 hcmd; /* last host command header */
+ u32 isr0; /* isr status register LMPM_NIC_ISR0:
+ * rxtx_flag */
+ u32 isr1; /* isr status register LMPM_NIC_ISR1:
+ * host_flag */
+ u32 isr2; /* isr status register LMPM_NIC_ISR2:
+ * enc_flag */
+ u32 isr3; /* isr status register LMPM_NIC_ISR3:
+ * time_flag */
+ u32 isr4; /* isr status register LMPM_NIC_ISR4:
+ * wico interrupt */
+ u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
+ u32 wait_event; /* wait event() caller address */
+ u32 l2p_control; /* L2pControlField */
+ u32 l2p_duration; /* L2pDurationField */
+ u32 l2p_mhvalid; /* L2pMhValidBits */
+ u32 l2p_addr_match; /* L2pAddrMatchStat */
+ u32 lmpm_pmg_sel; /* indicate which clocks are turned on
+ * (LMPM_PMG_SEL) */
+ u32 u_timestamp; /* indicate when the date and time of the
+ * compilation */
+ u32 flow_handler; /* FH read/write pointers, RX credit */
+} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */;
+
+struct iwl_error_event_table {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 trm_hw_status0; /* TRM HW status */
+ u32 trm_hw_status1; /* TRM HW status */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 data3; /* error-specific data */
+ u32 bcon_time; /* beacon timer */
+ u32 tsf_low; /* network timestamp function timer */
+ u32 tsf_hi; /* network timestamp function timer */
+ u32 gp1; /* GP1 timer register */
+ u32 gp2; /* GP2 timer register */
+ u32 fw_rev_type; /* firmware revision type */
+ u32 major; /* uCode version major */
+ u32 minor; /* uCode version minor */
+ u32 hw_ver; /* HW Silicon version */
+ u32 brd_ver; /* HW board version */
+ u32 log_pc; /* log program counter */
+ u32 frame_ptr; /* frame pointer */
+ u32 stack_ptr; /* stack pointer */
+ u32 hcmd; /* last host command header */
+ u32 isr0; /* isr status register LMPM_NIC_ISR0:
+ * rxtx_flag */
+ u32 isr1; /* isr status register LMPM_NIC_ISR1:
+ * host_flag */
+ u32 isr2; /* isr status register LMPM_NIC_ISR2:
+ * enc_flag */
+ u32 isr3; /* isr status register LMPM_NIC_ISR3:
+ * time_flag */
+ u32 isr4; /* isr status register LMPM_NIC_ISR4:
+ * wico interrupt */
+ u32 last_cmd_id; /* last HCMD id handled by the firmware */
+ u32 wait_event; /* wait event() caller address */
+ u32 l2p_control; /* L2pControlField */
+ u32 l2p_duration; /* L2pDurationField */
+ u32 l2p_mhvalid; /* L2pMhValidBits */
+ u32 l2p_addr_match; /* L2pAddrMatchStat */
+ u32 lmpm_pmg_sel; /* indicate which clocks are turned on
+ * (LMPM_PMG_SEL) */
+ u32 u_timestamp; /* indicate when the date and time of the
+ * compilation */
+ u32 flow_handler; /* FH read/write pointers, RX credit */
+} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */;
+
+/*
+ * UMAC error struct - relevant starting from family 8000 chip.
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_umac_error_event_table {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 blink1; /* branch link */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 data3; /* error-specific data */
+ u32 umac_major;
+ u32 umac_minor;
+ u32 frame_pointer; /* core register 27*/
+ u32 stack_pointer; /* core register 28 */
+ u32 cmd_header; /* latest host cmd sent to UMAC */
+ u32 nic_isr_pref; /* ISR status register */
+} __packed;
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ struct iwl_umac_error_event_table table = {};
+ u32 base = fwrt->trans->dbg.umac_error_event_table;
+
+ if (!base &&
+ !(fwrt->trans->dbg.error_event_table_tlv_status &
+ IWL_ERROR_EVENT_TABLE_UMAC))
+ return;
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ if (table.valid)
+ fwrt->dump.umac_err_id = table.error_id;
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+ IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n",
+ fwrt->trans->status, table.valid);
+ }
+
+ IWL_ERR(fwrt, "0x%08X | %s\n", table.error_id,
+ iwl_fw_lookup_assert_desc(table.error_id));
+ IWL_ERR(fwrt, "0x%08X | umac branchlink1\n", table.blink1);
+ IWL_ERR(fwrt, "0x%08X | umac branchlink2\n", table.blink2);
+ IWL_ERR(fwrt, "0x%08X | umac interruptlink1\n", table.ilink1);
+ IWL_ERR(fwrt, "0x%08X | umac interruptlink2\n", table.ilink2);
+ IWL_ERR(fwrt, "0x%08X | umac data1\n", table.data1);
+ IWL_ERR(fwrt, "0x%08X | umac data2\n", table.data2);
+ IWL_ERR(fwrt, "0x%08X | umac data3\n", table.data3);
+ IWL_ERR(fwrt, "0x%08X | umac major\n", table.umac_major);
+ IWL_ERR(fwrt, "0x%08X | umac minor\n", table.umac_minor);
+ IWL_ERR(fwrt, "0x%08X | frame pointer\n", table.frame_pointer);
+ IWL_ERR(fwrt, "0x%08X | stack pointer\n", table.stack_pointer);
+ IWL_ERR(fwrt, "0x%08X | last host cmd\n", table.cmd_header);
+ IWL_ERR(fwrt, "0x%08X | isr status reg\n", table.nic_isr_pref);
+}
+
+static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_num)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ struct iwl_error_event_table table = {};
+ u32 val, base = fwrt->trans->dbg.lmac_error_event_table[lmac_num];
+
+ if (fwrt->cur_fw_img == IWL_UCODE_INIT) {
+ if (!base)
+ base = fwrt->fw->init_errlog_ptr;
+ } else {
+ if (!base)
+ base = fwrt->fw->inst_errlog_ptr;
+ }
+
+ if (base < 0x400000) {
+ IWL_ERR(fwrt,
+ "Not valid error log pointer 0x%08X for %s uCode\n",
+ base,
+ (fwrt->cur_fw_img == IWL_UCODE_INIT)
+ ? "Init" : "RT");
+ return;
+ }
+
+ /* check if there is a HW error */
+ val = iwl_trans_read_mem32(trans, base);
+ if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) {
+ int err;
+
+ IWL_ERR(trans, "HW error, resetting before reading\n");
+
+ /* reset the device */
+ iwl_trans_sw_reset(trans);
+
+ err = iwl_finish_nic_init(trans, trans->trans_cfg);
+ if (err)
+ return;
+ }
+
+ iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
+
+ if (table.valid)
+ fwrt->dump.lmac_err_id[lmac_num] = table.error_id;
+
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
+ IWL_ERR(trans, "Start IWL Error Log Dump:\n");
+ IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n",
+ fwrt->trans->status, table.valid);
+ }
+
+ /* Do not change this output - scripts rely on it */
+
+ IWL_ERR(fwrt, "Loaded firmware version: %s\n", fwrt->fw->fw_version);
+
+ IWL_ERR(fwrt, "0x%08X | %-28s\n", table.error_id,
+ iwl_fw_lookup_assert_desc(table.error_id));
+ IWL_ERR(fwrt, "0x%08X | trm_hw_status0\n", table.trm_hw_status0);
+ IWL_ERR(fwrt, "0x%08X | trm_hw_status1\n", table.trm_hw_status1);
+ IWL_ERR(fwrt, "0x%08X | branchlink2\n", table.blink2);
+ IWL_ERR(fwrt, "0x%08X | interruptlink1\n", table.ilink1);
+ IWL_ERR(fwrt, "0x%08X | interruptlink2\n", table.ilink2);
+ IWL_ERR(fwrt, "0x%08X | data1\n", table.data1);
+ IWL_ERR(fwrt, "0x%08X | data2\n", table.data2);
+ IWL_ERR(fwrt, "0x%08X | data3\n", table.data3);
+ IWL_ERR(fwrt, "0x%08X | beacon time\n", table.bcon_time);
+ IWL_ERR(fwrt, "0x%08X | tsf low\n", table.tsf_low);
+ IWL_ERR(fwrt, "0x%08X | tsf hi\n", table.tsf_hi);
+ IWL_ERR(fwrt, "0x%08X | time gp1\n", table.gp1);
+ IWL_ERR(fwrt, "0x%08X | time gp2\n", table.gp2);
+ IWL_ERR(fwrt, "0x%08X | uCode revision type\n", table.fw_rev_type);
+ IWL_ERR(fwrt, "0x%08X | uCode version major\n", table.major);
+ IWL_ERR(fwrt, "0x%08X | uCode version minor\n", table.minor);
+ IWL_ERR(fwrt, "0x%08X | hw version\n", table.hw_ver);
+ IWL_ERR(fwrt, "0x%08X | board version\n", table.brd_ver);
+ IWL_ERR(fwrt, "0x%08X | hcmd\n", table.hcmd);
+ IWL_ERR(fwrt, "0x%08X | isr0\n", table.isr0);
+ IWL_ERR(fwrt, "0x%08X | isr1\n", table.isr1);
+ IWL_ERR(fwrt, "0x%08X | isr2\n", table.isr2);
+ IWL_ERR(fwrt, "0x%08X | isr3\n", table.isr3);
+ IWL_ERR(fwrt, "0x%08X | isr4\n", table.isr4);
+ IWL_ERR(fwrt, "0x%08X | last cmd Id\n", table.last_cmd_id);
+ IWL_ERR(fwrt, "0x%08X | wait_event\n", table.wait_event);
+ IWL_ERR(fwrt, "0x%08X | l2p_control\n", table.l2p_control);
+ IWL_ERR(fwrt, "0x%08X | l2p_duration\n", table.l2p_duration);
+ IWL_ERR(fwrt, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
+ IWL_ERR(fwrt, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
+ IWL_ERR(fwrt, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
+ IWL_ERR(fwrt, "0x%08X | timestamp\n", table.u_timestamp);
+ IWL_ERR(fwrt, "0x%08X | flow_handler\n", table.flow_handler);
+}
+
+static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ u32 error, data1;
+
+ if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {
+ error = UMAG_SB_CPU_2_STATUS;
+ data1 = UMAG_SB_CPU_1_STATUS;
+ } else if (fwrt->trans->trans_cfg->device_family >=
+ IWL_DEVICE_FAMILY_8000) {
+ error = SB_CPU_2_STATUS;
+ data1 = SB_CPU_1_STATUS;
+ } else {
+ return;
+ }
+
+ error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS);
+
+ IWL_ERR(trans, "IML/ROM dump:\n");
+
+ if (error & 0xFFFF0000)
+ IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16);
+
+ IWL_ERR(fwrt, "0x%08X | IML/ROM error/state\n", error);
+ IWL_ERR(fwrt, "0x%08X | IML/ROM data1\n",
+ iwl_read_umac_prph(trans, data1));
+
+ if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000)
+ IWL_ERR(fwrt, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n",
+ iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG));
+}
+
+#define FSEQ_REG(x) { .addr = (x), .str = #x, }
+
+static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_trans *trans = fwrt->trans;
+ int i;
+ struct {
+ u32 addr;
+ const char *str;
+ } fseq_regs[] = {
+ FSEQ_REG(FSEQ_ERROR_CODE),
+ FSEQ_REG(FSEQ_TOP_INIT_VERSION),
+ FSEQ_REG(FSEQ_CNVIO_INIT_VERSION),
+ FSEQ_REG(FSEQ_OTP_VERSION),
+ FSEQ_REG(FSEQ_TOP_CONTENT_VERSION),
+ FSEQ_REG(FSEQ_ALIVE_TOKEN),
+ FSEQ_REG(FSEQ_CNVI_ID),
+ FSEQ_REG(FSEQ_CNVR_ID),
+ FSEQ_REG(CNVI_AUX_MISC_CHIP),
+ FSEQ_REG(CNVR_AUX_MISC_CHIP),
+ FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM),
+ FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR),
+ };
+
+ if (!iwl_trans_grab_nic_access(trans))
+ return;
+
+ IWL_ERR(fwrt, "Fseq Registers:\n");
+
+ for (i = 0; i < ARRAY_SIZE(fseq_regs); i++)
+ IWL_ERR(fwrt, "0x%08X | %s\n",
+ iwl_read_prph_no_grab(trans, fseq_regs[i].addr),
+ fseq_regs[i].str);
+
+ iwl_trans_release_nic_access(trans);
+}
+
+void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt)
+{
+ if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) {
+ IWL_ERR(fwrt,
+ "DEVICE_ENABLED bit is not set. Aborting dump.\n");
+ return;
+ }
+
+ iwl_fwrt_dump_lmac_error_log(fwrt, 0);
+ if (fwrt->trans->dbg.lmac_error_event_table[1])
+ iwl_fwrt_dump_lmac_error_log(fwrt, 1);
+ iwl_fwrt_dump_umac_error_log(fwrt);
+ iwl_fwrt_dump_iml_error_log(fwrt);
+ iwl_fwrt_dump_fseq_regs(fwrt);
+}
+IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 7be747738016..7b08a4a86cee 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1472,7 +1472,12 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
struct ieee80211_tx_rate *r);
u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx);
u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac);
-void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm);
+
+static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
+{
+ iwl_fwrt_dump_error_logs(&mvm->fwrt);
+}
+
u8 first_antenna(u8 mask);
u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx);
void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, u32 *gp2,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index 0e8ad798ab57..4a3d2971a98b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -238,316 +238,6 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx)
return last_idx;
}

-/*
- * Note: This structure is read from the device with IO accesses,
- * and the reading already does the endian conversion. As it is
- * read with u32-sized accesses, any members with a different size
- * need to be ordered correctly though!
- */
-struct iwl_error_event_table_v1 {
- u32 valid; /* (nonzero) valid, (0) log is empty */
- u32 error_id; /* type of error */
- u32 pc; /* program counter */
- u32 blink1; /* branch link */
- u32 blink2; /* branch link */
- u32 ilink1; /* interrupt link */
- u32 ilink2; /* interrupt link */
- u32 data1; /* error-specific data */
- u32 data2; /* error-specific data */
- u32 data3; /* error-specific data */
- u32 bcon_time; /* beacon timer */
- u32 tsf_low; /* network timestamp function timer */
- u32 tsf_hi; /* network timestamp function timer */
- u32 gp1; /* GP1 timer register */
- u32 gp2; /* GP2 timer register */
- u32 gp3; /* GP3 timer register */
- u32 ucode_ver; /* uCode version */
- u32 hw_ver; /* HW Silicon version */
- u32 brd_ver; /* HW board version */
- u32 log_pc; /* log program counter */
- u32 frame_ptr; /* frame pointer */
- u32 stack_ptr; /* stack pointer */
- u32 hcmd; /* last host command header */
- u32 isr0; /* isr status register LMPM_NIC_ISR0:
- * rxtx_flag */
- u32 isr1; /* isr status register LMPM_NIC_ISR1:
- * host_flag */
- u32 isr2; /* isr status register LMPM_NIC_ISR2:
- * enc_flag */
- u32 isr3; /* isr status register LMPM_NIC_ISR3:
- * time_flag */
- u32 isr4; /* isr status register LMPM_NIC_ISR4:
- * wico interrupt */
- u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
- u32 wait_event; /* wait event() caller address */
- u32 l2p_control; /* L2pControlField */
- u32 l2p_duration; /* L2pDurationField */
- u32 l2p_mhvalid; /* L2pMhValidBits */
- u32 l2p_addr_match; /* L2pAddrMatchStat */
- u32 lmpm_pmg_sel; /* indicate which clocks are turned on
- * (LMPM_PMG_SEL) */
- u32 u_timestamp; /* indicate when the date and time of the
- * compilation */
- u32 flow_handler; /* FH read/write pointers, RX credit */
-} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */;
-
-struct iwl_error_event_table {
- u32 valid; /* (nonzero) valid, (0) log is empty */
- u32 error_id; /* type of error */
- u32 trm_hw_status0; /* TRM HW status */
- u32 trm_hw_status1; /* TRM HW status */
- u32 blink2; /* branch link */
- u32 ilink1; /* interrupt link */
- u32 ilink2; /* interrupt link */
- u32 data1; /* error-specific data */
- u32 data2; /* error-specific data */
- u32 data3; /* error-specific data */
- u32 bcon_time; /* beacon timer */
- u32 tsf_low; /* network timestamp function timer */
- u32 tsf_hi; /* network timestamp function timer */
- u32 gp1; /* GP1 timer register */
- u32 gp2; /* GP2 timer register */
- u32 fw_rev_type; /* firmware revision type */
- u32 major; /* uCode version major */
- u32 minor; /* uCode version minor */
- u32 hw_ver; /* HW Silicon version */
- u32 brd_ver; /* HW board version */
- u32 log_pc; /* log program counter */
- u32 frame_ptr; /* frame pointer */
- u32 stack_ptr; /* stack pointer */
- u32 hcmd; /* last host command header */
- u32 isr0; /* isr status register LMPM_NIC_ISR0:
- * rxtx_flag */
- u32 isr1; /* isr status register LMPM_NIC_ISR1:
- * host_flag */
- u32 isr2; /* isr status register LMPM_NIC_ISR2:
- * enc_flag */
- u32 isr3; /* isr status register LMPM_NIC_ISR3:
- * time_flag */
- u32 isr4; /* isr status register LMPM_NIC_ISR4:
- * wico interrupt */
- u32 last_cmd_id; /* last HCMD id handled by the firmware */
- u32 wait_event; /* wait event() caller address */
- u32 l2p_control; /* L2pControlField */
- u32 l2p_duration; /* L2pDurationField */
- u32 l2p_mhvalid; /* L2pMhValidBits */
- u32 l2p_addr_match; /* L2pAddrMatchStat */
- u32 lmpm_pmg_sel; /* indicate which clocks are turned on
- * (LMPM_PMG_SEL) */
- u32 u_timestamp; /* indicate when the date and time of the
- * compilation */
- u32 flow_handler; /* FH read/write pointers, RX credit */
-} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */;
-
-/*
- * UMAC error struct - relevant starting from family 8000 chip.
- * Note: This structure is read from the device with IO accesses,
- * and the reading already does the endian conversion. As it is
- * read with u32-sized accesses, any members with a different size
- * need to be ordered correctly though!
- */
-struct iwl_umac_error_event_table {
- u32 valid; /* (nonzero) valid, (0) log is empty */
- u32 error_id; /* type of error */
- u32 blink1; /* branch link */
- u32 blink2; /* branch link */
- u32 ilink1; /* interrupt link */
- u32 ilink2; /* interrupt link */
- u32 data1; /* error-specific data */
- u32 data2; /* error-specific data */
- u32 data3; /* error-specific data */
- u32 umac_major;
- u32 umac_minor;
- u32 frame_pointer; /* core register 27*/
- u32 stack_pointer; /* core register 28 */
- u32 cmd_header; /* latest host cmd sent to UMAC */
- u32 nic_isr_pref; /* ISR status register */
-} __packed;
-
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-
-static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
-{
- struct iwl_trans *trans = mvm->trans;
- struct iwl_umac_error_event_table table = {};
- u32 base = mvm->trans->dbg.umac_error_event_table;
-
- if (!base &&
- !(mvm->trans->dbg.error_event_table_tlv_status &
- IWL_ERROR_EVENT_TABLE_UMAC))
- return;
-
- iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
-
- if (table.valid)
- mvm->fwrt.dump.umac_err_id = table.error_id;
-
- if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
- IWL_ERR(trans, "Start IWL Error Log Dump:\n");
- IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
- mvm->status, table.valid);
- }
-
- IWL_ERR(mvm, "0x%08X | %s\n", table.error_id,
- iwl_fw_lookup_assert_desc(table.error_id));
- IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
- IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
- IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1);
- IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2);
- IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1);
- IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2);
- IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3);
- IWL_ERR(mvm, "0x%08X | umac major\n", table.umac_major);
- IWL_ERR(mvm, "0x%08X | umac minor\n", table.umac_minor);
- IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer);
- IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer);
- IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header);
- IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref);
-}
-
-static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num)
-{
- struct iwl_trans *trans = mvm->trans;
- struct iwl_error_event_table table = {};
- u32 val, base = mvm->trans->dbg.lmac_error_event_table[lmac_num];
-
- if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) {
- if (!base)
- base = mvm->fw->init_errlog_ptr;
- } else {
- if (!base)
- base = mvm->fw->inst_errlog_ptr;
- }
-
- if (base < 0x400000) {
- IWL_ERR(mvm,
- "Not valid error log pointer 0x%08X for %s uCode\n",
- base,
- (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT)
- ? "Init" : "RT");
- return;
- }
-
- /* check if there is a HW error */
- val = iwl_trans_read_mem32(trans, base);
- if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) {
- int err;
-
- IWL_ERR(trans, "HW error, resetting before reading\n");
-
- /* reset the device */
- iwl_trans_sw_reset(trans);
-
- err = iwl_finish_nic_init(trans, trans->trans_cfg);
- if (err)
- return;
- }
-
- iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table));
-
- if (table.valid)
- mvm->fwrt.dump.lmac_err_id[lmac_num] = table.error_id;
-
- if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
- IWL_ERR(trans, "Start IWL Error Log Dump:\n");
- IWL_ERR(trans, "Status: 0x%08lX, count: %d\n",
- mvm->status, table.valid);
- }
-
- /* Do not change this output - scripts rely on it */
-
- IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version);
-
- IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
- iwl_fw_lookup_assert_desc(table.error_id));
- IWL_ERR(mvm, "0x%08X | trm_hw_status0\n", table.trm_hw_status0);
- IWL_ERR(mvm, "0x%08X | trm_hw_status1\n", table.trm_hw_status1);
- IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2);
- IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1);
- IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2);
- IWL_ERR(mvm, "0x%08X | data1\n", table.data1);
- IWL_ERR(mvm, "0x%08X | data2\n", table.data2);
- IWL_ERR(mvm, "0x%08X | data3\n", table.data3);
- IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time);
- IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low);
- IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi);
- IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1);
- IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2);
- IWL_ERR(mvm, "0x%08X | uCode revision type\n", table.fw_rev_type);
- IWL_ERR(mvm, "0x%08X | uCode version major\n", table.major);
- IWL_ERR(mvm, "0x%08X | uCode version minor\n", table.minor);
- IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver);
- IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver);
- IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd);
- IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0);
- IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1);
- IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2);
- IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3);
- IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4);
- IWL_ERR(mvm, "0x%08X | last cmd Id\n", table.last_cmd_id);
- IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event);
- IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control);
- IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration);
- IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid);
- IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match);
- IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel);
- IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp);
- IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler);
-}
-
-static void iwl_mvm_dump_iml_error_log(struct iwl_mvm *mvm)
-{
- struct iwl_trans *trans = mvm->trans;
- u32 error, data1;
-
- if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) {
- error = UMAG_SB_CPU_2_STATUS;
- data1 = UMAG_SB_CPU_1_STATUS;
- } else if (mvm->trans->trans_cfg->device_family >=
- IWL_DEVICE_FAMILY_8000) {
- error = SB_CPU_2_STATUS;
- data1 = SB_CPU_1_STATUS;
- } else {
- return;
- }
-
- error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS);
-
- IWL_ERR(trans, "IML/ROM dump:\n");
-
- if (error & 0xFFFF0000)
- IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16);
-
- IWL_ERR(mvm, "0x%08X | IML/ROM error/state\n", error);
- IWL_ERR(mvm, "0x%08X | IML/ROM data1\n",
- iwl_read_umac_prph(trans, data1));
-
- if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000)
- IWL_ERR(mvm, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n",
- iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG));
-}
-
-void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
-{
- if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) {
- IWL_ERR(mvm,
- "DEVICE_ENABLED bit is not set. Aborting dump.\n");
- return;
- }
-
- iwl_mvm_dump_lmac_error_log(mvm, 0);
-
- if (mvm->trans->dbg.lmac_error_event_table[1])
- iwl_mvm_dump_lmac_error_log(mvm, 1);
-
- iwl_mvm_dump_umac_error_log(mvm);
-
- iwl_mvm_dump_iml_error_log(mvm);
-
- iwl_fw_error_print_fseq_regs(&mvm->fwrt);
-}
-
int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id,
int tid, int frame_limit, u16 ssn)
{
--
2.32.0

2021-06-22 12:29:47

by Luca Coelho

[permalink] [raw]
Subject: Re: [PATCH 1/9] iwlwifi: mvm: update iwl_wowlan_patterns_cmd

Luca Coelho <[email protected]> wrote:

> From: Emmanuel Grumbach <[email protected]>
>
> We need to pass the station id to tell the firmware
> on which station we want to configure the patterns.
>
> Signed-off-by: Emmanuel Grumbach <[email protected]>
> Signed-off-by: Luca Coelho <[email protected]>

9 patches applied to iwlwifi-next.git, thanks.

d9444014885d iwlwifi: mvm: update iwl_wowlan_patterns_cmd
df39ebbb89a5 iwlwifi: mvm: introduce iwl_wowlan_kek_kck_material_cmd_v4
1bb8e49cbe10 iwlwifi: mvm: introduce iwl_wowlan_get_status_cmd
805059d6018a iwlwifi: move UEFI code to a separate file
2f703c60a50f iwlwifi: support loading the reduced power table from UEFI
5f4fda58c705 iwlwifi: move error dump to fw utils
67bae0bfe733 iwlwifi: add 9560 killer device
e9e483e5fe6d iwlwifi: fw: dump TCM error table if present
daeeadc4f8f4 iwlwifi: bump FW API to 64 for AX devices