// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022, Intel Corporation. */
#include <linux/debugfs.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/net/intel/libie/fwlog.h>
#include <linux/pci.h>
#include <linux/random.h>
#include <linux/vmalloc.h>
#define DEFAULT_SYMBOL_NAMESPACE "LIBIE_FWLOG"
/* create a define that has an extra module that doesn't really exist. this
* is so we can add a module 'all' to easily enable/disable all the modules
*/
#define LIBIE_NR_FW_LOG_MODULES (LIBIE_AQC_FW_LOG_ID_MAX + 1)
/* the ordering in this array is important. it matches the ordering of the
* values in the FW so the index is the same value as in
* libie_aqc_fw_logging_mod
*/
static const char * const libie_fwlog_module_string[] = {
"general",
"ctrl",
"link",
"link_topo",
"dnl",
"i2c",
"sdp",
"mdio",
"adminq",
"hdma",
"lldp",
"dcbx",
"dcb",
"xlr",
"nvm",
"auth",
"vpd",
"iosf",
"parser",
"sw",
"scheduler",
"txq",
"rsvd",
"post",
"watchdog",
"task_dispatch",
"mng",
"synce",
"health",
"tsdrv",
"pfreg",
"mdlver",
"all",
};
/* the ordering in this array is important. it matches the ordering of the
* values in the FW so the index is the same value as in libie_fwlog_level
*/
static const char * const libie_fwlog_level_string[] = {
"none",
"error",
"warning",
"normal",
"verbose",
};
static const char * const libie_fwlog_log_size[] = {
"128K",
"256K",
"512K",
"1M",
"2M",
};
static bool libie_fwlog_ring_empty(struct libie_fwlog_ring *rings)
{
return rings->head == rings->tail;
}
static void libie_fwlog_ring_increment(u16 *item, u16 size)
{
*item = (*item + 1) & (size - 1);
}
static int libie_fwlog_alloc_ring_buffs(struct libie_fwlog_ring *rings)
{
int i, nr_bytes;
u8 *mem;
nr_bytes = rings->size * LIBIE_AQ_MAX_BUF_LEN;
mem = vzalloc(nr_bytes);
if (!mem)
return -ENOMEM;
for (i = 0; i < rings->size; i++) {
struct libie_fwlog_data *ring = &rings->rings[i];
ring->data_size = LIBIE_AQ_MAX_BUF_LEN;
ring->data = mem;
mem += LIBIE_AQ_MAX_BUF_LEN;
}
return 0;
}
static void libie_fwlog_free_ring_buffs(struct libie_fwlog_ring *rings)
{
int i;
for (i = 0; i < rings->size; i++) {
struct libie_fwlog_data *ring = &rings->rings[i];
/* the first ring is the base memory for the whole range so
* free it
*/
if (!i)
vfree(ring->data);
ring->data = NULL;
ring->data_size = 0;
}
}
#define LIBIE_FWLOG_INDEX_TO_BYTES(n) ((128 * 1024) << (n))
/**
* libie_fwlog_realloc_rings - reallocate the FW log rings
* @fwlog: pointer to the fwlog structure
* @index: the new index to use to allocate memory for the log data
*
*/
static void libie_fwlog_realloc_rings(struct libie_fwlog *fwlog, int index)
{
struct libie_fwlog_ring ring;
int status, ring_size;
/* convert the number of bytes into a number of 4K buffers. externally
* the driver presents the interface to the FW log data as a number of
* bytes because that's easy for users to understand. internally the
* driver uses a ring of buffers because the driver doesn't know where
* the beginning and end of any line of log data is so the driver has
* to overwrite data as complete blocks. when the data is returned to
* the user the driver knows that the data is correct and the FW log
* can be correctly parsed by the tools
*/
ring_size = LIBIE_FWLOG_INDEX_TO_BYTES(index) / LIBIE_AQ_MAX_BUF_LEN;
if (ring_size == fwlog-><