mirror of https://gitee.com/openkylin/linux.git
cxgb4vf: Add support to enable logging of firmware mailbox commands for VF
Add new /sys/kernel/debug/ support to dump firmware mailbox commands and replies for debugging purpose. Based on original work by Casey Leedom <leedom@chelsio.com> Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7f080c3f2f
commit
ae7b757622
|
@ -387,6 +387,10 @@ struct adapter {
|
||||||
/* various locks */
|
/* various locks */
|
||||||
spinlock_t stats_lock;
|
spinlock_t stats_lock;
|
||||||
|
|
||||||
|
/* support for mailbox command/reply logging */
|
||||||
|
#define T4VF_OS_LOG_MBOX_CMDS 256
|
||||||
|
struct mbox_cmd_log *mbox_log;
|
||||||
|
|
||||||
/* list of MAC addresses in MPS Hash */
|
/* list of MAC addresses in MPS Hash */
|
||||||
struct list_head mac_hlist;
|
struct list_head mac_hlist;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1703,6 +1703,105 @@ static const struct ethtool_ops cxgb4vf_ethtool_ops = {
|
||||||
* ================================================
|
* ================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show Firmware Mailbox Command/Reply Log
|
||||||
|
*
|
||||||
|
* Note that we don't do any locking when dumping the Firmware Mailbox Log so
|
||||||
|
* it's possible that we can catch things during a log update and therefore
|
||||||
|
* see partially corrupted log entries. But i9t's probably Good Enough(tm).
|
||||||
|
* If we ever decide that we want to make sure that we're dumping a coherent
|
||||||
|
* log, we'd need to perform locking in the mailbox logging and in
|
||||||
|
* mboxlog_open() where we'd need to grab the entire mailbox log in one go
|
||||||
|
* like we do for the Firmware Device Log. But as stated above, meh ...
|
||||||
|
*/
|
||||||
|
static int mboxlog_show(struct seq_file *seq, void *v)
|
||||||
|
{
|
||||||
|
struct adapter *adapter = seq->private;
|
||||||
|
struct mbox_cmd_log *log = adapter->mbox_log;
|
||||||
|
struct mbox_cmd *entry;
|
||||||
|
int entry_idx, i;
|
||||||
|
|
||||||
|
if (v == SEQ_START_TOKEN) {
|
||||||
|
seq_printf(seq,
|
||||||
|
"%10s %15s %5s %5s %s\n",
|
||||||
|
"Seq#", "Tstamp", "Atime", "Etime",
|
||||||
|
"Command/Reply");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry_idx = log->cursor + ((uintptr_t)v - 2);
|
||||||
|
if (entry_idx >= log->size)
|
||||||
|
entry_idx -= log->size;
|
||||||
|
entry = mbox_cmd_log_entry(log, entry_idx);
|
||||||
|
|
||||||
|
/* skip over unused entries */
|
||||||
|
if (entry->timestamp == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
seq_printf(seq, "%10u %15llu %5d %5d",
|
||||||
|
entry->seqno, entry->timestamp,
|
||||||
|
entry->access, entry->execute);
|
||||||
|
for (i = 0; i < MBOX_LEN / 8; i++) {
|
||||||
|
u64 flit = entry->cmd[i];
|
||||||
|
u32 hi = (u32)(flit >> 32);
|
||||||
|
u32 lo = (u32)flit;
|
||||||
|
|
||||||
|
seq_printf(seq, " %08x %08x", hi, lo);
|
||||||
|
}
|
||||||
|
seq_puts(seq, "\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *mboxlog_get_idx(struct seq_file *seq, loff_t pos)
|
||||||
|
{
|
||||||
|
struct adapter *adapter = seq->private;
|
||||||
|
struct mbox_cmd_log *log = adapter->mbox_log;
|
||||||
|
|
||||||
|
return ((pos <= log->size) ? (void *)(uintptr_t)(pos + 1) : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *mboxlog_start(struct seq_file *seq, loff_t *pos)
|
||||||
|
{
|
||||||
|
return *pos ? mboxlog_get_idx(seq, *pos) : SEQ_START_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *mboxlog_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||||
|
{
|
||||||
|
++*pos;
|
||||||
|
return mboxlog_get_idx(seq, *pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mboxlog_stop(struct seq_file *seq, void *v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct seq_operations mboxlog_seq_ops = {
|
||||||
|
.start = mboxlog_start,
|
||||||
|
.next = mboxlog_next,
|
||||||
|
.stop = mboxlog_stop,
|
||||||
|
.show = mboxlog_show
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mboxlog_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
int res = seq_open(file, &mboxlog_seq_ops);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
struct seq_file *seq = file->private_data;
|
||||||
|
|
||||||
|
seq->private = inode->i_private;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations mboxlog_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = mboxlog_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = seq_release,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Show SGE Queue Set information. We display QPL Queues Sets per line.
|
* Show SGE Queue Set information. We display QPL Queues Sets per line.
|
||||||
*/
|
*/
|
||||||
|
@ -2122,6 +2221,7 @@ struct cxgb4vf_debugfs_entry {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cxgb4vf_debugfs_entry debugfs_files[] = {
|
static struct cxgb4vf_debugfs_entry debugfs_files[] = {
|
||||||
|
{ "mboxlog", S_IRUGO, &mboxlog_fops },
|
||||||
{ "sge_qinfo", S_IRUGO, &sge_qinfo_debugfs_fops },
|
{ "sge_qinfo", S_IRUGO, &sge_qinfo_debugfs_fops },
|
||||||
{ "sge_qstats", S_IRUGO, &sge_qstats_proc_fops },
|
{ "sge_qstats", S_IRUGO, &sge_qstats_proc_fops },
|
||||||
{ "resources", S_IRUGO, &resources_proc_fops },
|
{ "resources", S_IRUGO, &resources_proc_fops },
|
||||||
|
@ -2664,6 +2764,16 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
|
||||||
adapter->pdev = pdev;
|
adapter->pdev = pdev;
|
||||||
adapter->pdev_dev = &pdev->dev;
|
adapter->pdev_dev = &pdev->dev;
|
||||||
|
|
||||||
|
adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) +
|
||||||
|
(sizeof(struct mbox_cmd) *
|
||||||
|
T4VF_OS_LOG_MBOX_CMDS),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!adapter->mbox_log) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto err_free_adapter;
|
||||||
|
}
|
||||||
|
adapter->mbox_log->size = T4VF_OS_LOG_MBOX_CMDS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize SMP data synchronization resources.
|
* Initialize SMP data synchronization resources.
|
||||||
*/
|
*/
|
||||||
|
@ -2913,6 +3023,7 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
|
||||||
iounmap(adapter->regs);
|
iounmap(adapter->regs);
|
||||||
|
|
||||||
err_free_adapter:
|
err_free_adapter:
|
||||||
|
kfree(adapter->mbox_log);
|
||||||
kfree(adapter);
|
kfree(adapter);
|
||||||
|
|
||||||
err_release_regions:
|
err_release_regions:
|
||||||
|
@ -2982,6 +3093,7 @@ static void cxgb4vf_pci_remove(struct pci_dev *pdev)
|
||||||
iounmap(adapter->regs);
|
iounmap(adapter->regs);
|
||||||
if (!is_t4(adapter->params.chip))
|
if (!is_t4(adapter->params.chip))
|
||||||
iounmap(adapter->bar2);
|
iounmap(adapter->bar2);
|
||||||
|
kfree(adapter->mbox_log);
|
||||||
kfree(adapter);
|
kfree(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#ifndef __T4VF_COMMON_H__
|
#ifndef __T4VF_COMMON_H__
|
||||||
#define __T4VF_COMMON_H__
|
#define __T4VF_COMMON_H__
|
||||||
|
|
||||||
|
#include "../cxgb4/t4_hw.h"
|
||||||
#include "../cxgb4/t4fw_api.h"
|
#include "../cxgb4/t4fw_api.h"
|
||||||
|
|
||||||
#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
|
#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
|
||||||
|
@ -227,6 +228,34 @@ struct adapter_params {
|
||||||
u8 nports; /* # of Ethernet "ports" */
|
u8 nports; /* # of Ethernet "ports" */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Firmware Mailbox Command/Reply log. All values are in Host-Endian format.
|
||||||
|
* The access and execute times are signed in order to accommodate negative
|
||||||
|
* error returns.
|
||||||
|
*/
|
||||||
|
struct mbox_cmd {
|
||||||
|
u64 cmd[MBOX_LEN / 8]; /* a Firmware Mailbox Command/Reply */
|
||||||
|
u64 timestamp; /* OS-dependent timestamp */
|
||||||
|
u32 seqno; /* sequence number */
|
||||||
|
s16 access; /* time (ms) to access mailbox */
|
||||||
|
s16 execute; /* time (ms) to execute */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mbox_cmd_log {
|
||||||
|
unsigned int size; /* number of entries in the log */
|
||||||
|
unsigned int cursor; /* next position in the log to write */
|
||||||
|
u32 seqno; /* next sequence number */
|
||||||
|
/* variable length mailbox command log starts here */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Given a pointer to a Firmware Mailbox Command Log and a log entry index,
|
||||||
|
* return a pointer to the specified entry.
|
||||||
|
*/
|
||||||
|
static inline struct mbox_cmd *mbox_cmd_log_entry(struct mbox_cmd_log *log,
|
||||||
|
unsigned int entry_idx)
|
||||||
|
{
|
||||||
|
return &((struct mbox_cmd *)&(log)[1])[entry_idx];
|
||||||
|
}
|
||||||
|
|
||||||
#include "adapter.h"
|
#include "adapter.h"
|
||||||
|
|
||||||
#ifndef PCI_VENDOR_ID_CHELSIO
|
#ifndef PCI_VENDOR_ID_CHELSIO
|
||||||
|
|
|
@ -76,21 +76,33 @@ static void get_mbox_rpl(struct adapter *adapter, __be64 *rpl, int size,
|
||||||
*rpl++ = cpu_to_be64(t4_read_reg64(adapter, mbox_data));
|
*rpl++ = cpu_to_be64(t4_read_reg64(adapter, mbox_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Dump contents of mailbox with a leading tag.
|
* t4vf_record_mbox - record a Firmware Mailbox Command/Reply in the log
|
||||||
|
* @adapter: the adapter
|
||||||
|
* @cmd: the Firmware Mailbox Command or Reply
|
||||||
|
* @size: command length in bytes
|
||||||
|
* @access: the time (ms) needed to access the Firmware Mailbox
|
||||||
|
* @execute: the time (ms) the command spent being executed
|
||||||
*/
|
*/
|
||||||
static void dump_mbox(struct adapter *adapter, const char *tag, u32 mbox_data)
|
static void t4vf_record_mbox(struct adapter *adapter, const __be64 *cmd,
|
||||||
|
int size, int access, int execute)
|
||||||
{
|
{
|
||||||
dev_err(adapter->pdev_dev,
|
struct mbox_cmd_log *log = adapter->mbox_log;
|
||||||
"mbox %s: %llx %llx %llx %llx %llx %llx %llx %llx\n", tag,
|
struct mbox_cmd *entry;
|
||||||
(unsigned long long)t4_read_reg64(adapter, mbox_data + 0),
|
int i;
|
||||||
(unsigned long long)t4_read_reg64(adapter, mbox_data + 8),
|
|
||||||
(unsigned long long)t4_read_reg64(adapter, mbox_data + 16),
|
entry = mbox_cmd_log_entry(log, log->cursor++);
|
||||||
(unsigned long long)t4_read_reg64(adapter, mbox_data + 24),
|
if (log->cursor == log->size)
|
||||||
(unsigned long long)t4_read_reg64(adapter, mbox_data + 32),
|
log->cursor = 0;
|
||||||
(unsigned long long)t4_read_reg64(adapter, mbox_data + 40),
|
|
||||||
(unsigned long long)t4_read_reg64(adapter, mbox_data + 48),
|
for (i = 0; i < size / 8; i++)
|
||||||
(unsigned long long)t4_read_reg64(adapter, mbox_data + 56));
|
entry->cmd[i] = be64_to_cpu(cmd[i]);
|
||||||
|
while (i < MBOX_LEN / 8)
|
||||||
|
entry->cmd[i++] = 0;
|
||||||
|
entry->timestamp = jiffies;
|
||||||
|
entry->seqno = log->seqno++;
|
||||||
|
entry->access = access;
|
||||||
|
entry->execute = execute;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,10 +132,13 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
|
||||||
1, 1, 3, 5, 10, 10, 20, 50, 100
|
1, 1, 3, 5, 10, 10, 20, 50, 100
|
||||||
};
|
};
|
||||||
|
|
||||||
|
u16 access = 0, execute = 0;
|
||||||
u32 v, mbox_data;
|
u32 v, mbox_data;
|
||||||
int i, ms, delay_idx;
|
int i, ms, delay_idx, ret;
|
||||||
const __be64 *p;
|
const __be64 *p;
|
||||||
u32 mbox_ctl = T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL;
|
u32 mbox_ctl = T4VF_CIM_BASE_ADDR + CIM_VF_EXT_MAILBOX_CTRL;
|
||||||
|
u32 cmd_op = FW_CMD_OP_G(be32_to_cpu(((struct fw_cmd_hdr *)cmd)->hi));
|
||||||
|
__be64 cmd_rpl[MBOX_LEN / 8];
|
||||||
|
|
||||||
/* In T6, mailbox size is changed to 128 bytes to avoid
|
/* In T6, mailbox size is changed to 128 bytes to avoid
|
||||||
* invalidating the entire prefetch buffer.
|
* invalidating the entire prefetch buffer.
|
||||||
|
@ -148,8 +163,11 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
|
||||||
v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl));
|
v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl));
|
||||||
for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
|
for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
|
||||||
v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl));
|
v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl));
|
||||||
if (v != MBOX_OWNER_DRV)
|
if (v != MBOX_OWNER_DRV) {
|
||||||
return v == MBOX_OWNER_FW ? -EBUSY : -ETIMEDOUT;
|
ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT;
|
||||||
|
t4vf_record_mbox(adapter, cmd, size, access, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write the command array into the Mailbox Data register array and
|
* Write the command array into the Mailbox Data register array and
|
||||||
|
@ -164,6 +182,8 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
|
||||||
* Data registers before doing the write to the VF Mailbox Control
|
* Data registers before doing the write to the VF Mailbox Control
|
||||||
* register.
|
* register.
|
||||||
*/
|
*/
|
||||||
|
if (cmd_op != FW_VI_STATS_CMD)
|
||||||
|
t4vf_record_mbox(adapter, cmd, size, access, 0);
|
||||||
for (i = 0, p = cmd; i < size; i += 8)
|
for (i = 0, p = cmd; i < size; i += 8)
|
||||||
t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++));
|
t4_write_reg64(adapter, mbox_data + i, be64_to_cpu(*p++));
|
||||||
t4_read_reg(adapter, mbox_data); /* flush write */
|
t4_read_reg(adapter, mbox_data); /* flush write */
|
||||||
|
@ -209,31 +229,33 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
|
||||||
* We return the (negated) firmware command return
|
* We return the (negated) firmware command return
|
||||||
* code (this depends on FW_SUCCESS == 0).
|
* code (this depends on FW_SUCCESS == 0).
|
||||||
*/
|
*/
|
||||||
|
get_mbox_rpl(adapter, cmd_rpl, size, mbox_data);
|
||||||
|
|
||||||
/* return value in low-order little-endian word */
|
/* return value in low-order little-endian word */
|
||||||
v = t4_read_reg(adapter, mbox_data);
|
v = be64_to_cpu(cmd_rpl[0]);
|
||||||
if (FW_CMD_RETVAL_G(v))
|
|
||||||
dump_mbox(adapter, "FW Error", mbox_data);
|
|
||||||
|
|
||||||
if (rpl) {
|
if (rpl) {
|
||||||
/* request bit in high-order BE word */
|
/* request bit in high-order BE word */
|
||||||
WARN_ON((be32_to_cpu(*(const __be32 *)cmd)
|
WARN_ON((be32_to_cpu(*(const __be32 *)cmd)
|
||||||
& FW_CMD_REQUEST_F) == 0);
|
& FW_CMD_REQUEST_F) == 0);
|
||||||
get_mbox_rpl(adapter, rpl, size, mbox_data);
|
memcpy(rpl, cmd_rpl, size);
|
||||||
WARN_ON((be32_to_cpu(*(__be32 *)rpl)
|
WARN_ON((be32_to_cpu(*(__be32 *)rpl)
|
||||||
& FW_CMD_REQUEST_F) != 0);
|
& FW_CMD_REQUEST_F) != 0);
|
||||||
}
|
}
|
||||||
t4_write_reg(adapter, mbox_ctl,
|
t4_write_reg(adapter, mbox_ctl,
|
||||||
MBOWNER_V(MBOX_OWNER_NONE));
|
MBOWNER_V(MBOX_OWNER_NONE));
|
||||||
|
execute = i + ms;
|
||||||
|
if (cmd_op != FW_VI_STATS_CMD)
|
||||||
|
t4vf_record_mbox(adapter, cmd_rpl, size, access,
|
||||||
|
execute);
|
||||||
return -FW_CMD_RETVAL_G(v);
|
return -FW_CMD_RETVAL_G(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* We timed out. Return the error ... */
|
||||||
* We timed out. Return the error ...
|
ret = -ETIMEDOUT;
|
||||||
*/
|
t4vf_record_mbox(adapter, cmd, size, access, ret);
|
||||||
dump_mbox(adapter, "FW Timeout", mbox_data);
|
return ret;
|
||||||
return -ETIMEDOUT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
|
#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
|
||||||
|
|
Loading…
Reference in New Issue