[qca-nss-drv] Dump logbuffer during the coredump
Change-Id: Icacb3056cb4baac1c18d0d3a802cadf2d94d1914
Signed-off-by: Cemil Coskun <ccoskun@codeaurora.org>
diff --git a/nss_core.c b/nss_core.c
index 244b87e..d5ed5c4 100644
--- a/nss_core.c
+++ b/nss_core.c
@@ -2891,4 +2891,3 @@
NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
return status;
}
-
diff --git a/nss_core.h b/nss_core.h
index 82897c9..3fc12b6 100644
--- a/nss_core.h
+++ b/nss_core.h
@@ -217,6 +217,13 @@
#define NSS_TX_UNBLOCKED_PROCESSING_WEIGHT 1
/*
+ * Cache line size of the NSS.
+ */
+#define NSS_CACHE_LINE_SIZE 32
+
+/*
+ * Statistics struct
+ *
* INFO: These numbers are based on previous generation chip
* These may change in future
*/
@@ -270,14 +277,18 @@
#if (NSS_DT_SUPPORT == 1)
#define NSSTCM_FREQ 400000000 /* NSS TCM Frequency in Hz */
-/* NSS Clock names */
+/*
+ * NSS Clock names
+ */
#define NSS_CORE_CLK "nss-core-clk"
#define NSS_TCM_SRC_CLK "nss-tcm-src"
#define NSS_TCM_CLK "nss-tcm-clk"
#define NSS_FABRIC0_CLK "nss-fab0-clk"
#define NSS_FABRIC1_CLK "nss-fab1-clk"
-/* NSS Fabric speeds */
+/*
+ * NSS Fabric speeds
+ */
#define NSS_FABRIC0_TURBO 533000000
#define NSS_FABRIC1_TURBO 266500000
#define NSS_FABRIC0_NOMINAL 400000000
diff --git a/nss_coredump.c b/nss_coredump.c
index 4692d48..ee3888b 100644
--- a/nss_coredump.c
+++ b/nss_coredump.c
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
@@ -21,6 +21,7 @@
#include "nss_core.h"
#include "nss_hal.h"
+#include "nss_log.h"
#include <linux/kernel.h>
#include <linux/notifier.h> /* for panic_notifier_list */
#include <linux/jiffies.h> /* for time */
@@ -131,23 +132,72 @@
void nss_fw_coredump_notify(struct nss_ctx_instance *nss_own,
int intr __attribute__ ((unused)))
{
- int i;
+ int i, j, curr_index, useful_entries;
+ struct nss_log_descriptor *nld;
+ struct nss_log_entry *nle_init, *nle_print;
+ dma_addr_t dma_addr;
+ uint32_t offset, index;
+
nss_warning("\n%p: COREDUMP %x Baddr %p stat %x\n",
nss_own, intr, nss_own->nmap, nss_own->state);
nss_own->state |= NSS_CORE_STATE_FW_DEAD;
queue_delayed_work(coredump_workqueue, &coredump_queuewait,
msecs_to_jiffies(3456));
+ /*
+ * If external log buffer is not set, use the nss initial log buffer.
+ */
+ nld = (struct nss_log_descriptor *)(nss_rbe[nss_own->id].addr);
+ dma_addr = nss_rbe[nss_own->id].dma_addr;
+ if (!nld) {
+ nld = nss_own->meminfo_ctx.logbuffer;
+ dma_addr = nss_own->meminfo_ctx.logbuffer_dma;
+ }
+
+ dma_sync_single_for_cpu(NULL, dma_addr, sizeof(struct nss_log_descriptor), DMA_FROM_DEVICE);
+
+ /*
+ * If the current entry is smaller than or equal to the number of NSS_LOG_COREDUMP_LINE_NUM,
+ * only print whatever is in the buffer. Otherwise, dump last NSS_LOG_COREDUMP_LINE_NUM
+ * to the dmessage.
+ */
+ nss_info_always("\n%p: Starting NSS-FW logbuffer dump for core %u\n",
+ nss_own, nss_own->id);
+ nle_init = nld->log_ring_buffer;
+ if (nld->current_entry <= NSS_LOG_COREDUMP_LINE_NUM) {
+ curr_index = 0;
+ useful_entries = nld->current_entry;
+ } else {
+ curr_index = ((nld->current_entry - NSS_LOG_COREDUMP_LINE_NUM) % nld->log_nentries);
+ useful_entries = NSS_LOG_COREDUMP_LINE_NUM;
+ }
+
+ nle_print = nle_init + curr_index;
+ for (j = index = curr_index; j < (curr_index + useful_entries); j++, index++) {
+ if (j == nld->log_nentries) {
+ nle_print = nle_init;
+ index = 0;
+ }
+
+ offset = (index * sizeof(struct nss_log_entry))
+ + offsetof(struct nss_log_descriptor, log_ring_buffer);
+ dma_sync_single_for_cpu(NULL, dma_addr + offset,
+ sizeof(struct nss_log_entry), DMA_FROM_DEVICE);
+ nss_info_always("%p: %s\n", nss_own, nle_print->message);
+ nle_print++;
+ }
+
if (nss_own->state & NSS_CORE_STATE_PANIC)
return;
for (i = 0; i < NSS_MAX_CORES; i++) {
- struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[i];
+
/*
* only for two core now; if more cores, a counter is required
* to remember how many core has dumped.
* Do not call panic() till all core dumped.
*/
+ struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[i];
if (nss_ctx != nss_own) {
if (nss_ctx->state & NSS_CORE_STATE_FW_DEAD ||
!nss_ctx->nmap) {
diff --git a/nss_log.c b/nss_log.c
index 4cf0795..7a0fdd5 100644
--- a/nss_log.c
+++ b/nss_log.c
@@ -46,17 +46,7 @@
int nss_id; /* NSS Core id being used */
};
-/*
- * Saves the ring buffer address for logging per NSS core
- */
-struct nss_ring_buffer_addr {
- void *addr; /* Pointer to struct nss_log_descriptor */
- dma_addr_t dma_addr; /* DMA Handle */
- uint32_t nentries; /* Number of entries in the ring buffer */
- int refcnt; /* Reference count */
-};
-
-static struct nss_ring_buffer_addr nss_rbe[NSS_MAX_CORES];
+struct nss_log_ring_buffer_addr nss_rbe[NSS_MAX_CORES];
static DEFINE_MUTEX(nss_log_mutex);
static wait_queue_head_t nss_log_wq;
@@ -140,7 +130,7 @@
* Increment the reference count so that we don't free
* the memory
*/
- nss_rbe[nss_id].refcnt++;
+ nss_rbe[nss_id].ref_cnt++;
data->nss_id = nss_id;
filp->private_data = data;
mutex_unlock(&nss_log_mutex);
@@ -162,9 +152,9 @@
}
mutex_lock(&nss_log_mutex);
- nss_rbe[data->nss_id].refcnt--;
- BUG_ON(nss_rbe[data->nss_id].refcnt < 0);
- if (nss_rbe[data->nss_id].refcnt == 0) {
+ nss_rbe[data->nss_id].ref_cnt--;
+ BUG_ON(nss_rbe[data->nss_id].ref_cnt < 0);
+ if (!nss_rbe[data->nss_id].ref_cnt) {
wake_up(&nss_log_wq);
}
mutex_unlock(&nss_log_mutex);
@@ -217,7 +207,7 @@
/*
* Get the current index
*/
- dma_sync_single_for_cpu(NULL, data->dma_addr, sizeof (struct nss_log_descriptor), DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(NULL, data->dma_addr, sizeof(struct nss_log_descriptor), DMA_FROM_DEVICE);
entry = nss_log_current_entry(desc);
/*
@@ -230,7 +220,7 @@
/*
* If this is the first read (after open) on our device file.
*/
- if (unlikely(*ppos == 0)) {
+ if (unlikely(!(*ppos))) {
/*
* If log buffer has rolled over. Almost all the time
* it will be true.
@@ -258,7 +248,7 @@
*/
while (entry > data->last_entry) {
index = offset = (data->last_entry % data->nentries);
- offset = (offset * sizeof (struct nss_log_entry))
+ offset = (offset * sizeof(struct nss_log_entry))
+ offsetof(struct nss_log_descriptor, log_ring_buffer);
dma_sync_single_for_cpu(NULL, data->dma_addr + offset,
@@ -274,13 +264,12 @@
* Copy to user buffer and if we fail then we return
* failure.
*/
- if (copy_to_user(buf + bytes, msg, b) == 0) {
- bytes += b;
- } else {
- bytes = -EFAULT;
- break;
+ if (copy_to_user(buf + bytes, msg, b)) {
+ return -EFAULT;
}
+ bytes += b;
+
/*
* If we ran out of space in the buffer.
*/
@@ -316,7 +305,7 @@
* nss_debug_interface_event()
* Received an event from NSS FW
*/
-static void nss_debug_interface_event(void *app_data, struct nss_debug_interface_msg *nim)
+static void nss_debug_interface_event(void *app_data, struct nss_log_debug_interface_msg *nim)
{
struct nss_cmn_msg *ncm = (struct nss_cmn_msg *)nim;
@@ -327,11 +316,11 @@
/*
* nss_debug_interface_handler()
- * handle NSS -> HLOS messages for debug interfaces
+ * handle NSS -> HLOS messages for debug interfaces
*/
static void nss_debug_interface_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
{
- struct nss_debug_interface_msg *ntm = (struct nss_debug_interface_msg *)ncm;
+ struct nss_log_debug_interface_msg *ntm = (struct nss_log_debug_interface_msg *)ncm;
nss_log_msg_callback_t cb;
BUG_ON(ncm->interface != NSS_DEBUG_INTERFACE);
@@ -344,7 +333,7 @@
return;
}
- if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_debug_interface_msg)) {
+ if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_log_debug_interface_msg)) {
nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
return;
}
@@ -373,9 +362,9 @@
/*
* nss_debug_interface_tx()
- * Transmit a debug interface message to NSS FW
+ * Transmit a debug interface message to NSS FW
*/
-static nss_tx_status_t nss_debug_interface_tx(struct nss_ctx_instance *nss_ctx, struct nss_debug_interface_msg *msg)
+static nss_tx_status_t nss_debug_interface_tx(struct nss_ctx_instance *nss_ctx, struct nss_log_debug_interface_msg *msg)
{
struct nss_cmn_msg *ncm = &msg->cm;
@@ -401,17 +390,14 @@
*/
bool nss_debug_log_buffer_alloc(uint8_t nss_id, uint32_t nentry)
{
- struct nss_ring_buffer_addr old_rbe;
- struct nss_debug_interface_msg msg;
- struct nss_debug_log_memory_msg *dbg;
+ struct nss_log_debug_interface_msg msg;
+ struct nss_log_debug_memory_msg *dbg;
struct nss_top_instance *nss_top;
struct nss_ctx_instance *nss_ctx;
dma_addr_t dma_addr;
uint32_t size;
void *addr = NULL;
nss_tx_status_t status;
- bool err = false;
- bool old_state = false;
if (nss_id >= NSS_MAX_CORES) {
return false;
@@ -425,9 +411,7 @@
return false;
}
- memset(&msg, 0, sizeof(struct nss_debug_interface_msg));
-
- size = sizeof (struct nss_log_descriptor) + (sizeof (struct nss_log_entry) * nentry);
+ size = sizeof(struct nss_log_descriptor) + (sizeof(struct nss_log_entry) * nentry);
addr = kmalloc(size, GFP_ATOMIC);
if (!addr) {
nss_warning("%p: Failed to allocate memory for logging (size:%d)\n", nss_ctx, size);
@@ -438,7 +422,8 @@
dma_addr = (uint32_t)dma_map_single(nss_ctx->dev, addr, size, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(nss_ctx->dev, dma_addr))) {
nss_warning("%p: Failed to map address in DMA", nss_ctx);
- goto fail2;
+ kfree(addr);
+ return false;
}
/*
@@ -448,40 +433,32 @@
mutex_lock(&nss_log_mutex);
if (nss_rbe[nss_id].addr) {
mutex_unlock(&nss_log_mutex);
- if (!wait_event_timeout(nss_log_wq, nss_rbe[nss_id].refcnt == 0, 5 * HZ)) {
+
+ /*
+ * Someone is using the current logbuffer. Wait until ref count become 0.
+ * We have to return mutex here, because the current user requires it to
+ * release the reference.
+ */
+ if (!wait_event_timeout(nss_log_wq, !nss_rbe[nss_id].ref_cnt, 5 * HZ)) {
nss_warning("%p: Timeout waiting for refcnt to become 0\n", nss_ctx);
- goto fail1;
+ goto fail;
}
mutex_lock(&nss_log_mutex);
if (!nss_rbe[nss_id].addr) {
mutex_unlock(&nss_log_mutex);
- goto fail1;
+ goto fail;
}
- if (nss_rbe[nss_id].refcnt > 0) {
+ if (nss_rbe[nss_id].ref_cnt > 0) {
mutex_unlock(&nss_log_mutex);
- nss_warning("%p: Some other thread is condenting..opting out\n", nss_ctx);
- goto fail1;
+ nss_warning("%p: Some other thread is contending..opting out\n", nss_ctx);
+ goto fail;
}
-
- /*
- * Save the original dma buffer. In case we fail down the line, we will
- * restore the state. Otherwise, old_state will be freed once we get
- * ACK from NSS FW.
- */
- old_state = true;
- memcpy(&old_rbe, &nss_rbe[nss_id], sizeof (struct nss_ring_buffer_addr));
}
- nss_rbe[nss_id].addr = addr;
- nss_rbe[nss_id].nentries = nentry;
- nss_rbe[nss_id].refcnt = 1; /* Block other threads till we are done */
- nss_rbe[nss_id].dma_addr = dma_addr;
- mutex_unlock(&nss_log_mutex);
-
- memset(&msg, 0, sizeof (struct nss_debug_interface_msg));
+ memset(&msg, 0, sizeof(struct nss_log_debug_interface_msg));
nss_cmn_msg_init(&msg.cm, NSS_DEBUG_INTERFACE, NSS_DEBUG_INTERFACE_TYPE_LOG_BUF_INIT,
- sizeof(struct nss_debug_log_memory_msg), nss_debug_interface_event, NULL);
+ sizeof(struct nss_log_debug_memory_msg), nss_debug_interface_event, NULL);
dbg = &msg.msg.addr;
dbg->nentry = nentry;
@@ -491,80 +468,49 @@
msg_event = false;
status = nss_debug_interface_tx(nss_ctx, &msg);
if (status != NSS_TX_SUCCESS) {
+ mutex_unlock(&nss_log_mutex);
nss_warning("%p: Failed to send message to debug interface:%d\n", nss_ctx, status);
- err = true;
- } else {
- int r;
+ goto fail;
+ }
- /*
- * Wait for 5 seconds since this is a critical operation.
- */
- r = wait_event_timeout(msg_wq, msg_event == true, 5 * HZ);
- if (r == 0) {
- nss_warning("%p: Timeout send message to debug interface\n", nss_ctx);
- err = true;
- } else if (msg_response != NSS_CMN_RESPONSE_ACK) {
- nss_warning("%p: Response error for send message to debug interface:%d\n", nss_ctx, msg_response);
- err = true;
- }
+ /*
+ * Wait for 5 seconds since this is a critical operation.
+ * Mutex is not unlocked here because we do not want someone to acquire the mutex and use the logbuffer
+ * while we are waiting message from NSS.
+ */
+ if (!wait_event_timeout(msg_wq, msg_event, 5 * HZ)) {
+ mutex_unlock(&nss_log_mutex);
+ nss_warning("%p: Timeout send message to debug interface\n", nss_ctx);
+ goto fail;
+ }
+
+ if (msg_response != NSS_CMN_RESPONSE_ACK) {
+ mutex_unlock(&nss_log_mutex);
+ nss_warning("%p: Response error for send message to debug interface:%d\n", nss_ctx, msg_response);
+ goto fail;
}
/*
* If we had to free the previous allocation for ring buffer.
*/
- if (old_state == true) {
- /*
- * If we didn't fail, then we must unmap and free previous dma buffer
- */
- if (err == false) {
- uint32_t old_size;
-
- old_size = sizeof (struct nss_log_descriptor) +
- (sizeof (struct nss_log_entry) * old_rbe.nentries);
- dma_unmap_single(nss_ctx->dev, old_rbe.dma_addr, old_size, DMA_FROM_DEVICE);
- kfree(old_rbe.addr);
- } else {
- /*
- * Restore the original dma buffer since we failed somewhere.
- */
- mutex_lock(&nss_log_mutex);
- memcpy(&nss_rbe[nss_id], &old_rbe, sizeof (struct nss_ring_buffer_addr));
- mutex_unlock(&nss_log_mutex);
- wake_up(&nss_log_wq);
- }
- } else {
- /*
- * There was no logbuffer allocated from host side.
- */
-
- /*
- * If there was error, then we need to reset back. Note that we are
- * still holding refcnt.
- */
- if (err == true) {
- mutex_lock(&nss_log_mutex);
- nss_rbe[nss_id].addr = NULL;
- nss_rbe[nss_id].nentries = 0;
- nss_rbe[nss_id].refcnt = 0;
- nss_rbe[nss_id].dma_addr = 0;
- mutex_unlock(&nss_log_mutex);
- wake_up(&nss_log_wq);
- }
+ if (nss_rbe[nss_id].addr) {
+ uint32_t old_size;
+ old_size = sizeof(struct nss_log_descriptor) +
+ (sizeof(struct nss_log_entry) * nss_rbe[nss_id].nentries);
+ dma_unmap_single(nss_ctx->dev, nss_rbe[nss_id].dma_addr, old_size, DMA_FROM_DEVICE);
+ kfree(nss_rbe[nss_id].addr);
}
- if (err == false) {
- mutex_lock(&nss_log_mutex);
- nss_rbe[nss_id].refcnt--; /* we are done */
- mutex_unlock(&nss_log_mutex);
- wake_up(&nss_log_wq);
- return true;
- }
+ nss_rbe[nss_id].addr = addr;
+ nss_rbe[nss_id].nentries = nentry;
+ nss_rbe[nss_id].ref_cnt = 0;
+ nss_rbe[nss_id].dma_addr = dma_addr;
+ mutex_unlock(&nss_log_mutex);
+ wake_up(&nss_log_wq);
+ return true;
-fail1:
- if (addr) {
- dma_unmap_single(NULL, dma_addr, size, DMA_FROM_DEVICE);
- }
-fail2:
+fail:
+ dma_unmap_single(NULL, dma_addr, size, DMA_FROM_DEVICE);
kfree(addr);
wake_up(&nss_log_wq);
return false;
@@ -590,7 +536,7 @@
}
if (nss_ctl_logbuf < 32) {
- printk("Invalid NSS FW logbuffer size:%d (must be > 32)\n", nss_ctl_logbuf);
+ nss_warning("Invalid NSS FW logbuffer size:%d (must be > 32)\n", nss_ctl_logbuf);
nss_ctl_logbuf = 0;
return ret;
}
@@ -604,7 +550,7 @@
nss_warning("NSS logbuffer init failed with register handler:%d\n", core_status);
}
- if (nss_debug_log_buffer_alloc(i, nss_ctl_logbuf) == false) {
+ if (!nss_debug_log_buffer_alloc(i, nss_ctl_logbuf)) {
nss_warning("%d: Failed to set debug log buffer on NSS core", i);
}
}
diff --git a/nss_log.h b/nss_log.h
index fd463c5..d5220d1 100644
--- a/nss_log.h
+++ b/nss_log.h
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
@@ -38,10 +38,26 @@
#define NSS_LOG_OUTPUT_LINE_SIZE 151 /* 5 + 12 + 132 + '\n' + '\0' (see below) */
#define NSS_LOG_LINE_FORMAT "%3d: %010u: %s\n"
#define NSS_LOG_LINE_WIDTH 132
-#define NSS_CACHE_LINE_SIZE 32
#define NSS_LOG_COOKIE 0xFF785634
/*
+ * Dump last N entry during the coredump.
+ * This number should be lower than the minimum size of the logbuf
+ * which 32 right now.
+ */
+#define NSS_LOG_COREDUMP_LINE_NUM 10
+
+/*
+ * Saves the ring buffer address for logging per NSS core
+ */
+struct nss_log_ring_buffer_addr {
+ void *addr; /* Pointer to struct nss_log_descriptor */
+ dma_addr_t dma_addr; /* DMA Handle */
+ uint32_t nentries; /* Number of entries in the ring buffer */
+ int ref_cnt; /* Reference count */
+};
+
+/*
* nss_log_entry is shared between Host and NSS FW
*/
struct nss_log_entry {
@@ -66,16 +82,16 @@
struct nss_log_entry log_ring_buffer[0]; /* The actual log entry ring buffer */
} __attribute__((aligned(NSS_CACHE_LINE_SIZE)));
-struct nss_debug_log_memory_msg {
+struct nss_log_debug_memory_msg {
uint32_t version;
uint32_t nentry;
uint32_t phy_addr;
};
-struct nss_debug_interface_msg {
+struct nss_log_debug_interface_msg {
struct nss_cmn_msg cm;
union {
- struct nss_debug_log_memory_msg addr;
+ struct nss_log_debug_memory_msg addr;
} msg;
};
@@ -87,11 +103,13 @@
*
* @return void
*/
-typedef void (*nss_log_msg_callback_t)(void *app_data, struct nss_debug_interface_msg *msg);
+typedef void (*nss_log_msg_callback_t)(void *app_data, struct nss_log_debug_interface_msg *msg);
/*
* Exported by nss_init.c and used in nss_log.c
*/
extern int nss_ctl_logbuf;
+extern struct nss_log_ring_buffer_addr nss_rbe[NSS_MAX_CORES];
+
#endif /* __NSS_LOG_H */
diff --git a/nss_meminfo.c b/nss_meminfo.c
index 2028948..719a4aa 100644
--- a/nss_meminfo.c
+++ b/nss_meminfo.c
@@ -299,6 +299,12 @@
mem_ctx->if_map = (struct nss_if_mem_map *)kern_addr;
}
+ if (!strcmp(r->name, "debug_boot_log_desc")) {
+ mem_ctx->logbuffer_memtype = mtype;
+ mem_ctx->logbuffer_dma = dma_addr;
+ mem_ctx->logbuffer = (struct nss_log_descriptor *)kern_addr;
+ }
+
/*
* Flush the updated meminfo request.
*/
diff --git a/nss_meminfo.h b/nss_meminfo.h
index bd7a8d7..d2f5d1e 100644
--- a/nss_meminfo.h
+++ b/nss_meminfo.h
@@ -112,6 +112,9 @@
struct nss_if_mem_map *if_map; /* nss_if_mem_map_inst virtual address */
uint32_t if_map_dma; /* nss_if_mem_map_inst physical address */
enum nss_meminfo_memtype if_map_memtype; /* Memory type for nss_if_mem_map */
+ struct nss_log_descriptor *logbuffer; /* nss_logbuffer virtual address */
+ uint32_t logbuffer_dma; /* nss_logbuffer physical address */
+ enum nss_meminfo_memtype logbuffer_memtype; /* Memory type for logbuffer */
struct nss_meminfo_map meminfo_map; /* Meminfo map */
struct nss_meminfo_block_list block_lists[NSS_MEMINFO_MEMTYPE_MAX];
/* Block lists for each memory type */