From: Ben Greear <[email protected]>
These are against wireless-testing from a few days ago.
Here are a bunch of ath10k patches. First one is a crash
fix. Next few are at least somewhat useful for generic
firmware, and more useful for CT firmware. Much of it is related
to better debugging of firmware crashes. If this can go in, then
I can much better handle random bug reports from prople using
stock kernels and CT firmware. With some small tweaks to how they
package firmware, QCA could benefit as well.
The last bit is some initial support for CT firmware. I figure it
is a long-shot, but it would surely be nice to get this (and more!)
upstream. If nothing else, these can be a basis for potential
inclusion in openwrt or similar.
These patches are not overly dependent on each other for the most
part, so even if a few are not acceptable, maybe others can be
applied upstream.
Ben Greear (21):
ath10k: Fix crash related to printing features.
ath10k: fix typo in logging message
ath10k: Support setting debug mask from driver code.
ath10k: rate-limit packet tx errors
ath10k: save firmware debug log messages.
ath10k: save firmware stacks upon firmware crash
ath10k: save firmware RAM and ROM BSS sections on crash
ath10k: make firmware text debug messages more verbose.
ath10k: print fw debug messages in hex.
ath10k: support logging ath10k_info as KERN_DEBUG
ath10k: add fw-powerup-fail to ethtool stats.
ath10k: Support up to 64 vdevs.
ath10k: Document cycle count related counters.
ath10k: Add tx/rx bytes, cycle counters to ethtool stats.
ath10k: support CT firmware flag.
ath10k: Support 32+ stations.
ath10k: Enable detecting failure to install key in firmware (CT).
ath10k: Note limitation on beaconing vdevs.
ath10k: Enable adhoc mode for CT firmware.
ath10k: read firmware crash over ioread32 if CE fails.
ath10k: Read dbglog buffers over register ping-pong.
drivers/net/wireless/ath/ath10k/core.c | 70 ++++++-
drivers/net/wireless/ath/ath10k/core.h | 52 +++++-
drivers/net/wireless/ath/ath10k/debug.c | 268 +++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/debug.h | 18 ++
drivers/net/wireless/ath/ath10k/htt.h | 7 +-
drivers/net/wireless/ath/ath10k/htt_rx.c | 23 ++-
drivers/net/wireless/ath/ath10k/htt_tx.c | 22 ++-
drivers/net/wireless/ath/ath10k/hw.h | 36 ++++
drivers/net/wireless/ath/ath10k/mac.c | 74 +++++++-
drivers/net/wireless/ath/ath10k/pci.c | 311 ++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/wmi.c | 43 ++++-
drivers/net/wireless/ath/ath10k/wmi.h | 6 +
12 files changed, 897 insertions(+), 33 deletions(-)
--
2.4.3
From: Ben Greear <[email protected]>
The (1 << x) - 1 trick won't work when you
are trying to fill up all 64 bits, so add special
case for that.
And, move the limits to the per-nic structure instead
of per-driver to allow better dynamic use of the limits.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 3f1786c..fa71d57 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1819,7 +1819,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
if (status)
goto err_hif_stop;
- ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
+ if (ar->max_num_vdevs >= 64)
+ ar->free_vdev_map = 0xFFFFFFFFFFFFFFFFLL;
+ else
+ ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
INIT_LIST_HEAD(&ar->arvifs);
--
2.4.3
From: Ben Greear <[email protected]>
This can be used to get a useful back trace out of a firmware
crash that involves an interrupt handler. For instance, a
null-pointer-exception would be this kind of trace. A user-space
tool can read the debugfs file and decode things as wished.
This requires a packaged firmware with a new IE to describe the
BSS section starts and length.
Signed-off-by: Ben Greear <[email protected]>
Signed-off-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 48 +++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/core.h | 14 +++++++++
drivers/net/wireless/ath/ath10k/debug.c | 40 +++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/hw.h | 2 ++
drivers/net/wireless/ath/ath10k/pci.c | 54 +++++++++++++++++++++++++++++++++
5 files changed, 157 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index b7318b8..3f1786c 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -922,6 +922,13 @@ err:
return ret;
}
+struct ath10k_bss_rom_ie {
+ __le32 ram_addr;
+ __le32 ram_len;
+ __le32 rom_addr;
+ __le32 rom_len;
+} __packed;
+
static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
size_t name_len)
{
@@ -983,6 +990,7 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
struct ath10k_fw_ie *hdr;
const u8 *data;
__le32 *timestamp, *version;
+ struct ath10k_bss_rom_ie *bss;
/* first fetch the firmware file (firmware-*.bin) */
fw_file->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
@@ -1100,6 +1108,12 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
break;
case ATH10K_FW_IE_WMI_OP_VERSION:
+ /* Upstream stole the ID CT firmware was using, so add
+ * hack-around to deal with backwards-compat. --Ben
+ */
+ if (ie_len >= sizeof(*bss))
+ goto fw_ie_bss_info_ct;
+
if (ie_len != sizeof(u32))
break;
@@ -1128,6 +1142,40 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
fw_file->codeswap_data = data;
fw_file->codeswap_len = ie_len;
break;
+ case ATH10K_FW_IE_BSS_INFO_CT:
+fw_ie_bss_info_ct:
+ if (ie_len < sizeof(*bss)) {
+ ath10k_warn(ar, "invalid ie len for bss-info (%zd)\n",
+ ie_len);
+ break;
+ }
+ bss = (struct ath10k_bss_rom_ie *)(data);
+
+ fw_file->ram_bss_addr = le32_to_cpu(bss->ram_addr);
+ fw_file->ram_bss_len = le32_to_cpu(bss->ram_len);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "found RAM BSS addr 0x%x length %d\n",
+ fw_file->ram_bss_addr, fw_file->ram_bss_len);
+
+ if (fw_file->ram_bss_len > ATH10K_RAM_BSS_BUF_LEN) {
+ ath10k_warn(ar, "too long firmware RAM BSS length: %d\n",
+ fw_file->ram_bss_len);
+ fw_file->ram_bss_len = 0;
+ }
+
+ fw_file->rom_bss_addr = le32_to_cpu(bss->rom_addr);
+ fw_file->rom_bss_len = le32_to_cpu(bss->rom_len);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "found ROM BSS addr 0x%x length %d\n",
+ fw_file->rom_bss_addr, fw_file->rom_bss_len);
+
+ if (fw_file->rom_bss_len > ATH10K_ROM_BSS_BUF_LEN) {
+ ath10k_warn(ar, "too long firmware ROM BSS length: %d\n",
+ fw_file->rom_bss_len);
+ fw_file->rom_bss_len = 0;
+ }
+
+ break;
default:
ath10k_warn(ar, "Unknown FW IE: %u\n",
le32_to_cpu(hdr->id));
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 644d077..6aa7a14 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -420,6 +420,10 @@ struct ath10k_dbglog_entry_storage {
#define DBGLOG_NUM_ARGS_MASK 0xFC000000 /* Bit 26-31 */
#define DBGLOG_NUM_ARGS_MAX 5 /* firmware tool chain limit */
+/* estimated values, hopefully these are enough */
+#define ATH10K_ROM_BSS_BUF_LEN 30000
+#define ATH10K_RAM_BSS_BUF_LEN 10000
+
/* used for crash-dump storage, protected by data-lock */
struct ath10k_fw_crash_data {
bool crashed_since_read;
@@ -431,6 +435,8 @@ struct ath10k_fw_crash_data {
__le32 exc_stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
__le32 stack_addr;
__le32 exc_stack_addr;
+ __le32 rom_bss_buf[ATH10K_ROM_BSS_BUF_LEN / sizeof(__le32)];
+ __le32 ram_bss_buf[ATH10K_RAM_BSS_BUF_LEN / sizeof(__le32)];
};
struct ath10k_debug {
@@ -666,6 +672,14 @@ struct ath10k_fw_file {
const void *codeswap_data;
size_t codeswap_len;
+
+ /* These are written to only during first firmware load from user
+ * space so no need for any locking.
+ */
+ u32 ram_bss_addr;
+ u32 ram_bss_len;
+ u32 rom_bss_addr;
+ u32 rom_bss_len;
};
struct ath10k_fw_components {
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 7bc3053..28e0c05 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -38,12 +38,16 @@
* @ATH10K_FW_ERROR_DUMP_DBGLOG: Recent firmware debug log entries
* @ATH10K_FW_CRASH_DUMP_STACK: Stack memory contents.
* @ATH10K_FW_CRASH_DUMP_EXC_STACK: Exception stack memory contents.
+ * @ATH10K_FW_CRASH_DUMP_RAM_BSS: BSS area for RAM code
+ * @ATH10K_FW_CRASH_DUMP_ROM_BSS: BSS area for ROM code
*/
enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
ATH10K_FW_CRASH_DUMP_STACK = 2,
ATH10K_FW_CRASH_DUMP_EXC_STACK = 3,
+ ATH10K_FW_CRASH_DUMP_RAM_BSS = 4,
+ ATH10K_FW_CRASH_DUMP_ROM_BSS = 5,
ATH10K_FW_CRASH_DUMP_MAX,
};
@@ -110,9 +114,11 @@ struct ath10k_dump_file_data {
__le32 stack_addr;
__le32 exc_stack_addr;
+ __le32 rom_bss_addr;
+ __le32 ram_bss_addr;
/* room for growth w/out changing binary format */
- u8 unused[120];
+ u8 unused[112];
/* struct ath10k_tlv_dump_data + more */
u8 data[0];
@@ -808,6 +814,14 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
len += sizeof(*dump_tlv) + sizeof(crash_data->stack_buf);
len += sizeof(*dump_tlv) + sizeof(crash_data->exc_stack_buf);
+ if (ar->running_fw->fw_file.ram_bss_addr &&
+ ar->running_fw->fw_file.ram_bss_len)
+ len += sizeof(*dump_tlv) + ar->running_fw->fw_file.ram_bss_len;
+
+ if (ar->running_fw->fw_file.rom_bss_addr &&
+ ar->running_fw->fw_file.rom_bss_len)
+ len += sizeof(*dump_tlv) + ar->running_fw->fw_file.rom_bss_len;
+
sofar += hdr_len;
/* This is going to get big when we start dumping FW RAM and such,
@@ -848,6 +862,10 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
dump_data->stack_addr = cpu_to_le32(crash_data->stack_addr);
dump_data->exc_stack_addr = cpu_to_le32(crash_data->exc_stack_addr);
+ dump_data->rom_bss_addr =
+ cpu_to_le32(ar->running_fw->fw_file.rom_bss_addr);
+ dump_data->ram_bss_addr =
+ cpu_to_le32(ar->running_fw->fw_file.ram_bss_addr);
strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
sizeof(dump_data->fw_ver));
@@ -898,6 +916,26 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
memcpy(dump_tlv->tlv_data, crash_data->exc_stack_buf, tmp);
sofar += sizeof(*dump_tlv) + tmp;
+ if (ar->running_fw->fw_file.ram_bss_addr &&
+ ar->running_fw->fw_file.ram_bss_len) {
+ tmp = ar->running_fw->fw_file.ram_bss_len;
+ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_BSS);
+ dump_tlv->tlv_len = cpu_to_le32(tmp);
+ memcpy(dump_tlv->tlv_data, crash_data->ram_bss_buf, tmp);
+ sofar += sizeof(*dump_tlv) + tmp;
+ }
+
+ if (ar->running_fw->fw_file.rom_bss_addr &&
+ ar->running_fw->fw_file.rom_bss_len) {
+ tmp = ar->running_fw->fw_file.rom_bss_len;
+ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_ROM_BSS);
+ dump_tlv->tlv_len = cpu_to_le32(tmp);
+ memcpy(dump_tlv->tlv_data, crash_data->rom_bss_buf, tmp);
+ sofar += sizeof(*dump_tlv) + tmp;
+ }
+
ar->debug.fw_crash_data->crashed_since_read = false;
WARN_ON(sofar != len);
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index e86ebf0..7b80e29 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -149,6 +149,8 @@ enum ath10k_fw_ie_type {
/* Code swap image for firmware binary */
ATH10K_FW_IE_FW_CODE_SWAP_IMAGE = 7,
+
+ ATH10K_FW_IE_BSS_INFO_CT = 30,
};
enum ath10k_fw_wmi_op_version {
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 62dd167..e6315ec 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1424,6 +1424,58 @@ u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
}
+static void ath10k_pci_dump_bss_ram(struct ath10k *ar,
+ struct ath10k_fw_crash_data *crash_data)
+{
+ int ret;
+
+ if (!crash_data)
+ return;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ if (!ar->running_fw->fw_file.ram_bss_addr)
+ return;
+
+ if (!ar->running_fw->fw_file.ram_bss_len)
+ return;
+
+ ret = ath10k_pci_diag_read_mem(ar, ar->running_fw->fw_file.ram_bss_addr,
+ crash_data->ram_bss_buf,
+ ar->running_fw->fw_file.ram_bss_len);
+ if (ret)
+ ath10k_warn(ar,
+ "failed to read firmware RAM BSS memory from %d (%d B): %d\n",
+ ar->running_fw->fw_file.ram_bss_addr,
+ ar->running_fw->fw_file.ram_bss_len, ret);
+}
+
+static void ath10k_pci_dump_bss_rom(struct ath10k *ar,
+ struct ath10k_fw_crash_data *crash_data)
+{
+ int ret;
+
+ if (!crash_data)
+ return;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ if (!ar->running_fw->fw_file.rom_bss_addr)
+ return;
+
+ if (!ar->running_fw->fw_file.rom_bss_len)
+ return;
+
+ ret = ath10k_pci_diag_read_mem(ar, ar->running_fw->fw_file.rom_bss_addr,
+ crash_data->rom_bss_buf,
+ ar->running_fw->fw_file.rom_bss_len);
+ if (ret)
+ ath10k_warn(ar,
+ "failed to read firmware ROM BSS memory from %d (%d B): %d\n",
+ ar->running_fw->fw_file.rom_bss_addr,
+ ar->running_fw->fw_file.rom_bss_len, ret);
+}
+
/* Save the main firmware stack */
static void ath10k_pci_dump_stack(struct ath10k *ar,
struct ath10k_fw_crash_data *crash_data)
@@ -1607,6 +1659,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
ath10k_pci_dump_dbglog(ar);
ath10k_pci_dump_stack(ar, crash_data);
ath10k_pci_dump_exc_stack(ar, crash_data);
+ ath10k_pci_dump_bss_ram(ar, crash_data);
+ ath10k_pci_dump_bss_rom(ar, crash_data);
if (crash_data)
crash_data->crashed_since_read = true;
--
2.4.3
From: Ben Greear <[email protected]>
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 0e24f9e..cd3016d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2747,7 +2747,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
if (ret)
- ath10k_warn(ar, "faield to down vdev %i: %d\n",
+ ath10k_warn(ar, "failed to down vdev %i: %d\n",
arvif->vdev_id, ret);
arvif->def_wep_key_idx = -1;
--
2.4.3
From: Ben Greear <[email protected]>
There are not many of these messages producted by the
firmware, but they are generally fairly useful, so print
them at info level.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/wmi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 1758b4a..d9e4b77 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4050,7 +4050,7 @@ void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb)
/* the last byte is always reserved for the null character */
buf[i] = '\0';
- ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf);
+ ath10k_info(ar, "wmi print '%s'\n", buf);
}
void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
--
2.4.3
From: Ben Greear <[email protected]>
Support up to 32 stations when using CT firmware.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 14 +++++++++++
drivers/net/wireless/ath/ath10k/hw.h | 6 +++++
drivers/net/wireless/ath/ath10k/mac.c | 43 ++++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/wmi.c | 16 ++++++++++---
4 files changed, 76 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 49c85c3..3869edd 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1567,6 +1567,20 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ fw_file->fw_features)) {
+ ar->max_num_peers = TARGET_10X_NUM_PEERS_CT;
+ ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+ ar->max_num_vdevs = TARGET_10X_NUM_VDEVS_CT;
+ } else {
+ ar->max_num_peers = TARGET_10X_NUM_PEERS;
+ ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+ ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
+ }
+ ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
+ ar->fw_stats_req_mask = WMI_STAT_PEER;
+ ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
+ break;
case ATH10K_FW_WMI_OP_VERSION_10_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
if (ath10k_peer_stats_enabled(ar)) {
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 7b80e29..d3f37d5 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -370,6 +370,12 @@ enum ath10k_hw_4addr_pad {
(TARGET_10X_NUM_VDEVS))
#define TARGET_10X_TX_STATS_NUM_PEERS ((TARGET_10X_TX_STATS_NUM_STATIONS) + \
(TARGET_10X_NUM_VDEVS))
+
+/* Over-rides for Candela Technologies firmware */
+#define TARGET_10X_NUM_VDEVS_CT 32
+#define TARGET_10X_NUM_PEERS_CT (32 + (TARGET_10X_NUM_VDEVS_CT))
+#define TARGET_10X_AST_SKID_LIMIT_CT (TARGET_10X_NUM_PEERS_CT * TARGET_10X_NUM_PEER_AST)
+
#define TARGET_10X_NUM_OFFLOAD_PEERS 0
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
#define TARGET_10X_NUM_PEER_KEYS 2
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 42cac32..2169337 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7451,6 +7451,22 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
},
};
+static const struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
+ {
+ .max = TARGET_10X_NUM_VDEVS_CT,
+ .types = BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_P2P_CLIENT)
+ },
+ {
+ .max = 3,
+ .types = BIT(NL80211_IFTYPE_P2P_GO)
+ },
+ {
+ .max = 7,
+ .types = BIT(NL80211_IFTYPE_AP)
+ },
+};
+
static const struct ieee80211_iface_combination ath10k_if_comb[] = {
{
.limits = ath10k_if_limits,
@@ -7531,6 +7547,22 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = {
},
};
+static const struct ieee80211_iface_combination ath10k_10x_ct_if_comb[] = {
+ {
+ .limits = ath10k_10x_ct_if_limits,
+ .n_limits = ARRAY_SIZE(ath10k_10x_ct_if_limits),
+ .max_interfaces = TARGET_10X_NUM_VDEVS_CT,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+#ifdef CONFIG_ATH10K_DFS_CERTIFIED
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80),
+#endif
+ },
+};
+
/* FIXME: This is not thouroughly tested. These combinations may over- or
* underestimate hw/fw capabilities.
*/
@@ -7808,6 +7840,17 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ ar->normal_mode_fw.fw_file.fw_features)) {
+ ar->hw->wiphy->iface_combinations = ath10k_10x_ct_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_10x_ct_if_comb);
+ } else {
+ ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_10x_if_comb);
+ }
+ break;
case ATH10K_FW_WMI_OP_VERSION_10_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 6cfba41..9ee2648 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -5497,12 +5497,22 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
struct sk_buff *buf;
struct wmi_resource_config_10x config = {};
u32 len, val;
+ u32 skid_limit;
+
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ ar->running_fw->fw_file.fw_features)) {
+ config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS_CT);
+ config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS_CT);
+ skid_limit = TARGET_10X_AST_SKID_LIMIT_CT;
+ } else {
+ config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+ config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+ skid_limit = TARGET_10X_AST_SKID_LIMIT;
+ }
+ config.ast_skid_limit = __cpu_to_le32(skid_limit);
- config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
- config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
- config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
--
2.4.3
From: Ben Greear <[email protected]>
Helps keep messages off of (serial) console when
that is desired.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/debug.c | 5 ++++-
drivers/net/wireless/ath/ath10k/debug.h | 6 ++++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index c38862b..7d9ad99 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -139,7 +139,10 @@ void ath10k_info(struct ath10k *ar, const char *fmt, ...)
va_start(args, fmt);
vaf.va = &args;
- dev_info(ar->dev, "%pV", &vaf);
+ if (ath10k_debug_mask & ATH10K_DBG_INFO_AS_DBG)
+ dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
+ else
+ dev_info(ar->dev, "%pV", &vaf);
trace_ath10k_log_info(ar, &vaf);
va_end(args);
}
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 6356dce..4f10685 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -21,6 +21,10 @@
#include <linux/types.h>
#include "trace.h"
+/**
+ * ATH10K_DBG_INFO_AS_DBG: use dev_dbg instead of dev_info
+ * for ath10k_info messages
+ */
enum ath10k_debug_mask {
ATH10K_DBG_PCI = 0x00000001,
ATH10K_DBG_WMI = 0x00000002,
@@ -38,6 +42,8 @@ enum ath10k_debug_mask {
ATH10K_DBG_WMI_PRINT = 0x00002000,
ATH10K_DBG_PCI_PS = 0x00004000,
ATH10K_DBG_AHB = 0x00008000,
+
+ ATH10K_DBG_INFO_AS_DBG = 0x40000000,
ATH10K_DBG_FW = 0x80000000,
ATH10K_DBG_ANY = 0xffffffff,
};
--
2.4.3
From: Ben Greear <[email protected]>
They may be dumped through the firmware dump debugfs
file.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.h | 18 ++++++
drivers/net/wireless/ath/ath10k/debug.c | 97 +++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath10k/debug.h | 6 ++
drivers/net/wireless/ath/ath10k/hw.h | 21 +++++++
drivers/net/wireless/ath/ath10k/pci.c | 99 +++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/wmi.c | 13 +++++
drivers/net/wireless/ath/ath10k/wmi.h | 6 ++
7 files changed, 258 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 1379054..7f9f460 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -404,6 +404,22 @@ struct ath10k_vif_iter {
struct ath10k_vif *arvif;
};
+/* This will store at least the last 128 entries. Each dbglog message
+ * is a max of 7 32-bit integers in length, but the length can be less
+ * than that as well.
+ */
+#define ATH10K_DBGLOG_DATA_LEN (128 * 7)
+struct ath10k_dbglog_entry_storage {
+ u32 head_idx; /* Where to write next chunk of data */
+ u32 tail_idx; /* Index of first msg */
+ __le32 data[ATH10K_DBGLOG_DATA_LEN];
+};
+
+/* Just enough info to decode firmware debug-log argument length */
+#define DBGLOG_NUM_ARGS_OFFSET 26
+#define DBGLOG_NUM_ARGS_MASK 0xFC000000 /* Bit 26-31 */
+#define DBGLOG_NUM_ARGS_MAX 5 /* firmware tool chain limit */
+
/* used for crash-dump storage, protected by data-lock */
struct ath10k_fw_crash_data {
bool crashed_since_read;
@@ -437,6 +453,8 @@ struct ath10k_debug {
u32 reg_addr;
u32 nf_cal_period;
+ struct ath10k_dbglog_entry_storage dbglog_entry_data;
+
struct ath10k_fw_crash_data *fw_crash_data;
};
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index a689bf1..38b3541 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -35,10 +35,11 @@
/**
* enum ath10k_fw_crash_dump_type - types of data in the dump file
* @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+ * @ATH10K_FW_ERROR_DUMP_DBGLOG: Recent firmware debug log entries
*/
enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
-
+ ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
ATH10K_FW_CRASH_DUMP_MAX,
};
@@ -109,6 +110,12 @@ struct ath10k_dump_file_data {
u8 data[0];
} __packed;
+struct ath10k_dbglog_entry_storage_user {
+ __le32 head_idx; /* Where to write next chunk of data */
+ __le32 tail_idx; /* Index of first msg */
+ __le32 data[ATH10K_DBGLOG_DATA_LEN];
+} __packed;
+
void ath10k_info(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
@@ -702,7 +709,6 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
lockdep_assert_held(&ar->data_lock);
- crash_data->crashed_since_read = true;
uuid_le_gen(&crash_data->uuid);
getnstimeofday(&crash_data->timestamp);
@@ -710,17 +716,87 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
}
EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
+static void ath10k_dbg_drop_dbg_buffer(struct ath10k *ar)
+{
+ /* Find next message boundary */
+ u32 lg_hdr;
+ int acnt;
+ int tail_idx = ar->debug.dbglog_entry_data.tail_idx;
+ int h_idx = (tail_idx + 1) % ATH10K_DBGLOG_DATA_LEN;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ /* Log header is second 32-bit word */
+ lg_hdr = le32_to_cpu(ar->debug.dbglog_entry_data.data[h_idx]);
+
+ acnt = (lg_hdr & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET;
+
+ if (acnt > DBGLOG_NUM_ARGS_MAX) {
+ /* Some sort of corruption it seems, recover as best we can. */
+ ath10k_err(ar, "invalid dbglog arg-count: %i %i %i\n",
+ acnt, ar->debug.dbglog_entry_data.tail_idx,
+ ar->debug.dbglog_entry_data.head_idx);
+ ar->debug.dbglog_entry_data.tail_idx =
+ ar->debug.dbglog_entry_data.head_idx;
+ return;
+ }
+
+ /* Move forward over the args and the two header fields */
+ ar->debug.dbglog_entry_data.tail_idx =
+ (tail_idx + acnt + 2) % ATH10K_DBGLOG_DATA_LEN;
+}
+
+void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer, int len)
+{
+ int i;
+ int z;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ z = ar->debug.dbglog_entry_data.head_idx;
+
+ /* Don't save any new logs until user-space reads this. */
+ if (ar->debug.fw_crash_data &&
+ ar->debug.fw_crash_data->crashed_since_read) {
+ ath10k_warn(ar, "dropping dbg buffer due to crash since read\n");
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ ar->debug.dbglog_entry_data.data[z] = buffer[i];
+ z++;
+ if (z >= ATH10K_DBGLOG_DATA_LEN)
+ z = 0;
+
+ /* If we are about to over-write an old message, move the
+ * tail_idx to the next message. If idx's are same, we
+ * are empty.
+ */
+ if (z == ar->debug.dbglog_entry_data.tail_idx)
+ ath10k_dbg_drop_dbg_buffer(ar);
+
+ ar->debug.dbglog_entry_data.head_idx = z;
+ }
+}
+EXPORT_SYMBOL(ath10k_dbg_save_fw_dbg_buffer);
+
static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
{
struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
struct ath10k_dump_file_data *dump_data;
struct ath10k_tlv_dump_data *dump_tlv;
+ struct ath10k_dbglog_entry_storage_user *dbglog_storage;
int hdr_len = sizeof(*dump_data);
unsigned int len, sofar = 0;
unsigned char *buf;
+ int tmp;
+
+ BUILD_BUG_ON(sizeof(struct ath10k_dbglog_entry_storage) !=
+ sizeof(struct ath10k_dbglog_entry_storage_user));
len = hdr_len;
len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+ len += sizeof(*dump_tlv) + sizeof(ar->debug.dbglog_entry_data);
sofar += hdr_len;
@@ -779,8 +855,25 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
sizeof(crash_data->registers));
sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+ /* Gather dbg-log */
+ tmp = sizeof(ar->debug.dbglog_entry_data);
+ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_DBGLOG);
+ dump_tlv->tlv_len = cpu_to_le32(tmp);
+ dbglog_storage =
+ (struct ath10k_dbglog_entry_storage_user *)(dump_tlv->tlv_data);
+ memcpy(dbglog_storage->data, ar->debug.dbglog_entry_data.data,
+ sizeof(dbglog_storage->data));
+ dbglog_storage->head_idx =
+ cpu_to_le32(ar->debug.dbglog_entry_data.head_idx);
+ dbglog_storage->tail_idx =
+ cpu_to_le32(ar->debug.dbglog_entry_data.tail_idx);
+
+ sofar += sizeof(*dump_tlv) + tmp;
+
ar->debug.fw_crash_data->crashed_since_read = false;
+ WARN_ON(sofar != len);
spin_unlock_bh(&ar->data_lock);
return dump_data;
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index a5c9aae..613ad7e 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -95,7 +95,13 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
+
+void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer, int len);
#else
+static inline void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar,
+ __le32 *buffer, int len)
+{
+}
static inline int ath10k_debug_start(struct ath10k *ar)
{
return 0;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index aedd898..5bbef4b 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -681,4 +681,25 @@ enum ath10k_hw_4addr_pad {
#define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
+/* Target debug log related defines and structs */
+
+/* Target is 32-bit CPU, so we just use u32 for
+ * the pointers. The memory space is relative to the
+ * target, not the host. Values are converted to host
+ * byte order when reading from firmware.
+ */
+struct ath10k_fw_dbglog_buf {
+ __le32 next; /* pointer to ath10k_fw_dbglog_buf. */
+ __le32 buffer; /* pointer to u8 buffer */
+ __le32 bufsize;
+ __le32 length;
+ __le32 count;
+ __le32 free;
+} __packed;
+
+struct ath10k_fw_dbglog_hdr {
+ __le32 dbuf; /* pointer to ath10k_fw_dbglog_buf */
+ __le32 dropped;
+} __packed;
+
#endif /* _HW_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 8133d7b..16e32d0 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1439,6 +1439,102 @@ static void ath10k_pci_dump_registers(struct ath10k *ar,
crash_data->registers[i] = reg_dump_values[i];
}
+/**
+ * Read any not-yet-delivered debug-log buffers on the target
+ * and save them to storage in the host driver. Typically
+ * only done on crash, as firmware will normally deliver
+ * logs periodically on its own if it is functioning
+ * properly.
+ */
+static void ath10k_pci_dump_dbglog(struct ath10k *ar)
+{
+ struct ath10k_fw_dbglog_hdr dbg_hdr;
+ u32 dbufp; /* pointer in target memory space */
+ struct ath10k_fw_dbglog_buf dbuf;
+ u8 *buffer;
+ int ret;
+ int i;
+ int len;
+
+ ret = ath10k_pci_diag_read_hi(ar, &dbg_hdr, hi_dbglog_hdr,
+ sizeof(dbg_hdr));
+ if (ret != 0) {
+ ath10k_err(ar, "failed to dump debug log area: %d\n", ret);
+ return;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI,
+ "debug log header, dbuf: 0x%x dropped: %i\n",
+ le32_to_cpu(dbg_hdr.dbuf), le32_to_cpu(dbg_hdr.dropped));
+ dbufp = le32_to_cpu(dbg_hdr.dbuf);
+
+ /* i is for logging purposes and sanity check in case firmware buffers
+ * are corrupted and will not properly terminate the list.
+ * In standard firmware, it appears there are no more than 2
+ * buffers, so 10 should be safe upper limit even if firmware
+ * changes quite a bit.
+ */
+ i = 0;
+ while (dbufp && i < 10) {
+ ret = ath10k_pci_diag_read_mem(ar, dbufp, &dbuf, sizeof(dbuf));
+ if (ret != 0) {
+ ath10k_err(ar, "failed to read debug log area: %d (addr 0x%x)\n",
+ ret, dbufp);
+ return;
+ }
+
+ len = le32_to_cpu(dbuf.length);
+
+ ath10k_dbg(ar, ATH10K_DBG_PCI,
+ "[%i] next: 0x%x buf: 0x%x sz: %i len: %i count: %i free: %i\n",
+ i, le32_to_cpu(dbuf.next), le32_to_cpu(dbuf.buffer),
+ le32_to_cpu(dbuf.bufsize), len,
+ le32_to_cpu(dbuf.count), le32_to_cpu(dbuf.free));
+ if (dbuf.buffer == 0 || len == 0)
+ goto next;
+
+ /* Pick arbitrary upper bound in case firmware is corrupted for
+ * whatever reason.
+ */
+ if (len > 4096) {
+ ath10k_err(ar,
+ "debuglog buf length is out of bounds: %d\n",
+ len);
+ /* Do not trust the next pointer either... */
+ return;
+ }
+
+ buffer = kmalloc(len, GFP_ATOMIC);
+
+ if (!buffer)
+ goto next;
+
+ ret = ath10k_pci_diag_read_mem(ar, le32_to_cpu(dbuf.buffer),
+ buffer, len);
+ if (ret != 0) {
+ ath10k_err(ar, "failed to read debug log buffer: %d (addr 0x%x)\n",
+ ret, le32_to_cpu(dbuf.buffer));
+ kfree(buffer);
+ return;
+ }
+
+ WARN_ON(len & 0x3);
+
+ ath10k_dbg_save_fw_dbg_buffer(ar, (__le32 *)(buffer), len >> 2);
+ kfree(buffer);
+
+next:
+ dbufp = le32_to_cpu(dbuf.next);
+ if (dbufp == le32_to_cpu(dbg_hdr.dbuf)) {
+ /* It is a circular buffer it seems, bail if next
+ * is head
+ */
+ break;
+ }
+ i++;
+ } /* While we have a debug buffer to read */
+}
+
static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
{
struct ath10k_fw_crash_data *crash_data;
@@ -1458,6 +1554,9 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid);
ath10k_print_driver_info(ar);
ath10k_pci_dump_registers(ar, crash_data);
+ ath10k_pci_dump_dbglog(ar);
+ if (crash_data)
+ crash_data->crashed_since_read = true;
spin_unlock_bh(&ar->data_lock);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 621019f..1758b4a 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2492,10 +2492,23 @@ void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
{
+ struct ath10k_fw_dbglog_report *ev;
+
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
skb->len);
trace_ath10k_wmi_dbglog(ar, skb->data, skb->len);
+ ev = (struct ath10k_fw_dbglog_report *)skb->data;
+
+ spin_lock_bh(&ar->data_lock);
+ /* First 4 bytes are a messages-dropped-due-to-overflow counter,
+ * and should not be recorded in the dbglog buffer, so we skip
+ * them.
+ */
+ WARN_ON(skb->len & 0x3);
+ ath10k_dbg_save_fw_dbg_buffer(ar, ev->messages,
+ (skb->len - 4)/sizeof(__le32));
+ spin_unlock_bh(&ar->data_lock);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index db25535..8d9b5b3 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -6262,6 +6262,12 @@ struct wmi_svc_rdy_ev_arg {
const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
};
+struct ath10k_fw_dbglog_report {
+ __le32 dropped_count;
+ __le32 messages[];
+} __packed;
+
+
struct wmi_rdy_ev_arg {
__le32 sw_version;
__le32 abi_version;
--
2.4.3
On 05/11/2016 03:40 AM, Michal Kazior wrote:
> On 10 May 2016 at 01:10, <[email protected]> wrote:
>> From: Ben Greear <[email protected]>
>>
>> Might want to turn off verbose debug as soon as you
>> see a firmware crash, for instance. Helps keep dmesg
>> output from over-running the stuff you care about.
>>
>> Signed-off-by: Ben Greear <[email protected]>
>> ---
>> drivers/net/wireless/ath/ath10k/debug.c | 5 +++++
>> drivers/net/wireless/ath/ath10k/debug.h | 1 +
>> 2 files changed, 6 insertions(+)
>>
>> diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
>> index e251155..a689bf1 100644
>> --- a/drivers/net/wireless/ath/ath10k/debug.c
>> +++ b/drivers/net/wireless/ath/ath10k/debug.c
>> @@ -194,6 +194,11 @@ void ath10k_print_driver_info(struct ath10k *ar)
>> }
>> EXPORT_SYMBOL(ath10k_print_driver_info);
>>
>> +void ath10k_set_debug_mask(unsigned int v) {
>
> The { should be on new line.
>
>
>> + ath10k_debug_mask = v;
>> +}
>> +EXPORT_SYMBOL(ath10k_set_debug_mask);
>
> I didn't see any uses of this in your patchset (it's commented out in
> 21/21) and I'm not fully convinced it's a good idea to override
> debug_mask like that. Once I set a debug_mask I expect it to stay
> unchanged. What if I do want to trace what happens after fw crash?
>
> Wouldn't it be better to have a knob to tell ath10k whether hw
> recovery should be automatic or manual?
Hmm, I have a later patch that allows twiddling this through debugfs,
that is what I meant to add to this series. I'll find that one and squash
it into this one.
Thanks,
Ben
--
Ben Greear <[email protected]>
Candela Technologies Inc http://www.candelatech.com
From: Ben Greear <[email protected]>
This only pertains to CT firmware, as standard firmware
can't do anywhere near this many vdevs anyway.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 373f2ee..f1bfb3a 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1343,6 +1343,22 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
+ /* CT Firmware can support 32+ VDEVS, but can only support
+ * beacon-ing devs with dev ids 0 - 31 due to firmware limitations.
+ * Create VAPs first and all should be well...likely most people
+ * won't ever hit this anyway, but some day the vdev ID allocation
+ * could be made smarter to make it more likely to work no matter the
+ * order the vdevs are created. --Ben
+ */
+ if ((arvif->vdev_type == WMI_VDEV_TYPE_AP) ||
+ (arvif->vdev_type == WMI_VDEV_TYPE_IBSS)) {
+ if (arg.vdev_id > 31) {
+ ath10k_warn(ar, "failed to start vdev %i Beaconing VIFS must have IDs <= 31 to work-around firmware limitations.\n",
+ arg.vdev_id);
+ return -EINVAL;
+ }
+ }
+
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
arg.ssid_len = arvif->u.ap.ssid_len;
--
2.4.3
From: Ben Greear <[email protected]>
When firmware crashes, stack can continue to send packets
for a bit, and existing code was spamming logs.
So, rate-limit the error message for tx failures.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index cd3016d..42cac32 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3432,8 +3432,9 @@ static int ath10k_mac_tx_submit(struct ath10k *ar,
}
if (ret) {
- ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
- ret);
+ if (net_ratelimit())
+ ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
+ ret);
ieee80211_free_txskb(ar->hw, skb);
}
--
2.4.3
From: Ben Greear <[email protected]>
This looks like a regression from
c4cdf753 (move fw_features to struct ath10k_fw_file)
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index e94cb87..b7318b8 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1078,7 +1078,7 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
}
ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",
- ar->running_fw->fw_file.fw_features,
+ fw_file->fw_features,
sizeof(fw_file->fw_features));
break;
case ATH10K_FW_IE_FW_IMAGE:
--
2.4.3
From: Ben Greear <[email protected]>
This gives much better debugging capability when debugging
crashes in the firmware that cause CE transport loss.
(Such as AXI errors).
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/pci.c | 47 ++++++++++++++++++++++++++++++++++-
1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 330c150..4069e72 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1532,7 +1532,7 @@ static int ath10k_ct_fw_crash_regs_harder(struct ath10k *ar,
return -EBUSY;
pingpong:
- ath10k_warn(ar, "Trying to read crash dump over pingpong registers.\n");
+ ath10k_warn(ar, "Trying to read crash dump over pingpong registers, len %d\n", len);
/* Firmware is trying to send us info it seems. */
for (q = 0; q<len; q++) {
reg_dump_values[q] = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + SCRATCH_2_ADDRESS);
@@ -1567,6 +1567,10 @@ static void ath10k_pci_dump_registers(struct ath10k *ar,
hi_failure_state,
REG_DUMP_COUNT_QCA988X * sizeof(__le32));
if (ret) {
+ __le32 *buffer;
+ int len = 1500; /* length in bytes for firmware dbglog buffer */
+ struct ath10k_fw_dbglog_buf dbuf;
+
ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
/* Try to read this directly over registers...only works on new
@@ -1575,6 +1579,46 @@ static void ath10k_pci_dump_registers(struct ath10k *ar,
ret = ath10k_ct_fw_crash_regs_harder(ar, reg_dump_values, REG_DUMP_COUNT_QCA988X);
if (ret)
return;
+
+ /* Try to read the debug-log buffers as well. */
+ buffer = kzalloc(len, GFP_ATOMIC);
+
+ if (!buffer)
+ goto free_and_cont;
+
+ if (ath10k_ct_fw_crash_regs_harder(ar, (__le32 *)(&dbuf), sizeof(dbuf)/4))
+ goto free_and_cont;
+
+ /* wow, it worked! */
+ len = le32_to_cpu(dbuf.length);
+ if (len > 1500) {
+ ath10k_err(ar, "dbuf length is greater than 1500: %d\n", len);
+ len = 1500;
+ }
+ if (ath10k_ct_fw_crash_regs_harder(ar, buffer, len/4))
+ goto free_and_cont;
+
+ ath10k_dbg_save_fw_dbg_buffer(ar, buffer, len/4);
+ ath10k_dbg_print_fw_dbg_buffer(ar, buffer, len/4, KERN_ERR);
+
+ /* See if the second one is available */
+ if (ath10k_ct_fw_crash_regs_harder(ar, (__le32 *)(&dbuf), sizeof(dbuf)/4))
+ goto free_and_cont;
+
+ len = le32_to_cpu(dbuf.length);
+ if (len > 1500) {
+ ath10k_err(ar, "dbuf[2] length is greater than 1500: %d\n", len);
+ len = 1500;
+ }
+
+ if (ath10k_ct_fw_crash_regs_harder(ar, buffer, len/4))
+ goto free_and_cont;
+
+ ath10k_dbg_save_fw_dbg_buffer(ar, buffer, len/4);
+ ath10k_dbg_print_fw_dbg_buffer(ar, buffer, len/4, KERN_ERR);
+
+ free_and_cont:
+ kfree(buffer);
}
BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
@@ -1723,6 +1767,7 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
spin_unlock_bh(&ar->data_lock);
+ /* ath10k_set_debug_mask(0); // stop more log spam */
queue_work(ar->workqueue, &ar->restart_work);
}
--
2.4.3
From: Ben Greear <[email protected]>
The firmware does not offer tx/rx bytes counters, so just keep track of
it in the driver.
For the cycle counters:
Note these counters are since the chip reset, though the counters
wrap often. When cycle-counters counter overflows on
certain hardware, it will right shift all 4 of the
related registers to the right by one bit (basically,
divide by two). Since you have no idea what the others
were at when cycle-counter wrapped, you must simply
ignore any sample where cycle-counter wraps, and set
new baseline values to calculate diffs against next
time.
Hardware with this funny wrap logic will cause the
d_flags 'counter' to have bit 0x1 set, so that is how
user-space can know how to deal with this.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.h | 3 +++
drivers/net/wireless/ath/ath10k/debug.c | 22 +++++++++++++++++-----
drivers/net/wireless/ath/ath10k/htt_rx.c | 3 +++
drivers/net/wireless/ath/ath10k/htt_tx.c | 22 +++++++++++++++++-----
4 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index c4f649f..1a75e2e 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -466,6 +466,9 @@ struct ath10k_debug {
struct ath10k_dbglog_entry_storage dbglog_entry_data;
struct ath10k_fw_crash_data *fw_crash_data;
+
+ u64 tx_bytes; /* counter, firmware does not offer this stat */
+ u64 rx_bytes; /* counter, firmware does not offer this stat */
};
enum ath10k_state {
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 54a2194..684a39d 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1442,11 +1442,15 @@ exit:
/* This generally cooresponds to the debugfs fw_stats file */
static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx_pkts_nic",
- "tx_bytes_nic",
+ "tx_bytes_nic", /* from driver, firmware does not keep this stat. */
"rx_pkts_nic",
- "rx_bytes_nic",
+ "rx_bytes_nic", /* from driver, firmware does not keep this stat. */
"d_noise_floor",
- "d_cycle_count",
+ "d_cycle_count", /* this is duty cycle counter, basically channel-time. 88MHz clock */
+ "d_tx_cycle_count", /* tx cycle count */
+ "d_rx_cycle_count", /* rx cycle count */
+ "d_busy_count", /* Total channel busy time cycles (called 'clear' by firmware) */
+ "d_flags", /* 0x1: hw has shifted cycle-count wrap, see ath10k_hw_fill_survey_time */
"d_phy_error",
"d_rts_bad",
"d_rts_good",
@@ -1518,6 +1522,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
static const struct ath10k_fw_stats_pdev zero_stats = {};
const struct ath10k_fw_stats_pdev *pdev_stats;
int i = 0, ret;
+ u64 d_flags = 0;
mutex_lock(&ar->conf_mutex);
@@ -1541,12 +1546,19 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
spin_lock_bh(&ar->data_lock);
+ if (ar->hw_params.has_shifted_cc_wraparound)
+ d_flags |= 0x1;
+
data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
- data[i++] = 0; /* tx bytes */
+ data[i++] = ar->debug.tx_bytes;
data[i++] = pdev_stats->htt_mpdus;
- data[i++] = 0; /* rx bytes */
+ data[i++] = ar->debug.rx_bytes;
data[i++] = pdev_stats->ch_noise_floor;
data[i++] = pdev_stats->cycle_count;
+ data[i++] = pdev_stats->tx_frame_count;
+ data[i++] = pdev_stats->rx_frame_count;
+ data[i++] = pdev_stats->rx_clear_count; /* yes, this appears to actually be 'busy' count */
+ data[i++] = d_flags; /* give user-space a chance to decode cycle counters */
data[i++] = pdev_stats->phy_err_count;
data[i++] = pdev_stats->rts_bad;
data[i++] = pdev_stats->rts_good;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index cc979a4..47da904 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1379,6 +1379,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
}
skb_queue_walk(amsdu, msdu) {
+#ifdef CONFIG_ATH10K_DEBUGFS
+ ar->debug.rx_bytes += msdu->len;
+#endif
ath10k_htt_rx_h_csum_offload(msdu);
ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
is_decrypted);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 6269c61..06ec995 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -769,6 +769,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
int len = 0;
int msdu_id = -1;
int res;
+ int skb_len;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
len += sizeof(cmd->hdr);
@@ -795,7 +796,8 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
goto err_free_msdu_id;
}
- skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,
+ skb_len = msdu->len;
+ skb_cb->paddr = dma_map_single(dev, msdu->data, skb_len,
DMA_TO_DEVICE);
res = dma_mapping_error(dev, skb_cb->paddr);
if (res) {
@@ -809,16 +811,20 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_MGMT_TX;
cmd->mgmt_tx.msdu_paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr);
- cmd->mgmt_tx.len = __cpu_to_le32(msdu->len);
+ cmd->mgmt_tx.len = __cpu_to_le32(skb_len);
cmd->mgmt_tx.desc_id = __cpu_to_le32(msdu_id);
cmd->mgmt_tx.vdev_id = __cpu_to_le32(vdev_id);
memcpy(cmd->mgmt_tx.hdr, msdu->data,
- min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN));
+ min_t(int, skb_len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN));
res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
if (res)
goto err_unmap_msdu;
+#ifdef CONFIG_ATH10K_DEBUGFS
+ ar->debug.tx_bytes += skb_len;
+#endif
+
return 0;
err_unmap_msdu:
@@ -852,6 +858,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
u8 flags0 = 0;
u16 msdu_id, flags1 = 0;
u16 freq = 0;
+ int skb_len;
u32 frags_paddr = 0;
u32 txbuf_paddr;
struct htt_msdu_ext_desc *ext_desc = NULL;
@@ -990,13 +997,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
__cpu_to_le32(HTT_INVALID_PEERID);
}
+ skb_len = msdu->len;
trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n",
- flags0, flags1, msdu->len, msdu_id, frags_paddr,
+ flags0, flags1, skb_len, msdu_id, frags_paddr,
(u32)skb_cb->paddr, vdev_id, tid, freq);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
- msdu->data, msdu->len);
+ msdu->data, skb_len);
trace_ath10k_tx_hdr(ar, msdu->data, msdu->len);
trace_ath10k_tx_payload(ar, msdu->data, msdu->len);
@@ -1021,6 +1029,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
if (res)
goto err_unmap_msdu;
+#ifdef CONFIG_ATH10K_DEBUGFS
+ ar->debug.tx_bytes += skb_len;
+#endif
+
return 0;
err_unmap_msdu:
--
2.4.3
On 10 May 2016 at 01:10, <[email protected]> wrote:
> From: Ben Greear <[email protected]>
>
> Might want to turn off verbose debug as soon as you
> see a firmware crash, for instance. Helps keep dmesg
> output from over-running the stuff you care about.
>
> Signed-off-by: Ben Greear <[email protected]>
> ---
> drivers/net/wireless/ath/ath10k/debug.c | 5 +++++
> drivers/net/wireless/ath/ath10k/debug.h | 1 +
> 2 files changed, 6 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
> index e251155..a689bf1 100644
> --- a/drivers/net/wireless/ath/ath10k/debug.c
> +++ b/drivers/net/wireless/ath/ath10k/debug.c
> @@ -194,6 +194,11 @@ void ath10k_print_driver_info(struct ath10k *ar)
> }
> EXPORT_SYMBOL(ath10k_print_driver_info);
>
> +void ath10k_set_debug_mask(unsigned int v) {
The { should be on new line.
> + ath10k_debug_mask = v;
> +}
> +EXPORT_SYMBOL(ath10k_set_debug_mask);
I didn't see any uses of this in your patchset (it's commented out in
21/21) and I'm not fully convinced it's a good idea to override
debug_mask like that. Once I set a debug_mask I expect it to stay
unchanged. What if I do want to trace what happens after fw crash?
Wouldn't it be better to have a knob to tell ath10k whether hw
recovery should be automatic or manual?
Michał
Hi Ben,
On Mon, May 09, 2016 at 04:11:09PM -0700, [email protected] wrote:
> From: Ben Greear <[email protected]>
>
> Add placeholder so CT firmware can more easily co-exist with upstream
> kernel.
[shafi] nitpick: good to provide an expansion in commit log as well, so that
if we can easily figure out in git log alone, rather than going through
the change and suggesting that it supports more vif's etc
>
> Signed-off-by: Ben Greear <[email protected]>
> ---
> drivers/net/wireless/ath/ath10k/core.c | 1 +
> drivers/net/wireless/ath/ath10k/core.h | 3 +++
> 2 files changed, 4 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
> index fa71d57..49c85c3 100644
> --- a/drivers/net/wireless/ath/ath10k/core.c
> +++ b/drivers/net/wireless/ath/ath10k/core.c
> @@ -235,6 +235,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
> [ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
> [ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",
> [ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl",
> + [ATH10K_FW_FEATURE_WMI_10X_CT] = "wmi-10.x-CT",
> };
>
> static unsigned int ath10k_core_get_fw_feature_str(char *buf,
> diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
> index 1a75e2e..dd38f34 100644
> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -566,6 +566,9 @@ enum ath10k_fw_features {
> */
> ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13,
>
> + /* Firmware from Candela Technologies, enables more VIFs, etc */
> + ATH10K_FW_FEATURE_WMI_10X_CT = 31,
> +
> /* keep last */
> ATH10K_FW_FEATURE_COUNT,
> };
>
regards,
shafi
>
> _______________________________________________
> ath10k mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/ath10k
From: Ben Greear <[email protected]>
Should help debug firmware crashes, and give users a way
to provide some useful debug reports to firmware developers.
Signed-off-by: Ben Greear <[email protected]>
Signed-off-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.h | 4 +++
drivers/net/wireless/ath/ath10k/debug.c | 29 +++++++++++++++++-
drivers/net/wireless/ath/ath10k/hw.h | 2 ++
drivers/net/wireless/ath/ath10k/pci.c | 52 +++++++++++++++++++++++++++++++++
4 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 7f9f460..644d077 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -427,6 +427,10 @@ struct ath10k_fw_crash_data {
uuid_le uuid;
struct timespec timestamp;
__le32 registers[REG_DUMP_COUNT_QCA988X];
+ __le32 stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
+ __le32 exc_stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
+ __le32 stack_addr;
+ __le32 exc_stack_addr;
};
struct ath10k_debug {
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 38b3541..7bc3053 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -36,10 +36,15 @@
* enum ath10k_fw_crash_dump_type - types of data in the dump file
* @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
* @ATH10K_FW_ERROR_DUMP_DBGLOG: Recent firmware debug log entries
+ * @ATH10K_FW_CRASH_DUMP_STACK: Stack memory contents.
+ * @ATH10K_FW_CRASH_DUMP_EXC_STACK: Exception stack memory contents.
*/
enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
+ ATH10K_FW_CRASH_DUMP_STACK = 2,
+ ATH10K_FW_CRASH_DUMP_EXC_STACK = 3,
+
ATH10K_FW_CRASH_DUMP_MAX,
};
@@ -103,8 +108,11 @@ struct ath10k_dump_file_data {
/* VERMAGIC_STRING */
char kernel_ver[64];
+ __le32 stack_addr;
+ __le32 exc_stack_addr;
+
/* room for growth w/out changing binary format */
- u8 unused[128];
+ u8 unused[120];
/* struct ath10k_tlv_dump_data + more */
u8 data[0];
@@ -797,6 +805,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
len = hdr_len;
len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
len += sizeof(*dump_tlv) + sizeof(ar->debug.dbglog_entry_data);
+ len += sizeof(*dump_tlv) + sizeof(crash_data->stack_buf);
+ len += sizeof(*dump_tlv) + sizeof(crash_data->exc_stack_buf);
sofar += hdr_len;
@@ -836,6 +846,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
+ dump_data->stack_addr = cpu_to_le32(crash_data->stack_addr);
+ dump_data->exc_stack_addr = cpu_to_le32(crash_data->exc_stack_addr);
strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
sizeof(dump_data->fw_ver));
@@ -868,7 +880,22 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
cpu_to_le32(ar->debug.dbglog_entry_data.head_idx);
dbglog_storage->tail_idx =
cpu_to_le32(ar->debug.dbglog_entry_data.tail_idx);
+ sofar += sizeof(*dump_tlv) + tmp;
+ /* Gather firmware stack dump */
+ tmp = sizeof(crash_data->stack_buf);
+ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_STACK);
+ dump_tlv->tlv_len = cpu_to_le32(tmp);
+ memcpy(dump_tlv->tlv_data, crash_data->stack_buf, tmp);
+ sofar += sizeof(*dump_tlv) + tmp;
+
+ /* Gather firmware exception stack dump */
+ tmp = sizeof(crash_data->exc_stack_buf);
+ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_EXC_STACK);
+ dump_tlv->tlv_len = cpu_to_le32(tmp);
+ memcpy(dump_tlv->tlv_data, crash_data->exc_stack_buf, tmp);
sofar += sizeof(*dump_tlv) + tmp;
ar->debug.fw_crash_data->crashed_since_read = false;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 5bbef4b..e86ebf0 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -122,6 +122,8 @@ enum qca9377_chip_id_rev {
#define REG_DUMP_COUNT_QCA988X 60
+#define ATH10K_FW_STACK_SIZE 4096
+
struct ath10k_fw_ie {
__le32 id;
__le32 len;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 16e32d0..62dd167 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -985,6 +985,22 @@ static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value)
return ret;
}
+static int __ath10k_pci_diag_read_hi_addr(struct ath10k *ar, __le32 *dest,
+ u32 src)
+{
+ u32 host_addr;
+ int ret;
+
+ host_addr = host_interest_item_address(src);
+
+ ret = ath10k_pci_diag_read32(ar, host_addr, dest);
+ if (ret != 0) {
+ ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n",
+ src, ret);
+ }
+ return ret;
+}
+
static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
u32 src, u32 len)
{
@@ -1013,6 +1029,9 @@ static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
#define ath10k_pci_diag_read_hi(ar, dest, src, len) \
__ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len)
+#define ath10k_pci_diag_read_hi_addr(ar, dest, src) \
+ __ath10k_pci_diag_read_hi_addr(ar, dest, HI_ITEM(src))
+
int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
const void *data, int nbytes)
{
@@ -1405,6 +1424,37 @@ u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
}
+/* Save the main firmware stack */
+static void ath10k_pci_dump_stack(struct ath10k *ar,
+ struct ath10k_fw_crash_data *crash_data)
+{
+ if (!crash_data)
+ return;
+
+ lockdep_assert_held(&ar->data_lock);
+ BUILD_BUG_ON(ATH10K_FW_STACK_SIZE % 4);
+
+ ath10k_pci_diag_read_hi(ar, crash_data->stack_buf,
+ hi_stack, ATH10K_FW_STACK_SIZE);
+ ath10k_pci_diag_read_hi_addr(ar, &crash_data->stack_addr, hi_stack);
+}
+
+/* Save the exception firmware stack */
+static void ath10k_pci_dump_exc_stack(struct ath10k *ar,
+ struct ath10k_fw_crash_data *crash_data)
+{
+ if (!crash_data)
+ return;
+
+ lockdep_assert_held(&ar->data_lock);
+
+ ath10k_pci_diag_read_hi(ar, crash_data->exc_stack_buf,
+ hi_err_stack, ATH10K_FW_STACK_SIZE);
+
+ ath10k_pci_diag_read_hi_addr(ar, &crash_data->exc_stack_addr,
+ hi_err_stack);
+}
+
static void ath10k_pci_dump_registers(struct ath10k *ar,
struct ath10k_fw_crash_data *crash_data)
{
@@ -1555,6 +1605,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
ath10k_print_driver_info(ar);
ath10k_pci_dump_registers(ar, crash_data);
ath10k_pci_dump_dbglog(ar);
+ ath10k_pci_dump_stack(ar, crash_data);
+ ath10k_pci_dump_exc_stack(ar, crash_data);
if (crash_data)
crash_data->crashed_since_read = true;
--
2.4.3
From: Ben Greear <[email protected]>
They are not necessarily named in an intuitive manner,
so at least add some comments to help the next person.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index e7c228a..c4f649f 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -189,10 +189,10 @@ struct ath10k_fw_stats_pdev {
/* PDEV stats */
s32 ch_noise_floor;
- u32 tx_frame_count;
- u32 rx_frame_count;
- u32 rx_clear_count;
- u32 cycle_count;
+ u32 tx_frame_count; /* cycles spent transmitting frames */
+ u32 rx_frame_count; /* cycles spent receiving frames */
+ u32 rx_clear_count; /* Total channel busy time, evidently */
+ u32 cycle_count; /* Total on-channel time */
u32 phy_err_count;
u32 chan_tx_power;
u32 ack_rx_bad;
--
2.4.3
On 10 May 2016 at 01:11, <[email protected]> wrote:
> From: Ben Greear <[email protected]>
>
> They are not necessarily named in an intuitive manner,
> so at least add some comments to help the next person.
>
> Signed-off-by: Ben Greear <[email protected]>
> ---
> drivers/net/wireless/ath/ath10k/core.h | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
> index e7c228a..c4f649f 100644
> --- a/drivers/net/wireless/ath/ath10k/core.h
> +++ b/drivers/net/wireless/ath/ath10k/core.h
> @@ -189,10 +189,10 @@ struct ath10k_fw_stats_pdev {
>
> /* PDEV stats */
> s32 ch_noise_floor;
> - u32 tx_frame_count;
> - u32 rx_frame_count;
> - u32 rx_clear_count;
> - u32 cycle_count;
> + u32 tx_frame_count; /* cycles spent transmitting frames */
> + u32 rx_frame_count; /* cycles spent receiving frames */
> + u32 rx_clear_count; /* Total channel busy time, evidently */
> + u32 cycle_count; /* Total on-channel time */
Hmm, there are also other instances of these vars in wmi.h. Although
redundant maybe it's worth to comment them as well (or first and
foremost they should be the ones that need a comment as they are the
"source"). Just an idea.
(oh, and my silly OCD is irritated at the big/small first letters in
the comments not being consistent)
Michał
On 05/10/2016 12:20 AM, Mohammed Shafi Shajakhan wrote:
> Hi Ben,
>
> On Mon, May 09, 2016 at 04:11:09PM -0700, [email protected] wrote:
>> From: Ben Greear <[email protected]>
>>
>> Add placeholder so CT firmware can more easily co-exist with upstream
>> kernel.
>
> [shafi] nitpick: good to provide an expansion in commit log as well, so that
> if we can easily figure out in git log alone, rather than going through
> the change and suggesting that it supports more vif's etc
CT firmware supports a great deal of things, such as IBSS, tx-rate reporting,
more control over tx-buffer allocation, rate-ctrl improvements and so forth.
I have another hundred or so patches that can enable and take advantage
of this sort of thing, but in the past, there has been no desire to allow
these patches upstream, so I am trying to feed some of the least controversial
patches first in case attitudes have changed.
If you would like to see my full patch tree, it is here:
http://dmz2.candelatech.com/?p=linux-4.4.dev.y/.git;a=summary
And, you can clone it:
git clone git://dmz2.candelatech.com/linux-4.4.dev.y
With regard to the patches in this series to dump the BSS regions and similar, I would
be happy to share my packaging script with QCA folks so they can add that info to their
own firmware. With BSS and Stack dumps, you can walk back through null-pointer exceptions
in the firmware and get a full backtrace instead of just the last call location. This means
you can remove a huge number of ASSERTS, which frees up IRAM and overall makes the code
faster.
Thanks,
Ben
--
Ben Greear <[email protected]>
Candela Technologies Inc http://www.candelatech.com
From: Ben Greear <[email protected]>
Add placeholder so CT firmware can more easily co-exist with upstream
kernel.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 1 +
drivers/net/wireless/ath/ath10k/core.h | 3 +++
2 files changed, 4 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index fa71d57..49c85c3 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -235,6 +235,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
[ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",
[ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl",
+ [ATH10K_FW_FEATURE_WMI_10X_CT] = "wmi-10.x-CT",
};
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 1a75e2e..dd38f34 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -566,6 +566,9 @@ enum ath10k_fw_features {
*/
ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13,
+ /* Firmware from Candela Technologies, enables more VIFs, etc */
+ ATH10K_FW_FEATURE_WMI_10X_CT = 31,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
};
--
2.4.3
From: Ben Greear <[email protected]>
Might want to turn off verbose debug as soon as you
see a firmware crash, for instance. Helps keep dmesg
output from over-running the stuff you care about.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/debug.c | 5 +++++
drivers/net/wireless/ath/ath10k/debug.h | 1 +
2 files changed, 6 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index e251155..a689bf1 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -194,6 +194,11 @@ void ath10k_print_driver_info(struct ath10k *ar)
}
EXPORT_SYMBOL(ath10k_print_driver_info);
+void ath10k_set_debug_mask(unsigned int v) {
+ ath10k_debug_mask = v;
+}
+EXPORT_SYMBOL(ath10k_set_debug_mask);
+
void ath10k_err(struct ath10k *ar, const char *fmt, ...)
{
struct va_format vaf = {
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 75c89e3..a5c9aae 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -69,6 +69,7 @@ void ath10k_debug_print_hwfw_info(struct ath10k *ar);
void ath10k_debug_print_board_info(struct ath10k *ar);
void ath10k_debug_print_boot_info(struct ath10k *ar);
void ath10k_print_driver_info(struct ath10k *ar);
+void ath10k_set_debug_mask(unsigned int v);
#ifdef CONFIG_ATH10K_DEBUGFS
int ath10k_debug_start(struct ath10k *ar);
--
2.4.3
From: Ben Greear <[email protected]>
This gives user-space a normal-ish way to detect that
firmware has failed to start and that a reboot is
probably required.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.h | 1 +
drivers/net/wireless/ath/ath10k/debug.c | 2 ++
drivers/net/wireless/ath/ath10k/pci.c | 2 ++
3 files changed, 5 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 6aa7a14..e7c228a 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -698,6 +698,7 @@ struct ath10k {
enum ath10k_hw_rev hw_rev;
u16 dev_id;
+ bool fw_powerup_failed; /* If true, might take reboot to recover. */
u32 chip_id;
u32 target_version;
u8 fw_version_major;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 7d9ad99..54a2194 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1487,6 +1487,7 @@ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
"d_fw_crash_count",
"d_fw_warm_reset_count",
"d_fw_cold_reset_count",
+ "d_fw_powerup_failed", /* boolean */
};
#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)
@@ -1586,6 +1587,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
data[i++] = ar->stats.fw_crash_counter;
data[i++] = ar->stats.fw_warm_reset_counter;
data[i++] = ar->stats.fw_cold_reset_counter;
+ data[i++] = ar->fw_powerup_failed;
spin_unlock_bh(&ar->data_lock);
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index dbf0db8..2adc459 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2709,10 +2709,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
goto err_ce;
}
+ ar->fw_powerup_failed = false;
return 0;
err_ce:
ath10k_pci_ce_deinit(ar);
+ ar->fw_powerup_failed = true;
err_sleep:
return ret;
--
2.4.3
From: Ben Greear <[email protected]>
This might work around problem where sometimes host cannot
access firmware crash over normal CE transport.
Requires CT firmware with matching logic in it's assert
handler (-13 and higher releases).
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/hw.h | 5 ++++
drivers/net/wireless/ath/ath10k/pci.c | 56 ++++++++++++++++++++++++++++++++++-
2 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index d3f37d5..5ff1fac 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -603,6 +603,7 @@ enum ath10k_hw_4addr_pad {
#define PCIE_INTR_ENABLE_ADDRESS 0x0008
#define PCIE_INTR_CAUSE_ADDRESS 0x000c
#define PCIE_INTR_CLR_ADDRESS ar->regs->pcie_intr_clr_address
+#define SCRATCH_2_ADDRESS 0x002c
#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address
#define CPU_INTR_ADDRESS 0x0010
@@ -614,6 +615,10 @@ enum ath10k_hw_4addr_pad {
#define FW_IND_INITIALIZED 2
#define FW_IND_HOST_READY 0x80000000
+/* CT firmware only */
+#define FW_IND_SCRATCH2_WR (1<<14) /* scratch2 has data written to it */
+#define FW_IND_SCRATCH2_RD (1<<15) /* scratch2 has been read (by host) */
+
/* HOST_REG interrupt from firmware */
#define PCIE_INTR_FIRMWARE_MASK ar->regs->pcie_intr_fw_mask
#define PCIE_INTR_CE_MASK_ALL ar->regs->pcie_intr_ce_mask_all
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 2adc459..330c150 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1507,6 +1507,54 @@ static void ath10k_pci_dump_exc_stack(struct ath10k *ar,
hi_err_stack);
}
+/* Only CT firmware can do this. Attempt to read crash dump over pci
+ * registers since normal CE transport is not working.
+ */
+static int ath10k_ct_fw_crash_regs_harder(struct ath10k *ar,
+ __le32 *reg_dump_values,
+ int len)
+{
+ u32 val;
+ int i;
+ int q;
+#define MAX_SPIN_TRIES 1000000
+
+ if (!test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ ar->running_fw->fw_file.fw_features)) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i<MAX_SPIN_TRIES; i++) {
+ val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
+ if (val & FW_IND_SCRATCH2_WR)
+ goto pingpong;
+ }
+ return -EBUSY;
+
+pingpong:
+ ath10k_warn(ar, "Trying to read crash dump over pingpong registers.\n");
+ /* Firmware is trying to send us info it seems. */
+ for (q = 0; q<len; q++) {
+ reg_dump_values[q] = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + SCRATCH_2_ADDRESS);
+ val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
+ val |= FW_IND_SCRATCH2_RD; /* tell firmware we read it */
+ val &= ~FW_IND_SCRATCH2_WR; /* clear firmware's write flag */
+ ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
+
+ for (i = 0; i<MAX_SPIN_TRIES; i++) {
+ val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
+ if (val & FW_IND_SCRATCH2_WR)
+ break;
+ }
+ if (!(val & FW_IND_SCRATCH2_WR)) {
+ ath10k_err(ar, "failed to read reg %i via pingpong method.\n",
+ q);
+ return 0; // partial read is better than nothing I guess
+ }
+ }
+ return 0;
+}
+
static void ath10k_pci_dump_registers(struct ath10k *ar,
struct ath10k_fw_crash_data *crash_data)
{
@@ -1520,7 +1568,13 @@ static void ath10k_pci_dump_registers(struct ath10k *ar,
REG_DUMP_COUNT_QCA988X * sizeof(__le32));
if (ret) {
ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
- return;
+
+ /* Try to read this directly over registers...only works on new
+ * CT firmware.
+ */
+ ret = ath10k_ct_fw_crash_regs_harder(ar, reg_dump_values, REG_DUMP_COUNT_QCA988X);
+ if (ret)
+ return;
}
BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
--
2.4.3
From: Ben Greear <[email protected]>
CT firmware can support IBSS mode, so allow users to configure this.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index f1bfb3a..3fc9006 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7482,6 +7482,10 @@ static const struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
.max = 7,
.types = BIT(NL80211_IFTYPE_AP)
},
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_ADHOC)
+ },
};
static const struct ieee80211_iface_combination ath10k_if_comb[] = {
@@ -7862,6 +7866,7 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->iface_combinations = ath10k_10x_ct_if_comb;
ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_10x_ct_if_comb);
+ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
} else {
ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
ar->hw->wiphy->n_iface_combinations =
--
2.4.3
From: Ben Greear <[email protected]>
CT firmware has been modified so that it will always return
a response message when user requests to add a key, even if
the key could not actually be added. Upstream firmware may
assert or just not respond in a failure case.
This change should be compatible with non CT firmware.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.h | 1 +
drivers/net/wireless/ath/ath10k/htt.h | 7 +++++--
drivers/net/wireless/ath/ath10k/htt_rx.c | 20 +++++++++++++++++---
drivers/net/wireless/ath/ath10k/mac.c | 3 ++-
4 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index dd38f34..dae453a 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -848,6 +848,7 @@ struct ath10k {
unsigned int filter_flags;
unsigned long dev_flags;
bool dfs_block_radar_events;
+ int install_key_rv; /* Store error code from key-install */
/* protected by conf_mutex */
bool radar_enabled;
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 911c535..c50b343 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -702,8 +702,9 @@ enum htt_security_types {
};
enum htt_security_flags {
-#define HTT_SECURITY_TYPE_MASK 0x7F
+#define HTT_SECURITY_TYPE_MASK 0x3F
#define HTT_SECURITY_TYPE_LSB 0
+ HTT_SECURITY_IS_FAILURE = 1 << 6, /* CT firmware only */
HTT_SECURITY_IS_UNICAST = 1 << 7
};
@@ -712,7 +713,9 @@ struct htt_security_indication {
/* dont use bitfields; undefined behaviour */
u8 flags; /* %htt_security_flags */
struct {
- u8 security_type:7, /* %htt_security_types */
+ u8 security_type:6, /* %htt_security_types */
+ is_failure:1, /* does this response indicate failure
+ (CT Firmware) */
is_unicast:1;
} __packed;
} __packed;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 47da904..02b5417 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2307,9 +2307,23 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
ath10k_dbg(ar, ATH10K_DBG_HTT,
"sec ind peer_id %d unicast %d type %d\n",
- __le16_to_cpu(ev->peer_id),
- !!(ev->flags & HTT_SECURITY_IS_UNICAST),
- MS(ev->flags, HTT_SECURITY_TYPE));
+ __le16_to_cpu(ev->peer_id),
+ !!(ev->flags & HTT_SECURITY_IS_UNICAST),
+ MS(ev->flags, HTT_SECURITY_TYPE));
+
+ /* CT firmware adds way to determine failure of key set, without
+ * just timing things out. Indication of failure is determined
+ * by the 6th bit of the security-type being set.
+ */
+ if (ev->flags & HTT_SECURITY_IS_FAILURE) {
+ ath10k_warn(ar, "Firmware failed to set security key, peer_id: %d unicast %d type %d\n",
+ __le16_to_cpu(ev->peer_id),
+ !!(ev->flags & HTT_SECURITY_IS_UNICAST),
+ MS(ev->flags, HTT_SECURITY_TYPE));
+ ar->install_key_rv = -EINVAL;
+ } else {
+ ar->install_key_rv = 0;
+ }
complete(&ar->install_key_done);
break;
}
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 2169337..373f2ee 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -255,7 +255,8 @@ static int ath10k_install_key(struct ath10k_vif *arvif,
if (time_left == 0)
return -ETIMEDOUT;
- return 0;
+ ret = ar->install_key_rv;
+ return ret;
}
static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
--
2.4.3
From: Ben Greear <[email protected]>
This allows user-space tools to decode debug-log
messages by parsing dmesg or /var/log/messages.
Signed-off-by: Ben Greear <[email protected]>
---
drivers/net/wireless/ath/ath10k/debug.c | 72 +++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/debug.h | 5 +++
drivers/net/wireless/ath/ath10k/pci.c | 3 ++
drivers/net/wireless/ath/ath10k/wmi.c | 12 ++++++
4 files changed, 92 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 28e0c05..c38862b 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -2660,3 +2660,75 @@ void ath10k_dbg_dump(struct ath10k *ar,
EXPORT_SYMBOL(ath10k_dbg_dump);
#endif /* CONFIG_ATH10K_DEBUG */
+
+void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *ibuf, int len,
+ const char* lvl)
+{
+ /* Print out raw hex, external tools can decode if
+ * they care.
+ * TODO: Add ar identifier to messages.
+ */
+ int q = 0;
+
+ dev_printk(lvl, ar->dev, "ath10k_pci ATH10K_DBG_BUFFER:\n");
+ while (q < len) {
+ if (q + 8 <= len) {
+ printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X %08X %08X\n",
+ lvl, q,
+ ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+ ibuf[q+4], ibuf[q+5], ibuf[q+6], ibuf[q+7]);
+ q += 8;
+ }
+ else if (q + 7 <= len) {
+ printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X %08X\n",
+ lvl, q,
+ ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+ ibuf[q+4], ibuf[q+5], ibuf[q+6]);
+ q += 7;
+ }
+ else if (q + 6 <= len) {
+ printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X\n",
+ lvl, q,
+ ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+ ibuf[q+4], ibuf[q+5]);
+ q += 6;
+ }
+ else if (q + 5 <= len) {
+ printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X\n",
+ lvl, q,
+ ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+ ibuf[q+4]);
+ q += 5;
+ }
+ else if (q + 4 <= len) {
+ printk("%sath10k: [%04d]: %08X %08X %08X %08X\n",
+ lvl, q,
+ ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3]);
+ q += 4;
+ }
+ else if (q + 3 <= len) {
+ printk("%sath10k: [%04d]: %08X %08X %08X\n",
+ lvl, q,
+ ibuf[q], ibuf[q+1], ibuf[q+2]);
+ q += 3;
+ }
+ else if (q + 2 <= len) {
+ printk("%sath10k: [%04d]: %08X %08X\n",
+ lvl, q,
+ ibuf[q], ibuf[q+1]);
+ q += 2;
+ }
+ else if (q + 1 <= len) {
+ printk("%sath10k: [%04d]: %08X\n",
+ lvl, q,
+ ibuf[q]);
+ q += 1;
+ }
+ else {
+ break;
+ }
+ }/* while */
+
+ dev_printk(lvl, ar->dev, "ATH10K_END\n");
+}
+EXPORT_SYMBOL(ath10k_dbg_print_fw_dbg_buffer);
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 613ad7e..6356dce 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -38,6 +38,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_WMI_PRINT = 0x00002000,
ATH10K_DBG_PCI_PS = 0x00004000,
ATH10K_DBG_AHB = 0x00008000,
+ ATH10K_DBG_FW = 0x80000000,
ATH10K_DBG_ANY = 0xffffffff,
};
@@ -193,4 +194,8 @@ static inline void ath10k_dbg_dump(struct ath10k *ar,
{
}
#endif /* CONFIG_ATH10K_DEBUG */
+
+void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer,
+ int len, const char* lvl);
+
#endif /* _DEBUG_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index e6315ec..dbf0db8 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1623,6 +1623,9 @@ static void ath10k_pci_dump_dbglog(struct ath10k *ar)
WARN_ON(len & 0x3);
ath10k_dbg_save_fw_dbg_buffer(ar, (__le32 *)(buffer), len >> 2);
+ ath10k_dbg_print_fw_dbg_buffer(ar, (__le32 *)(buffer),
+ dbuf.length/sizeof(__le32),
+ KERN_ERR);
kfree(buffer);
next:
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index d9e4b77..6cfba41 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2510,6 +2510,18 @@ int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
(skb->len - 4)/sizeof(__le32));
spin_unlock_bh(&ar->data_lock);
+ if (ev->dropped_count)
+ ath10k_warn(ar, "WARNING: Dropped dbglog buffers: %d\n", __le32_to_cpu(ev->dropped_count));
+
+ if (ath10k_debug_mask & ATH10K_DBG_FW)
+ ath10k_dbg_print_fw_dbg_buffer(ar, ev->messages,
+ (skb->len - 4)/sizeof(__le32),
+ KERN_INFO);
+ else
+ ath10k_dbg_print_fw_dbg_buffer(ar, ev->messages,
+ (skb->len - 4)/sizeof(__le32),
+ KERN_DEBUG);
+
return 0;
}
--
2.4.3