Commit 2d277b3b authored by Hariprasad Shenai's avatar Hariprasad Shenai Committed by David S. Miller

cxgb4: Added support in debugfs to display TP logic analyzer output

Dump Transport Processor event trace.
Signed-off-by: default avatarHariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 70a5f3bb
...@@ -221,6 +221,7 @@ struct sge_params { ...@@ -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); ...@@ -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 = { ...@@ -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) ...@@ -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 @@ int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) ...@@ -4782,3 +4782,50 @@ int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr)
} }
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 { ...@@ -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 @@ ...@@ -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)
......
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