Merge branch 'npc-hw-block-support-for-cn20k'

Ratheesh Kannoth says:

====================
NPC HW block support for cn20k

This patchset adds comprehensive support for the CN20K NPC
architecture. CN20K introduces significant changes in MCAM layout,
parser design, KPM/KPU mapping, index management, virtual index handling,
and dynamic rule installation. The patches update the AF, PF/VF, and
common layers to correctly support these new capabilities while
preserving compatibility with previous silicon variants.

MCAM on CN20K differs from older designs: the hardware now contains
two vertical banks of depth 8192, and thirty-two horizontal subbanks of
depth 256. Each subbank can be configured as x2 or x4, enabling
256-bit or 512-bit key storage. Several allocation models are added to
support this layout, including contiguous and non-contiguous allocation
with or without reference ranges and priorities.

Parser and extraction logic are also enhanced. CN20K introduces a new
profile model where up to twenty-four extractors may be configured for
each parsing profile. A new KPM profile scheme is added, grouping
sixteen KPUs into eight KPM profiles, each formed by two KPUs.

Support is added for default index allocation for CN20K-specific
MCAM entry structures, virtual index allocation, improved defragmentation,
and TC rule installation by allowing the AF driver to determine
required x2/x4 rule width during flow install.
====================

Link: https://patch.msgid.link/20260224080009.4147301-1-rkannoth@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-02-28 10:30:26 -08:00
commit d578b47293
27 changed files with 7442 additions and 472 deletions

View File

@ -13,4 +13,4 @@ rvu_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \
rvu_cpt.o rvu_devlink.o rpm.o rvu_cn10k.o rvu_switch.o \
rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o \
rvu_rep.o cn20k/mbox_init.o cn20k/nix.o cn20k/debugfs.o \
cn20k/npa.o
cn20k/npa.o cn20k/npc.o

View File

@ -11,7 +11,280 @@
#include <linux/pci.h>
#include "struct.h"
#include "rvu.h"
#include "debugfs.h"
#include "cn20k/npc.h"
static int npc_mcam_layout_show(struct seq_file *s, void *unused)
{
int i, j, sbd, idx0, idx1, vidx0, vidx1;
struct npc_priv_t *npc_priv;
char buf0[32], buf1[32];
struct npc_subbank *sb;
unsigned int bw0, bw1;
bool v0, v1;
int pf1, pf2;
bool e0, e1;
void *map;
npc_priv = s->private;
sbd = npc_priv->subbank_depth;
for (i = npc_priv->num_subbanks - 1; i >= 0; i--) {
sb = &npc_priv->sb[i];
mutex_lock(&sb->lock);
if (sb->flags & NPC_SUBBANK_FLAG_FREE)
goto next;
bw0 = bitmap_weight(sb->b0map, npc_priv->subbank_depth);
if (sb->key_type == NPC_MCAM_KEY_X4) {
seq_printf(s, "\n\nsubbank:%u, x4, free=%u, used=%u\n",
sb->idx, sb->free_cnt, bw0);
for (j = sbd - 1; j >= 0; j--) {
if (!test_bit(j, sb->b0map))
continue;
idx0 = sb->b0b + j;
map = xa_load(&npc_priv->xa_idx2pf_map, idx0);
pf1 = xa_to_value(map);
map = xa_load(&npc_priv->xa_idx2vidx_map, idx0);
if (map) {
vidx0 = xa_to_value(map);
snprintf(buf0, sizeof(buf0),
"v:%u", vidx0);
}
seq_printf(s, "\t%u(%#x) %s\n", idx0, pf1,
map ? buf0 : " ");
}
goto next;
}
bw1 = bitmap_weight(sb->b1map, npc_priv->subbank_depth);
seq_printf(s, "\n\nsubbank:%u, x2, free=%u, used=%u\n",
sb->idx, sb->free_cnt, bw0 + bw1);
seq_printf(s, "bank1(%u)\t\tbank0(%u)\n", bw1, bw0);
for (j = sbd - 1; j >= 0; j--) {
e0 = test_bit(j, sb->b0map);
e1 = test_bit(j, sb->b1map);
if (!e1 && !e0)
continue;
if (e1 && e0) {
idx0 = sb->b0b + j;
map = xa_load(&npc_priv->xa_idx2pf_map, idx0);
pf1 = xa_to_value(map);
map = xa_load(&npc_priv->xa_idx2vidx_map, idx0);
v0 = !!map;
if (v0) {
vidx0 = xa_to_value(map);
snprintf(buf0, sizeof(buf0), "v:%05u",
vidx0);
}
idx1 = sb->b1b + j;
map = xa_load(&npc_priv->xa_idx2pf_map, idx1);
pf2 = xa_to_value(map);
map = xa_load(&npc_priv->xa_idx2vidx_map, idx1);
v1 = !!map;
if (v1) {
vidx1 = xa_to_value(map);
snprintf(buf1, sizeof(buf1), "v:%05u",
vidx1);
}
seq_printf(s, "%05u(%#x) %s\t\t%05u(%#x) %s\n",
idx1, pf2, v1 ? buf1 : " ",
idx0, pf1, v0 ? buf0 : " ");
continue;
}
if (e0) {
idx0 = sb->b0b + j;
map = xa_load(&npc_priv->xa_idx2pf_map, idx0);
pf1 = xa_to_value(map);
map = xa_load(&npc_priv->xa_idx2vidx_map, idx0);
if (map) {
vidx0 = xa_to_value(map);
snprintf(buf0, sizeof(buf0), "v:%05u",
vidx0);
}
seq_printf(s, "\t\t \t\t%05u(%#x) %s\n", idx0,
pf1, map ? buf0 : " ");
continue;
}
idx1 = sb->b1b + j;
map = xa_load(&npc_priv->xa_idx2pf_map, idx1);
pf1 = xa_to_value(map);
map = xa_load(&npc_priv->xa_idx2vidx_map, idx1);
if (map) {
vidx1 = xa_to_value(map);
snprintf(buf1, sizeof(buf1), "v:%05u", vidx1);
}
seq_printf(s, "%05u(%#x) %s\n", idx1, pf1,
map ? buf1 : " ");
}
next:
mutex_unlock(&sb->lock);
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(npc_mcam_layout);
static int npc_mcam_default_show(struct seq_file *s, void *unused)
{
struct npc_priv_t *npc_priv;
unsigned long index;
u16 ptr[4], pcifunc;
struct rvu *rvu;
int rc, i;
void *map;
npc_priv = npc_priv_get();
rvu = s->private;
seq_puts(s, "\npcifunc\tBcast\tmcast\tpromisc\tucast\n");
xa_for_each(&npc_priv->xa_pf_map, index, map) {
pcifunc = index;
for (i = 0; i < ARRAY_SIZE(ptr); i++)
ptr[i] = USHRT_MAX;
rc = npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &ptr[0],
&ptr[1], &ptr[2], &ptr[3]);
if (rc)
continue;
seq_printf(s, "%#x\t", pcifunc);
for (i = 0; i < ARRAY_SIZE(ptr); i++) {
if (ptr[i] != USHRT_MAX)
seq_printf(s, "%u\t", ptr[i]);
else
seq_puts(s, "\t");
}
seq_puts(s, "\n");
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(npc_mcam_default);
static int npc_vidx2idx_map_show(struct seq_file *s, void *unused)
{
struct npc_priv_t *npc_priv;
unsigned long index, start;
struct xarray *xa;
void *map;
npc_priv = s->private;
start = npc_priv->bank_depth * 2;
xa = &npc_priv->xa_vidx2idx_map;
seq_puts(s, "\nvidx\tmcam_idx\n");
xa_for_each_start(xa, index, map, start)
seq_printf(s, "%lu\t%lu\n", index, xa_to_value(map));
return 0;
}
DEFINE_SHOW_ATTRIBUTE(npc_vidx2idx_map);
static int npc_idx2vidx_map_show(struct seq_file *s, void *unused)
{
struct npc_priv_t *npc_priv;
unsigned long index;
struct xarray *xa;
void *map;
npc_priv = s->private;
xa = &npc_priv->xa_idx2vidx_map;
seq_puts(s, "\nmidx\tvidx\n");
xa_for_each(xa, index, map)
seq_printf(s, "%lu\t%lu\n", index, xa_to_value(map));
return 0;
}
DEFINE_SHOW_ATTRIBUTE(npc_idx2vidx_map);
static int npc_defrag_show(struct seq_file *s, void *unused)
{
struct npc_defrag_show_node *node;
struct npc_priv_t *npc_priv;
u16 sbd, bdm;
npc_priv = s->private;
bdm = npc_priv->bank_depth - 1;
sbd = npc_priv->subbank_depth;
seq_puts(s, "\nold(sb) -> new(sb)\t\tvidx\n");
mutex_lock(&npc_priv->lock);
list_for_each_entry(node, &npc_priv->defrag_lh, list)
seq_printf(s, "%u(%u)\t%u(%u)\t%u\n", node->old_midx,
(node->old_midx & bdm) / sbd,
node->new_midx,
(node->new_midx & bdm) / sbd,
node->vidx);
mutex_unlock(&npc_priv->lock);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(npc_defrag);
int npc_cn20k_debugfs_init(struct rvu *rvu)
{
struct npc_priv_t *npc_priv = npc_priv_get();
struct dentry *npc_dentry;
npc_dentry = debugfs_create_file("mcam_layout", 0444, rvu->rvu_dbg.npc,
npc_priv, &npc_mcam_layout_fops);
if (!npc_dentry)
return -EFAULT;
npc_dentry = debugfs_create_file("mcam_default", 0444, rvu->rvu_dbg.npc,
rvu, &npc_mcam_default_fops);
if (!npc_dentry)
return -EFAULT;
npc_dentry = debugfs_create_file("vidx2idx", 0444, rvu->rvu_dbg.npc,
npc_priv, &npc_vidx2idx_map_fops);
if (!npc_dentry)
return -EFAULT;
npc_dentry = debugfs_create_file("idx2vidx", 0444, rvu->rvu_dbg.npc,
npc_priv, &npc_idx2vidx_map_fops);
if (!npc_dentry)
return -EFAULT;
npc_dentry = debugfs_create_file("defrag", 0444, rvu->rvu_dbg.npc,
npc_priv, &npc_defrag_fops);
if (!npc_dentry)
return -EFAULT;
return 0;
}
void npc_cn20k_debugfs_deinit(struct rvu *rvu)
{
debugfs_remove_recursive(rvu->rvu_dbg.npc);
}
void print_nix_cn20k_sq_ctx(struct seq_file *m,
struct nix_cn20k_sq_ctx_s *sq_ctx)

View File

@ -16,6 +16,9 @@
#include "struct.h"
#include "../mbox.h"
int npc_cn20k_debugfs_init(struct rvu *rvu);
void npc_cn20k_debugfs_deinit(struct rvu *rvu);
void print_nix_cn20k_sq_ctx(struct seq_file *m,
struct nix_cn20k_sq_ctx_s *sq_ctx);
void print_nix_cn20k_cq_ctx(struct seq_file *m,

View File

@ -397,6 +397,12 @@ int rvu_alloc_cint_qint_mem(struct rvu *rvu, struct rvu_pfvf *pfvf,
if (is_rvu_otx2(rvu) || is_cn20k(rvu->pdev))
return 0;
/* sanity check */
cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_NIXX_CFG(0) |
(RVU_AFPF << 16));
if (!cfg)
return 0;
ctx_cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST3);
/* Alloc memory for CQINT's HW contexts */
cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
@ -420,5 +426,16 @@ int rvu_alloc_cint_qint_mem(struct rvu *rvu, struct rvu_pfvf *pfvf,
rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf),
(u64)pfvf->nix_qints_ctx->iova);
rvu_write64(rvu, BLKADDR_NIX0, RVU_AF_BAR2_SEL, RVU_AF_BAR2_PFID);
rvu_write64(rvu, BLKADDR_NIX0,
AF_BAR2_ALIASX(0, NIX_GINT_INT_W1S), ALTAF_RDY);
/* wait for ack */
err = rvu_poll_reg(rvu, BLKADDR_NIX0,
AF_BAR2_ALIASX(0, NIX_GINT_INT), ALTAF_RDY, true);
if (err)
rvu->altaf_ready = false;
else
rvu->altaf_ready = true;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,340 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Marvell RVU Admin Function driver
*
* Copyright (C) 2026 Marvell.
*
*/
#ifndef NPC_CN20K_H
#define NPC_CN20K_H
#define MKEX_CN20K_SIGN 0x19bbfdbd160
#define MAX_NUM_BANKS 2
#define MAX_NUM_SUB_BANKS 32
#define MAX_SUBBANK_DEPTH 256
/* strtoull of "mkexprof" with base:36 */
#define MKEX_END_SIGN 0xdeadbeef
#define NPC_CN20K_BYTESM GENMASK_ULL(18, 16)
#define NPC_CN20K_PARSE_NIBBLE GENMASK_ULL(22, 0)
#define NPC_CN20K_TOTAL_NIBBLE 23
#define CN20K_SET_EXTR_LT(intf, extr, ltype, cfg) \
rvu_write64(rvu, BLKADDR_NPC, \
NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype), cfg)
#define CN20K_GET_KEX_CFG(intf) \
rvu_read64(rvu, BLKADDR_NPC, NPC_AF_INTFX_KEX_CFG(intf))
#define CN20K_GET_EXTR_LID(intf, extr) \
rvu_read64(rvu, BLKADDR_NPC, \
NPC_AF_INTFX_EXTRACTORX_CFG(intf, extr))
#define CN20K_SET_EXTR_LT(intf, extr, ltype, cfg) \
rvu_write64(rvu, BLKADDR_NPC, \
NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype), cfg)
#define CN20K_GET_EXTR_LT(intf, extr, ltype) \
rvu_read64(rvu, BLKADDR_NPC, \
NPC_AF_INTFX_EXTRACTORX_LTX_CFG(intf, extr, ltype))
/* NPC_PARSE_KEX_S nibble definitions for each field */
#define NPC_CN20K_PARSE_NIBBLE_CHAN GENMASK_ULL(2, 0)
#define NPC_CN20K_PARSE_NIBBLE_ERRLEV BIT_ULL(3)
#define NPC_CN20K_PARSE_NIBBLE_ERRCODE GENMASK_ULL(5, 4)
#define NPC_CN20K_PARSE_NIBBLE_L2L3_BCAST BIT_ULL(6)
#define NPC_CN20K_PARSE_NIBBLE_LA_FLAGS BIT_ULL(7)
#define NPC_CN20K_PARSE_NIBBLE_LA_LTYPE BIT_ULL(8)
#define NPC_CN20K_PARSE_NIBBLE_LB_FLAGS BIT_ULL(9)
#define NPC_CN20K_PARSE_NIBBLE_LB_LTYPE BIT_ULL(10)
#define NPC_CN20K_PARSE_NIBBLE_LC_FLAGS BIT_ULL(11)
#define NPC_CN20K_PARSE_NIBBLE_LC_LTYPE BIT_ULL(12)
#define NPC_CN20K_PARSE_NIBBLE_LD_FLAGS BIT_ULL(13)
#define NPC_CN20K_PARSE_NIBBLE_LD_LTYPE BIT_ULL(14)
#define NPC_CN20K_PARSE_NIBBLE_LE_FLAGS BIT_ULL(15)
#define NPC_CN20K_PARSE_NIBBLE_LE_LTYPE BIT_ULL(16)
#define NPC_CN20K_PARSE_NIBBLE_LF_FLAGS BIT_ULL(17)
#define NPC_CN20K_PARSE_NIBBLE_LF_LTYPE BIT_ULL(18)
#define NPC_CN20K_PARSE_NIBBLE_LG_FLAGS BIT_ULL(19)
#define NPC_CN20K_PARSE_NIBBLE_LG_LTYPE BIT_ULL(20)
#define NPC_CN20K_PARSE_NIBBLE_LH_FLAGS BIT_ULL(21)
#define NPC_CN20K_PARSE_NIBBLE_LH_LTYPE BIT_ULL(22)
/* Rx parse key extract nibble enable */
#define NPC_CN20K_PARSE_NIBBLE_INTF_RX (NPC_CN20K_PARSE_NIBBLE_CHAN | \
NPC_CN20K_PARSE_NIBBLE_L2L3_BCAST | \
NPC_CN20K_PARSE_NIBBLE_LA_LTYPE | \
NPC_CN20K_PARSE_NIBBLE_LB_LTYPE | \
NPC_CN20K_PARSE_NIBBLE_LC_FLAGS | \
NPC_CN20K_PARSE_NIBBLE_LC_LTYPE | \
NPC_CN20K_PARSE_NIBBLE_LD_LTYPE | \
NPC_CN20K_PARSE_NIBBLE_LE_LTYPE)
/* Tx parse key extract nibble enable */
#define NPC_CN20K_PARSE_NIBBLE_INTF_TX (NPC_CN20K_PARSE_NIBBLE_LA_LTYPE | \
NPC_CN20K_PARSE_NIBBLE_LB_LTYPE | \
NPC_CN20K_PARSE_NIBBLE_LC_LTYPE | \
NPC_CN20K_PARSE_NIBBLE_LD_LTYPE | \
NPC_CN20K_PARSE_NIBBLE_LE_LTYPE)
/**
* enum npc_subbank_flag - NPC subbank status
*
* subbank flag indicates whether the subbank is free
* or used.
*
* @NPC_SUBBANK_FLAG_UNINIT: Subbank is not initialized.
* @NPC_SUBBANK_FLAG_FREE: Subbank is free.
* @NPC_SUBBANK_FLAG_USED: Subbank is used.
*/
enum npc_subbank_flag {
NPC_SUBBANK_FLAG_UNINIT,
NPC_SUBBANK_FLAG_FREE = BIT(0),
NPC_SUBBANK_FLAG_USED = BIT(1),
};
/**
* enum npc_dft_rule_id - Default rule type
*
* Mcam default rule type.
*
* @NPC_DFT_RULE_START_ID: Not used
* @NPC_DFT_RULE_PROMISC_ID: promiscuous rule
* @NPC_DFT_RULE_MCAST_ID: multicast rule
* @NPC_DFT_RULE_BCAST_ID: broadcast rule
* @NPC_DFT_RULE_UCAST_ID: unicast rule
* @NPC_DFT_RULE_MAX_ID: Maximum index.
*/
enum npc_dft_rule_id {
NPC_DFT_RULE_START_ID = 1,
NPC_DFT_RULE_PROMISC_ID = NPC_DFT_RULE_START_ID,
NPC_DFT_RULE_MCAST_ID,
NPC_DFT_RULE_BCAST_ID,
NPC_DFT_RULE_UCAST_ID,
NPC_DFT_RULE_MAX_ID,
};
/**
* struct npc_subbank - Subbank fields.
* @b0b: Subbanks bottom index for bank0
* @b1b: Subbanks bottom index for bank1
* @b0t: Subbanks top index for bank0
* @b1t: Subbanks top index for bank1
* @flags: Subbank flags
* @lock: Mutex lock for flags and rsrc mofiication
* @b0map: Bitmap map for bank0 indexes
* @b1map: Bitmap map for bank1 indexes
* @idx: Subbank index
* @arr_idx: Index to the free array or used array
* @free_cnt: Number of free slots in the subbank.
* @key_type: X4 or X2 subbank.
*
* MCAM resource is divided horizontally into multiple subbanks and
* Resource allocation from each subbank is managed by this data
* structure.
*/
struct npc_subbank {
u16 b0t, b0b, b1t, b1b;
enum npc_subbank_flag flags;
struct mutex lock; /* Protect subbank resources */
DECLARE_BITMAP(b0map, MAX_SUBBANK_DEPTH);
DECLARE_BITMAP(b1map, MAX_SUBBANK_DEPTH);
u16 idx;
u16 arr_idx;
u16 free_cnt;
u8 key_type;
};
/**
* struct npc_defrag_show_node - Defragmentation show node
* @old_midx: Old mcam index.
* @new_midx: New mcam index.
* @vidx: Virtual index
* @list: Linked list of these nodes
*
* This structure holds information on last defragmentation
* executed on mcam resource.
*/
struct npc_defrag_show_node {
u16 old_midx;
u16 new_midx;
u16 vidx;
struct list_head list;
};
/**
* struct npc_priv_t - NPC private structure.
* @bank_depth: Total entries in each bank.
* @num_banks: Number of banks.
* @num_subbanks: Number of subbanks.
* @subbank_depth: Depth of subbank.
* @kw: Kex configured key type.
* @sb: Subbank array.
* @xa_sb_used: Array of used subbanks.
* @xa_sb_free: Array of free subbanks.
* @xa_pf2idx_map: PF to mcam index map.
* @xa_idx2pf_map: Mcam index to PF map.
* @xa_pf_map: Pcifunc to index map.
* @pf_cnt: Number of PFs.
* @init_done: Indicates MCAM initialization is done.
* @xa_pf2dfl_rmap: PF to default rule index map.
* @xa_idx2vidx_map: Mcam index to virtual index map.
* @xa_vidx2idx_map: virtual index to mcam index map.
* @defrag_lh: Defrag list head.
* @lock: Lock for defrag list
*
* This structure is populated during probing time by reading
* HW csr registers.
*/
struct npc_priv_t {
int bank_depth;
const int num_banks;
int num_subbanks;
int subbank_depth;
u8 kw;
struct npc_subbank *sb;
struct xarray xa_sb_used;
struct xarray xa_sb_free;
struct xarray *xa_pf2idx_map;
struct xarray xa_idx2pf_map;
struct xarray xa_pf_map;
struct xarray xa_pf2dfl_rmap;
struct xarray xa_idx2vidx_map;
struct xarray xa_vidx2idx_map;
struct list_head defrag_lh;
struct mutex lock; /* protect defrag nodes */
int pf_cnt;
bool init_done;
};
struct npc_kpm_action0 {
#if defined(__BIG_ENDIAN_BITFIELD)
u64 rsvd_63_57 : 7;
u64 byp_count : 3;
u64 capture_ena : 1;
u64 parse_done : 1;
u64 next_state : 8;
u64 rsvd_43 : 1;
u64 capture_lid : 3;
u64 capture_ltype : 4;
u64 rsvd_32_35 : 4;
u64 capture_flags : 4;
u64 ptr_advance : 8;
u64 var_len_offset : 8;
u64 var_len_mask : 8;
u64 var_len_right : 1;
u64 var_len_shift : 3;
#else
u64 var_len_shift : 3;
u64 var_len_right : 1;
u64 var_len_mask : 8;
u64 var_len_offset : 8;
u64 ptr_advance : 8;
u64 capture_flags : 4;
u64 rsvd_32_35 : 4;
u64 capture_ltype : 4;
u64 capture_lid : 3;
u64 rsvd_43 : 1;
u64 next_state : 8;
u64 parse_done : 1;
u64 capture_ena : 1;
u64 byp_count : 3;
u64 rsvd_63_57 : 7;
#endif
};
struct npc_mcam_kex_extr {
/* MKEX Profle Header */
u64 mkex_sign; /* "mcam-kex-profile" (8 bytes/ASCII characters) */
u8 name[MKEX_NAME_LEN]; /* MKEX Profile name */
u64 cpu_model; /* Format as profiled by CPU hardware */
u64 kpu_version; /* KPU firmware/profile version */
u64 reserved; /* Reserved for extension */
/* MKEX Profle Data */
u64 keyx_cfg[NPC_MAX_INTF]; /* NPC_AF_INTF(0..1)_KEX_CFG */
#define NPC_MAX_EXTRACTOR 24
/* MKEX Extractor data */
u64 intf_extr_lid[NPC_MAX_INTF][NPC_MAX_EXTRACTOR];
/* KEX configuration per extractor */
u64 intf_extr_lt[NPC_MAX_INTF][NPC_MAX_EXTRACTOR][NPC_MAX_LT];
} __packed;
struct npc_cn20k_kpu_profile_fwdata {
#define KPU_SIGN 0x00666f727075706b
#define KPU_NAME_LEN 32
/* Maximum number of custom KPU entries supported by
* the built-in profile.
*/
#define KPU_CN20K_MAX_CST_ENT 6
/* KPU Profle Header */
__le64 signature; /* "kpuprof\0" (8 bytes/ASCII characters) */
u8 name[KPU_NAME_LEN]; /* KPU Profile name */
__le64 version; /* KPU profile version */
u8 kpus;
u8 reserved[7];
/* Default MKEX profile to be used with this KPU profile. May be
* overridden with mkex_profile module parameter.
* Format is same as for the MKEX profile to streamline processing.
*/
struct npc_mcam_kex_extr mkex;
/* LTYPE values for specific HW offloaded protocols. */
struct npc_lt_def_cfg lt_def;
/* Dynamically sized data:
* Custom KPU CAM and ACTION configuration entries.
* struct npc_kpu_fwdata kpu[kpus];
*/
u8 data[];
} __packed;
struct rvu;
struct npc_priv_t *npc_priv_get(void);
int npc_cn20k_init(struct rvu *rvu);
void npc_cn20k_deinit(struct rvu *rvu);
void npc_cn20k_subbank_calc_free(struct rvu *rvu, int *x2_free,
int *x4_free, int *sb_free);
int npc_cn20k_ref_idx_alloc(struct rvu *rvu, int pcifunc, int key_type,
int prio, u16 *mcam_idx, int ref, int limit,
bool contig, int count, bool virt);
int npc_cn20k_idx_free(struct rvu *rvu, u16 *mcam_idx, int count);
void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr);
struct npc_mcam_kex_extr *npc_mkex_extr_default_get(void);
void npc_cn20k_load_mkex_profile(struct rvu *rvu, int blkaddr,
const char *mkex_profile);
int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
struct npc_kpu_profile_adapter *profile);
void
npc_cn20k_update_action_entries_n_flags(struct rvu *rvu,
struct npc_kpu_profile_adapter *pfl);
int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc);
void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc);
int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
u16 *mcast, u16 *promisc, u16 *ucast);
void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
u8 intf, struct cn20k_mcam_entry *entry,
bool enable, u8 hw_prio, u8 req_kw_type);
void npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
int index, bool enable);
void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr,
u16 src, u16 dest);
void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
struct cn20k_mcam_entry *entry, u8 *intf,
u8 *ena, u8 *hw_prio);
void npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr,
int bank, int index);
int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type);
u16 npc_cn20k_vidx2idx(u16 index);
u16 npc_cn20k_idx2vidx(u16 idx);
int npc_cn20k_defrag(struct rvu *rvu);
#endif /* NPC_CN20K_H */

View File

@ -78,4 +78,69 @@
#define RVU_MBOX_VF_INT_ENA_W1C (0x38)
#define RVU_MBOX_VF_VFAF_TRIGX(a) (0x2000 | (a) << 3)
#define NIX_GINT_INT (0x200)
#define NIX_GINT_INT_W1S (0x208)
#define ALTAF_FLR BIT_ULL(0)
#define ALTAF_RDY BIT_ULL(1)
/* NPC registers */
#define NPC_AF_INTFX_EXTRACTORX_CFG(a, b) \
(0x20c000ull | (a) << 16 | (b) << 8)
#define NPC_AF_INTFX_EXTRACTORX_LTX_CFG(a, b, c) \
(0x204000ull | (a) << 16 | (b) << 8 | (c) << 3)
#define NPC_AF_KPMX_ENTRYX_CAMX(a, b, c) \
(0x20000ull | (a) << 12 | (b) << 3 | (c) << 16)
#define NPC_AF_KPMX_ENTRYX_ACTION0(a, b) \
(0x40000ull | (a) << 12 | (b) << 3)
#define NPC_AF_KPMX_ENTRYX_ACTION1(a, b) \
(0x50000ull | (a) << 12 | (b) << 3)
#define NPC_AF_KPMX_ENTRY_DISX(a, b) (0x60000ull | (a) << 12 | (b) << 3)
#define NPC_AF_KPM_PASS2_CFG 0x10210
#define NPC_AF_KPMX_PASS2_OFFSET(a) (0x60040ull | (a) << 12)
#define NPC_AF_MCAM_SECTIONX_CFG_EXT(a) (0xf000000ull | (a) << 3)
#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(a, b, c) ({ \
u64 offset; \
offset = (0x8000000ull | (a) << 4 | (b) << 20 | (c) << 3); \
offset; })
#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(a, b, c) ({ \
u64 offset; \
offset = (0x9000000ull | (a) << 4 | (b) << 20 | (c) << 3); \
offset; })
#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(a, b, c) ({ \
u64 offset; \
offset = (0x9400000ull | (a) << 4 | (b) << 20 | (c) << 3); \
offset; })
#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(a, b, c) ({ \
u64 offset; \
offset = (0x9800000ull | (a) << 4 | (b) << 20 | (c) << 3); \
offset; })
#define NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(a, b, c) ({ \
u64 offset; \
offset = (0x9c00000ull | (a) << 4 | (b) << 20 | (c) << 3); \
offset; })
#define NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(a, b) ({ \
u64 offset; \
offset = (0xa000000ull | (a) << 4 | (b) << 20); \
offset; })
#define NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(a, b, c) ({ \
u64 offset; \
offset = (0xc000000ull | (a) << 4 | (b) << 20 | (c) << 22); \
offset; })
#define NPC_AF_INTFX_MISS_ACTX(a, b) (0xf003000 | (a) << 6 | (b) << 4)
#define NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(a, b) ({ \
u64 offset; \
offset = (0xb000000ull | (a) << 4 | (b) << 20); \
offset; })
#endif /* RVU_MBOX_REG_H */

View File

@ -177,10 +177,6 @@ enum nix_scheduler {
#define NIX_TX_ACTIONOP_MCAST (0x3ull)
#define NIX_TX_ACTIONOP_DROP_VIOL (0x5ull)
#define NPC_MCAM_KEY_X1 0
#define NPC_MCAM_KEY_X2 1
#define NPC_MCAM_KEY_X4 2
#define NIX_INTFX_RX(a) (0x0ull | (a) << 1)
#define NIX_INTFX_TX(a) (0x1ull | (a) << 1)

View File

@ -52,6 +52,14 @@
#define MBOX_DIR_PFVF_UP 6 /* PF sends messages to VF */
#define MBOX_DIR_VFPF_UP 7 /* VF replies to PF */
enum {
NPC_MCAM_KEY_X1 = 0,
NPC_MCAM_KEY_DYN = NPC_MCAM_KEY_X1,
NPC_MCAM_KEY_X2,
NPC_MCAM_KEY_X4,
NPC_MCAM_KEY_MAX,
};
enum {
TYPE_AFVF,
TYPE_AFPF,
@ -275,6 +283,33 @@ M(NPC_GET_FIELD_HASH_INFO, 0x6013, npc_get_field_hash_info,
M(NPC_GET_FIELD_STATUS, 0x6014, npc_get_field_status, \
npc_get_field_status_req, \
npc_get_field_status_rsp) \
M(NPC_CN20K_MCAM_GET_FREE_COUNT, 0x6015, npc_cn20k_get_fcnt, \
msg_req, npc_cn20k_get_fcnt_rsp) \
M(NPC_CN20K_GET_KEX_CFG, 0x6016, npc_cn20k_get_kex_cfg, \
msg_req, npc_cn20k_get_kex_cfg_rsp) \
M(NPC_CN20K_MCAM_WRITE_ENTRY, 0x6017, npc_cn20k_mcam_write_entry, \
npc_cn20k_mcam_write_entry_req, msg_rsp) \
M(NPC_CN20K_MCAM_ALLOC_AND_WRITE_ENTRY, 0x6018, \
npc_cn20k_mcam_alloc_and_write_entry, \
npc_cn20k_mcam_alloc_and_write_entry_req, \
npc_mcam_alloc_and_write_entry_rsp) \
M(NPC_CN20K_MCAM_READ_ENTRY, 0x6019, npc_cn20k_mcam_read_entry, \
npc_mcam_read_entry_req, \
npc_cn20k_mcam_read_entry_rsp) \
M(NPC_CN20K_MCAM_READ_BASE_RULE, 0x601a, npc_cn20k_read_base_steer_rule, \
msg_req, npc_cn20k_mcam_read_base_rule_rsp) \
M(NPC_MCAM_DEFRAG, 0x601b, npc_defrag, \
msg_req, \
msg_rsp) \
M(NPC_MCAM_GET_NUM_KWS, 0x601c, npc_get_num_kws, \
npc_get_num_kws_req, \
npc_get_num_kws_rsp) \
M(NPC_MCAM_GET_DFT_RL_IDXS, 0x601d, npc_get_dft_rl_idxs, \
msg_req, \
npc_get_dft_rl_idxs_rsp)\
M(NPC_MCAM_GET_NPC_PFL_INFO, 0x601e, npc_get_pfl_info, \
msg_req, \
npc_get_pfl_info_rsp) \
/* NIX mbox IDs (range 0x8000 - 0xFFFF) */ \
M(NIX_LF_ALLOC, 0x8000, nix_lf_alloc, \
nix_lf_alloc_req, nix_lf_alloc_rsp) \
@ -1527,9 +1562,11 @@ struct npc_mcam_alloc_entry_req {
#define NPC_MCAM_ANY_PRIO 0
#define NPC_MCAM_LOWER_PRIO 1
#define NPC_MCAM_HIGHER_PRIO 2
u8 priority; /* Lower or higher w.r.t ref_entry */
u8 ref_prio; /* Lower or higher w.r.t ref_entry */
u16 ref_entry;
u16 count; /* Number of entries requested */
u8 kw_type; /* entry key type, valid for cn20k */
u8 virt; /* Request virtual index */
};
struct npc_mcam_alloc_entry_rsp {
@ -1548,14 +1585,47 @@ struct npc_mcam_free_entry_req {
u8 all; /* If all entries allocated to this PFVF to be freed */
};
struct mcam_entry_mdata {
u64 *kw;
u64 *kw_mask;
u64 *action;
u64 *vtag_action;
u8 max_kw;
};
enum npc_kws_in_key_sz {
NPC_KWS_IN_KEY_SZ_7 = 7,
NPC_KWS_IN_KEY_SZ_8 = 8,
NPC_KWS_IN_KEY_SZ_MAX,
};
struct mcam_entry {
#define NPC_MAX_KWS_IN_KEY 7 /* Number of keywords in max keywidth */
u64 kw[NPC_MAX_KWS_IN_KEY];
u64 kw_mask[NPC_MAX_KWS_IN_KEY];
u64 kw[NPC_KWS_IN_KEY_SZ_7];
u64 kw_mask[NPC_KWS_IN_KEY_SZ_7];
u64 action;
u64 vtag_action;
};
struct cn20k_mcam_entry {
u64 kw[NPC_KWS_IN_KEY_SZ_8];
u64 kw_mask[NPC_KWS_IN_KEY_SZ_8];
u64 action;
u64 vtag_action;
u64 action2;
};
struct npc_cn20k_mcam_write_entry_req {
struct mbox_msghdr hdr;
struct cn20k_mcam_entry entry_data;
u16 entry; /* MCAM entry to write this match key */
u16 cntr; /* Counter for this MCAM entry */
u8 intf; /* Rx or Tx interface */
u8 enable_entry;/* Enable this MCAM entry ? */
u8 hw_prio; /* hardware priority, valid for cn20k */
u8 req_kw_type; /* Type of kw which should be written */
u64 reserved; /* reserved for future use */
};
struct npc_mcam_write_entry_req {
struct mbox_msghdr hdr;
struct mcam_entry entry_data;
@ -1564,6 +1634,8 @@ struct npc_mcam_write_entry_req {
u8 intf; /* Rx or Tx interface */
u8 enable_entry;/* Enable this MCAM entry ? */
u8 set_cntr; /* Set counter for this entry ? */
u8 hw_prio; /* hardware priority, valid for cn20k */
u64 reserved; /* reserved for future use */
};
/* Enable/Disable a given entry */
@ -1622,12 +1694,38 @@ struct npc_mcam_alloc_and_write_entry_req {
struct mbox_msghdr hdr;
struct mcam_entry entry_data;
u16 ref_entry;
u8 priority; /* Lower or higher w.r.t ref_entry */
u8 ref_prio; /* Lower or higher w.r.t ref_entry */
u8 intf; /* Rx or Tx interface */
u8 enable_entry;/* Enable this MCAM entry ? */
u8 alloc_cntr; /* Allocate counter and map ? */
};
struct npc_cn20k_mcam_alloc_and_write_entry_req {
struct mbox_msghdr hdr;
struct cn20k_mcam_entry entry_data;
u16 ref_entry;
u8 ref_prio; /* Lower or higher w.r.t ref_entry */
u8 intf; /* Rx or Tx interface */
u8 enable_entry;/* Enable this MCAM entry ? */
u8 hw_prio; /* hardware priority, valid for cn20k */
u8 virt; /* Allocate virtual index */
u8 req_kw_type; /* Key type to be written */
u16 reserved[4]; /* reserved for future use */
};
struct npc_cn20k_mcam_read_entry_rsp {
struct mbox_msghdr hdr;
struct cn20k_mcam_entry entry_data;
u8 intf;
u8 enable;
u8 hw_prio; /* valid for cn20k */
};
struct npc_cn20k_mcam_read_base_rule_rsp {
struct mbox_msghdr hdr;
struct cn20k_mcam_entry entry;
};
struct npc_mcam_alloc_and_write_entry_rsp {
struct mbox_msghdr hdr;
u16 entry;
@ -1653,6 +1751,19 @@ struct npc_get_kex_cfg_rsp {
u8 mkex_pfl_name[MKEX_NAME_LEN];
};
struct npc_cn20k_get_kex_cfg_rsp {
struct mbox_msghdr hdr;
u64 rx_keyx_cfg; /* NPC_AF_INTF(0)_KEX_CFG */
u64 tx_keyx_cfg; /* NPC_AF_INTF(1)_KEX_CFG */
#define NPC_MAX_EXTRACTOR 24
/* MKEX Extractor data */
u64 intf_extr_lid[NPC_MAX_INTF][NPC_MAX_EXTRACTOR];
/* KEX configuration per extractor */
u64 intf_extr_lt[NPC_MAX_INTF][NPC_MAX_EXTRACTOR][NPC_MAX_LT];
#define MKEX_NAME_LEN 128
u8 mkex_pfl_name[MKEX_NAME_LEN];
};
struct ptp_get_cap_rsp {
struct mbox_msghdr hdr;
#define PTP_CAP_HW_ATOMIC_UPDATE BIT_ULL(0)
@ -1765,11 +1876,53 @@ struct npc_install_flow_req {
u8 vtag1_op;
/* old counter value */
u16 cntr_val;
u8 hw_prio;
u8 req_kw_type; /* Key type to be written */
u8 alloc_entry; /* only for cn20k */
/* For now use any priority, once AF driver is changed to
* allocate least priority entry instead of mid zone then make
* NPC_MCAM_LEAST_PRIO as 3
*/
#define NPC_MCAM_LEAST_PRIO NPC_MCAM_ANY_PRIO
u16 ref_prio;
u16 ref_entry;
};
struct npc_install_flow_rsp {
struct mbox_msghdr hdr;
int counter; /* negative if no counter else counter number */
u16 entry;
u8 kw_type;
};
struct npc_get_num_kws_req {
struct mbox_msghdr hdr;
struct npc_install_flow_req fl;
u32 rsvd[4];
};
struct npc_get_num_kws_rsp {
struct mbox_msghdr hdr;
int kws;
u32 rsvd[4];
};
struct npc_get_dft_rl_idxs_rsp {
struct mbox_msghdr hdr;
u16 bcast;
u16 mcast;
u16 promisc;
u16 ucast;
u16 vf_ucast;
u16 rsvd[7];
};
struct npc_get_pfl_info_rsp {
struct mbox_msghdr hdr;
u16 x4_slots;
u8 kw_type;
u8 rsvd1[3];
u32 rsvd2[4];
};
struct npc_delete_flow_req {
@ -1795,6 +1948,15 @@ struct npc_mcam_read_entry_rsp {
struct mcam_entry entry_data;
u8 intf;
u8 enable;
u8 hw_prio; /* valid for cn20k */
};
/* Available entries to use */
struct npc_cn20k_get_fcnt_rsp {
struct mbox_msghdr hdr;
int free_x2;
int free_x4;
int free_subbanks;
};
struct npc_mcam_read_base_rule_rsp {

View File

@ -429,6 +429,7 @@ struct nix_rx_action {
/* NPC_AF_INTFX_KEX_CFG field masks */
#define NPC_PARSE_NIBBLE GENMASK_ULL(30, 0)
#define NPC_TOTAL_NIBBLE 31
/* NPC_PARSE_KEX_S nibble definitions for each field */
#define NPC_PARSE_NIBBLE_CHAN GENMASK_ULL(2, 0)
@ -643,6 +644,7 @@ struct rvu_npc_mcam_rule {
u16 chan;
u16 chan_mask;
u8 lxmb;
u8 hw_prio;
};
#endif /* NPC_H */

View File

@ -321,6 +321,18 @@ enum npc_kpu_lb_lflag {
NPC_F_LB_L_FDSA,
};
enum npc_cn20k_kpu_lc_uflag {
NPC_CN20K_F_LC_U_MPLS_IN_IP = 0x20,
NPC_CN20K_F_LC_U_IP6_TUN_IP6 = 0x40,
NPC_CN20K_F_LC_U_IP6_MPLS_IN_IP = 0x80,
};
enum npc_cn20k_kpu_lc_lflag {
NPC_CN20K_F_LC_L_IP_FRAG = 2,
NPC_CN20K_F_LC_L_IP6_FRAG,
NPC_CN20K_F_LC_L_6TO4,
};
enum npc_kpu_lc_uflag {
NPC_F_LC_U_UNK_PROTO = 0x10,
NPC_F_LC_U_IP_FRAG = 0x20,
@ -489,7 +501,7 @@ enum NPC_ERRLEV_E {
0, 0, 0, 0, \
}
static struct npc_kpu_profile_action ikpu_action_entries[] = {
static struct npc_kpu_profile_action ikpu_action_entries[] __maybe_unused = {
{
NPC_ERRLEV_RE, NPC_EC_NOERR,
12, 16, 20, 0, 0,
@ -1068,7 +1080,7 @@ static struct npc_kpu_profile_action ikpu_action_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu1_cam_entries[] = {
static struct npc_kpu_profile_cam kpu1_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -1878,7 +1890,7 @@ static struct npc_kpu_profile_cam kpu1_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu2_cam_entries[] = {
static struct npc_kpu_profile_cam kpu2_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -2823,7 +2835,7 @@ static struct npc_kpu_profile_cam kpu2_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu3_cam_entries[] = {
static struct npc_kpu_profile_cam kpu3_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -3804,7 +3816,7 @@ static struct npc_kpu_profile_cam kpu3_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu4_cam_entries[] = {
static struct npc_kpu_profile_cam kpu4_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -4119,7 +4131,7 @@ static struct npc_kpu_profile_cam kpu4_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu5_cam_entries[] = {
static struct npc_kpu_profile_cam kpu5_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -5172,7 +5184,7 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu6_cam_entries[] = {
static struct npc_kpu_profile_cam kpu6_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -5901,7 +5913,7 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu7_cam_entries[] = {
static struct npc_kpu_profile_cam kpu7_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -6252,7 +6264,7 @@ static struct npc_kpu_profile_cam kpu7_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu8_cam_entries[] = {
static struct npc_kpu_profile_cam kpu8_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -7089,7 +7101,7 @@ static struct npc_kpu_profile_cam kpu8_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu9_cam_entries[] = {
static struct npc_kpu_profile_cam kpu9_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -7575,7 +7587,7 @@ static struct npc_kpu_profile_cam kpu9_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu10_cam_entries[] = {
static struct npc_kpu_profile_cam kpu10_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -7746,7 +7758,7 @@ static struct npc_kpu_profile_cam kpu10_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu11_cam_entries[] = {
static struct npc_kpu_profile_cam kpu11_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -8061,7 +8073,7 @@ static struct npc_kpu_profile_cam kpu11_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu12_cam_entries[] = {
static struct npc_kpu_profile_cam kpu12_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -8322,7 +8334,7 @@ static struct npc_kpu_profile_cam kpu12_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu13_cam_entries[] = {
static struct npc_kpu_profile_cam kpu13_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -8340,7 +8352,7 @@ static struct npc_kpu_profile_cam kpu13_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu14_cam_entries[] = {
static struct npc_kpu_profile_cam kpu14_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -8358,7 +8370,7 @@ static struct npc_kpu_profile_cam kpu14_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu15_cam_entries[] = {
static struct npc_kpu_profile_cam kpu15_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -8565,7 +8577,7 @@ static struct npc_kpu_profile_cam kpu15_cam_entries[] = {
},
};
static struct npc_kpu_profile_cam kpu16_cam_entries[] = {
static struct npc_kpu_profile_cam kpu16_cam_entries[] __maybe_unused = {
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
NPC_KPU_NOP_CAM,
@ -8628,7 +8640,7 @@ static struct npc_kpu_profile_cam kpu16_cam_entries[] = {
},
};
static struct npc_kpu_profile_action kpu1_action_entries[] = {
static struct npc_kpu_profile_action kpu1_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -9368,7 +9380,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu2_action_entries[] = {
static struct npc_kpu_profile_action kpu2_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -10209,7 +10221,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu3_action_entries[] = {
static struct npc_kpu_profile_action kpu3_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -11082,7 +11094,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu4_action_entries[] = {
static struct npc_kpu_profile_action kpu4_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -11363,7 +11375,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu5_action_entries[] = {
static struct npc_kpu_profile_action kpu5_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -12300,7 +12312,7 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu6_action_entries[] = {
static struct npc_kpu_profile_action kpu6_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -12949,7 +12961,7 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu7_action_entries[] = {
static struct npc_kpu_profile_action kpu7_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -13262,7 +13274,7 @@ static struct npc_kpu_profile_action kpu7_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu8_action_entries[] = {
static struct npc_kpu_profile_action kpu8_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -14007,7 +14019,7 @@ static struct npc_kpu_profile_action kpu8_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu9_action_entries[] = {
static struct npc_kpu_profile_action kpu9_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -14440,7 +14452,7 @@ static struct npc_kpu_profile_action kpu9_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu10_action_entries[] = {
static struct npc_kpu_profile_action kpu10_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -14593,7 +14605,7 @@ static struct npc_kpu_profile_action kpu10_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu11_action_entries[] = {
static struct npc_kpu_profile_action kpu11_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -14874,7 +14886,7 @@ static struct npc_kpu_profile_action kpu11_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu12_action_entries[] = {
static struct npc_kpu_profile_action kpu12_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -15107,7 +15119,7 @@ static struct npc_kpu_profile_action kpu12_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu13_action_entries[] = {
static struct npc_kpu_profile_action kpu13_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -15124,7 +15136,7 @@ static struct npc_kpu_profile_action kpu13_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu14_action_entries[] = {
static struct npc_kpu_profile_action kpu14_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -15141,7 +15153,7 @@ static struct npc_kpu_profile_action kpu14_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu15_action_entries[] = {
static struct npc_kpu_profile_action kpu15_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -15326,7 +15338,7 @@ static struct npc_kpu_profile_action kpu15_action_entries[] = {
},
};
static struct npc_kpu_profile_action kpu16_action_entries[] = {
static struct npc_kpu_profile_action kpu16_action_entries[] __maybe_unused = {
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
NPC_KPU_NOP_ACTION,
@ -15383,7 +15395,7 @@ static struct npc_kpu_profile_action kpu16_action_entries[] = {
},
};
static struct npc_kpu_profile npc_kpu_profiles[] = {
static struct npc_kpu_profile npc_kpu_profiles[] __maybe_unused = {
{
ARRAY_SIZE(kpu1_cam_entries),
ARRAY_SIZE(kpu1_action_entries),
@ -15482,7 +15494,7 @@ static struct npc_kpu_profile npc_kpu_profiles[] = {
},
};
static struct npc_lt_def_cfg npc_lt_defaults = {
static struct npc_lt_def_cfg npc_lt_defaults __maybe_unused = {
.rx_ol2 = {
.lid = NPC_LID_LA,
.ltype_match = NPC_LT_LA_ETHER,
@ -15604,7 +15616,7 @@ static struct npc_lt_def_cfg npc_lt_defaults = {
},
};
static struct npc_mcam_kex npc_mkex_default = {
static struct npc_mcam_kex npc_mkex_default __maybe_unused = {
.mkex_sign = MKEX_SIGN,
.name = "default",
.kpu_version = NPC_KPU_PROFILE_VER,

View File

@ -22,6 +22,7 @@
#include "rvu_npc_hash.h"
#include "cn20k/reg.h"
#include "cn20k/api.h"
#include "cn20k/npc.h"
#define DRV_NAME "rvu_af"
#define DRV_STRING "Marvell OcteonTX2 RVU Admin Function Driver"
@ -599,6 +600,7 @@ static void rvu_check_min_msix_vec(struct rvu *rvu, int nvecs, int pf, int vf)
static int rvu_setup_msix_resources(struct rvu *rvu)
{
struct altaf_intr_notify *altaf_intr_data;
struct rvu_hwinfo *hw = rvu->hw;
int pf, vf, numvfs, hwvf, err;
int nvecs, offset, max_msix;
@ -705,7 +707,30 @@ static int rvu_setup_msix_resources(struct rvu *rvu)
rvu->msix_base_iova = iova;
rvu->msixtr_base_phy = phy_addr;
if (is_rvu_otx2(rvu) || is_cn20k(rvu->pdev))
return 0;
if (!rvu->fwdata)
goto fail;
altaf_intr_data = &rvu->fwdata->altaf_intr_info;
if (altaf_intr_data->gint_paddr) {
iova = dma_map_resource(rvu->dev, altaf_intr_data->gint_paddr,
PCI_MSIX_ENTRY_SIZE,
DMA_BIDIRECTIONAL, 0);
if (dma_mapping_error(rvu->dev, iova))
goto fail;
altaf_intr_data->gint_iova_addr = iova;
}
return 0;
fail:
dma_unmap_resource(rvu->dev, phy_addr, max_msix * PCI_MSIX_ENTRY_SIZE,
DMA_BIDIRECTIONAL, 0);
return -EFAULT;
}
static void rvu_reset_msix(struct rvu *rvu)
@ -1396,7 +1421,6 @@ static void rvu_detach_block(struct rvu *rvu, int pcifunc, int blktype)
if (blkaddr < 0)
return;
block = &hw->block[blkaddr];
num_lfs = rvu_get_rsrc_mapcount(pfvf, block->addr);
@ -1467,6 +1491,13 @@ static int rvu_detach_rsrcs(struct rvu *rvu, struct rsrc_detach *detach,
else if ((blkid == BLKADDR_CPT1) && !detach->cptlfs)
continue;
}
if (detach_all ||
(detach && (blkid == BLKADDR_NIX0 ||
blkid == BLKADDR_NIX1) &&
detach->nixlf))
npc_cn20k_dft_rules_free(rvu, pcifunc);
rvu_detach_block(rvu, pcifunc, block->type);
}
@ -1750,6 +1781,12 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu,
err = rvu_attach_block(rvu, pcifunc, BLKTYPE_NIX, 1, attach);
if (err)
goto fail2;
if (is_cn20k(rvu->pdev)) {
err = npc_cn20k_dft_rules_alloc(rvu, pcifunc);
if (err)
goto fail3;
}
}
if (attach->sso) {
@ -1763,7 +1800,7 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu,
err = rvu_attach_block(rvu, pcifunc, BLKTYPE_SSO,
attach->sso, attach);
if (err)
goto fail3;
goto fail4;
}
if (attach->ssow) {
@ -1772,7 +1809,7 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu,
err = rvu_attach_block(rvu, pcifunc, BLKTYPE_SSOW,
attach->ssow, attach);
if (err)
goto fail4;
goto fail5;
}
if (attach->timlfs) {
@ -1781,7 +1818,7 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu,
err = rvu_attach_block(rvu, pcifunc, BLKTYPE_TIM,
attach->timlfs, attach);
if (err)
goto fail5;
goto fail6;
}
if (attach->cptlfs) {
@ -1791,24 +1828,28 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu,
err = rvu_attach_block(rvu, pcifunc, BLKTYPE_CPT,
attach->cptlfs, attach);
if (err)
goto fail6;
goto fail7;
}
mutex_unlock(&rvu->rsrc_lock);
return 0;
fail6:
fail7:
if (attach->timlfs)
rvu_detach_block(rvu, pcifunc, BLKTYPE_TIM);
fail5:
fail6:
if (attach->ssow)
rvu_detach_block(rvu, pcifunc, BLKTYPE_SSOW);
fail4:
fail5:
if (attach->sso)
rvu_detach_block(rvu, pcifunc, BLKTYPE_SSO);
fail4:
if (is_cn20k(rvu->pdev))
npc_cn20k_dft_rules_free(rvu, pcifunc);
fail3:
if (attach->nixlf)
rvu_detach_block(rvu, pcifunc, BLKTYPE_NIX);
@ -2185,6 +2226,33 @@ int rvu_mbox_handler_ndc_sync_op(struct rvu *rvu,
return 0;
}
static void rvu_notify_altaf(struct rvu *rvu, u16 pcifunc, u64 op)
{
int pf, vf;
if (!rvu->fwdata)
return;
if (op == ALTAF_FLR) {
pf = rvu_get_pf(rvu->pdev, pcifunc);
set_bit(pf, rvu->fwdata->altaf_intr_info.flr_pf_bmap);
if (pcifunc & RVU_PFVF_FUNC_MASK) {
vf = pcifunc & RVU_PFVF_FUNC_MASK;
if (vf >= 128) {
WARN(1,
"flr_vf_bmap size is 128 bits, vf=%u\n",
vf);
return;
}
set_bit(vf, rvu->fwdata->altaf_intr_info.flr_vf_bmap);
}
}
rvu_write64(rvu, BLKADDR_NIX0, AF_BAR2_ALIASX(0, NIX_GINT_INT_W1S), op);
usleep_range(5000, 6000);
}
static int rvu_process_mbox_msg(struct otx2_mbox *mbox, int devid,
struct mbox_msghdr *req)
{
@ -2268,7 +2336,8 @@ static void __rvu_mbox_handler(struct rvu_work *mwork, int type, bool poll)
offset = mbox->rx_start + ALIGN(sizeof(*req_hdr), MBOX_MSG_ALIGN);
if (req_hdr->sig && !(is_rvu_otx2(rvu) || is_cn20k(rvu->pdev))) {
if (req_hdr->sig && rvu->altaf_ready &&
!(is_rvu_otx2(rvu) || is_cn20k(rvu->pdev))) {
req_hdr->opt_msg = mw->mbox_wrk[devid].num_msgs;
rvu_write64(rvu, BLKADDR_NIX0, RVU_AF_BAR2_SEL,
RVU_AF_BAR2_PFID);
@ -2777,6 +2846,16 @@ static void rvu_blklf_teardown(struct rvu *rvu, u16 pcifunc, u8 blkaddr)
block = &rvu->hw->block[blkaddr];
num_lfs = rvu_get_rsrc_mapcount(rvu_get_pfvf(rvu, pcifunc),
block->addr);
if (block->addr == BLKADDR_TIM && rvu->altaf_ready) {
rvu_notify_altaf(rvu, pcifunc, ALTAF_FLR);
return;
}
if ((block->addr == BLKADDR_SSO || block->addr == BLKADDR_SSOW) &&
rvu->altaf_ready)
return;
if (!num_lfs)
return;
for (slot = 0; slot < num_lfs; slot++) {
@ -3060,12 +3139,12 @@ static int rvu_afvf_msix_vectors_num_ok(struct rvu *rvu)
static int rvu_register_interrupts(struct rvu *rvu)
{
int ret, offset, pf_vec_start;
int i, ret, offset, pf_vec_start;
rvu->num_vec = pci_msix_vec_count(rvu->pdev);
rvu->irq_name = devm_kmalloc_array(rvu->dev, rvu->num_vec,
NAME_SIZE, GFP_KERNEL);
rvu->irq_name = devm_kcalloc(rvu->dev, rvu->num_vec,
NAME_SIZE, GFP_KERNEL);
if (!rvu->irq_name)
return -ENOMEM;
@ -3251,6 +3330,13 @@ static int rvu_register_interrupts(struct rvu *rvu)
if (ret)
goto fail;
for (i = 0; i < rvu->num_vec; i++) {
if (strstr(&rvu->irq_name[i * NAME_SIZE], "Mbox") ||
strstr(&rvu->irq_name[i * NAME_SIZE], "FLR"))
irq_set_affinity(pci_irq_vector(rvu->pdev, i),
cpumask_of(0));
}
return 0;
fail:
@ -3279,8 +3365,8 @@ static int rvu_flr_init(struct rvu *rvu)
cfg | BIT_ULL(22));
}
rvu->flr_wq = alloc_ordered_workqueue("rvu_afpf_flr",
WQ_HIGHPRI | WQ_MEM_RECLAIM);
rvu->flr_wq = alloc_workqueue("rvu_afpf_flr",
WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
if (!rvu->flr_wq)
return -ENOMEM;

View File

@ -197,7 +197,7 @@ struct npc_key_field {
/* Masks where all set bits indicate position
* of a field in the key
*/
u64 kw_mask[NPC_MAX_KWS_IN_KEY];
u64 kw_mask[NPC_KWS_IN_KEY_SZ_MAX];
/* Number of words in the key a field spans. If a field is
* of 16 bytes and key offset is 4 then the field will use
* 4 bytes in KW0, 8 bytes in KW1 and 4 bytes in KW2 and
@ -308,6 +308,7 @@ struct rvu_pfvf {
u64 lmt_map_ent_w1; /* Preseving the word1 of lmtst map table entry*/
unsigned long flags;
struct sdp_node_info *sdp_info;
u8 hw_prio; /* Hw priority of default rules */
};
enum rvu_pfvf_flags {
@ -447,9 +448,11 @@ struct rvu_hwinfo {
u8 sdp_links;
u8 cpt_links; /* Number of CPT links */
u8 npc_kpus; /* No of parser units */
u8 npc_kpms; /* Number of enhanced parser units */
u8 npc_kex_extr; /* Number of LDATA extractors per KEX */
u8 npc_pkinds; /* No of port kinds */
u8 npc_intfs; /* No of interfaces */
u8 npc_kpu_entries; /* No of KPU entries */
u16 npc_kpu_entries; /* No of KPU entries */
u16 npc_counters; /* No of match stats counters */
u32 lbk_bufsize; /* FIFO size supported by LBK */
bool npc_ext_set; /* Extended register set */
@ -552,7 +555,11 @@ struct npc_kpu_profile_adapter {
const struct npc_lt_def_cfg *lt_def;
const struct npc_kpu_profile_action *ikpu; /* array[pkinds] */
const struct npc_kpu_profile *kpu; /* array[kpus] */
struct npc_mcam_kex *mkex;
union npc_mcam_key_prfl {
struct npc_mcam_kex *mkex;
/* used for cn9k and cn10k */
struct npc_mcam_kex_extr *mkex_extr; /* used for cn20k */
} mcam_kex_prfl;
struct npc_mcam_kex_hash *mkex_hash;
bool custom;
size_t pkinds;
@ -1117,8 +1124,8 @@ int rvu_cgx_cfg_pause_frm(struct rvu *rvu, u16 pcifunc, u8 tx_pause, u8 rx_pause
void rvu_mac_reset(struct rvu *rvu, u16 pcifunc);
u32 rvu_cgx_get_lmac_fifolen(struct rvu *rvu, int cgx, int lmac);
void cgx_start_linkup(struct rvu *rvu);
int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf,
int type);
int npc_get_nixlf_mcam_index(struct npc_mcam *mcam,
u16 pcifunc, int nixlf, int type);
bool is_mcam_entry_enabled(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr,
int index);
int rvu_npc_init(struct rvu *rvu);
@ -1184,4 +1191,5 @@ int rvu_rep_pf_init(struct rvu *rvu);
int rvu_rep_install_mcam_rules(struct rvu *rvu);
void rvu_rep_update_rules(struct rvu *rvu, u16 pcifunc, bool ena);
int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable);
int npc_mcam_verify_entry(struct npc_mcam *mcam, u16 pcifunc, int entry);
#endif /* RVU_H */

View File

@ -21,7 +21,9 @@
#include "rvu_npc_hash.h"
#include "mcs.h"
#include "cn20k/reg.h"
#include "cn20k/debugfs.h"
#include "cn20k/npc.h"
#define DEBUGFS_DIR_NAME "octeontx2"
@ -3196,7 +3198,9 @@ static void rvu_print_npc_mcam_info(struct seq_file *s,
static int rvu_dbg_npc_mcam_info_display(struct seq_file *filp, void *unsued)
{
struct rvu *rvu = filp->private;
int x4_free, x2_free, sb_free;
int pf, vf, numvfs, blkaddr;
struct npc_priv_t *npc_priv;
struct npc_mcam *mcam;
u16 pcifunc, counters;
u64 cfg;
@ -3210,16 +3214,34 @@ static int rvu_dbg_npc_mcam_info_display(struct seq_file *filp, void *unsued)
seq_puts(filp, "\nNPC MCAM info:\n");
/* MCAM keywidth on receive and transmit sides */
cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX));
cfg = (cfg >> 32) & 0x07;
seq_printf(filp, "\t\t RX keywidth \t: %s\n", (cfg == NPC_MCAM_KEY_X1) ?
"112bits" : ((cfg == NPC_MCAM_KEY_X2) ?
"224bits" : "448bits"));
cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX));
cfg = (cfg >> 32) & 0x07;
seq_printf(filp, "\t\t TX keywidth \t: %s\n", (cfg == NPC_MCAM_KEY_X1) ?
"112bits" : ((cfg == NPC_MCAM_KEY_X2) ?
"224bits" : "448bits"));
if (is_cn20k(rvu->pdev)) {
npc_priv = npc_priv_get();
seq_printf(filp, "\t\t RX keywidth \t: %s\n",
(npc_priv->kw == NPC_MCAM_KEY_X1) ?
"256bits" : "512bits");
npc_cn20k_subbank_calc_free(rvu, &x2_free, &x4_free, &sb_free);
seq_printf(filp, "\t\t free x4 slots\t: %d\n", x4_free);
seq_printf(filp, "\t\t free x2 slots\t: %d\n", x2_free);
seq_printf(filp, "\t\t free subbanks\t: %d\n", sb_free);
} else {
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX));
cfg = (cfg >> 32) & 0x07;
seq_printf(filp, "\t\t RX keywidth \t: %s\n",
(cfg == NPC_MCAM_KEY_X1) ?
"112bits" : ((cfg == NPC_MCAM_KEY_X2) ?
"224bits" : "448bits"));
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX));
cfg = (cfg >> 32) & 0x07;
seq_printf(filp, "\t\t TX keywidth \t: %s\n",
(cfg == NPC_MCAM_KEY_X1) ?
"112bits" : ((cfg == NPC_MCAM_KEY_X2) ?
"224bits" : "448bits"));
}
mutex_lock(&mcam->lock);
/* MCAM entries */
@ -3506,11 +3528,11 @@ static int rvu_dbg_npc_mcam_show_rules(struct seq_file *s, void *unused)
struct rvu_npc_mcam_rule *iter;
struct rvu *rvu = s->private;
struct npc_mcam *mcam;
int pf, vf = -1;
int pf, vf = -1, bank;
u16 target, index;
bool enabled;
u64 hits, off;
int blkaddr;
u16 target;
u64 hits;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
@ -3554,6 +3576,15 @@ static int rvu_dbg_npc_mcam_show_rules(struct seq_file *s, void *unused)
enabled = is_mcam_entry_enabled(rvu, mcam, blkaddr, iter->entry);
seq_printf(s, "\tenabled: %s\n", enabled ? "yes" : "no");
if (is_cn20k(rvu->pdev)) {
seq_printf(s, "\tpriority: %u\n", iter->hw_prio);
index = iter->entry & (mcam->banksize - 1);
bank = npc_get_bank(mcam, iter->entry);
off = NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(index, bank);
hits = rvu_read64(rvu, blkaddr, off);
seq_printf(s, "\thits: %lld\n", hits);
continue;
}
if (!iter->has_cntr)
continue;
@ -3698,9 +3729,9 @@ static int rvu_dbg_npc_exact_drop_cnt(struct seq_file *s, void *unused)
struct npc_exact_table *table;
struct rvu *rvu = s->private;
struct npc_key_field *field;
u64 cfg, cam1, off;
u16 chan, pcifunc;
int blkaddr, i;
u64 cfg, cam1;
char *str;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
@ -3721,11 +3752,17 @@ static int rvu_dbg_npc_exact_drop_cnt(struct seq_file *s, void *unused)
chan = field->kw_mask[0] & cam1;
str = (cfg & 1) ? "enabled" : "disabled";
if (is_cn20k(rvu->pdev)) {
off = NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(i, 0);
seq_printf(s, "0x%x\t%d\t\t%llu\t0x%x\t%s\n", pcifunc,
i, rvu_read64(rvu, blkaddr, off), chan, str);
} else {
off = NPC_AF_MATCH_STATX(table->counter_idx[i]);
seq_printf(s, "0x%x\t%d\t\t%llu\t0x%x\t%s\n", pcifunc,
i, rvu_read64(rvu, blkaddr, off),
chan, str);
}
seq_printf(s, "0x%x\t%d\t\t%llu\t0x%x\t%s\n", pcifunc, i,
rvu_read64(rvu, blkaddr,
NPC_AF_MATCH_STATX(table->counter_idx[i])),
chan, str);
}
return 0;
@ -3745,6 +3782,9 @@ static void rvu_dbg_npc_init(struct rvu *rvu)
debugfs_create_file("rx_miss_act_stats", 0444, rvu->rvu_dbg.npc, rvu,
&rvu_dbg_npc_rx_miss_act_fops);
if (is_cn20k(rvu->pdev))
npc_cn20k_debugfs_init(rvu);
if (!rvu->hw->cap.npc_exact_match_enabled)
return;

View File

@ -11,6 +11,7 @@
#include "rvu_reg.h"
#include "rvu_struct.h"
#include "rvu_npc_hash.h"
#include "cn20k/npc.h"
#define DRV_NAME "octeontx2-af"
@ -1256,9 +1257,71 @@ enum rvu_af_dl_param_id {
RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT,
RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE,
RVU_AF_DEVLINK_PARAM_ID_NPC_DEF_RULE_CNTR_ENABLE,
RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG,
RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF,
};
static int rvu_af_npc_defrag_feature_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
bool enabled;
enabled = is_cn20k(rvu->pdev);
snprintf(ctx->val.vstr, sizeof(ctx->val.vstr), "%s",
enabled ? "enabled" : "disabled");
return 0;
}
static int rvu_af_npc_defrag(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
/* It is hard to roll back if defrag process fails.
* print a error message and return fault.
*/
if (npc_cn20k_defrag(rvu)) {
dev_err(rvu->dev, "Defrag process failed\n");
return -EFAULT;
}
return 0;
}
static int rvu_af_npc_defrag_feature_validate(struct devlink *devlink, u32 id,
union devlink_param_value val,
struct netlink_ext_ack *extack)
{
struct rvu_devlink *rvu_dl = devlink_priv(devlink);
struct rvu *rvu = rvu_dl->rvu;
u64 enable;
if (kstrtoull(val.vstr, 10, &enable)) {
NL_SET_ERR_MSG_MOD(extack,
"Only 1 value is supported");
return -EINVAL;
}
if (enable != 1) {
NL_SET_ERR_MSG_MOD(extack,
"Only initiating defrag is supported");
return -EINVAL;
}
if (is_cn20k(rvu->pdev))
return 0;
NL_SET_ERR_MSG_MOD(extack,
"Can defrag NPC only in cn20k silicon");
return -EFAULT;
}
static int rvu_af_npc_exact_feature_get(struct devlink *devlink, u32 id,
struct devlink_param_gset_ctx *ctx,
struct netlink_ext_ack *extack)
@ -1561,6 +1624,15 @@ static const struct devlink_ops rvu_devlink_ops = {
.eswitch_mode_set = rvu_devlink_eswitch_mode_set,
};
static const struct devlink_param rvu_af_dl_param_defrag[] = {
DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG,
"npc_defrag", DEVLINK_PARAM_TYPE_STRING,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
rvu_af_npc_defrag_feature_get,
rvu_af_npc_defrag,
rvu_af_npc_defrag_feature_validate),
};
int rvu_register_dl(struct rvu *rvu)
{
struct rvu_devlink *rvu_dl;
@ -1593,6 +1665,17 @@ int rvu_register_dl(struct rvu *rvu)
goto err_dl_health;
}
if (is_cn20k(rvu->pdev)) {
err = devlink_params_register(dl, rvu_af_dl_param_defrag,
ARRAY_SIZE(rvu_af_dl_param_defrag));
if (err) {
dev_err(rvu->dev,
"devlink defrag params register failed with error %d",
err);
goto err_dl_defrag;
}
}
/* Register exact match devlink only for CN10K-B */
if (!rvu_npc_exact_has_match_table(rvu))
goto done;
@ -1601,7 +1684,8 @@ int rvu_register_dl(struct rvu *rvu)
ARRAY_SIZE(rvu_af_dl_param_exact_match));
if (err) {
dev_err(rvu->dev,
"devlink exact match params register failed with error %d", err);
"devlink exact match params register failed with error %d",
err);
goto err_dl_exact_match;
}
@ -1610,6 +1694,11 @@ int rvu_register_dl(struct rvu *rvu)
return 0;
err_dl_exact_match:
if (is_cn20k(rvu->pdev))
devlink_params_unregister(dl, rvu_af_dl_param_defrag,
ARRAY_SIZE(rvu_af_dl_param_defrag));
err_dl_defrag:
devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
err_dl_health:
@ -1627,6 +1716,10 @@ void rvu_unregister_dl(struct rvu *rvu)
devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
if (is_cn20k(rvu->pdev))
devlink_params_unregister(dl, rvu_af_dl_param_defrag,
ARRAY_SIZE(rvu_af_dl_param_defrag));
/* Unregister exact match devlink only for CN10K-B */
if (rvu_npc_exact_has_match_table(rvu))
devlink_params_unregister(dl, rvu_af_dl_param_exact_match,

View File

@ -5289,7 +5289,6 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req,
/* Disable the interface if it is in any multicast list */
nix_mcast_update_mce_entry(rvu, pcifunc, 0);
pfvf = rvu_get_pfvf(rvu, pcifunc);
clear_bit(NIXLF_INITIALIZED, &pfvf->flags);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Marvell RVU Admin Function driver
*
* Copyright (C) 2026 Marvell.
*
*/
#ifndef RVU_NPC_H
#define RVU_NPC_H
u64 npc_enable_mask(int count);
void npc_load_kpu_profile(struct rvu *rvu);
void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
const struct npc_kpu_profile_action *kpuaction,
int kpu, int entry, bool pkind);
int npc_fwdb_prfl_img_map(struct rvu *rvu, void __iomem **prfl_img_addr,
u64 *size);
void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index);
void npc_mcam_set_bit(struct npc_mcam *mcam, u16 index);
#endif /* RVU_NPC_H */

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,19 @@
#define NPC_LDATA_EN BIT_ULL(7)
void npc_update_entry(struct rvu *rvu, enum key_fields type,
struct mcam_entry *entry, u64 val_lo,
struct mcam_entry_mdata *mdata, u64 val_lo,
u64 val_hi, u64 mask_lo, u64 mask_hi, u8 intf);
void npc_update_flow(struct rvu *rvu, struct mcam_entry_mdata *mdata,
u64 features, struct flow_msg *pkt,
struct flow_msg *mask,
struct rvu_npc_mcam_rule *output, u8 intf,
int blkaddr);
void
npc_populate_mcam_mdata(struct rvu *rvu,
struct mcam_entry_mdata *mdata,
struct cn20k_mcam_entry *cn20k_entry,
struct mcam_entry *entry);
#endif /* RVU_NPC_FS_H */

View File

@ -125,6 +125,9 @@ static void npc_program_mkex_hash_rx(struct rvu *rvu, int blkaddr,
struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash;
int lid, lt, ld, hash_cnt = 0;
if (is_cn20k(rvu->pdev))
return;
if (is_npc_intf_tx(intf))
return;
@ -165,6 +168,9 @@ static void npc_program_mkex_hash_tx(struct rvu *rvu, int blkaddr,
struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash;
int lid, lt, ld, hash_cnt = 0;
if (is_cn20k(rvu->pdev))
return;
if (is_npc_intf_rx(intf))
return;
@ -224,6 +230,9 @@ void npc_program_mkex_hash(struct rvu *rvu, int blkaddr)
struct rvu_hwinfo *hw = rvu->hw;
u64 cfg;
if (is_cn20k(rvu->pdev))
return;
/* Check if hardware supports hash extraction */
if (!hwcap->npc_hash_extract)
return;
@ -273,7 +282,7 @@ void npc_program_mkex_hash(struct rvu *rvu, int blkaddr)
}
void npc_update_field_hash(struct rvu *rvu, u8 intf,
struct mcam_entry *entry,
struct mcam_entry_mdata *mdata,
int blkaddr,
u64 features,
struct flow_msg *pkt,
@ -284,9 +293,13 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf,
struct npc_mcam_kex_hash *mkex_hash = rvu->kpu.mkex_hash;
struct npc_get_field_hash_info_req req;
struct npc_get_field_hash_info_rsp rsp;
u8 hash_idx, lid, ltype, ltype_mask;
u64 ldata[2], cfg;
u32 field_hash;
u8 hash_idx;
bool en;
if (is_cn20k(rvu->pdev))
return;
if (!rvu->hw->cap.npc_hash_extract) {
dev_dbg(rvu->dev, "%s: Field hash extract feature is not supported\n", __func__);
@ -298,60 +311,60 @@ void npc_update_field_hash(struct rvu *rvu, u8 intf,
for (hash_idx = 0; hash_idx < NPC_MAX_HASH; hash_idx++) {
cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_HASHX_CFG(intf, hash_idx));
if ((cfg & BIT_ULL(11)) && (cfg & BIT_ULL(12))) {
u8 lid = (cfg & GENMASK_ULL(10, 8)) >> 8;
u8 ltype = (cfg & GENMASK_ULL(7, 4)) >> 4;
u8 ltype_mask = cfg & GENMASK_ULL(3, 0);
en = !!(cfg & BIT_ULL(11)) && (cfg & BIT_ULL(12));
if (!en)
continue;
if (mkex_hash->lid_lt_ld_hash_en[intf][lid][ltype][hash_idx]) {
switch (ltype & ltype_mask) {
/* If hash extract enabled is supported for IPv6 then
* 128 bit IPv6 source and destination addressed
* is hashed to 32 bit value.
*/
case NPC_LT_LC_IP6:
/* ld[0] == hash_idx[0] == Source IPv6
* ld[1] == hash_idx[1] == Destination IPv6
*/
if ((features & BIT_ULL(NPC_SIP_IPV6)) && !hash_idx) {
u32 src_ip[IPV6_WORDS];
lid = (cfg & GENMASK_ULL(10, 8)) >> 8;
ltype = (cfg & GENMASK_ULL(7, 4)) >> 4;
ltype_mask = cfg & GENMASK_ULL(3, 0);
be32_to_cpu_array(src_ip, pkt->ip6src, IPV6_WORDS);
ldata[1] = (u64)src_ip[0] << 32 | src_ip[1];
ldata[0] = (u64)src_ip[2] << 32 | src_ip[3];
field_hash = npc_field_hash_calc(ldata,
rsp,
intf,
hash_idx);
npc_update_entry(rvu, NPC_SIP_IPV6, entry,
field_hash, 0,
GENMASK(31, 0), 0, intf);
memcpy(&opkt->ip6src, &pkt->ip6src,
sizeof(pkt->ip6src));
memcpy(&omask->ip6src, &mask->ip6src,
sizeof(mask->ip6src));
} else if ((features & BIT_ULL(NPC_DIP_IPV6)) && hash_idx) {
u32 dst_ip[IPV6_WORDS];
if (!mkex_hash->lid_lt_ld_hash_en[intf][lid][ltype][hash_idx])
continue;
be32_to_cpu_array(dst_ip, pkt->ip6dst, IPV6_WORDS);
ldata[1] = (u64)dst_ip[0] << 32 | dst_ip[1];
ldata[0] = (u64)dst_ip[2] << 32 | dst_ip[3];
field_hash = npc_field_hash_calc(ldata,
rsp,
intf,
hash_idx);
npc_update_entry(rvu, NPC_DIP_IPV6, entry,
field_hash, 0,
GENMASK(31, 0), 0, intf);
memcpy(&opkt->ip6dst, &pkt->ip6dst,
sizeof(pkt->ip6dst));
memcpy(&omask->ip6dst, &mask->ip6dst,
sizeof(mask->ip6dst));
}
/* If hash extract enabled is supported for IPv6 then
* 128 bit IPv6 source and destination addressed
* is hashed to 32 bit value.
*/
if ((ltype & ltype_mask) != NPC_LT_LC_IP6)
continue;
break;
}
}
/* ld[0] == hash_idx[0] == Source IPv6
* ld[1] == hash_idx[1] == Destination IPv6
*/
if ((features & BIT_ULL(NPC_SIP_IPV6)) && !hash_idx) {
u32 src_ip[IPV6_WORDS];
be32_to_cpu_array(src_ip, pkt->ip6src, IPV6_WORDS);
ldata[1] = (u64)src_ip[0] << 32 | src_ip[1];
ldata[0] = (u64)src_ip[2] << 32 | src_ip[3];
field_hash = npc_field_hash_calc(ldata, rsp, intf,
hash_idx);
npc_update_entry(rvu, NPC_SIP_IPV6, mdata, field_hash,
0, GENMASK(31, 0), 0, intf);
memcpy(&opkt->ip6src, &pkt->ip6src,
sizeof(pkt->ip6src));
memcpy(&omask->ip6src, &mask->ip6src,
sizeof(mask->ip6src));
continue;
}
if ((features & BIT_ULL(NPC_DIP_IPV6)) && hash_idx) {
u32 dst_ip[IPV6_WORDS];
be32_to_cpu_array(dst_ip, pkt->ip6dst, IPV6_WORDS);
ldata[1] = (u64)dst_ip[0] << 32 | dst_ip[1];
ldata[0] = (u64)dst_ip[2] << 32 | dst_ip[3];
field_hash = npc_field_hash_calc(ldata, rsp, intf,
hash_idx);
npc_update_entry(rvu, NPC_DIP_IPV6, mdata,
field_hash, 0, GENMASK(31, 0),
0, intf);
memcpy(&opkt->ip6dst, &pkt->ip6dst,
sizeof(pkt->ip6dst));
memcpy(&omask->ip6dst, &mask->ip6dst,
sizeof(mask->ip6dst));
continue;
}
}
}
@ -1874,6 +1887,9 @@ int rvu_npc_exact_init(struct rvu *rvu)
u64 cfg;
bool rc;
if (is_cn20k(rvu->pdev))
return 0;
/* Read NPC_AF_CONST3 and check for have exact
* match functionality is present
*/

View File

@ -53,7 +53,7 @@ struct npc_mcam_kex_hash {
} __packed;
void npc_update_field_hash(struct rvu *rvu, u8 intf,
struct mcam_entry *entry,
struct mcam_entry_mdata *mdata,
int blkaddr,
u64 features,
struct flow_msg *pkt,

View File

@ -251,6 +251,272 @@ static u8 cn20k_aura_bpid_idx(struct otx2_nic *pfvf, int aura_id)
#endif
}
static int cn20k_tc_get_entry_index(struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node)
{
struct otx2_tc_flow *tmp;
int index = 0;
list_for_each_entry(tmp, &flow_cfg->flow_list_tc, list) {
if (tmp == node)
return index;
index++;
}
return -1;
}
int cn20k_tc_free_mcam_entry(struct otx2_nic *nic, u16 entry)
{
struct npc_mcam_free_entry_req *req;
int err;
mutex_lock(&nic->mbox.lock);
req = otx2_mbox_alloc_msg_npc_mcam_free_entry(&nic->mbox);
if (!req) {
mutex_unlock(&nic->mbox.lock);
return -ENOMEM;
}
req->entry = entry;
/* Send message to AF to free MCAM entries */
err = otx2_sync_mbox_msg(&nic->mbox);
if (err) {
mutex_unlock(&nic->mbox.lock);
return err;
}
mutex_unlock(&nic->mbox.lock);
return 0;
}
static bool cn20k_tc_check_entry_shiftable(struct otx2_nic *nic,
struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node, int index,
bool error)
{
struct otx2_tc_flow *first, *tmp, *n;
u32 prio = 0;
int i = 0;
u8 type;
first = list_first_entry(&flow_cfg->flow_list_tc, struct otx2_tc_flow,
list);
type = first->kw_type;
/* Check all the nodes from start to given index (including index) has
* same type i.e, either X2 or X4
*/
list_for_each_entry_safe(tmp, n, &flow_cfg->flow_list_tc, list) {
if (i > index)
break;
if (type != tmp->kw_type) {
/* List has both X2 and X4 entries so entries cannot be
* shifted to save MCAM space.
*/
if (error)
dev_err(nic->dev, "Rule %d cannot be shifted to %d\n",
tmp->prio, prio);
return false;
}
type = tmp->kw_type;
prio = tmp->prio;
i++;
}
return true;
}
void cn20k_tc_update_mcam_table_del_req(struct otx2_nic *nic,
struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node)
{
struct otx2_tc_flow *first, *tmp, *n;
int i = 0, index;
u16 cntr_val = 0;
u16 entry;
index = cn20k_tc_get_entry_index(flow_cfg, node);
if (index < 0) {
netdev_dbg(nic->netdev, "Could not find node\n");
return;
}
first = list_first_entry(&flow_cfg->flow_list_tc, struct otx2_tc_flow,
list);
entry = first->entry;
/* If entries cannot be shifted then delete given entry
* and free it to AF too.
*/
if (!cn20k_tc_check_entry_shiftable(nic, flow_cfg, node,
index, false)) {
list_del(&node->list);
entry = node->entry;
goto free_mcam_entry;
}
/* Find and delete the entry from the list and re-install
* all the entries from beginning to the index of the
* deleted entry to higher mcam indexes.
*/
list_for_each_entry_safe(tmp, n, &flow_cfg->flow_list_tc, list) {
if (node == tmp) {
list_del(&tmp->list);
break;
}
otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
tmp->entry = (list_next_entry(tmp, list))->entry;
tmp->req.entry = tmp->entry;
tmp->req.cntr_val = cntr_val;
}
list_for_each_entry_safe(tmp, n, &flow_cfg->flow_list_tc, list) {
if (i == index)
break;
otx2_add_mcam_flow_entry(nic, &tmp->req);
i++;
}
free_mcam_entry:
if (cn20k_tc_free_mcam_entry(nic, entry))
netdev_err(nic->netdev, "Freeing entry %d to AF failed\n",
entry);
}
int cn20k_tc_update_mcam_table_add_req(struct otx2_nic *nic,
struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node)
{
struct otx2_tc_flow *tmp;
u16 cntr_val = 0;
int list_idx, i;
int entry, prev;
/* Find the index of the entry(list_idx) whose priority
* is greater than the new entry and re-install all
* the entries from beginning to list_idx to higher
* mcam indexes.
*/
list_idx = otx2_tc_add_to_flow_list(flow_cfg, node);
entry = node->entry;
if (!cn20k_tc_check_entry_shiftable(nic, flow_cfg, node,
list_idx, true))
/* Due to mix of X2 and X4, entries cannot be shifted.
* In this case free the entry allocated for this rule.
*/
return -EINVAL;
for (i = 0; i < list_idx; i++) {
tmp = otx2_tc_get_entry_by_index(flow_cfg, i);
if (!tmp)
return -ENOMEM;
otx2_del_mcam_flow_entry(nic, tmp->entry, &cntr_val);
prev = tmp->entry;
tmp->entry = entry;
tmp->req.entry = tmp->entry;
tmp->req.cntr_val = cntr_val;
otx2_add_mcam_flow_entry(nic, &tmp->req);
entry = prev;
}
return entry;
}
#define MAX_TC_HW_PRIORITY 125
#define MAX_TC_VF_PRIORITY 126
#define MAX_TC_PF_PRIORITY 127
static int __cn20k_tc_alloc_entry(struct otx2_nic *nic,
struct npc_install_flow_req *flow_req,
u16 *entry, u8 *type,
u32 tc_priority, bool hw_priority)
{
struct otx2_flow_config *flow_cfg = nic->flow_cfg;
struct npc_install_flow_req *req;
struct npc_install_flow_rsp *rsp;
struct otx2_tc_flow *tmp;
int ret = 0;
req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
if (!req)
return -ENOMEM;
memcpy(&flow_req->hdr, &req->hdr, sizeof(struct mbox_msghdr));
memcpy(req, flow_req, sizeof(struct npc_install_flow_req));
req->alloc_entry = 1;
/* Allocate very least priority for first rule */
if (hw_priority || list_empty(&flow_cfg->flow_list_tc)) {
req->ref_prio = NPC_MCAM_LEAST_PRIO;
} else {
req->ref_prio = NPC_MCAM_HIGHER_PRIO;
tmp = list_first_entry(&flow_cfg->flow_list_tc,
struct otx2_tc_flow, list);
req->ref_entry = tmp->entry;
}
ret = otx2_sync_mbox_msg(&nic->mbox);
if (ret)
return ret;
rsp = (struct npc_install_flow_rsp *)otx2_mbox_get_rsp(&nic->mbox.mbox,
0, &req->hdr);
if (IS_ERR(rsp))
return -EFAULT;
if (entry)
*entry = rsp->entry;
if (type)
*type = rsp->kw_type;
return ret;
}
int cn20k_tc_alloc_entry(struct otx2_nic *nic,
struct flow_cls_offload *tc_flow_cmd,
struct otx2_tc_flow *new_node,
struct npc_install_flow_req *flow_req)
{
bool hw_priority = false;
u16 entry_from_af;
u8 entry_type;
int ret;
if (is_otx2_vf(nic->pcifunc))
flow_req->hw_prio = MAX_TC_VF_PRIORITY;
else
flow_req->hw_prio = MAX_TC_PF_PRIORITY;
if (new_node->prio <= MAX_TC_HW_PRIORITY) {
flow_req->hw_prio = new_node->prio;
hw_priority = true;
}
mutex_lock(&nic->mbox.lock);
ret = __cn20k_tc_alloc_entry(nic, flow_req, &entry_from_af, &entry_type,
new_node->prio, hw_priority);
if (ret) {
mutex_unlock(&nic->mbox.lock);
return ret;
}
new_node->kw_type = entry_type;
new_node->entry = entry_from_af;
mutex_unlock(&nic->mbox.lock);
return 0;
}
static int cn20k_aura_aq_init(struct otx2_nic *pfvf, int aura_id,
int pool_id, int numptrs)
{

View File

@ -10,8 +10,22 @@
#include "otx2_common.h"
struct otx2_flow_config;
struct otx2_tc_flow;
void cn20k_init(struct otx2_nic *pfvf);
int cn20k_register_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs);
void cn20k_disable_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs);
void cn20k_enable_pfvf_mbox_intr(struct otx2_nic *pf, int numvfs);
void cn20k_tc_update_mcam_table_del_req(struct otx2_nic *nic,
struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node);
int cn20k_tc_update_mcam_table_add_req(struct otx2_nic *nic,
struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node);
int cn20k_tc_alloc_entry(struct otx2_nic *nic,
struct flow_cls_offload *tc_flow_cmd,
struct otx2_tc_flow *new_node,
struct npc_install_flow_req *dummy);
int cn20k_tc_free_mcam_entry(struct otx2_nic *nic, u16 entry);
#endif /* CN20K_H */

View File

@ -366,6 +366,31 @@ struct otx2_flow_config {
u16 ntuple_cnt;
};
struct otx2_tc_flow_stats {
u64 bytes;
u64 pkts;
u64 used;
};
struct otx2_tc_flow {
struct list_head list;
unsigned long cookie;
struct rcu_head rcu;
struct otx2_tc_flow_stats stats;
spinlock_t lock; /* lock for stats */
u16 rq;
u16 entry;
u16 leaf_profile;
bool is_act_police;
u32 prio;
struct npc_install_flow_req req;
u64 rate;
u32 burst;
u32 mcast_grp_idx;
bool is_pps;
u8 kw_type; /* X2/X4 */
};
struct dev_hw_ops {
int (*sq_aq_init)(void *dev, u16 qidx, u8 chan_offset,
u16 sqb_aura);
@ -1223,4 +1248,14 @@ void otx2_dma_unmap_skb_frags(struct otx2_nic *pfvf, struct sg_list *sg);
int otx2_read_free_sqe(struct otx2_nic *pfvf, u16 qidx);
void otx2_queue_vf_work(struct mbox *mw, struct workqueue_struct *mbox_wq,
int first, int mdevs, u64 intr);
int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry,
u16 *cntr_val);
int otx2_add_mcam_flow_entry(struct otx2_nic *nic,
struct npc_install_flow_req *req);
int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node);
struct otx2_tc_flow *
otx2_tc_get_entry_by_index(struct otx2_flow_config *flow_cfg,
int index);
#endif /* OTX2_COMMON_H */

View File

@ -37,6 +37,98 @@ static void otx2_clear_ntuple_flow_info(struct otx2_nic *pfvf, struct otx2_flow_
flow_cfg->max_flows = 0;
}
static int otx2_mcam_pfl_info_get(struct otx2_nic *pfvf, bool *is_x2,
u16 *x4_slots)
{
struct npc_get_pfl_info_rsp *rsp;
struct msg_req *req;
static struct {
bool is_set;
bool is_x2;
u16 x4_slots;
} pfl_info;
/* Avoid sending mboxes for constant information
* like x4_slots
*/
mutex_lock(&pfvf->mbox.lock);
if (pfl_info.is_set) {
*is_x2 = pfl_info.is_x2;
*x4_slots = pfl_info.x4_slots;
mutex_unlock(&pfvf->mbox.lock);
return 0;
}
req = otx2_mbox_alloc_msg_npc_get_pfl_info(&pfvf->mbox);
if (!req) {
mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}
/* Send message to AF */
if (otx2_sync_mbox_msg(&pfvf->mbox)) {
mutex_unlock(&pfvf->mbox.lock);
return -EFAULT;
}
rsp = (struct npc_get_pfl_info_rsp *)otx2_mbox_get_rsp
(&pfvf->mbox.mbox, 0, &req->hdr);
if (IS_ERR(rsp)) {
mutex_unlock(&pfvf->mbox.lock);
return -EFAULT;
}
*is_x2 = (rsp->kw_type == NPC_MCAM_KEY_X2);
if (*is_x2)
*x4_slots = 0;
else
*x4_slots = rsp->x4_slots;
pfl_info.is_x2 = *is_x2;
pfl_info.x4_slots = *x4_slots;
pfl_info.is_set = true;
mutex_unlock(&pfvf->mbox.lock);
return 0;
}
static int otx2_get_dft_rl_idx(struct otx2_nic *pfvf, u16 *mcam_idx)
{
struct npc_get_dft_rl_idxs_rsp *rsp;
struct msg_req *req;
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_npc_get_dft_rl_idxs(&pfvf->mbox);
if (!req) {
mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}
/* Send message to AF */
if (otx2_sync_mbox_msg(&pfvf->mbox)) {
mutex_unlock(&pfvf->mbox.lock);
return -EINVAL;
}
rsp = (struct npc_get_dft_rl_idxs_rsp *)otx2_mbox_get_rsp
(&pfvf->mbox.mbox, 0, &req->hdr);
if (IS_ERR(rsp)) {
mutex_unlock(&pfvf->mbox.lock);
return -EFAULT;
}
if (is_otx2_lbkvf(pfvf->pdev))
*mcam_idx = rsp->promisc;
else
*mcam_idx = rsp->ucast;
mutex_unlock(&pfvf->mbox.lock);
return 0;
}
static int otx2_free_ntuple_mcam_entries(struct otx2_nic *pfvf)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
@ -69,7 +161,10 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct npc_mcam_alloc_entry_req *req;
struct npc_mcam_alloc_entry_rsp *rsp;
int ent, allocated = 0;
u16 dft_idx = 0, x4_slots = 0;
int ent, allocated = 0, ref;
bool is_x2 = false;
int rc;
/* Free current ones and allocate new ones with requested count */
otx2_free_ntuple_mcam_entries(pfvf);
@ -86,6 +181,22 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
return -ENOMEM;
}
if (is_cn20k(pfvf->pdev)) {
rc = otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots);
if (rc) {
netdev_err(pfvf->netdev, "Error to retrieve profile info\n");
return rc;
}
rc = otx2_get_dft_rl_idx(pfvf, &dft_idx);
if (rc) {
netdev_err(pfvf->netdev,
"Error to retrieve ucast mcam idx for pcifunc %#x\n",
pfvf->pcifunc);
return rc;
}
}
mutex_lock(&pfvf->mbox.lock);
/* In a single request a max of NPC_MAX_NONCONTIG_ENTRIES MCAM entries
@ -96,18 +207,31 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count)
if (!req)
goto exit;
req->kw_type = is_x2 ? NPC_MCAM_KEY_X2 : NPC_MCAM_KEY_X4;
req->contig = false;
req->count = (count - allocated) > NPC_MAX_NONCONTIG_ENTRIES ?
NPC_MAX_NONCONTIG_ENTRIES : count - allocated;
ref = 0;
if (is_cn20k(pfvf->pdev)) {
req->ref_prio = NPC_MCAM_HIGHER_PRIO;
ref = dft_idx;
}
/* Allocate higher priority entries for PFs, so that VF's entries
* will be on top of PF.
*/
if (!is_otx2_vf(pfvf->pcifunc)) {
req->priority = NPC_MCAM_HIGHER_PRIO;
req->ref_entry = flow_cfg->def_ent[0];
req->ref_prio = NPC_MCAM_HIGHER_PRIO;
ref = flow_cfg->def_ent[0];
}
if (is_cn20k(pfvf->pdev))
ref = is_x2 ? ref : ref & (x4_slots - 1);
req->ref_entry = ref;
/* Send message to AF */
if (otx2_sync_mbox_msg(&pfvf->mbox))
goto exit;
@ -163,8 +287,24 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
struct npc_get_field_status_rsp *frsp;
struct npc_mcam_alloc_entry_req *req;
struct npc_mcam_alloc_entry_rsp *rsp;
int vf_vlan_max_flows;
int ent, count;
int vf_vlan_max_flows, count;
int rc, ref, prio, ent;
u16 dft_idx;
ref = 0;
prio = 0;
if (is_cn20k(pfvf->pdev)) {
rc = otx2_get_dft_rl_idx(pfvf, &dft_idx);
if (rc) {
netdev_err(pfvf->netdev,
"Error to retrieve ucast mcam idx for pcifunc %#x\n",
pfvf->pcifunc);
return rc;
}
ref = dft_idx;
prio = NPC_MCAM_HIGHER_PRIO;
}
vf_vlan_max_flows = pfvf->total_vfs * OTX2_PER_VF_VLAN_FLOWS;
count = flow_cfg->ucast_flt_cnt +
@ -183,8 +323,11 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf)
return -ENOMEM;
}
req->kw_type = NPC_MCAM_KEY_X2;
req->contig = false;
req->count = count;
req->ref_prio = prio;
req->ref_entry = ref;
/* Send message to AF */
if (otx2_sync_mbox_msg(&pfvf->mbox)) {
@ -819,7 +962,7 @@ static int otx2_prepare_ipv6_flow(struct ethtool_rx_flow_spec *fsp,
}
static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
struct npc_install_flow_req *req)
struct npc_install_flow_req *req)
{
struct ethhdr *eth_mask = &fsp->m_u.ether_spec;
struct ethhdr *eth_hdr = &fsp->h_u.ether_spec;
@ -945,6 +1088,58 @@ static int otx2_prepare_flow_request(struct ethtool_rx_flow_spec *fsp,
return 0;
}
static int otx2_get_kw_type(struct otx2_nic *pfvf,
struct npc_install_flow_req *fl_req,
u8 *kw_type)
{
struct npc_get_num_kws_req *req;
struct npc_get_num_kws_rsp *rsp;
u8 *src, *dst;
int off, err;
int kw_bits;
off = offsetof(struct npc_install_flow_req, packet);
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_npc_get_num_kws(&pfvf->mbox);
if (!req) {
mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}
dst = (u8 *)&req->fl + off;
src = (u8 *)fl_req + off;
memcpy(dst, src, sizeof(struct npc_install_flow_req) - off);
err = otx2_sync_mbox_msg(&pfvf->mbox);
if (err) {
mutex_unlock(&pfvf->mbox.lock);
netdev_err(pfvf->netdev,
"Error to get default number of keywords\n");
return err;
}
rsp = (struct npc_get_num_kws_rsp *)otx2_mbox_get_rsp
(&pfvf->mbox.mbox, 0, &req->hdr);
if (IS_ERR(rsp)) {
mutex_unlock(&pfvf->mbox.lock);
return -EFAULT;
}
kw_bits = rsp->kws * 64;
if (kw_bits <= 256)
*kw_type = NPC_MCAM_KEY_X2;
else
*kw_type = NPC_MCAM_KEY_X4;
mutex_unlock(&pfvf->mbox.lock);
return 0;
}
static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
struct ethtool_rx_flow_spec *fsp)
{
@ -973,12 +1168,41 @@ static int otx2_is_flow_rule_dmacfilter(struct otx2_nic *pfvf,
static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
{
struct otx2_flow_config *flow_cfg = pfvf->flow_cfg;
struct npc_install_flow_req *req, treq = { 0 };
u64 ring_cookie = flow->flow_spec.ring_cookie;
#ifdef CONFIG_DCB
int vlan_prio, qidx, pfc_rule = 0;
#endif
struct npc_install_flow_req *req;
int err, vf = 0;
int err, vf = 0, off, sz;
bool modify = false;
u8 kw_type = 0;
u8 *src, *dst;
u16 x4_slots;
bool is_x2;
if (is_cn20k(pfvf->pdev)) {
err = otx2_mcam_pfl_info_get(pfvf, &is_x2, &x4_slots);
if (err) {
netdev_err(pfvf->netdev,
"Error to retrieve NPC profile info, pcifunc=%#x\n",
pfvf->pcifunc);
return -EFAULT;
}
if (!is_x2) {
err = otx2_prepare_flow_request(&flow->flow_spec,
&treq);
if (err)
return err;
err = otx2_get_kw_type(pfvf, &treq, &kw_type);
if (err)
return err;
modify = true;
}
}
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_npc_install_flow(&pfvf->mbox);
@ -987,14 +1211,29 @@ static int otx2_add_flow_msg(struct otx2_nic *pfvf, struct otx2_flow *flow)
return -ENOMEM;
}
err = otx2_prepare_flow_request(&flow->flow_spec, req);
if (err) {
/* free the allocated msg above */
otx2_mbox_reset(&pfvf->mbox.mbox, 0);
mutex_unlock(&pfvf->mbox.lock);
return err;
if (modify) {
off = offsetof(struct npc_install_flow_req, packet);
sz = sizeof(struct npc_install_flow_req) - off;
dst = (u8 *)req + off;
src = (u8 *)&treq + off;
memcpy(dst, src, sz);
req->req_kw_type = kw_type;
} else {
err = otx2_prepare_flow_request(&flow->flow_spec, req);
if (err) {
/* free the allocated msg above */
otx2_mbox_reset(&pfvf->mbox.mbox, 0);
mutex_unlock(&pfvf->mbox.lock);
return err;
}
}
netdev_dbg(pfvf->netdev,
"flow entry (%u) installed at loc:%u kw_type=%u\n",
flow_cfg->flow_ent[flow->location],
flow->location, kw_type);
req->entry = flow->entry;
req->intf = NIX_INTF_RX;
req->set_cntr = 1;

View File

@ -31,30 +31,6 @@
#define MCAST_INVALID_GRP (-1U)
struct otx2_tc_flow_stats {
u64 bytes;
u64 pkts;
u64 used;
};
struct otx2_tc_flow {
struct list_head list;
unsigned long cookie;
struct rcu_head rcu;
struct otx2_tc_flow_stats stats;
spinlock_t lock; /* lock for stats */
u16 rq;
u16 entry;
u16 leaf_profile;
bool is_act_police;
u32 prio;
struct npc_install_flow_req req;
u32 mcast_grp_idx;
u64 rate;
u32 burst;
bool is_pps;
};
static void otx2_get_egress_burst_cfg(struct otx2_nic *nic, u32 burst,
u32 *burst_exp, u32 *burst_mantissa)
{
@ -971,8 +947,9 @@ static void otx2_destroy_tc_flow_list(struct otx2_nic *pfvf)
}
}
static struct otx2_tc_flow *otx2_tc_get_entry_by_cookie(struct otx2_flow_config *flow_cfg,
unsigned long cookie)
static struct otx2_tc_flow *
otx2_tc_get_entry_by_cookie(struct otx2_flow_config *flow_cfg,
unsigned long cookie)
{
struct otx2_tc_flow *tmp;
@ -984,8 +961,8 @@ static struct otx2_tc_flow *otx2_tc_get_entry_by_cookie(struct otx2_flow_config
return NULL;
}
static struct otx2_tc_flow *otx2_tc_get_entry_by_index(struct otx2_flow_config *flow_cfg,
int index)
struct otx2_tc_flow *
otx2_tc_get_entry_by_index(struct otx2_flow_config *flow_cfg, int index)
{
struct otx2_tc_flow *tmp;
int i = 0;
@ -1014,8 +991,8 @@ static void otx2_tc_del_from_flow_list(struct otx2_flow_config *flow_cfg,
}
}
static int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node)
int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg,
struct otx2_tc_flow *node)
{
struct list_head *pos, *n;
struct otx2_tc_flow *tmp;
@ -1038,7 +1015,8 @@ static int otx2_tc_add_to_flow_list(struct otx2_flow_config *flow_cfg,
return index;
}
static int otx2_add_mcam_flow_entry(struct otx2_nic *nic, struct npc_install_flow_req *req)
int otx2_add_mcam_flow_entry(struct otx2_nic *nic,
struct npc_install_flow_req *req)
{
struct npc_install_flow_req *tmp_req;
int err;
@ -1064,7 +1042,7 @@ static int otx2_add_mcam_flow_entry(struct otx2_nic *nic, struct npc_install_flo
return 0;
}
static int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry, u16 *cntr_val)
int otx2_del_mcam_flow_entry(struct otx2_nic *nic, u16 entry, u16 *cntr_val)
{
struct npc_delete_flow_rsp *rsp;
struct npc_delete_flow_req *req;
@ -1114,6 +1092,11 @@ static int otx2_tc_update_mcam_table_del_req(struct otx2_nic *nic,
int i = 0, index = 0;
u16 cntr_val = 0;
if (is_cn20k(nic->pdev)) {
cn20k_tc_update_mcam_table_del_req(nic, flow_cfg, node);
return 0;
}
/* Find and delete the entry from the list and re-install
* all the entries from beginning to the index of the
* deleted entry to higher mcam indexes.
@ -1153,6 +1136,9 @@ static int otx2_tc_update_mcam_table_add_req(struct otx2_nic *nic,
int list_idx, i;
u16 cntr_val = 0;
if (is_cn20k(nic->pdev))
return cn20k_tc_update_mcam_table_add_req(nic, flow_cfg, node);
/* Find the index of the entry(list_idx) whose priority
* is greater than the new entry and re-install all
* the entries from beginning to list_idx to higher
@ -1172,7 +1158,7 @@ static int otx2_tc_update_mcam_table_add_req(struct otx2_nic *nic,
mcam_idx++;
}
return mcam_idx;
return flow_cfg->flow_ent[mcam_idx];
}
static int otx2_tc_update_mcam_table(struct otx2_nic *nic,
@ -1238,7 +1224,6 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
mutex_unlock(&nic->mbox.lock);
}
free_mcam_flow:
otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL);
otx2_tc_update_mcam_table(nic, flow_cfg, flow_node, false);
@ -1254,7 +1239,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
struct otx2_flow_config *flow_cfg = nic->flow_cfg;
struct otx2_tc_flow *new_node, *old_node;
struct npc_install_flow_req *req, dummy;
int rc, err, mcam_idx;
int rc, err, entry;
if (!(nic->flags & OTX2_FLAG_TC_FLOWER_SUPPORT))
return -ENOMEM;
@ -1264,7 +1249,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
return -EINVAL;
}
if (flow_cfg->nr_flows == flow_cfg->max_flows) {
if (!is_cn20k(nic->pdev) && flow_cfg->nr_flows == flow_cfg->max_flows) {
NL_SET_ERR_MSG_MOD(extack,
"Free MCAM entry not available to add the flow");
return -ENOMEM;
@ -1292,7 +1277,23 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
if (old_node)
otx2_tc_del_flow(nic, tc_flow_cmd);
mcam_idx = otx2_tc_update_mcam_table(nic, flow_cfg, new_node, true);
if (is_cn20k(nic->pdev)) {
rc = cn20k_tc_alloc_entry(nic, tc_flow_cmd, new_node, &dummy);
if (rc) {
NL_SET_ERR_MSG_MOD(extack,
"MCAM rule allocation failed");
kfree_rcu(new_node, rcu);
return rc;
}
}
entry = otx2_tc_update_mcam_table(nic, flow_cfg, new_node, true);
if (entry < 0) {
NL_SET_ERR_MSG_MOD(extack, "Adding rule failed");
rc = entry;
goto free_leaf;
}
mutex_lock(&nic->mbox.lock);
req = otx2_mbox_alloc_msg_npc_install_flow(&nic->mbox);
if (!req) {
@ -1304,7 +1305,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
memcpy(&dummy.hdr, &req->hdr, sizeof(struct mbox_msghdr));
memcpy(req, &dummy, sizeof(struct npc_install_flow_req));
req->channel = nic->hw.rx_chan_base;
req->entry = flow_cfg->flow_ent[mcam_idx];
req->entry = (u16)entry;
req->intf = NIX_INTF_RX;
req->vf = nic->pcifunc;
req->set_cntr = 1;
@ -1325,6 +1326,8 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
return 0;
free_leaf:
if (is_cn20k(nic->pdev))
cn20k_tc_free_mcam_entry(nic, new_node->entry);
otx2_tc_del_from_flow_list(flow_cfg, new_node);
if (new_node->is_act_police) {
mutex_lock(&nic->mbox.lock);