mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
octeontx2-af: npc: cn20k: debugfs enhancements
Improve MCAM visibility and field debugging for CN20K NPC. - Extend "mcam_layout" to show enabled (+) or disabled state per entry so status can be verified without parsing the full "mcam_entry" dump. - Add "dstats" debugfs entry: for enabled MCAM indices, print hit deltas since the prior read by comparing hardware counters to a per-entry software baseline and advancing that baseline after each read (hardware counters are not cleared). - Add "mismatch" debugfs entry: lists MCAM entries that are enabled but not explicitly allocated, helping diagnose allocation/field issues. Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com> Link: https://patch.msgid.link/20260609040453.711932-3-rkannoth@marvell.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
6056a11b8d
commit
4655902dee
|
|
@ -13,6 +13,7 @@
|
|||
#include "struct.h"
|
||||
#include "rvu.h"
|
||||
#include "debugfs.h"
|
||||
#include "cn20k/reg.h"
|
||||
#include "cn20k/npc.h"
|
||||
|
||||
static int npc_mcam_layout_show(struct seq_file *s, void *unused)
|
||||
|
|
@ -58,7 +59,8 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
|
|||
"v:%u", vidx0);
|
||||
}
|
||||
|
||||
seq_printf(s, "\t%u(%#x) %s\n", idx0, pf1,
|
||||
seq_printf(s, "\t%u(%#x)%c %s\n", idx0, pf1,
|
||||
test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
|
||||
map ? buf0 : " ");
|
||||
}
|
||||
goto next;
|
||||
|
|
@ -101,9 +103,13 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
|
|||
vidx1);
|
||||
}
|
||||
|
||||
seq_printf(s, "%05u(%#x) %s\t\t%05u(%#x) %s\n",
|
||||
idx1, pf2, v1 ? buf1 : " ",
|
||||
idx0, pf1, v0 ? buf0 : " ");
|
||||
seq_printf(s, "%05u(%#x)%c %s\t\t%05u(%#x)%c %s\n",
|
||||
idx1, pf2,
|
||||
test_bit(idx1, npc_priv->en_map) ? '+' : ' ',
|
||||
v1 ? buf1 : " ",
|
||||
idx0, pf1,
|
||||
test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
|
||||
v0 ? buf0 : " ");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
|
@ -120,8 +126,9 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
|
|||
vidx0);
|
||||
}
|
||||
|
||||
seq_printf(s, "\t\t \t\t%05u(%#x) %s\n", idx0,
|
||||
pf1, map ? buf0 : " ");
|
||||
seq_printf(s, "\t\t \t\t%05u(%#x)%c %s\n", idx0, pf1,
|
||||
test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
|
||||
map ? buf0 : " ");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +141,8 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
|
|||
snprintf(buf1, sizeof(buf1), "v:%05u", vidx1);
|
||||
}
|
||||
|
||||
seq_printf(s, "%05u(%#x) %s\n", idx1, pf1,
|
||||
seq_printf(s, "%05u(%#x)%c %s\n", idx1, pf1,
|
||||
test_bit(idx1, npc_priv->en_map) ? '+' : ' ',
|
||||
map ? buf1 : " ");
|
||||
}
|
||||
next:
|
||||
|
|
@ -145,6 +153,136 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
|
|||
|
||||
DEFINE_SHOW_ATTRIBUTE(npc_mcam_layout);
|
||||
|
||||
#define __OCTEONTX2_DEBUGFS_ATTRIBUTE_FOPS(__name) \
|
||||
static const struct file_operations __name ## _fops = { \
|
||||
.owner = THIS_MODULE, \
|
||||
.open = __name ## _open, \
|
||||
.read = seq_read, \
|
||||
.llseek = seq_lseek, \
|
||||
.release = single_release, \
|
||||
}
|
||||
|
||||
#define DEFINE_OCTEONTX2_DEBUGFS_ATTRIBUTE_WITH_SIZE(__name, __size) \
|
||||
static int __name ## _open(struct inode *inode, struct file *file) \
|
||||
{ \
|
||||
return single_open_size(file, __name ## _show, inode->i_private, \
|
||||
__size); \
|
||||
} \
|
||||
__OCTEONTX2_DEBUGFS_ATTRIBUTE_FOPS(__name)
|
||||
|
||||
static DEFINE_MUTEX(stats_lock);
|
||||
|
||||
/* MAX_NUM_BANKS, MAX_SUBBANK_DEPTH and MAX_NUM_SUB_BANKS represent
|
||||
* hard limit on all silicon variants, preventing any possibility of
|
||||
* out-of-bounds access.
|
||||
*/
|
||||
static u64 dstats[MAX_NUM_BANKS][MAX_SUBBANK_DEPTH * MAX_NUM_SUB_BANKS] = {};
|
||||
static int npc_mcam_dstats_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct npc_priv_t *npc_priv;
|
||||
int blkaddr, pf, mcam_idx;
|
||||
u64 stats, delta;
|
||||
struct rvu *rvu;
|
||||
char buff[64];
|
||||
u8 key_type;
|
||||
void *map;
|
||||
|
||||
npc_priv = npc_priv_get();
|
||||
rvu = s->private;
|
||||
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
|
||||
if (blkaddr < 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&stats_lock);
|
||||
seq_puts(s, "idx\tpfunc\tstats\n");
|
||||
for (int bank = npc_priv->num_banks - 1; bank >= 0; bank--) {
|
||||
for (int idx = npc_priv->bank_depth - 1; idx >= 0; idx--) {
|
||||
mcam_idx = bank * npc_priv->bank_depth + idx;
|
||||
|
||||
if (npc_mcam_idx_2_key_type(rvu, mcam_idx, &key_type))
|
||||
continue;
|
||||
|
||||
if (key_type == NPC_MCAM_KEY_X4 && bank != 0)
|
||||
continue;
|
||||
|
||||
if (!test_bit(mcam_idx, npc_priv->en_map))
|
||||
continue;
|
||||
|
||||
stats = rvu_read64(rvu, blkaddr,
|
||||
NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(idx, bank));
|
||||
if (!stats)
|
||||
continue;
|
||||
if (stats == dstats[bank][idx])
|
||||
continue;
|
||||
|
||||
if (stats < dstats[bank][idx])
|
||||
dstats[bank][idx] = 0;
|
||||
|
||||
pf = 0xFFFF;
|
||||
map = xa_load(&npc_priv->xa_idx2pf_map, mcam_idx);
|
||||
if (map)
|
||||
pf = xa_to_value(map);
|
||||
|
||||
delta = stats - dstats[bank][idx];
|
||||
|
||||
snprintf(buff, sizeof(buff), "%u\t%#04x\t%llu\n",
|
||||
mcam_idx, pf, delta);
|
||||
seq_puts(s, buff);
|
||||
|
||||
dstats[bank][idx] = stats;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&stats_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* "%u\t%#04x\t%llu\n" needs less than 64 characters to print */
|
||||
#define TOTAL_SZ (MAX_NUM_BANKS * MAX_NUM_SUB_BANKS * MAX_SUBBANK_DEPTH * 64)
|
||||
DEFINE_OCTEONTX2_DEBUGFS_ATTRIBUTE_WITH_SIZE(npc_mcam_dstats, TOTAL_SZ);
|
||||
|
||||
static int npc_mcam_mismatch_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct npc_priv_t *npc_priv;
|
||||
struct npc_subbank *sb;
|
||||
int mcam_idx, sb_off;
|
||||
struct rvu *rvu;
|
||||
char buff[64];
|
||||
void *map;
|
||||
int rc;
|
||||
|
||||
npc_priv = npc_priv_get();
|
||||
rvu = s->private;
|
||||
|
||||
seq_puts(s, "index\tsb idx\tkw type\n");
|
||||
for (int bank = npc_priv->num_banks - 1; bank >= 0; bank--) {
|
||||
for (int idx = npc_priv->bank_depth - 1; idx >= 0; idx--) {
|
||||
mcam_idx = bank * npc_priv->bank_depth + idx;
|
||||
|
||||
if (!test_bit(mcam_idx, npc_priv->en_map))
|
||||
continue;
|
||||
|
||||
map = xa_load(&npc_priv->xa_idx2pf_map, mcam_idx);
|
||||
if (map)
|
||||
continue;
|
||||
|
||||
rc = npc_mcam_idx_2_subbank_idx(rvu, mcam_idx,
|
||||
&sb, &sb_off);
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
snprintf(buff, sizeof(buff), "%u\t%d\t%u\n",
|
||||
mcam_idx, sb->idx, sb->key_type);
|
||||
|
||||
seq_puts(s, buff);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* "%u\t%d\t%u\n" needs less than 64 characters to print. */
|
||||
DEFINE_OCTEONTX2_DEBUGFS_ATTRIBUTE_WITH_SIZE(npc_mcam_mismatch, TOTAL_SZ);
|
||||
|
||||
static int npc_mcam_default_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct npc_priv_t *npc_priv;
|
||||
|
|
@ -259,6 +397,12 @@ int npc_cn20k_debugfs_init(struct rvu *rvu)
|
|||
debugfs_create_file("vidx2idx", 0444, rvu->rvu_dbg.npc,
|
||||
npc_priv, &npc_vidx2idx_map_fops);
|
||||
|
||||
debugfs_create_file("dstats", 0444, rvu->rvu_dbg.npc, rvu,
|
||||
&npc_mcam_dstats_fops);
|
||||
|
||||
debugfs_create_file("mismatch", 0444, rvu->rvu_dbg.npc, rvu,
|
||||
&npc_mcam_mismatch_fops);
|
||||
|
||||
debugfs_create_file("idx2vidx", 0444, rvu->rvu_dbg.npc,
|
||||
npc_priv, &npc_idx2vidx_map_fops);
|
||||
|
||||
|
|
|
|||
|
|
@ -824,7 +824,7 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
|
|||
rvu_write64(rvu, blkaddr,
|
||||
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
|
||||
cfg);
|
||||
return 0;
|
||||
goto update_en_map;
|
||||
}
|
||||
|
||||
/* For NPC_CN20K_MCAM_KEY_X4 keys, both the banks
|
||||
|
|
@ -842,6 +842,12 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
|
|||
cfg);
|
||||
}
|
||||
|
||||
update_en_map:
|
||||
if (enable)
|
||||
set_bit(index, npc_priv.en_map);
|
||||
else
|
||||
clear_bit(index, npc_priv.en_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1785,9 +1791,9 @@ static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank *sb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
|
||||
struct npc_subbank **sb,
|
||||
int *sb_off)
|
||||
int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
|
||||
struct npc_subbank **sb,
|
||||
int *sb_off)
|
||||
{
|
||||
int bank_off, sb_id;
|
||||
|
||||
|
|
@ -4494,11 +4500,17 @@ static int npc_priv_init(struct rvu *rvu)
|
|||
npc_const2 = rvu_read64(rvu, blkaddr, NPC_AF_CONST2);
|
||||
|
||||
num_banks = mcam->banks;
|
||||
bank_depth = mcam->banksize;
|
||||
if (!num_banks || num_banks > MAX_NUM_BANKS) {
|
||||
dev_err(rvu->dev,
|
||||
"Number of banks(%u) is invalid\n", num_banks);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_subbanks = FIELD_GET(GENMASK_ULL(39, 32), npc_const2);
|
||||
if (!num_subbanks) {
|
||||
dev_err(rvu->dev, "Number of subbanks is zero\n");
|
||||
if (!num_subbanks || num_subbanks > MAX_NUM_SUB_BANKS) {
|
||||
dev_err(rvu->dev,
|
||||
"Number of subbanks is invalid %u\n",
|
||||
num_subbanks);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
|
@ -4509,10 +4521,23 @@ static int npc_priv_init(struct rvu *rvu)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
npc_priv.num_subbanks = num_subbanks;
|
||||
bank_depth = mcam->banksize;
|
||||
if (!bank_depth || bank_depth % num_subbanks) {
|
||||
dev_err(rvu->dev,
|
||||
"Bank depth(%u) should be a multiple of num_subbanks(%u)\n",
|
||||
bank_depth, num_subbanks);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
subbank_depth = bank_depth / num_subbanks;
|
||||
if (!subbank_depth || subbank_depth > MAX_SUBBANK_DEPTH) {
|
||||
dev_err(rvu->dev,
|
||||
"Invalid subbank depth %u\n",
|
||||
subbank_depth);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
npc_priv.num_subbanks = num_subbanks;
|
||||
npc_priv.bank_depth = bank_depth;
|
||||
npc_priv.subbank_depth = subbank_depth;
|
||||
|
||||
|
|
@ -4601,6 +4626,8 @@ void npc_cn20k_deinit(struct rvu *rvu)
|
|||
*/
|
||||
kfree(npc_priv.sb);
|
||||
kfree(subbank_srch_order);
|
||||
bitmap_clear(npc_priv.en_map, 0, MAX_NUM_BANKS * MAX_NUM_SUB_BANKS *
|
||||
MAX_SUBBANK_DEPTH);
|
||||
}
|
||||
|
||||
static int npc_setup_mcam_section(struct rvu *rvu, int key_type)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
#define MKEX_CN20K_SIGN 0x19bbfdbd160
|
||||
|
||||
/* MAX_NUM_BANKS, MAX_SUBBANK_DEPTH and MAX_NUM_SUB_BANKS represent
|
||||
* hard limit on all silicon variants, preventing any possibility of
|
||||
* out-of-bounds access on matrix defined using these values.
|
||||
*/
|
||||
#define MAX_NUM_BANKS 2
|
||||
#define MAX_NUM_SUB_BANKS 32
|
||||
#define MAX_SUBBANK_DEPTH 256
|
||||
|
|
@ -170,6 +174,7 @@ struct npc_defrag_show_node {
|
|||
* @num_banks: Number of banks.
|
||||
* @num_subbanks: Number of subbanks.
|
||||
* @subbank_depth: Depth of subbank.
|
||||
* @en_map: Enable/disable status.
|
||||
* @kw: Kex configured key type.
|
||||
* @sb: Subbank array.
|
||||
* @xa_sb_used: Array of used subbanks.
|
||||
|
|
@ -193,6 +198,9 @@ struct npc_priv_t {
|
|||
const int num_banks;
|
||||
int num_subbanks;
|
||||
int subbank_depth;
|
||||
DECLARE_BITMAP(en_map, MAX_NUM_BANKS *
|
||||
MAX_NUM_SUB_BANKS *
|
||||
MAX_SUBBANK_DEPTH);
|
||||
u8 kw;
|
||||
struct npc_subbank *sb;
|
||||
struct xarray xa_sb_used;
|
||||
|
|
@ -336,5 +344,8 @@ u16 npc_cn20k_vidx2idx(u16 index);
|
|||
u16 npc_cn20k_idx2vidx(u16 idx);
|
||||
int npc_cn20k_defrag(struct rvu *rvu);
|
||||
bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc);
|
||||
int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
|
||||
struct npc_subbank **sb,
|
||||
int *sb_off);
|
||||
|
||||
#endif /* NPC_CN20K_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user