[net-next,3/8] cxgb4: collect on-chip memory dump

Message ID c33d67b3caa86c3f57438d13dd9341a8a0fe63c9.1507795407.git.rahul.lakkireddy@chelsio.com
State Changes Requested
Delegated to: David Miller
Headers show
Series
  • cxgb4: add support to get hardware debug logs via ethtool
Related show

Commit Message

Rahul Lakkireddy Oct. 12, 2017, 8:24 a.m.
Collect EDC0 and EDC1 memory dump.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
---
 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h  |  29 +++++
 drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h      |   8 ++
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c     | 132 +++++++++++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h     |   6 +
 .../net/ethernet/chelsio/cxgb4/cudbg_lib_common.h  |   3 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c   |  38 +++++-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h   |   1 +
 7 files changed, 216 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h

Patch

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
new file mode 100644
index 000000000000..71a426dd22f5
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
@@ -0,0 +1,29 @@ 
+/*
+ *  Copyright (C) 2017 Chelsio Communications.  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms and conditions of the GNU General Public License,
+ *  version 2, as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  The full GNU General Public License is included in this distribution in
+ *  the file called "COPYING".
+ *
+ */
+
+#ifndef __CUDBG_ENTITY_H__
+#define __CUDBG_ENTITY_H__
+
+#define EDC0_FLAG 3
+#define EDC1_FLAG 4
+
+struct card_mem {
+	u16 size_edc0;
+	u16 size_edc1;
+	u16 mem_flag;
+};
+#endif /* __CUDBG_ENTITY_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
index 73725a8666df..e45690fd0932 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
@@ -20,6 +20,7 @@ 
 
 /* Error codes */
 #define CUDBG_STATUS_NO_MEM -19
+#define CUDBG_STATUS_ENTITY_NOT_FOUND -24
 #define CUDBG_SYSTEM_ERROR -29
 
 #define CUDBG_MAJOR_VERSION 1
@@ -27,6 +28,8 @@ 
 
 enum cudbg_dbg_entity_type {
 	CUDBG_REG_DUMP = 1,
+	CUDBG_EDC0 = 18,
+	CUDBG_EDC1 = 19,
 	CUDBG_MAX_ENTITY = 70,
 };
 
@@ -35,4 +38,9 @@  struct cudbg_init {
 	void *outbuf; /* Output buffer */
 	u32 outbuf_size;  /* Output buffer size */
 };
+
+static inline unsigned int mbytes_to_bytes(unsigned int size)
+{
+	return size * 1024 * 1024;
+}
 #endif /* __CUDBG_IF_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index 4605481706ec..b0a747a6fbb2 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -15,10 +15,12 @@ 
  *
  */
 
+#include "t4_regs.h"
 #include "cxgb4.h"
 #include "cudbg_if.h"
 #include "cudbg_lib_common.h"
 #include "cudbg_lib.h"
+#include "cudbg_entity.h"
 
 static void write_and_release_buff(struct cudbg_buffer *pin_buff,
 				   struct cudbg_buffer *dbg_buff)
@@ -27,6 +29,16 @@  static void write_and_release_buff(struct cudbg_buffer *pin_buff,
 	put_cudbg_buff(pin_buff, dbg_buff);
 }
 
+static int is_fw_attached(struct cudbg_init *pdbg_init)
+{
+	struct adapter *padap = pdbg_init->adap;
+
+	if (!(padap->flags & FW_OK) || padap->use_bd)
+		return 0;
+
+	return 1;
+}
+
 /* This function will add additional padding bytes into debug_buffer to make it
  * 4 byte aligned.
  */
@@ -77,3 +89,123 @@  int collect_reg_dump(struct cudbg_init *pdbg_init,
 	write_and_release_buff(&temp_buff, dbg_buff);
 	return rc;
 }
+
+static int read_fw_mem(struct cudbg_init *pdbg_init,
+		       struct cudbg_buffer *dbg_buff, u8 mem_type,
+		       unsigned long tot_len, struct cudbg_error *cudbg_err)
+{
+	unsigned long bytes, bytes_left, bytes_read = 0;
+	struct adapter *padap = pdbg_init->adap;
+	struct cudbg_buffer temp_buff = { 0 };
+	int rc = 0;
+
+	bytes_left = tot_len;
+	while (bytes_left > 0) {
+		bytes = min_t(unsigned long, bytes_left,
+			      (unsigned long)CUDBG_CHUNK_SIZE);
+		rc = get_cudbg_buff(dbg_buff, bytes, &temp_buff);
+		if (rc)
+			return rc;
+		spin_lock(&padap->win0_lock);
+		rc = t4_memory_rw(padap, MEMWIN_NIC, mem_type,
+				  bytes_read, bytes,
+				  (__be32 *)temp_buff.data,
+				  1);
+		spin_unlock(&padap->win0_lock);
+		if (rc) {
+			cudbg_err->sys_err = rc;
+			put_cudbg_buff(&temp_buff, dbg_buff);
+			return rc;
+		}
+		bytes_left -= bytes;
+		bytes_read += bytes;
+		write_and_release_buff(&temp_buff, dbg_buff);
+	}
+	return rc;
+}
+
+void collect_mem_info(struct cudbg_init *pdbg_init, struct card_mem *mem_info)
+{
+	struct adapter *padap = pdbg_init->adap;
+	u32 value;
+
+	value = t4_read_reg(padap, MA_EDRAM0_BAR_A);
+	value = EDRAM0_SIZE_G(value);
+	mem_info->size_edc0 = (u16)value;
+
+	value = t4_read_reg(padap, MA_EDRAM1_BAR_A);
+	value = EDRAM1_SIZE_G(value);
+	mem_info->size_edc1 = (u16)value;
+
+	value = t4_read_reg(padap, MA_TARGET_MEM_ENABLE_A);
+	if (value & EDRAM0_ENABLE_F)
+		mem_info->mem_flag |= (1 << EDC0_FLAG);
+	if (value & EDRAM1_ENABLE_F)
+		mem_info->mem_flag |= (1 << EDC1_FLAG);
+}
+
+static void cudbg_t4_fwcache(struct cudbg_init *pdbg_init,
+			     struct cudbg_error *cudbg_err)
+{
+	struct adapter *padap = pdbg_init->adap;
+	int rc;
+
+	if (is_fw_attached(pdbg_init)) {
+		/* Flush uP dcache before reading edcX/mcX  */
+		rc = t4_fwcache(padap, FW_PARAM_DEV_FWCACHE_FLUSH);
+		if (rc)
+			cudbg_err->sys_warn = rc;
+	}
+}
+
+static int collect_mem_region(struct cudbg_init *pdbg_init,
+			      struct cudbg_buffer *dbg_buff,
+			      struct cudbg_error *cudbg_err,
+			      u8 mem_type)
+{
+	struct card_mem mem_info = {0};
+	unsigned long flag, size;
+	int rc;
+
+	cudbg_t4_fwcache(pdbg_init, cudbg_err);
+	collect_mem_info(pdbg_init, &mem_info);
+	switch (mem_type) {
+	case MEM_EDC0:
+		flag = (1 << EDC0_FLAG);
+		size = mbytes_to_bytes(mem_info.size_edc0);
+		break;
+	case MEM_EDC1:
+		flag = (1 << EDC1_FLAG);
+		size = mbytes_to_bytes(mem_info.size_edc1);
+		break;
+	default:
+		rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
+		goto err;
+	}
+
+	if (mem_info.mem_flag & flag) {
+		rc = read_fw_mem(pdbg_init, dbg_buff, mem_type,
+				 size, cudbg_err);
+		if (rc)
+			goto err;
+	} else {
+		rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
+		goto err;
+	}
+err:
+	return rc;
+}
+
+int collect_edc0_meminfo(struct cudbg_init *pdbg_init,
+			 struct cudbg_buffer *dbg_buff,
+			 struct cudbg_error *cudbg_err)
+{
+	return collect_mem_region(pdbg_init, dbg_buff, cudbg_err, MEM_EDC0);
+}
+
+int collect_edc1_meminfo(struct cudbg_init *pdbg_init,
+			 struct cudbg_buffer *dbg_buff,
+			 struct cudbg_error *cudbg_err)
+{
+	return collect_mem_region(pdbg_init, dbg_buff, cudbg_err, MEM_EDC1);
+}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
index c6baeb533c44..04d66807c153 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
@@ -21,6 +21,12 @@ 
 int collect_reg_dump(struct cudbg_init *pdbg_init,
 		     struct cudbg_buffer *dbg_buff,
 		     struct cudbg_error *cudbg_err);
+int collect_edc0_meminfo(struct cudbg_init *pdbg_init,
+			 struct cudbg_buffer *dbg_buff,
+			 struct cudbg_error *cudbg_err);
+int collect_edc1_meminfo(struct cudbg_init *pdbg_init,
+			 struct cudbg_buffer *dbg_buff,
+			 struct cudbg_error *cudbg_err);
 
 struct cudbg_entity_hdr *get_entity_hdr(void *outbuf, int i);
 void align_debug_buffer(struct cudbg_buffer *dbg_buff,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
index 851284db0812..a5b92ae8fc85 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
@@ -69,6 +69,9 @@  struct cudbg_error {
 	int app_err;
 };
 
+#define CDUMP_MAX_COMP_BUF_SIZE ((64 * 1024) - 1)
+#define CUDBG_CHUNK_SIZE ((CDUMP_MAX_COMP_BUF_SIZE / 1024) * 1024)
+
 int get_cudbg_buff(struct cudbg_buffer *pdbg_buff, u32 size,
 		   struct cudbg_buffer *pin_buff);
 void put_cudbg_buff(struct cudbg_buffer *pin_buff,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
index 5c351ee8ab58..cd8599083a69 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
@@ -15,16 +15,22 @@ 
  *
  */
 
+#include "t4_regs.h"
 #include "cxgb4.h"
 #include "cxgb4_cudbg.h"
 
+static const struct cudbg_collect_entity collect_mem_dump[] = {
+	{ CUDBG_EDC0, collect_edc0_meminfo },
+	{ CUDBG_EDC1, collect_edc1_meminfo },
+};
+
 static const struct cudbg_collect_entity collect_hw_dump[] = {
 	{ CUDBG_REG_DUMP, collect_reg_dump },
 };
 
 static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
 {
-	u32 len = 0;
+	u32 value, len = 0;
 
 	switch (entity) {
 	case CUDBG_REG_DUMP:
@@ -40,6 +46,22 @@  static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
 			break;
 		}
 		break;
+	case CUDBG_EDC0:
+		value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+		if (value & EDRAM0_ENABLE_F) {
+			value = t4_read_reg(adap, MA_EDRAM0_BAR_A);
+			len = EDRAM0_SIZE_G(value);
+		}
+		len = mbytes_to_bytes(len);
+		break;
+	case CUDBG_EDC1:
+		value = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+		if (value & EDRAM1_ENABLE_F) {
+			value = t4_read_reg(adap, MA_EDRAM1_BAR_A);
+			len = EDRAM1_SIZE_G(value);
+		}
+		len = mbytes_to_bytes(len);
+		break;
 	default:
 		break;
 	}
@@ -59,6 +81,13 @@  u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag)
 		}
 	}
 
+	if (flag & CXGB4_ETH_DUMP_MEM) {
+		for (i = 0; i < ARRAY_SIZE(collect_mem_dump); i++) {
+			entity = collect_mem_dump[i].entity;
+			len += cxgb4_get_entity_length(adap, entity);
+		}
+	}
+
 	return len;
 }
 
@@ -152,6 +181,13 @@  int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
 					   buf,
 					   &total_size);
 
+	if (flag & CXGB4_ETH_DUMP_MEM)
+		cxgb4_cudbg_collect_entity(&cudbg_init, &dbg_buff,
+					   collect_mem_dump,
+					   ARRAY_SIZE(collect_mem_dump),
+					   buf,
+					   &total_size);
+
 	cudbg_hdr->data_len = total_size;
 	*buf_size = total_size;
 	return 0;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
index 3aeb887831c9..79fcea1ad163 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h
@@ -33,6 +33,7 @@  struct cudbg_collect_entity {
 
 enum CXGB4_ETHTOOL_DUMP_FLAGS {
 	CXGB4_ETH_DUMP_NONE = ETH_FW_DUMP_DISABLE,
+	CXGB4_ETH_DUMP_MEM = (1 << 0), /* On-Chip Memory Dumps */
 	CXGB4_ETH_DUMP_HW = (1 << 1), /* various FW and HW dumps */
 };