Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49aa284f authored by Hariprasad Shenai's avatar Hariprasad Shenai Committed by David S. Miller
Browse files

cxgb4: Add support for devlog



Add support for device log entry in debugfs

Signed-off-by: default avatarHariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cd91cc5b
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -290,11 +290,19 @@ enum chip_type {
	T5_LAST_REV	= T5_A1,
};

struct devlog_params {
	u32 memtype;                    /* which memory (EDC0, EDC1, MC) */
	u32 start;                      /* start of log in firmware memory */
	u32 size;                       /* size of log */
};

struct adapter_params {
	struct sge_params sge;
	struct tp_params  tp;
	struct vpd_params vpd;
	struct pci_params pci;
	struct devlog_params devlog;
	enum pcie_memwin drv_memwin;

	unsigned int sf_size;             /* serial flash size in bytes */
	unsigned int sf_nsec;             /* # of flash sectors */
+198 −0
Original line number Diff line number Diff line
@@ -43,6 +43,203 @@
#include "cxgb4_debugfs.h"
#include "l2t.h"

/* Firmware Device Log dump.
 */
static const char * const devlog_level_strings[] = {
	[FW_DEVLOG_LEVEL_EMERG]		= "EMERG",
	[FW_DEVLOG_LEVEL_CRIT]		= "CRIT",
	[FW_DEVLOG_LEVEL_ERR]		= "ERR",
	[FW_DEVLOG_LEVEL_NOTICE]	= "NOTICE",
	[FW_DEVLOG_LEVEL_INFO]		= "INFO",
	[FW_DEVLOG_LEVEL_DEBUG]		= "DEBUG"
};

static const char * const devlog_facility_strings[] = {
	[FW_DEVLOG_FACILITY_CORE]	= "CORE",
	[FW_DEVLOG_FACILITY_SCHED]	= "SCHED",
	[FW_DEVLOG_FACILITY_TIMER]	= "TIMER",
	[FW_DEVLOG_FACILITY_RES]	= "RES",
	[FW_DEVLOG_FACILITY_HW]		= "HW",
	[FW_DEVLOG_FACILITY_FLR]	= "FLR",
	[FW_DEVLOG_FACILITY_DMAQ]	= "DMAQ",
	[FW_DEVLOG_FACILITY_PHY]	= "PHY",
	[FW_DEVLOG_FACILITY_MAC]	= "MAC",
	[FW_DEVLOG_FACILITY_PORT]	= "PORT",
	[FW_DEVLOG_FACILITY_VI]		= "VI",
	[FW_DEVLOG_FACILITY_FILTER]	= "FILTER",
	[FW_DEVLOG_FACILITY_ACL]	= "ACL",
	[FW_DEVLOG_FACILITY_TM]		= "TM",
	[FW_DEVLOG_FACILITY_QFC]	= "QFC",
	[FW_DEVLOG_FACILITY_DCB]	= "DCB",
	[FW_DEVLOG_FACILITY_ETH]	= "ETH",
	[FW_DEVLOG_FACILITY_OFLD]	= "OFLD",
	[FW_DEVLOG_FACILITY_RI]		= "RI",
	[FW_DEVLOG_FACILITY_ISCSI]	= "ISCSI",
	[FW_DEVLOG_FACILITY_FCOE]	= "FCOE",
	[FW_DEVLOG_FACILITY_FOISCSI]	= "FOISCSI",
	[FW_DEVLOG_FACILITY_FOFCOE]	= "FOFCOE"
};

/* Information gathered by Device Log Open routine for the display routine.
 */
struct devlog_info {
	unsigned int nentries;		/* number of entries in log[] */
	unsigned int first;		/* first [temporal] entry in log[] */
	struct fw_devlog_e log[0];	/* Firmware Device Log */
};

/* Dump a Firmaware Device Log entry.
 */
static int devlog_show(struct seq_file *seq, void *v)
{
	if (v == SEQ_START_TOKEN)
		seq_printf(seq, "%10s  %15s  %8s  %8s  %s\n",
			   "Seq#", "Tstamp", "Level", "Facility", "Message");
	else {
		struct devlog_info *dinfo = seq->private;
		int fidx = (uintptr_t)v - 2;
		unsigned long index;
		struct fw_devlog_e *e;

		/* Get a pointer to the log entry to display.  Skip unused log
		 * entries.
		 */
		index = dinfo->first + fidx;
		if (index >= dinfo->nentries)
			index -= dinfo->nentries;
		e = &dinfo->log[index];
		if (e->timestamp == 0)
			return 0;

		/* Print the message.  This depends on the firmware using
		 * exactly the same formating strings as the kernel so we may
		 * eventually have to put a format interpreter in here ...
		 */
		seq_printf(seq, "%10d  %15llu  %8s  %8s  ",
			   e->seqno, e->timestamp,
			   (e->level < ARRAY_SIZE(devlog_level_strings)
			    ? devlog_level_strings[e->level]
			    : "UNKNOWN"),
			   (e->facility < ARRAY_SIZE(devlog_facility_strings)
			    ? devlog_facility_strings[e->facility]
			    : "UNKNOWN"));
		seq_printf(seq, e->fmt, e->params[0], e->params[1],
			   e->params[2], e->params[3], e->params[4],
			   e->params[5], e->params[6], e->params[7]);
	}
	return 0;
}

/* Sequential File Operations for Device Log.
 */
static inline void *devlog_get_idx(struct devlog_info *dinfo, loff_t pos)
{
	if (pos > dinfo->nentries)
		return NULL;

	return (void *)(uintptr_t)(pos + 1);
}

static void *devlog_start(struct seq_file *seq, loff_t *pos)
{
	struct devlog_info *dinfo = seq->private;

	return (*pos
		? devlog_get_idx(dinfo, *pos)
		: SEQ_START_TOKEN);
}

static void *devlog_next(struct seq_file *seq, void *v, loff_t *pos)
{
	struct devlog_info *dinfo = seq->private;

	(*pos)++;
	return devlog_get_idx(dinfo, *pos);
}

static void devlog_stop(struct seq_file *seq, void *v)
{
}

static const struct seq_operations devlog_seq_ops = {
	.start = devlog_start,
	.next  = devlog_next,
	.stop  = devlog_stop,
	.show  = devlog_show
};

/* Set up for reading the firmware's device log.  We read the entire log here
 * and then display it incrementally in devlog_show().
 */
static int devlog_open(struct inode *inode, struct file *file)
{
	struct adapter *adap = inode->i_private;
	struct devlog_params *dparams = &adap->params.devlog;
	struct devlog_info *dinfo;
	unsigned int index;
	u32 fseqno;
	int ret;

	/* If we don't know where the log is we can't do anything.
	 */
	if (dparams->start == 0)
		return -ENXIO;

	/* Allocate the space to read in the firmware's device log and set up
	 * for the iterated call to our display function.
	 */
	dinfo = __seq_open_private(file, &devlog_seq_ops,
				   sizeof(*dinfo) + dparams->size);
	if (!dinfo)
		return -ENOMEM;

	/* Record the basic log buffer information and read in the raw log.
	 */
	dinfo->nentries = (dparams->size / sizeof(struct fw_devlog_e));
	dinfo->first = 0;
	spin_lock(&adap->win0_lock);
	ret = t4_memory_rw(adap, adap->params.drv_memwin, dparams->memtype,
			   dparams->start, dparams->size, (__be32 *)dinfo->log,
			   T4_MEMORY_READ);
	spin_unlock(&adap->win0_lock);
	if (ret) {
		seq_release_private(inode, file);
		return ret;
	}

	/* Translate log multi-byte integral elements into host native format
	 * and determine where the first entry in the log is.
	 */
	for (fseqno = ~((u32)0), index = 0; index < dinfo->nentries; index++) {
		struct fw_devlog_e *e = &dinfo->log[index];
		int i;
		__u32 seqno;

		if (e->timestamp == 0)
			continue;

		e->timestamp = (__force __be64)be64_to_cpu(e->timestamp);
		seqno = be32_to_cpu(e->seqno);
		for (i = 0; i < 8; i++)
			e->params[i] =
				(__force __be32)be32_to_cpu(e->params[i]);

		if (seqno < fseqno) {
			fseqno = seqno;
			dinfo->first = index;
		}
	}
	return 0;
}

static const struct file_operations devlog_fops = {
	.owner   = THIS_MODULE,
	.open    = devlog_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release_private
};

static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
			loff_t *ppos)
{
@@ -121,6 +318,7 @@ int t4_setup_debugfs(struct adapter *adap)
	u32 size;

	static struct t4_debugfs_entry t4_debugfs_files[] = {
		{ "devlog", &devlog_fops, S_IRUSR, 0 },
		{ "l2t", &t4_l2t_fops, S_IRUSR, 0},
	};

+26 −0
Original line number Diff line number Diff line
@@ -5541,6 +5541,8 @@ static int adap_init0(struct adapter *adap)
	enum dev_state state;
	u32 params[7], val[7];
	struct fw_caps_config_cmd caps_cmd;
	struct fw_devlog_cmd devlog_cmd;
	u32 devlog_meminfo;
	int reset = 1;

	/* Contact FW, advertising Master capability */
@@ -5621,6 +5623,30 @@ static int adap_init0(struct adapter *adap)
	if (ret < 0)
		goto bye;

	/* Read firmware device log parameters.  We really need to find a way
	 * to get these parameters initialized with some default values (which
	 * are likely to be correct) for the case where we either don't
	 * attache to the firmware or it's crashed when we probe the adapter.
	 * That way we'll still be able to perform early firmware startup
	 * debugging ...  If the request to get the Firmware's Device Log
	 * parameters fails, we'll live so we don't make that a fatal error.
	 */
	memset(&devlog_cmd, 0, sizeof(devlog_cmd));
	devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
				       FW_CMD_REQUEST_F | FW_CMD_READ_F);
	devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
	ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
			 &devlog_cmd);
	if (ret == 0) {
		devlog_meminfo =
			ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
		adap->params.devlog.memtype =
			FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
		adap->params.devlog.start =
			FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
		adap->params.devlog.size = ntohl(devlog_cmd.memsize_devlog);
	}

	/*
	 * Find out what ports are available to us.  Note that we need to do
	 * this before calling adap_init0_no_config() since it needs nports
+12 −0
Original line number Diff line number Diff line
@@ -110,6 +110,18 @@ enum {
	SGE_INGPADBOUNDARY_SHIFT = 5,/* ingress queue pad boundary */
};

/* PCI-e memory window access */
enum pcie_memwin {
	MEMWIN_NIC      = 0,
	MEMWIN_RSVD1    = 1,
	MEMWIN_RSVD2    = 2,
	MEMWIN_RDMA     = 3,
	MEMWIN_RSVD4    = 4,
	MEMWIN_FOISCSI  = 5,
	MEMWIN_CSIOSTOR = 6,
	MEMWIN_RSVD7    = 7,
};

struct sge_qstat {                /* data written to SGE queue status entries */
	__be32 qid;
	__be16 cidx;
+81 −0
Original line number Diff line number Diff line
@@ -673,6 +673,7 @@ enum fw_cmd_opcodes {
	FW_RSS_IND_TBL_CMD             = 0x20,
	FW_RSS_GLB_CONFIG_CMD          = 0x22,
	FW_RSS_VI_CONFIG_CMD           = 0x23,
	FW_DEVLOG_CMD                  = 0x25,
	FW_CLIP_CMD                    = 0x28,
	FW_LASTC2E_CMD                 = 0x40,
	FW_ERROR_CMD                   = 0x80,
@@ -3038,4 +3039,84 @@ enum fw_hdr_flags {
	FW_HDR_FLAGS_RESET_HALT = 0x00000001,
};

/* length of the formatting string  */
#define FW_DEVLOG_FMT_LEN	192

/* maximum number of the formatting string parameters */
#define FW_DEVLOG_FMT_PARAMS_NUM 8

/* priority levels */
enum fw_devlog_level {
	FW_DEVLOG_LEVEL_EMERG	= 0x0,
	FW_DEVLOG_LEVEL_CRIT	= 0x1,
	FW_DEVLOG_LEVEL_ERR	= 0x2,
	FW_DEVLOG_LEVEL_NOTICE	= 0x3,
	FW_DEVLOG_LEVEL_INFO	= 0x4,
	FW_DEVLOG_LEVEL_DEBUG	= 0x5,
	FW_DEVLOG_LEVEL_MAX	= 0x5,
};

/* facilities that may send a log message */
enum fw_devlog_facility {
	FW_DEVLOG_FACILITY_CORE		= 0x00,
	FW_DEVLOG_FACILITY_CF		= 0x01,
	FW_DEVLOG_FACILITY_SCHED	= 0x02,
	FW_DEVLOG_FACILITY_TIMER	= 0x04,
	FW_DEVLOG_FACILITY_RES		= 0x06,
	FW_DEVLOG_FACILITY_HW		= 0x08,
	FW_DEVLOG_FACILITY_FLR		= 0x10,
	FW_DEVLOG_FACILITY_DMAQ		= 0x12,
	FW_DEVLOG_FACILITY_PHY		= 0x14,
	FW_DEVLOG_FACILITY_MAC		= 0x16,
	FW_DEVLOG_FACILITY_PORT		= 0x18,
	FW_DEVLOG_FACILITY_VI		= 0x1A,
	FW_DEVLOG_FACILITY_FILTER	= 0x1C,
	FW_DEVLOG_FACILITY_ACL		= 0x1E,
	FW_DEVLOG_FACILITY_TM		= 0x20,
	FW_DEVLOG_FACILITY_QFC		= 0x22,
	FW_DEVLOG_FACILITY_DCB		= 0x24,
	FW_DEVLOG_FACILITY_ETH		= 0x26,
	FW_DEVLOG_FACILITY_OFLD		= 0x28,
	FW_DEVLOG_FACILITY_RI		= 0x2A,
	FW_DEVLOG_FACILITY_ISCSI	= 0x2C,
	FW_DEVLOG_FACILITY_FCOE		= 0x2E,
	FW_DEVLOG_FACILITY_FOISCSI	= 0x30,
	FW_DEVLOG_FACILITY_FOFCOE	= 0x32,
	FW_DEVLOG_FACILITY_MAX		= 0x32,
};

/* log message format */
struct fw_devlog_e {
	__be64	timestamp;
	__be32	seqno;
	__be16	reserved1;
	__u8	level;
	__u8	facility;
	__u8	fmt[FW_DEVLOG_FMT_LEN];
	__be32	params[FW_DEVLOG_FMT_PARAMS_NUM];
	__be32	reserved3[4];
};

struct fw_devlog_cmd {
	__be32 op_to_write;
	__be32 retval_len16;
	__u8   level;
	__u8   r2[7];
	__be32 memtype_devlog_memaddr16_devlog;
	__be32 memsize_devlog;
	__be32 r3[2];
};

#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_S		28
#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_M		0xf
#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(x)	\
	(((x) >> FW_DEVLOG_CMD_MEMTYPE_DEVLOG_S) & \
	 FW_DEVLOG_CMD_MEMTYPE_DEVLOG_M)

#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S	0
#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M	0xfffffff
#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(x)	\
	(((x) >> FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S) & \
	 FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M)

#endif /* _T4FW_INTERFACE_H_ */