Skip to content

Commit 8e3d04f

Browse files
Hariprasad Shenaidavem330
authored andcommitted
cxgb4: Add MPS tracing support
Handle TRACE_PKT, stack can sniff them on the first port Add debubfs enrty to configure tracing for offload traffic like iWARP & iSCSI for debugging purpose. Signed-off-by: Hariprasad Shenai <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f02e58f commit 8e3d04f

File tree

4 files changed

+475
-0
lines changed

4 files changed

+475
-0
lines changed

drivers/net/ethernet/chelsio/cxgb4/cxgb4.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,10 @@ struct adapter {
768768

769769
struct dentry *debugfs_root;
770770
u32 use_bd; /* Use SGE Back Door intfc for reading SGE Contexts */
771+
u32 trace_rss; /* 1 implies that different RSS flit per filter is
772+
* used per filter else if 0 default RSS flit is
773+
* used for all 4 filters.
774+
*/
771775

772776
spinlock_t stats_lock;
773777
spinlock_t win0_lock ____cacheline_aligned_in_smp;
@@ -1441,6 +1445,10 @@ int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
14411445
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
14421446
void t4_db_full(struct adapter *adapter);
14431447
void t4_db_dropped(struct adapter *adapter);
1448+
int t4_set_trace_filter(struct adapter *adapter, const struct trace_params *tp,
1449+
int filter_index, int enable);
1450+
void t4_get_trace_filter(struct adapter *adapter, struct trace_params *tp,
1451+
int filter_index, int *enabled);
14441452
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
14451453
u32 addr, u32 val);
14461454
void t4_sge_decode_idma_state(struct adapter *adapter, int state);

drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,298 @@ static const struct file_operations mbox_debugfs_fops = {
12011201
.write = mbox_write
12021202
};
12031203

1204+
static int mps_trc_show(struct seq_file *seq, void *v)
1205+
{
1206+
int enabled, i;
1207+
struct trace_params tp;
1208+
unsigned int trcidx = (uintptr_t)seq->private & 3;
1209+
struct adapter *adap = seq->private - trcidx;
1210+
1211+
t4_get_trace_filter(adap, &tp, trcidx, &enabled);
1212+
if (!enabled) {
1213+
seq_puts(seq, "tracer is disabled\n");
1214+
return 0;
1215+
}
1216+
1217+
if (tp.skip_ofst * 8 >= TRACE_LEN) {
1218+
dev_err(adap->pdev_dev, "illegal trace pattern skip offset\n");
1219+
return -EINVAL;
1220+
}
1221+
if (tp.port < 8) {
1222+
i = adap->chan_map[tp.port & 3];
1223+
if (i >= MAX_NPORTS) {
1224+
dev_err(adap->pdev_dev, "tracer %u is assigned "
1225+
"to non-existing port\n", trcidx);
1226+
return -EINVAL;
1227+
}
1228+
seq_printf(seq, "tracer is capturing %s %s, ",
1229+
adap->port[i]->name, tp.port < 4 ? "Rx" : "Tx");
1230+
} else
1231+
seq_printf(seq, "tracer is capturing loopback %d, ",
1232+
tp.port - 8);
1233+
seq_printf(seq, "snap length: %u, min length: %u\n", tp.snap_len,
1234+
tp.min_len);
1235+
seq_printf(seq, "packets captured %smatch filter\n",
1236+
tp.invert ? "do not " : "");
1237+
1238+
if (tp.skip_ofst) {
1239+
seq_puts(seq, "filter pattern: ");
1240+
for (i = 0; i < tp.skip_ofst * 2; i += 2)
1241+
seq_printf(seq, "%08x%08x", tp.data[i], tp.data[i + 1]);
1242+
seq_putc(seq, '/');
1243+
for (i = 0; i < tp.skip_ofst * 2; i += 2)
1244+
seq_printf(seq, "%08x%08x", tp.mask[i], tp.mask[i + 1]);
1245+
seq_puts(seq, "@0\n");
1246+
}
1247+
1248+
seq_puts(seq, "filter pattern: ");
1249+
for (i = tp.skip_ofst * 2; i < TRACE_LEN / 4; i += 2)
1250+
seq_printf(seq, "%08x%08x", tp.data[i], tp.data[i + 1]);
1251+
seq_putc(seq, '/');
1252+
for (i = tp.skip_ofst * 2; i < TRACE_LEN / 4; i += 2)
1253+
seq_printf(seq, "%08x%08x", tp.mask[i], tp.mask[i + 1]);
1254+
seq_printf(seq, "@%u\n", (tp.skip_ofst + tp.skip_len) * 8);
1255+
return 0;
1256+
}
1257+
1258+
static int mps_trc_open(struct inode *inode, struct file *file)
1259+
{
1260+
return single_open(file, mps_trc_show, inode->i_private);
1261+
}
1262+
1263+
static unsigned int xdigit2int(unsigned char c)
1264+
{
1265+
return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10;
1266+
}
1267+
1268+
#define TRC_PORT_NONE 0xff
1269+
#define TRC_RSS_ENABLE 0x33
1270+
#define TRC_RSS_DISABLE 0x13
1271+
1272+
/* Set an MPS trace filter. Syntax is:
1273+
*
1274+
* disable
1275+
*
1276+
* to disable tracing, or
1277+
*
1278+
* interface qid=<qid no> [snaplen=<val>] [minlen=<val>] [not] [<pattern>]...
1279+
*
1280+
* where interface is one of rxN, txN, or loopbackN, N = 0..3, qid can be one
1281+
* of the NIC's response qid obtained from sge_qinfo and pattern has the form
1282+
*
1283+
* <pattern data>[/<pattern mask>][@<anchor>]
1284+
*
1285+
* Up to 2 filter patterns can be specified. If 2 are supplied the first one
1286+
* must be anchored at 0. An omited mask is taken as a mask of 1s, an omitted
1287+
* anchor is taken as 0.
1288+
*/
1289+
static ssize_t mps_trc_write(struct file *file, const char __user *buf,
1290+
size_t count, loff_t *pos)
1291+
{
1292+
int i, j, enable, ret;
1293+
u32 *data, *mask;
1294+
struct trace_params tp;
1295+
const struct inode *ino;
1296+
unsigned int trcidx;
1297+
char *s, *p, *word, *end;
1298+
struct adapter *adap;
1299+
1300+
ino = file_inode(file);
1301+
trcidx = (uintptr_t)ino->i_private & 3;
1302+
adap = ino->i_private - trcidx;
1303+
1304+
/* Don't accept input more than 1K, can't be anything valid except lots
1305+
* of whitespace. Well, use less.
1306+
*/
1307+
if (count > 1024)
1308+
return -EFBIG;
1309+
p = s = kzalloc(count + 1, GFP_USER);
1310+
if (!s)
1311+
return -ENOMEM;
1312+
if (copy_from_user(s, buf, count)) {
1313+
count = -EFAULT;
1314+
goto out;
1315+
}
1316+
1317+
if (s[count - 1] == '\n')
1318+
s[count - 1] = '\0';
1319+
1320+
enable = strcmp("disable", s) != 0;
1321+
if (!enable)
1322+
goto apply;
1323+
1324+
/* enable or disable trace multi rss filter */
1325+
if (adap->trace_rss)
1326+
t4_write_reg(adap, MPS_TRC_CFG_A, TRC_RSS_ENABLE);
1327+
else
1328+
t4_write_reg(adap, MPS_TRC_CFG_A, TRC_RSS_DISABLE);
1329+
1330+
memset(&tp, 0, sizeof(tp));
1331+
tp.port = TRC_PORT_NONE;
1332+
i = 0; /* counts pattern nibbles */
1333+
1334+
while (p) {
1335+
while (isspace(*p))
1336+
p++;
1337+
word = strsep(&p, " ");
1338+
if (!*word)
1339+
break;
1340+
1341+
if (!strncmp(word, "qid=", 4)) {
1342+
end = (char *)word + 4;
1343+
ret = kstrtoul(end, 10, (unsigned long *)&j);
1344+
if (ret)
1345+
goto out;
1346+
if (!adap->trace_rss) {
1347+
t4_write_reg(adap, MPS_T5_TRC_RSS_CONTROL_A, j);
1348+
continue;
1349+
}
1350+
1351+
switch (trcidx) {
1352+
case 0:
1353+
t4_write_reg(adap, MPS_TRC_RSS_CONTROL_A, j);
1354+
break;
1355+
case 1:
1356+
t4_write_reg(adap,
1357+
MPS_TRC_FILTER1_RSS_CONTROL_A, j);
1358+
break;
1359+
case 2:
1360+
t4_write_reg(adap,
1361+
MPS_TRC_FILTER2_RSS_CONTROL_A, j);
1362+
break;
1363+
case 3:
1364+
t4_write_reg(adap,
1365+
MPS_TRC_FILTER3_RSS_CONTROL_A, j);
1366+
break;
1367+
}
1368+
continue;
1369+
}
1370+
if (!strncmp(word, "snaplen=", 8)) {
1371+
end = (char *)word + 8;
1372+
ret = kstrtoul(end, 10, (unsigned long *)&j);
1373+
if (ret || j > 9600) {
1374+
inval: count = -EINVAL;
1375+
goto out;
1376+
}
1377+
tp.snap_len = j;
1378+
continue;
1379+
}
1380+
if (!strncmp(word, "minlen=", 7)) {
1381+
end = (char *)word + 7;
1382+
ret = kstrtoul(end, 10, (unsigned long *)&j);
1383+
if (ret || j > TFMINPKTSIZE_M)
1384+
goto inval;
1385+
tp.min_len = j;
1386+
continue;
1387+
}
1388+
if (!strcmp(word, "not")) {
1389+
tp.invert = !tp.invert;
1390+
continue;
1391+
}
1392+
if (!strncmp(word, "loopback", 8) && tp.port == TRC_PORT_NONE) {
1393+
if (word[8] < '0' || word[8] > '3' || word[9])
1394+
goto inval;
1395+
tp.port = word[8] - '0' + 8;
1396+
continue;
1397+
}
1398+
if (!strncmp(word, "tx", 2) && tp.port == TRC_PORT_NONE) {
1399+
if (word[2] < '0' || word[2] > '3' || word[3])
1400+
goto inval;
1401+
tp.port = word[2] - '0' + 4;
1402+
if (adap->chan_map[tp.port & 3] >= MAX_NPORTS)
1403+
goto inval;
1404+
continue;
1405+
}
1406+
if (!strncmp(word, "rx", 2) && tp.port == TRC_PORT_NONE) {
1407+
if (word[2] < '0' || word[2] > '3' || word[3])
1408+
goto inval;
1409+
tp.port = word[2] - '0';
1410+
if (adap->chan_map[tp.port] >= MAX_NPORTS)
1411+
goto inval;
1412+
continue;
1413+
}
1414+
if (!isxdigit(*word))
1415+
goto inval;
1416+
1417+
/* we have found a trace pattern */
1418+
if (i) { /* split pattern */
1419+
if (tp.skip_len) /* too many splits */
1420+
goto inval;
1421+
tp.skip_ofst = i / 16;
1422+
}
1423+
1424+
data = &tp.data[i / 8];
1425+
mask = &tp.mask[i / 8];
1426+
j = i;
1427+
1428+
while (isxdigit(*word)) {
1429+
if (i >= TRACE_LEN * 2) {
1430+
count = -EFBIG;
1431+
goto out;
1432+
}
1433+
*data = (*data << 4) + xdigit2int(*word++);
1434+
if (++i % 8 == 0)
1435+
data++;
1436+
}
1437+
if (*word == '/') {
1438+
word++;
1439+
while (isxdigit(*word)) {
1440+
if (j >= i) /* mask longer than data */
1441+
goto inval;
1442+
*mask = (*mask << 4) + xdigit2int(*word++);
1443+
if (++j % 8 == 0)
1444+
mask++;
1445+
}
1446+
if (i != j) /* mask shorter than data */
1447+
goto inval;
1448+
} else { /* no mask, use all 1s */
1449+
for ( ; i - j >= 8; j += 8)
1450+
*mask++ = 0xffffffff;
1451+
if (i % 8)
1452+
*mask = (1 << (i % 8) * 4) - 1;
1453+
}
1454+
if (*word == '@') {
1455+
end = (char *)word + 1;
1456+
ret = kstrtoul(end, 10, (unsigned long *)&j);
1457+
if (*end && *end != '\n')
1458+
goto inval;
1459+
if (j & 7) /* doesn't start at multiple of 8 */
1460+
goto inval;
1461+
j /= 8;
1462+
if (j < tp.skip_ofst) /* overlaps earlier pattern */
1463+
goto inval;
1464+
if (j - tp.skip_ofst > 31) /* skip too big */
1465+
goto inval;
1466+
tp.skip_len = j - tp.skip_ofst;
1467+
}
1468+
if (i % 8) {
1469+
*data <<= (8 - i % 8) * 4;
1470+
*mask <<= (8 - i % 8) * 4;
1471+
i = (i + 15) & ~15; /* 8-byte align */
1472+
}
1473+
}
1474+
1475+
if (tp.port == TRC_PORT_NONE)
1476+
goto inval;
1477+
1478+
apply:
1479+
i = t4_set_trace_filter(adap, &tp, trcidx, enable);
1480+
if (i)
1481+
count = i;
1482+
out:
1483+
kfree(s);
1484+
return count;
1485+
}
1486+
1487+
static const struct file_operations mps_trc_debugfs_fops = {
1488+
.owner = THIS_MODULE,
1489+
.open = mps_trc_open,
1490+
.read = seq_read,
1491+
.llseek = seq_lseek,
1492+
.release = single_release,
1493+
.write = mps_trc_write
1494+
};
1495+
12041496
static ssize_t flash_read(struct file *file, char __user *buf, size_t count,
12051497
loff_t *ppos)
12061498
{
@@ -2708,6 +3000,10 @@ int t4_setup_debugfs(struct adapter *adap)
27083000
{ "mbox5", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 5 },
27093001
{ "mbox6", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 6 },
27103002
{ "mbox7", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 7 },
3003+
{ "trace0", &mps_trc_debugfs_fops, S_IRUSR | S_IWUSR, 0 },
3004+
{ "trace1", &mps_trc_debugfs_fops, S_IRUSR | S_IWUSR, 1 },
3005+
{ "trace2", &mps_trc_debugfs_fops, S_IRUSR | S_IWUSR, 2 },
3006+
{ "trace3", &mps_trc_debugfs_fops, S_IRUSR | S_IWUSR, 3 },
27113007
{ "l2t", &t4_l2t_fops, S_IRUSR, 0},
27123008
{ "mps_tcam", &mps_tcam_debugfs_fops, S_IRUSR, 0 },
27133009
{ "rss", &rss_debugfs_fops, S_IRUSR, 0 },
@@ -2789,6 +3085,8 @@ int t4_setup_debugfs(struct adapter *adap)
27893085
&flash_debugfs_fops, adap->params.sf_size);
27903086
debugfs_create_bool("use_backdoor", S_IWUSR | S_IRUSR,
27913087
adap->debugfs_root, &adap->use_bd);
3088+
debugfs_create_bool("trace_rss", S_IWUSR | S_IRUSR,
3089+
adap->debugfs_root, &adap->trace_rss);
27923090

27933091
return 0;
27943092
}

0 commit comments

Comments
 (0)