Commit e0e8a149 authored by David S. Miller's avatar David S. Miller

Merge branch 'cxgb4-reduce-memory-footprint-for-collecting-firmware-dump'

Rahul Lakkireddy says:

====================
cxgb4: reduce memory footprint for collecting firmware dump

Firmware dump can be large (upto 2 GB).  In low memory conditions,
ethtool fails to allocate such large memory.  So, use zlib deflate
to compress collected firmware dump.

Patch 1 updates collection logic to use compression.

Patch 2 adds zlib deflate to compress collected firmware dump.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5165674f 91c1953d
...@@ -12,3 +12,4 @@ cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o ...@@ -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_DCB) += cxgb4_dcb.o
cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o
cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
cxgb4-$(CONFIG_ZLIB_DEFLATE) += cudbg_zlib.o
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
#include "cudbg_if.h" #include "cudbg_if.h"
#include "cudbg_lib_common.h" #include "cudbg_lib_common.h"
int cudbg_get_buff(struct cudbg_buffer *pdbg_buff, u32 size, int cudbg_get_buff(struct cudbg_init *pdbg_init,
struct cudbg_buffer *pdbg_buff, u32 size,
struct cudbg_buffer *pin_buff) struct cudbg_buffer *pin_buff)
{ {
u32 offset; u32 offset;
...@@ -28,17 +29,30 @@ int cudbg_get_buff(struct cudbg_buffer *pdbg_buff, u32 size, ...@@ -28,17 +29,30 @@ int cudbg_get_buff(struct cudbg_buffer *pdbg_buff, u32 size,
if (offset + size > pdbg_buff->size) if (offset + size > pdbg_buff->size)
return CUDBG_STATUS_NO_MEM; return CUDBG_STATUS_NO_MEM;
if (pdbg_init->compress_type != CUDBG_COMPRESSION_NONE) {
if (size > pdbg_init->compress_buff_size)
return CUDBG_STATUS_NO_MEM;
pin_buff->data = (char *)pdbg_init->compress_buff;
pin_buff->offset = 0;
pin_buff->size = size;
return 0;
}
pin_buff->data = (char *)pdbg_buff->data + offset; pin_buff->data = (char *)pdbg_buff->data + offset;
pin_buff->offset = offset; pin_buff->offset = offset;
pin_buff->size = size; pin_buff->size = size;
pdbg_buff->size -= size;
return 0; return 0;
} }
void cudbg_put_buff(struct cudbg_buffer *pin_buff, void cudbg_put_buff(struct cudbg_init *pdbg_init,
struct cudbg_buffer *pdbg_buff) struct cudbg_buffer *pin_buff)
{ {
pdbg_buff->size += pin_buff->size; /* Clear compression buffer for re-use */
if (pdbg_init->compress_type != CUDBG_COMPRESSION_NONE)
memset(pdbg_init->compress_buff, 0,
pdbg_init->compress_buff_size);
pin_buff->data = NULL; pin_buff->data = NULL;
pin_buff->offset = 0; pin_buff->offset = 0;
pin_buff->size = 0; pin_buff->size = 0;
......
...@@ -87,6 +87,10 @@ struct cudbg_init { ...@@ -87,6 +87,10 @@ struct cudbg_init {
struct adapter *adap; /* Pointer to adapter structure */ struct adapter *adap; /* Pointer to adapter structure */
void *outbuf; /* Output buffer */ void *outbuf; /* Output buffer */
u32 outbuf_size; /* Output buffer size */ u32 outbuf_size; /* Output buffer size */
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) static inline unsigned int cudbg_mbytes_to_bytes(unsigned int size)
......
...@@ -26,6 +26,7 @@ enum cudbg_dump_type { ...@@ -26,6 +26,7 @@ enum cudbg_dump_type {
enum cudbg_compression_type { enum cudbg_compression_type {
CUDBG_COMPRESSION_NONE = 1, CUDBG_COMPRESSION_NONE = 1,
CUDBG_COMPRESSION_ZLIB,
}; };
struct cudbg_hdr { struct cudbg_hdr {
...@@ -78,10 +79,11 @@ struct cudbg_error { ...@@ -78,10 +79,11 @@ struct cudbg_error {
#define CDUMP_MAX_COMP_BUF_SIZE ((64 * 1024) - 1) #define CDUMP_MAX_COMP_BUF_SIZE ((64 * 1024) - 1)
#define CUDBG_CHUNK_SIZE ((CDUMP_MAX_COMP_BUF_SIZE / 1024) * 1024) #define CUDBG_CHUNK_SIZE ((CDUMP_MAX_COMP_BUF_SIZE / 1024) * 1024)
int cudbg_get_buff(struct cudbg_buffer *pdbg_buff, u32 size, int cudbg_get_buff(struct cudbg_init *pdbg_init,
struct cudbg_buffer *pdbg_buff, u32 size,
struct cudbg_buffer *pin_buff);
void cudbg_put_buff(struct cudbg_init *pdbg_init,
struct cudbg_buffer *pin_buff); struct cudbg_buffer *pin_buff);
void cudbg_put_buff(struct cudbg_buffer *pin_buff,
struct cudbg_buffer *pdbg_buff);
void cudbg_update_buff(struct cudbg_buffer *pin_buff, void cudbg_update_buff(struct cudbg_buffer *pin_buff,
struct cudbg_buffer *pout_buff); struct cudbg_buffer *pout_buff);
#endif /* __CUDBG_LIB_COMMON_H__ */ #endif /* __CUDBG_LIB_COMMON_H__ */
/*
* 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;
}
/*
* 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".
*
*/
#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__ */
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "t4_regs.h" #include "t4_regs.h"
#include "cxgb4.h" #include "cxgb4.h"
#include "cxgb4_cudbg.h" #include "cxgb4_cudbg.h"
#include "cudbg_zlib.h"
static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = { static const struct cxgb4_collect_entity cxgb4_collect_mem_dump[] = {
{ CUDBG_EDC0, cudbg_collect_edc0_meminfo }, { CUDBG_EDC0, cudbg_collect_edc0_meminfo },
...@@ -318,6 +319,7 @@ u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag) ...@@ -318,6 +319,7 @@ u32 cxgb4_get_dump_length(struct adapter *adap, u32 flag)
{ {
u32 i, entity; u32 i, entity;
u32 len = 0; u32 len = 0;
u32 wsize;
if (flag & CXGB4_ETH_DUMP_HW) { if (flag & CXGB4_ETH_DUMP_HW) {
for (i = 0; i < ARRAY_SIZE(cxgb4_collect_hw_dump); i++) { 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) ...@@ -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; return len;
} }
...@@ -341,22 +348,14 @@ static void cxgb4_cudbg_collect_entity(struct cudbg_init *pdbg_init, ...@@ -341,22 +348,14 @@ static void cxgb4_cudbg_collect_entity(struct cudbg_init *pdbg_init,
const struct cxgb4_collect_entity *e_arr, const struct cxgb4_collect_entity *e_arr,
u32 arr_size, void *buf, u32 *tot_size) u32 arr_size, void *buf, u32 *tot_size)
{ {
struct adapter *adap = pdbg_init->adap;
struct cudbg_error cudbg_err = { 0 }; struct cudbg_error cudbg_err = { 0 };
struct cudbg_entity_hdr *entity_hdr; struct cudbg_entity_hdr *entity_hdr;
u32 entity_size, i; u32 i, total_size = 0;
u32 total_size = 0;
int ret; int ret;
for (i = 0; i < arr_size; i++) { for (i = 0; i < arr_size; i++) {
const struct cxgb4_collect_entity *e = &e_arr[i]; const struct cxgb4_collect_entity *e = &e_arr[i];
/* Skip entities that won't fit in output buffer */
entity_size = cxgb4_get_entity_length(adap, e->entity);
if (entity_size >
pdbg_init->outbuf_size - *tot_size - total_size)
continue;
entity_hdr = cudbg_get_entity_hdr(buf, e->entity); entity_hdr = cudbg_get_entity_hdr(buf, e->entity);
entity_hdr->entity_type = e->entity; entity_hdr->entity_type = e->entity;
entity_hdr->start_offset = dbg_buff->offset; entity_hdr->start_offset = dbg_buff->offset;
...@@ -382,6 +381,28 @@ static void cxgb4_cudbg_collect_entity(struct cudbg_init *pdbg_init, ...@@ -382,6 +381,28 @@ static void cxgb4_cudbg_collect_entity(struct cudbg_init *pdbg_init,
*tot_size += total_size; *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, int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
u32 flag) u32 flag)
{ {
...@@ -389,6 +410,7 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size, ...@@ -389,6 +410,7 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
struct cudbg_buffer dbg_buff = { 0 }; struct cudbg_buffer dbg_buff = { 0 };
u32 size, min_size, total_size = 0; u32 size, min_size, total_size = 0;
struct cudbg_hdr *cudbg_hdr; struct cudbg_hdr *cudbg_hdr;
int rc;
size = *buf_size; size = *buf_size;
...@@ -408,7 +430,6 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size, ...@@ -408,7 +430,6 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
cudbg_hdr->max_entities = CUDBG_MAX_ENTITY; cudbg_hdr->max_entities = CUDBG_MAX_ENTITY;
cudbg_hdr->chip_ver = adap->params.chip; cudbg_hdr->chip_ver = adap->params.chip;
cudbg_hdr->dump_type = CUDBG_DUMP_TYPE_MINI; cudbg_hdr->dump_type = CUDBG_DUMP_TYPE_MINI;
cudbg_hdr->compress_type = CUDBG_COMPRESSION_NONE;
min_size = sizeof(struct cudbg_hdr) + min_size = sizeof(struct cudbg_hdr) +
sizeof(struct cudbg_entity_hdr) * sizeof(struct cudbg_entity_hdr) *
...@@ -416,6 +437,24 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size, ...@@ -416,6 +437,24 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
if (size < min_size) if (size < min_size)
return -ENOMEM; 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; dbg_buff.offset += min_size;
total_size = dbg_buff.offset; total_size = dbg_buff.offset;
...@@ -433,7 +472,11 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size, ...@@ -433,7 +472,11 @@ int cxgb4_cudbg_collect(struct adapter *adap, void *buf, u32 *buf_size,
buf, buf,
&total_size); &total_size);
cudbg_free_compress_buff(&cudbg_init);
cudbg_hdr->data_len = total_size; cudbg_hdr->data_len = total_size;
if (cudbg_init.compress_type != CUDBG_COMPRESSION_NONE)
*buf_size = size;
else
*buf_size = total_size; *buf_size = total_size;
return 0; return 0;
} }
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#include "cudbg_entity.h" #include "cudbg_entity.h"
#include "cudbg_lib.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, typedef int (*cudbg_collect_callback_t)(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff, struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err); struct cudbg_error *cudbg_err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment