cxgb4: collect on-chip memory dump
authorRahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Fri, 13 Oct 2017 13:18:15 +0000 (18:48 +0530)
committerDavid S. Miller <davem@davemloft.net>
Sun, 15 Oct 2017 01:35:14 +0000 (18:35 -0700)
Collect EDC0 and EDC1 memory dump.

Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h [new file with mode: 0644]
drivers/net/ethernet/chelsio/cxgb4/cudbg_if.h
drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.h
drivers/net/ethernet/chelsio/cxgb4/cudbg_lib_common.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.h

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h
new file mode 100644 (file)
index 0000000..71a426d
--- /dev/null
@@ -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__ */
index 73725a8666df469a796e6305f6fbc165b8e2fb95..8bcea985af771b275f86bc90fd5f8385412255a6 100644 (file)
@@ -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 cudbg_mbytes_to_bytes(unsigned int size)
+{
+       return size * 1024 * 1024;
+}
 #endif /* __CUDBG_IF_H__ */
index b37d8f7825dd66acf2ccac26b9259401552fb1ba..fb0e97e6a6a073e844a6c3b0a67f287185a3ebd5 100644 (file)
  *
  */
 
+#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 cudbg_write_and_release_buff(struct cudbg_buffer *pin_buff,
                                         struct cudbg_buffer *dbg_buff)
@@ -27,6 +29,16 @@ static void cudbg_write_and_release_buff(struct cudbg_buffer *pin_buff,
        cudbg_put_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,127 @@ int cudbg_collect_reg_dump(struct cudbg_init *pdbg_init,
        cudbg_write_and_release_buff(&temp_buff, dbg_buff);
        return rc;
 }
+
+static int cudbg_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 = cudbg_get_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;
+                       cudbg_put_buff(&temp_buff, dbg_buff);
+                       return rc;
+               }
+               bytes_left -= bytes;
+               bytes_read += bytes;
+               cudbg_write_and_release_buff(&temp_buff, dbg_buff);
+       }
+       return rc;
+}
+
+static void cudbg_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 cudbg_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);
+       cudbg_collect_mem_info(pdbg_init, &mem_info);
+       switch (mem_type) {
+       case MEM_EDC0:
+               flag = (1 << EDC0_FLAG);
+               size = cudbg_mbytes_to_bytes(mem_info.size_edc0);
+               break;
+       case MEM_EDC1:
+               flag = (1 << EDC1_FLAG);
+               size = cudbg_mbytes_to_bytes(mem_info.size_edc1);
+               break;
+       default:
+               rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
+               goto err;
+       }
+
+       if (mem_info.mem_flag & flag) {
+               rc = cudbg_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 cudbg_collect_edc0_meminfo(struct cudbg_init *pdbg_init,
+                              struct cudbg_buffer *dbg_buff,
+                              struct cudbg_error *cudbg_err)
+{
+       return cudbg_collect_mem_region(pdbg_init, dbg_buff, cudbg_err,
+                                       MEM_EDC0);
+}
+
+int cudbg_collect_edc1_meminfo(struct cudbg_init *pdbg_init,
+                              struct cudbg_buffer *dbg_buff,
+                              struct cudbg_error *cudbg_err)
+{
+       return cudbg_collect_mem_region(pdbg_init, dbg_buff, cudbg_err,
+                                       MEM_EDC1);
+}
index 5b0a0e9646017c9ad2aa1a682b2224474cea2d7b..f7be5090b1725b0c738294deafdcf3e1c4770bef 100644 (file)
 int cudbg_collect_reg_dump(struct cudbg_init *pdbg_init,
                           struct cudbg_buffer *dbg_buff,
                           struct cudbg_error *cudbg_err);
+int cudbg_collect_edc0_meminfo(struct cudbg_init *pdbg_init,
+                              struct cudbg_buffer *dbg_buff,
+                              struct cudbg_error *cudbg_err);
+int cudbg_collect_edc1_meminfo(struct cudbg_init *pdbg_init,
+                              struct cudbg_buffer *dbg_buff,
+                              struct cudbg_error *cudbg_err);
 
 struct cudbg_entity_hdr *cudbg_get_entity_hdr(void *outbuf, int i);
 void cudbg_align_debug_buffer(struct cudbg_buffer *dbg_buff,
index 422a5ceedd2e5c5441f54c8959d86634e3d6f5eb..b150c5d1f7c0b3d02f4ef603b82c0c8125bb171f 100644 (file)
@@ -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 cudbg_get_buff(struct cudbg_buffer *pdbg_buff, u32 size,
                   struct cudbg_buffer *pin_buff);
 void cudbg_put_buff(struct cudbg_buffer *pin_buff,
index 4ec322eec68ca277107b60f3eb970dbf33a122e6..286d172a9c198728be1da05885c18375ad7f166a 100644 (file)
  *
  */
 
+#include "t4_regs.h"
 #include "cxgb4.h"
 #include "cxgb4_cudbg.h"
 
+static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
+       { CUDBG_EDC0, cudbg_collect_edc0_meminfo },
+       { CUDBG_EDC1, cudbg_collect_edc1_meminfo },
+};
+
 static const struct cxgb4_collect_entity cxgb4_collect_hw_dump[] = {
        { CUDBG_REG_DUMP, cudbg_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 = cudbg_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 = cudbg_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(cxgb4_collect_mem_dump); i++) {
+                       entity = cxgb4_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,
+                                          cxgb4_collect_mem_dump,
+                                          ARRAY_SIZE(cxgb4_collect_mem_dump),
+                                          buf,
+                                          &total_size);
+
        cudbg_hdr->data_len = total_size;
        *buf_size = total_size;
        return 0;
index 7369a7e22b890da65ababbbb83133fc700887b98..c099b5aa22142abef3ed26ff6eaec8575e5f5403 100644 (file)
@@ -33,6 +33,7 @@ struct cxgb4_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 */
 };