cxgb4: Added support in debugfs to display TP logic analyzer output
Dump Transport Processor event trace. Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
70a5f3bb5f
commit
2d277b3b44
@ -221,6 +221,7 @@ struct sge_params {
|
|||||||
struct tp_params {
|
struct tp_params {
|
||||||
unsigned int ntxchan; /* # of Tx channels */
|
unsigned int ntxchan; /* # of Tx channels */
|
||||||
unsigned int tre; /* log2 of core clocks per TP tick */
|
unsigned int tre; /* log2 of core clocks per TP tick */
|
||||||
|
unsigned int la_mask; /* what events are recorded by TP LA */
|
||||||
unsigned short tx_modq_map; /* TX modulation scheduler queue to */
|
unsigned short tx_modq_map; /* TX modulation scheduler queue to */
|
||||||
/* channel map */
|
/* channel map */
|
||||||
|
|
||||||
@ -1174,6 +1175,7 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p);
|
|||||||
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
|
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
|
||||||
void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
|
void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
|
||||||
unsigned int mask, unsigned int val);
|
unsigned int mask, unsigned int val);
|
||||||
|
void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr);
|
||||||
void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
|
void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
|
||||||
struct tp_tcp_stats *v6);
|
struct tp_tcp_stats *v6);
|
||||||
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
|
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
|
||||||
|
@ -315,6 +315,253 @@ static const struct file_operations cim_obq_fops = {
|
|||||||
.release = seq_release_private
|
.release = seq_release_private
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct field_desc {
|
||||||
|
const char *name;
|
||||||
|
unsigned int start;
|
||||||
|
unsigned int width;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void field_desc_show(struct seq_file *seq, u64 v,
|
||||||
|
const struct field_desc *p)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
int line_size = 0;
|
||||||
|
|
||||||
|
while (p->name) {
|
||||||
|
u64 mask = (1ULL << p->width) - 1;
|
||||||
|
int len = scnprintf(buf, sizeof(buf), "%s: %llu", p->name,
|
||||||
|
((unsigned long long)v >> p->start) & mask);
|
||||||
|
|
||||||
|
if (line_size + len >= 79) {
|
||||||
|
line_size = 8;
|
||||||
|
seq_puts(seq, "\n ");
|
||||||
|
}
|
||||||
|
seq_printf(seq, "%s ", buf);
|
||||||
|
line_size += len + 1;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
seq_putc(seq, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct field_desc tp_la0[] = {
|
||||||
|
{ "RcfOpCodeOut", 60, 4 },
|
||||||
|
{ "State", 56, 4 },
|
||||||
|
{ "WcfState", 52, 4 },
|
||||||
|
{ "RcfOpcSrcOut", 50, 2 },
|
||||||
|
{ "CRxError", 49, 1 },
|
||||||
|
{ "ERxError", 48, 1 },
|
||||||
|
{ "SanityFailed", 47, 1 },
|
||||||
|
{ "SpuriousMsg", 46, 1 },
|
||||||
|
{ "FlushInputMsg", 45, 1 },
|
||||||
|
{ "FlushInputCpl", 44, 1 },
|
||||||
|
{ "RssUpBit", 43, 1 },
|
||||||
|
{ "RssFilterHit", 42, 1 },
|
||||||
|
{ "Tid", 32, 10 },
|
||||||
|
{ "InitTcb", 31, 1 },
|
||||||
|
{ "LineNumber", 24, 7 },
|
||||||
|
{ "Emsg", 23, 1 },
|
||||||
|
{ "EdataOut", 22, 1 },
|
||||||
|
{ "Cmsg", 21, 1 },
|
||||||
|
{ "CdataOut", 20, 1 },
|
||||||
|
{ "EreadPdu", 19, 1 },
|
||||||
|
{ "CreadPdu", 18, 1 },
|
||||||
|
{ "TunnelPkt", 17, 1 },
|
||||||
|
{ "RcfPeerFin", 16, 1 },
|
||||||
|
{ "RcfReasonOut", 12, 4 },
|
||||||
|
{ "TxCchannel", 10, 2 },
|
||||||
|
{ "RcfTxChannel", 8, 2 },
|
||||||
|
{ "RxEchannel", 6, 2 },
|
||||||
|
{ "RcfRxChannel", 5, 1 },
|
||||||
|
{ "RcfDataOutSrdy", 4, 1 },
|
||||||
|
{ "RxDvld", 3, 1 },
|
||||||
|
{ "RxOoDvld", 2, 1 },
|
||||||
|
{ "RxCongestion", 1, 1 },
|
||||||
|
{ "TxCongestion", 0, 1 },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tp_la_show(struct seq_file *seq, void *v, int idx)
|
||||||
|
{
|
||||||
|
const u64 *p = v;
|
||||||
|
|
||||||
|
field_desc_show(seq, *p, tp_la0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tp_la_show2(struct seq_file *seq, void *v, int idx)
|
||||||
|
{
|
||||||
|
const u64 *p = v;
|
||||||
|
|
||||||
|
if (idx)
|
||||||
|
seq_putc(seq, '\n');
|
||||||
|
field_desc_show(seq, p[0], tp_la0);
|
||||||
|
if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL)
|
||||||
|
field_desc_show(seq, p[1], tp_la0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tp_la_show3(struct seq_file *seq, void *v, int idx)
|
||||||
|
{
|
||||||
|
static struct field_desc tp_la1[] = {
|
||||||
|
{ "CplCmdIn", 56, 8 },
|
||||||
|
{ "CplCmdOut", 48, 8 },
|
||||||
|
{ "ESynOut", 47, 1 },
|
||||||
|
{ "EAckOut", 46, 1 },
|
||||||
|
{ "EFinOut", 45, 1 },
|
||||||
|
{ "ERstOut", 44, 1 },
|
||||||
|
{ "SynIn", 43, 1 },
|
||||||
|
{ "AckIn", 42, 1 },
|
||||||
|
{ "FinIn", 41, 1 },
|
||||||
|
{ "RstIn", 40, 1 },
|
||||||
|
{ "DataIn", 39, 1 },
|
||||||
|
{ "DataInVld", 38, 1 },
|
||||||
|
{ "PadIn", 37, 1 },
|
||||||
|
{ "RxBufEmpty", 36, 1 },
|
||||||
|
{ "RxDdp", 35, 1 },
|
||||||
|
{ "RxFbCongestion", 34, 1 },
|
||||||
|
{ "TxFbCongestion", 33, 1 },
|
||||||
|
{ "TxPktSumSrdy", 32, 1 },
|
||||||
|
{ "RcfUlpType", 28, 4 },
|
||||||
|
{ "Eread", 27, 1 },
|
||||||
|
{ "Ebypass", 26, 1 },
|
||||||
|
{ "Esave", 25, 1 },
|
||||||
|
{ "Static0", 24, 1 },
|
||||||
|
{ "Cread", 23, 1 },
|
||||||
|
{ "Cbypass", 22, 1 },
|
||||||
|
{ "Csave", 21, 1 },
|
||||||
|
{ "CPktOut", 20, 1 },
|
||||||
|
{ "RxPagePoolFull", 18, 2 },
|
||||||
|
{ "RxLpbkPkt", 17, 1 },
|
||||||
|
{ "TxLpbkPkt", 16, 1 },
|
||||||
|
{ "RxVfValid", 15, 1 },
|
||||||
|
{ "SynLearned", 14, 1 },
|
||||||
|
{ "SetDelEntry", 13, 1 },
|
||||||
|
{ "SetInvEntry", 12, 1 },
|
||||||
|
{ "CpcmdDvld", 11, 1 },
|
||||||
|
{ "CpcmdSave", 10, 1 },
|
||||||
|
{ "RxPstructsFull", 8, 2 },
|
||||||
|
{ "EpcmdDvld", 7, 1 },
|
||||||
|
{ "EpcmdFlush", 6, 1 },
|
||||||
|
{ "EpcmdTrimPrefix", 5, 1 },
|
||||||
|
{ "EpcmdTrimPostfix", 4, 1 },
|
||||||
|
{ "ERssIp4Pkt", 3, 1 },
|
||||||
|
{ "ERssIp6Pkt", 2, 1 },
|
||||||
|
{ "ERssTcpUdpPkt", 1, 1 },
|
||||||
|
{ "ERssFceFipPkt", 0, 1 },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
static struct field_desc tp_la2[] = {
|
||||||
|
{ "CplCmdIn", 56, 8 },
|
||||||
|
{ "MpsVfVld", 55, 1 },
|
||||||
|
{ "MpsPf", 52, 3 },
|
||||||
|
{ "MpsVf", 44, 8 },
|
||||||
|
{ "SynIn", 43, 1 },
|
||||||
|
{ "AckIn", 42, 1 },
|
||||||
|
{ "FinIn", 41, 1 },
|
||||||
|
{ "RstIn", 40, 1 },
|
||||||
|
{ "DataIn", 39, 1 },
|
||||||
|
{ "DataInVld", 38, 1 },
|
||||||
|
{ "PadIn", 37, 1 },
|
||||||
|
{ "RxBufEmpty", 36, 1 },
|
||||||
|
{ "RxDdp", 35, 1 },
|
||||||
|
{ "RxFbCongestion", 34, 1 },
|
||||||
|
{ "TxFbCongestion", 33, 1 },
|
||||||
|
{ "TxPktSumSrdy", 32, 1 },
|
||||||
|
{ "RcfUlpType", 28, 4 },
|
||||||
|
{ "Eread", 27, 1 },
|
||||||
|
{ "Ebypass", 26, 1 },
|
||||||
|
{ "Esave", 25, 1 },
|
||||||
|
{ "Static0", 24, 1 },
|
||||||
|
{ "Cread", 23, 1 },
|
||||||
|
{ "Cbypass", 22, 1 },
|
||||||
|
{ "Csave", 21, 1 },
|
||||||
|
{ "CPktOut", 20, 1 },
|
||||||
|
{ "RxPagePoolFull", 18, 2 },
|
||||||
|
{ "RxLpbkPkt", 17, 1 },
|
||||||
|
{ "TxLpbkPkt", 16, 1 },
|
||||||
|
{ "RxVfValid", 15, 1 },
|
||||||
|
{ "SynLearned", 14, 1 },
|
||||||
|
{ "SetDelEntry", 13, 1 },
|
||||||
|
{ "SetInvEntry", 12, 1 },
|
||||||
|
{ "CpcmdDvld", 11, 1 },
|
||||||
|
{ "CpcmdSave", 10, 1 },
|
||||||
|
{ "RxPstructsFull", 8, 2 },
|
||||||
|
{ "EpcmdDvld", 7, 1 },
|
||||||
|
{ "EpcmdFlush", 6, 1 },
|
||||||
|
{ "EpcmdTrimPrefix", 5, 1 },
|
||||||
|
{ "EpcmdTrimPostfix", 4, 1 },
|
||||||
|
{ "ERssIp4Pkt", 3, 1 },
|
||||||
|
{ "ERssIp6Pkt", 2, 1 },
|
||||||
|
{ "ERssTcpUdpPkt", 1, 1 },
|
||||||
|
{ "ERssFceFipPkt", 0, 1 },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
const u64 *p = v;
|
||||||
|
|
||||||
|
if (idx)
|
||||||
|
seq_putc(seq, '\n');
|
||||||
|
field_desc_show(seq, p[0], tp_la0);
|
||||||
|
if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL)
|
||||||
|
field_desc_show(seq, p[1], (p[0] & BIT(17)) ? tp_la2 : tp_la1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tp_la_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct seq_tab *p;
|
||||||
|
struct adapter *adap = inode->i_private;
|
||||||
|
|
||||||
|
switch (DBGLAMODE_G(t4_read_reg(adap, TP_DBG_LA_CONFIG_A))) {
|
||||||
|
case 2:
|
||||||
|
p = seq_open_tab(file, TPLA_SIZE / 2, 2 * sizeof(u64), 0,
|
||||||
|
tp_la_show2);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
p = seq_open_tab(file, TPLA_SIZE / 2, 2 * sizeof(u64), 0,
|
||||||
|
tp_la_show3);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
p = seq_open_tab(file, TPLA_SIZE, sizeof(u64), 0, tp_la_show);
|
||||||
|
}
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
t4_tp_read_la(adap, (u64 *)p->data, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t tp_la_write(struct file *file, const char __user *buf,
|
||||||
|
size_t count, loff_t *pos)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
char s[32];
|
||||||
|
unsigned long val;
|
||||||
|
size_t size = min(sizeof(s) - 1, count);
|
||||||
|
struct adapter *adap = FILE_DATA(file)->i_private;
|
||||||
|
|
||||||
|
if (copy_from_user(s, buf, size))
|
||||||
|
return -EFAULT;
|
||||||
|
s[size] = '\0';
|
||||||
|
err = kstrtoul(s, 0, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (val > 0xffff)
|
||||||
|
return -EINVAL;
|
||||||
|
adap->params.tp.la_mask = val << 16;
|
||||||
|
t4_set_reg_field(adap, TP_DBG_LA_CONFIG_A, 0xffff0000U,
|
||||||
|
adap->params.tp.la_mask);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations tp_la_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = tp_la_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = seq_release_private,
|
||||||
|
.write = tp_la_write
|
||||||
|
};
|
||||||
|
|
||||||
/* Show the PM memory stats. These stats include:
|
/* Show the PM memory stats. These stats include:
|
||||||
*
|
*
|
||||||
* TX:
|
* TX:
|
||||||
@ -1619,6 +1866,7 @@ int t4_setup_debugfs(struct adapter *adap)
|
|||||||
{ "obq_ulp3", &cim_obq_fops, S_IRUSR, 3 },
|
{ "obq_ulp3", &cim_obq_fops, S_IRUSR, 3 },
|
||||||
{ "obq_sge", &cim_obq_fops, S_IRUSR, 4 },
|
{ "obq_sge", &cim_obq_fops, S_IRUSR, 4 },
|
||||||
{ "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 },
|
{ "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 },
|
||||||
|
{ "tp_la", &tp_la_fops, S_IRUSR, 0 },
|
||||||
{ "sensors", &sensors_debugfs_fops, S_IRUSR, 0 },
|
{ "sensors", &sensors_debugfs_fops, S_IRUSR, 0 },
|
||||||
{ "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 },
|
{ "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 },
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
@ -4782,3 +4782,50 @@ restart:
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* t4_tp_read_la - read TP LA capture buffer
|
||||||
|
* @adap: the adapter
|
||||||
|
* @la_buf: where to store the LA data
|
||||||
|
* @wrptr: the HW write pointer within the capture buffer
|
||||||
|
*
|
||||||
|
* Reads the contents of the TP LA buffer with the most recent entry at
|
||||||
|
* the end of the returned data and with the entry at @wrptr first.
|
||||||
|
* We leave the LA in the running state we find it in.
|
||||||
|
*/
|
||||||
|
void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr)
|
||||||
|
{
|
||||||
|
bool last_incomplete;
|
||||||
|
unsigned int i, cfg, val, idx;
|
||||||
|
|
||||||
|
cfg = t4_read_reg(adap, TP_DBG_LA_CONFIG_A) & 0xffff;
|
||||||
|
if (cfg & DBGLAENABLE_F) /* freeze LA */
|
||||||
|
t4_write_reg(adap, TP_DBG_LA_CONFIG_A,
|
||||||
|
adap->params.tp.la_mask | (cfg ^ DBGLAENABLE_F));
|
||||||
|
|
||||||
|
val = t4_read_reg(adap, TP_DBG_LA_CONFIG_A);
|
||||||
|
idx = DBGLAWPTR_G(val);
|
||||||
|
last_incomplete = DBGLAMODE_G(val) >= 2 && (val & DBGLAWHLF_F) == 0;
|
||||||
|
if (last_incomplete)
|
||||||
|
idx = (idx + 1) & DBGLARPTR_M;
|
||||||
|
if (wrptr)
|
||||||
|
*wrptr = idx;
|
||||||
|
|
||||||
|
val &= 0xffff;
|
||||||
|
val &= ~DBGLARPTR_V(DBGLARPTR_M);
|
||||||
|
val |= adap->params.tp.la_mask;
|
||||||
|
|
||||||
|
for (i = 0; i < TPLA_SIZE; i++) {
|
||||||
|
t4_write_reg(adap, TP_DBG_LA_CONFIG_A, DBGLARPTR_V(idx) | val);
|
||||||
|
la_buf[i] = t4_read_reg64(adap, TP_DBG_LA_DATAL_A);
|
||||||
|
idx = (idx + 1) & DBGLARPTR_M;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wipe out last entry if it isn't valid */
|
||||||
|
if (last_incomplete)
|
||||||
|
la_buf[TPLA_SIZE - 1] = ~0ULL;
|
||||||
|
|
||||||
|
if (cfg & DBGLAENABLE_F) /* restore running state */
|
||||||
|
t4_write_reg(adap, TP_DBG_LA_CONFIG_A,
|
||||||
|
cfg | adap->params.tp.la_mask);
|
||||||
|
}
|
||||||
|
@ -63,6 +63,7 @@ enum {
|
|||||||
CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */
|
CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */
|
||||||
CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */
|
CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */
|
||||||
CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */
|
CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */
|
||||||
|
TPLA_SIZE = 128, /* # of 64-bit words in TP LA */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -1183,9 +1183,31 @@
|
|||||||
#define RSVDSPACEINT_F RSVDSPACEINT_V(1U)
|
#define RSVDSPACEINT_F RSVDSPACEINT_V(1U)
|
||||||
|
|
||||||
/* registers for module TP */
|
/* registers for module TP */
|
||||||
|
#define DBGLAWHLF_S 23
|
||||||
|
#define DBGLAWHLF_V(x) ((x) << DBGLAWHLF_S)
|
||||||
|
#define DBGLAWHLF_F DBGLAWHLF_V(1U)
|
||||||
|
|
||||||
|
#define DBGLAWPTR_S 16
|
||||||
|
#define DBGLAWPTR_M 0x7fU
|
||||||
|
#define DBGLAWPTR_G(x) (((x) >> DBGLAWPTR_S) & DBGLAWPTR_M)
|
||||||
|
|
||||||
|
#define DBGLAENABLE_S 12
|
||||||
|
#define DBGLAENABLE_V(x) ((x) << DBGLAENABLE_S)
|
||||||
|
#define DBGLAENABLE_F DBGLAENABLE_V(1U)
|
||||||
|
|
||||||
|
#define DBGLARPTR_S 0
|
||||||
|
#define DBGLARPTR_M 0x7fU
|
||||||
|
#define DBGLARPTR_V(x) ((x) << DBGLARPTR_S)
|
||||||
|
|
||||||
|
#define TP_DBG_LA_DATAL_A 0x7ed8
|
||||||
|
#define TP_DBG_LA_CONFIG_A 0x7ed4
|
||||||
#define TP_OUT_CONFIG_A 0x7d04
|
#define TP_OUT_CONFIG_A 0x7d04
|
||||||
#define TP_GLOBAL_CONFIG_A 0x7d08
|
#define TP_GLOBAL_CONFIG_A 0x7d08
|
||||||
|
|
||||||
|
#define DBGLAMODE_S 14
|
||||||
|
#define DBGLAMODE_M 0x3U
|
||||||
|
#define DBGLAMODE_G(x) (((x) >> DBGLAMODE_S) & DBGLAMODE_M)
|
||||||
|
|
||||||
#define FIVETUPLELOOKUP_S 17
|
#define FIVETUPLELOOKUP_S 17
|
||||||
#define FIVETUPLELOOKUP_M 0x3U
|
#define FIVETUPLELOOKUP_M 0x3U
|
||||||
#define FIVETUPLELOOKUP_V(x) ((x) << FIVETUPLELOOKUP_S)
|
#define FIVETUPLELOOKUP_V(x) ((x) << FIVETUPLELOOKUP_S)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user