cxgb4: use zlib deflate to compress firmware dump
authorRahul Lakkireddy <rahul.lakkireddy@chelsio.com>
Wed, 17 Jan 2018 07:23:47 +0000 (12:53 +0530)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Jan 2018 19:56:32 +0000 (14:56 -0500)
Use zlib deflate to compress firmware dump. Collect and compress
as much firmware dump as possible into a 32 MB buffer.

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

index 8c9c6b0d2e5d44559265349ede4c8a7124ad1c06..5df923798669c814e208f27d34b672952faa2b94 100644 (file)
@@ -12,3 +12,4 @@ cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o
 cxgb4-$(CONFIG_CHELSIO_T4_DCB) +=  cxgb4_dcb.o
 cxgb4-$(CONFIG_CHELSIO_T4_FCOE) +=  cxgb4_fcoe.o
 cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
+cxgb4-$(CONFIG_ZLIB_DEFLATE) += cudbg_zlib.o
index eb1d2f48ebd38eb81731001907e72cc7e19aa4c6..8568a51f641483ac1ec352ef0d4b0f28dac35102 100644 (file)
@@ -90,6 +90,7 @@ struct cudbg_init {
        u8 compress_type; /* Type of compression to use */
        void *compress_buff; /* Compression buffer */
        u32 compress_buff_size; /* Compression buffer size */
+       void *workspace; /* Workspace for zlib */
 };
 
 static inline unsigned int cudbg_mbytes_to_bytes(unsigned int size)
index 2e1c8e87c9bdc4f6a0803f9578ec07db48ce88c6..8150ea85d6a5f01a3db9008eee02901b1894f425 100644 (file)
@@ -26,6 +26,7 @@ enum cudbg_dump_type {
 
 enum cudbg_compression_type {
        CUDBG_COMPRESSION_NONE = 1,
+       CUDBG_COMPRESSION_ZLIB,
 };
 
 struct cudbg_hdr {
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_zlib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_zlib.c
new file mode 100644 (file)
index 0000000..4c3854c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *  Copyright (C) 2018 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".
+ *
+ */
+
+#include <linux/zlib.h>
+
+#include "cxgb4.h"
+#include "cudbg_if.h"
+#include "cudbg_lib_common.h"
+#include "cudbg_zlib.h"
+
+static int cudbg_get_compress_hdr(struct cudbg_buffer *pdbg_buff,
+                                 struct cudbg_buffer *pin_buff)
+{
+       if (pdbg_buff->offset + sizeof(struct cudbg_compress_hdr) >
+           pdbg_buff->size)
+               return CUDBG_STATUS_NO_MEM;
+
+       pin_buff->data = (char *)pdbg_buff->data + pdbg_buff->offset;
+       pin_buff->offset = 0;
+       pin_buff->size = sizeof(struct cudbg_compress_hdr);
+       pdbg_buff->offset += sizeof(struct cudbg_compress_hdr);
+       return 0;
+}
+
+int cudbg_compress_buff(struct cudbg_init *pdbg_init,
+                       struct cudbg_buffer *pin_buff,
+                       struct cudbg_buffer *pout_buff)
+{
+       struct z_stream_s compress_stream = { 0 };
+       struct cudbg_buffer temp_buff = { 0 };
+       struct cudbg_compress_hdr *c_hdr;
+       int rc;
+
+       /* Write compression header to output buffer before compression */
+       rc = cudbg_get_compress_hdr(pout_buff, &temp_buff);
+       if (rc)
+               return rc;
+
+       c_hdr = (struct cudbg_compress_hdr *)temp_buff.data;
+       c_hdr->compress_id = CUDBG_ZLIB_COMPRESS_ID;
+
+       compress_stream.workspace = pdbg_init->workspace;
+       rc = zlib_deflateInit2(&compress_stream, Z_DEFAULT_COMPRESSION,
+                              Z_DEFLATED, CUDBG_ZLIB_WIN_BITS,
+                              CUDBG_ZLIB_MEM_LVL, Z_DEFAULT_STRATEGY);
+       if (rc != Z_OK)
+               return CUDBG_SYSTEM_ERROR;
+
+       compress_stream.next_in = pin_buff->data;
+       compress_stream.avail_in = pin_buff->size;
+       compress_stream.next_out = pout_buff->data + pout_buff->offset;
+       compress_stream.avail_out = pout_buff->size - pout_buff->offset;
+
+       rc = zlib_deflate(&compress_stream, Z_FINISH);
+       if (rc != Z_STREAM_END)
+               return CUDBG_SYSTEM_ERROR;
+
+       rc = zlib_deflateEnd(&compress_stream);
+       if (rc != Z_OK)
+               return CUDBG_SYSTEM_ERROR;
+
+       c_hdr->compress_size = compress_stream.total_out;
+       c_hdr->decompress_size = pin_buff->size;
+       pout_buff->offset += compress_stream.total_out;
+
+       return 0;
+}
index f4b4a4a2301d734b8f54a5e3656d16824a9aeb06..9d55c4c38c849f2a3e86292ad40b2e34060c1c4d 100644 (file)
 #ifndef __CUDBG_ZLIB_H__
 #define __CUDBG_ZLIB_H__
 
+#include <linux/zlib.h>
+
+#define CUDBG_ZLIB_COMPRESS_ID 17
+#define CUDBG_ZLIB_WIN_BITS 12
+#define CUDBG_ZLIB_MEM_LVL 4
+
+struct cudbg_compress_hdr {
+       u32 compress_id;
+       u64 decompress_size;
+       u64 compress_size;
+       u64 rsvd[32];
+};
+
+static inline int cudbg_get_workspace_size(void)
+{
+#ifdef CONFIG_ZLIB_DEFLATE
+       return zlib_deflate_workspacesize(CUDBG_ZLIB_WIN_BITS,
+                                         CUDBG_ZLIB_MEM_LVL);
+#else
+       return 0;
+#endif /* CONFIG_ZLIB_DEFLATE */
+}
+
+#ifndef CONFIG_ZLIB_DEFLATE
 static inline int cudbg_compress_buff(struct cudbg_init *pdbg_init,
                                      struct cudbg_buffer *pin_buff,
                                      struct cudbg_buffer *pout_buff)
 {
        return 0;
 }
+#else
+int cudbg_compress_buff(struct cudbg_init *pdbg_init,
+                       struct cudbg_buffer *pin_buff,
+                       struct cudbg_buffer *pout_buff);
+#endif /* CONFIG_ZLIB_DEFLATE */
 #endif /* __CUDBG_ZLIB_H__ */
index bf1732da8c6da079b8c74f633464198914f0701d..9e0a8a8186c4c421e7c39b22bb0e8b493cba965c 100644 (file)
@@ -18,6 +18,7 @@
 #include "t4_regs.h"
 #include "cxgb4.h"
 #include "cxgb4_cudbg.h"
+#include "cudbg_zlib.h"
 
 static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
        { CUDBG_EDC0, cudbg_collect_edc0_meminfo },
@@ -318,6 +319,7 @@ u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag)
 {
        u32 i, entity;
        u32 len = 0;
+       u32 wsize;
 
        if (flag & CXGB4_ETH_DUMP_HW) {
                for (i = 0; i < ARRAY_SIZE(cxgb4_collect_hw_dump); i++) {
@@ -333,6 +335,11 @@ u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag)
                }
        }
 
+       /* If compression is enabled, a smaller destination buffer is enough */
+       wsize = cudbg_get_workspace_size();
+       if (wsize && len > CUDBG_DUMP_BUFF_SIZE)
+               len = CUDBG_DUMP_BUFF_SIZE;
+
        return len;
 }
 
@@ -374,6 +381,28 @@ static void cxgb4_cudbg_collect_entity(struct cudbg_init *pdbg_init,
        *tot_size += total_size;
 }
 
+static int cudbg_alloc_compress_buff(struct cudbg_init *pdbg_init)
+{
+       u32 workspace_size;
+
+       workspace_size = cudbg_get_workspace_size();
+       pdbg_init->compress_buff = vzalloc(CUDBG_COMPRESS_BUFF_SIZE +
+                                          workspace_size);
+       if (!pdbg_init->compress_buff)
+               return -ENOMEM;
+
+       pdbg_init->compress_buff_size = CUDBG_COMPRESS_BUFF_SIZE;
+       pdbg_init->workspace = (u8 *)pdbg_init->compress_buff +
+                              CUDBG_COMPRESS_BUFF_SIZE - workspace_size;
+       return 0;
+}
+
+static void cudbg_free_compress_buff(struct cudbg_init *pdbg_init)
+{
+       if (pdbg_init->compress_buff)
+               vfree(pdbg_init->compress_buff);
+}
+
 int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
                        u32 flag)
 {
@@ -381,6 +410,7 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
        struct cudbg_buffer dbg_buff = { 0 };
        u32 size, min_size, total_size = 0;
        struct cudbg_hdr *cudbg_hdr;
+       int rc;
 
        size = *buf_size;
 
@@ -400,8 +430,6 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
        cudbg_hdr->max_entities = CUDBG_MAX_ENTITY;
        cudbg_hdr->chip_ver = adap->params.chip;
        cudbg_hdr->dump_type = CUDBG_DUMP_TYPE_MINI;
-       cudbg_init.compress_type = CUDBG_COMPRESSION_NONE;
-       cudbg_hdr->compress_type = cudbg_init.compress_type;
 
        min_size = sizeof(struct cudbg_hdr) +
                   sizeof(struct cudbg_entity_hdr) *
@@ -409,6 +437,24 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
        if (size < min_size)
                return -ENOMEM;
 
+       rc = cudbg_get_workspace_size();
+       if (rc) {
+               /* Zlib available.  So, use zlib deflate */
+               cudbg_init.compress_type = CUDBG_COMPRESSION_ZLIB;
+               rc = cudbg_alloc_compress_buff(&cudbg_init);
+               if (rc) {
+                       /* Ignore error and continue without compression. */
+                       dev_warn(adap->pdev_dev,
+                                "Fail allocating compression buffer ret: %d.  Continuing without compression.\n",
+                                rc);
+                       cudbg_init.compress_type = CUDBG_COMPRESSION_NONE;
+                       rc = 0;
+               }
+       } else {
+               cudbg_init.compress_type = CUDBG_COMPRESSION_NONE;
+       }
+
+       cudbg_hdr->compress_type = cudbg_init.compress_type;
        dbg_buff.offset += min_size;
        total_size = dbg_buff.offset;
 
@@ -426,8 +472,12 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
                                           buf,
                                           &total_size);
 
+       cudbg_free_compress_buff(&cudbg_init);
        cudbg_hdr->data_len = total_size;
-       *buf_size = total_size;
+       if (cudbg_init.compress_type != CUDBG_COMPRESSION_NONE)
+               *buf_size = size;
+       else
+               *buf_size = total_size;
        return 0;
 }
 
index 7ceeb0bc9fa82837de7ad17a1fef007fe25a464d..ce1ac9a1c8781c843e9e453bceb85f56efe3268a 100644 (file)
@@ -23,6 +23,9 @@
 #include "cudbg_entity.h"
 #include "cudbg_lib.h"
 
+#define CUDBG_DUMP_BUFF_SIZE (32 * 1024 * 1024) /* 32 MB */
+#define CUDBG_COMPRESS_BUFF_SIZE (4 * 1024 * 1024) /* 4 MB */
+
 typedef int (*cudbg_collect_callback_t)(struct cudbg_init *pdbg_init,
                                        struct cudbg_buffer *dbg_buff,
                                        struct cudbg_error *cudbg_err);