iounmap(mkex_prfl_addr);
}
+void
+npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
+ int index, bool enable)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int mcam_idx = index % mcam->banksize;
+ int bank = index / mcam->banksize;
+ u64 cfg, hw_prio;
+ u8 kw_type;
+
+ npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+ if (kw_type == NPC_MCAM_KEY_X2) {
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
+ bank));
+ hw_prio = cfg & GENMASK_ULL(14, 8);
+ cfg = enable ? 1 : 0;
+ cfg |= hw_prio;
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
+ cfg);
+ return;
+ }
+
+ /* For NPC_CN20K_MCAM_KEY_X4 keys, both the banks
+ * need to be programmed with the same value.
+ */
+ for (bank = 0; bank < mcam->banks_per_entry; bank++) {
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
+ bank));
+ hw_prio = cfg & GENMASK_ULL(14, 8);
+ cfg = enable ? 1 : 0;
+ cfg |= hw_prio;
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
+ cfg);
+ }
+}
+
+void
+npc_cn20k_clear_mcam_entry(struct rvu *rvu, int blkaddr, int bank, int index)
+{
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 1),
+ 0);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 0),
+ 0);
+
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, bank, 1), 0);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, bank, 0), 0);
+
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, bank, 1), 0);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, bank, 0), 0);
+
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, bank, 1), 0);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, bank, 0), 0);
+
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 1), 0);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 0), 0);
+}
+
+static void npc_cn20k_get_keyword(struct mcam_entry *entry, int idx,
+ u64 *cam0, u64 *cam1)
+{
+ u64 kw_mask;
+
+ /* The two banks of every MCAM entry are used as a single double-wide
+ * entry that is compared with the search key as follows:
+ *
+ * NPC_AF_MCAME()_BANK(0)_CAM(0..1)_W0_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW0]
+ * NPC_AF_MCAME()_BANK(0)_CAM(0..1)_W1_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW1]
+ * NPC_AF_MCAME()_BANK(0)_CAM(0..1)_W2_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW2]
+ * NPC_AF_MCAME()_BANK(0)_CAM(0..1)_W3_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW3]
+ * NPC_AF_MCAME()_BANK(1)_CAM(0..1)_W0_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW4]
+ * NPC_AF_MCAME()_BANK(1)_CAM(0..1)_W1_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW5]
+ * NPC_AF_MCAME()_BANK(1)_CAM(0..1)_W2_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW6]
+ * NPC_AF_MCAME()_BANK(1)_CAM(0..1)_W3_EXT[MD] ->NPC_MCAM_KEY_X4_S[KW7]
+ */
+ *cam1 = entry->kw[idx];
+ kw_mask = entry->kw_mask[idx];
+ *cam1 &= kw_mask;
+ *cam0 = ~*cam1 & kw_mask;
+}
+
+/*-----------------------------------------------------------------------------|
+ *Kex type | mcam entry | cam1 | cam 0 || <----- output ----> |
+ *profile | len | (key type) | (key type) || len | type |
+ *-----------------------------------------------------------------------------|
+ *X2 | 256 (X2) | 001b | 110b || X2 | X2 |
+ *-----------------------------------------------------------------------------|
+ *X4 | 256 (X2) | 000b | 000b || X2 | DYNAMIC |
+ *-----------------------------------------------------------------------------|
+ *X4 | 512 (X4) | 010b | 101b || X4 | X4 |
+ *-----------------------------------------------------------------------------|
+ *DYN | 256 (X2) | 000b | 000b || X2 | DYNAMIC |
+ *-----------------------------------------------------------------------------|
+ *DYN | 512 (X4) | 010b | 101b || X4 | X4 |
+ *-----------------------------------------------------------------------------|
+ */
+static void npc_cn20k_config_kw_x2(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index, u8 intf,
+ struct mcam_entry *entry,
+ int bank, u8 kw_type, int kw)
+{
+ u64 intf_ext = 0, intf_ext_mask = 0;
+ u8 tx_intf_mask = ~intf & 0x3;
+ u8 tx_intf = intf, kex_type;
+ u8 kw_type_mask = ~kw_type;
+ u64 cam0, cam1, kex_cfg;
+
+ if (is_npc_intf_tx(intf)) {
+ /* Last bit must be set and rest don't care
+ * for TX interfaces
+ */
+ tx_intf_mask = 0x1;
+ tx_intf = intf & tx_intf_mask;
+ tx_intf_mask = ~tx_intf & tx_intf_mask;
+ }
+
+ kex_cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf));
+ kex_type = (kex_cfg & GENMASK_ULL(34, 32)) >> 32;
+ if ((kex_type == NPC_MCAM_KEY_DYN || kex_type == NPC_MCAM_KEY_X4) &&
+ kw_type == NPC_MCAM_KEY_X2) {
+ kw_type = 0;
+ kw_type_mask = 0;
+ }
+
+ intf_ext = ((u64)kw_type << 16) | tx_intf;
+ intf_ext_mask = (((u64)kw_type_mask << 16) & GENMASK_ULL(18, 16)) |
+ tx_intf_mask;
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 1),
+ intf_ext);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index, bank, 0),
+ intf_ext_mask);
+
+ /* Set the match key */
+ npc_cn20k_get_keyword(entry, kw, &cam0, &cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, bank, 1),
+ cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index, bank, 0),
+ cam0);
+
+ npc_cn20k_get_keyword(entry, kw + 1, &cam0, &cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, bank, 1),
+ cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index, bank, 0),
+ cam0);
+
+ npc_cn20k_get_keyword(entry, kw + 2, &cam0, &cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, bank, 1),
+ cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index, bank, 0),
+ cam0);
+
+ npc_cn20k_get_keyword(entry, kw + 3, &cam0, &cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 1),
+ cam1);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index, bank, 0),
+ cam0);
+}
+
+static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index, u8 intf,
+ struct mcam_entry *entry, u8 kw_type)
+{
+ int kw = 0, bank;
+
+ for (bank = 0; bank < mcam->banks_per_entry; bank++, kw = kw + 4)
+ npc_cn20k_config_kw_x2(rvu, mcam, blkaddr,
+ index, intf,
+ entry, bank, kw_type, kw);
+}
+
+static void
+npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx,
+ int bank, u8 kw_type, bool enable, u8 hw_prio)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ u64 bank_cfg;
+
+ bank_cfg = (u64)hw_prio << 8;
+ if (enable)
+ bank_cfg |= 0x1;
+
+ if (kw_type == NPC_MCAM_KEY_X2) {
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
+ bank_cfg);
+ return;
+ }
+
+ /* For NPC_MCAM_KEY_X4 keys, both the banks
+ * need to be programmed with the same value.
+ */
+ for (bank = 0; bank < mcam->banks_per_entry; bank++) {
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx, bank),
+ bank_cfg);
+ }
+}
+
+void
+npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index, u8 intf,
+ struct mcam_entry *entry, bool enable, u8 hw_prio)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ int mcam_idx = index % mcam->banksize;
+ int bank = index / mcam->banksize;
+ int kw = 0;
+ u8 kw_type;
+
+ /* Disable before mcam entry update */
+ npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false);
+
+ npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+ /* CAM1 takes the comparison value and
+ * CAM0 specifies match for a bit in key being '0' or '1' or 'dontcare'.
+ * CAM1<n> = 0 & CAM0<n> = 1 => match if key<n> = 0
+ * CAM1<n> = 1 & CAM0<n> = 0 => match if key<n> = 1
+ * CAM1<n> = 0 & CAM0<n> = 0 => always match i.e dontcare.
+ */
+ if (kw_type == NPC_MCAM_KEY_X2) {
+ /* Clear mcam entry to avoid writes being suppressed by NPC */
+ npc_cn20k_clear_mcam_entry(rvu, blkaddr, bank, mcam_idx);
+ npc_cn20k_config_kw_x2(rvu, mcam, blkaddr,
+ mcam_idx, intf, entry,
+ bank, kw_type, kw);
+ /* Set 'action' */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 0),
+ entry->action);
+
+ /* Set TAG 'action' */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 1),
+ entry->vtag_action);
+
+ goto set_cfg;
+ }
+ /* Clear mcam entry to avoid writes being suppressed by NPC */
+ npc_cn20k_clear_mcam_entry(rvu, blkaddr, 0, mcam_idx);
+ npc_cn20k_clear_mcam_entry(rvu, blkaddr, 1, mcam_idx);
+
+ npc_cn20k_config_kw_x4(rvu, mcam, blkaddr,
+ mcam_idx, intf, entry, kw_type);
+ for (bank = 0; bank < mcam->banks_per_entry; bank++) {
+ /* Set 'action' */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 0),
+ entry->action);
+
+ /* Set TAG 'action' */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 1),
+ entry->vtag_action);
+ }
+
+set_cfg:
+ /* TODO: */
+ /* PF installing VF rule */
+ npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank,
+ kw_type, enable, hw_prio);
+}
+
+void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ u64 cfg, sreg, dreg, soff, doff;
+ u8 src_kwtype, dest_kwtype;
+ int bank, i, sb, db;
+ int dbank, sbank;
+
+ dbank = npc_get_bank(mcam, dest);
+ sbank = npc_get_bank(mcam, src);
+ npc_mcam_idx_2_key_type(rvu, src, &src_kwtype);
+ npc_mcam_idx_2_key_type(rvu, dest, &dest_kwtype);
+ if (src_kwtype != dest_kwtype)
+ return;
+
+ src &= (mcam->banksize - 1);
+ dest &= (mcam->banksize - 1);
+
+ /* Copy INTF's, W0's, W1's, W2's, W3s CAM0 and CAM1 configuration */
+ for (bank = 0; bank < mcam->banks_per_entry; bank++) {
+ sb = sbank + bank;
+ sreg = NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(src, sb, 0);
+ db = dbank + bank;
+ dreg = NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(dest, db, 0);
+ for (i = 0; i < 10; i++) {
+ cfg = rvu_read64(rvu, blkaddr, sreg + (i * 8));
+ rvu_write64(rvu, blkaddr, dreg + (i * 8), cfg);
+ }
+
+ /* Copy action */
+ for (i = 0; i < 3; i++) {
+ soff = NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(src,
+ sb, i);
+ cfg = rvu_read64(rvu, blkaddr, soff);
+
+ doff = NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(dest, db,
+ i);
+ rvu_write64(rvu, blkaddr, doff, cfg);
+ }
+
+ /* Copy bank configuration */
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(src, sb));
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(dest, db), cfg);
+ if (src_kwtype == NPC_MCAM_KEY_X2)
+ break;
+ }
+}
+
+static void npc_cn20k_fill_entryword(struct mcam_entry *entry, int idx,
+ u64 cam0, u64 cam1)
+{
+ entry->kw[idx] = cam1;
+ entry->kw_mask[idx] = cam1 ^ cam0;
+}
+
+void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
+ struct mcam_entry *entry, u8 *intf, u8 *ena,
+ u8 *hw_prio)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ u64 cam0, cam1, bank_cfg, cfg;
+ int kw = 0, bank;
+ u8 kw_type;
+
+ npc_mcam_idx_2_key_type(rvu, index, &kw_type);
+
+ bank = npc_get_bank(mcam, index);
+ index &= (mcam->banksize - 1);
+
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index,
+ bank, 1)) & 3;
+ *intf = cfg;
+
+ bank_cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(index, bank));
+ *ena = bank_cfg & 0x1;
+ *hw_prio = (bank_cfg & GENMASK_ULL(14, 8)) >> 8;
+ if (kw_type == NPC_MCAM_KEY_X2) {
+ cam1 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index,
+ bank,
+ 1));
+ cam0 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index,
+ bank,
+ 0));
+ npc_cn20k_fill_entryword(entry, kw, cam0, cam1);
+
+ cam1 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index,
+ bank,
+ 1));
+ cam0 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index,
+ bank,
+ 0));
+ npc_cn20k_fill_entryword(entry, kw + 1, cam0, cam1);
+
+ cam1 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index,
+ bank,
+ 1));
+ cam0 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index,
+ bank,
+ 0));
+ npc_cn20k_fill_entryword(entry, kw + 2, cam0, cam1);
+
+ cam1 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index,
+ bank,
+ 1));
+ cam0 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index,
+ bank,
+ 0));
+ npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1);
+ goto read_action;
+ }
+
+ for (bank = 0; bank < mcam->banks_per_entry; bank++, kw = kw + 4) {
+ cam1 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index,
+ bank,
+ 1));
+ cam0 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index,
+ bank,
+ 0));
+ npc_cn20k_fill_entryword(entry, kw, cam0, cam1);
+
+ cam1 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index,
+ bank,
+ 1));
+ cam0 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W1_EXT(index,
+ bank,
+ 0));
+ npc_cn20k_fill_entryword(entry, kw + 1, cam0, cam1);
+
+ cam1 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index,
+ bank,
+ 1));
+ cam0 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W2_EXT(index,
+ bank,
+ 0));
+ npc_cn20k_fill_entryword(entry, kw + 2, cam0, cam1);
+
+ cam1 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index,
+ bank,
+ 1));
+ cam0 = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W3_EXT(index,
+ bank,
+ 0));
+ npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1);
+ }
+
+read_action:
+ /* 'action' is set to same value for both bank '0' and '1'.
+ * Hence, reading bank '0' should be enough.
+ */
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 0));
+ entry->action = cfg;
+
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 1));
+ entry->vtag_action = cfg;
+}
+
static u8 npc_map2cn20k_flag(u8 flag)
{
switch (flag) {
int npc_cn20k_apply_custom_kpu(struct rvu *rvu,
struct npc_kpu_profile_adapter *profile)
{
+ size_t hdr_sz = sizeof(struct npc_cn20k_kpu_profile_fwdata);
struct npc_cn20k_kpu_profile_fwdata *fw = rvu->kpu_fwdata;
struct npc_kpu_profile_action *action;
struct npc_kpu_profile_cam *cam;
struct npc_kpu_fwdata *fw_kpu;
- size_t hdr_sz, offset = 0;
+ size_t offset = 0;
u16 kpu, entry;
int entries;
return 0;
}
+int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type)
+{
+ struct npc_subbank *sb;
+ int bank_off, sb_id;
+
+ /* mcam_idx should be less than (2 * bank depth) */
+ if (mcam_idx >= npc_priv.bank_depth * 2) {
+ dev_err(rvu->dev, "%s:%d bad params\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ /* find mcam offset per bank */
+ bank_off = mcam_idx & (npc_priv.bank_depth - 1);
+
+ /* Find subbank id */
+ sb_id = bank_off / npc_priv.subbank_depth;
+
+ /* Check if subbank id is more than maximum
+ * number of subbanks available
+ */
+ if (sb_id >= npc_priv.num_subbanks) {
+ dev_err(rvu->dev, "%s:%d invalid subbank %d\n",
+ __func__, __LINE__, sb_id);
+ return -EINVAL;
+ }
+
+ sb = &npc_priv.sb[sb_id];
+
+ *key_type = sb->key_type;
+
+ return 0;
+}
+
static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank *sb,
u16 sub_off, u16 *mcam_idx)
{
#include "rvu_npc_hash.h"
#include "cn20k/npc.h"
#include "rvu_npc.h"
+#include "cn20k/reg.h"
#define RSVD_MCAM_ENTRIES_PER_PF 3 /* Broadcast, Promisc and AllMulticast */
#define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */
{
struct rvu_hwinfo *hw = container_of(mcam, struct rvu_hwinfo, mcam);
struct rvu *rvu = hw->rvu;
- int pf = rvu_get_pf(rvu->pdev, pcifunc);
+ u16 bcast, mcast, promisc, ucast;
int index;
+ int rc;
+ int pf;
+
+ if (is_cn20k(rvu->pdev)) {
+ rc = npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &bcast, &mcast,
+ &promisc, &ucast);
+ if (rc)
+ return -EFAULT;
+
+ switch (type) {
+ case NIXLF_BCAST_ENTRY:
+ return bcast;
+ case NIXLF_ALLMULTI_ENTRY:
+ return mcast;
+ case NIXLF_PROMISC_ENTRY:
+ return promisc;
+ case NIXLF_UCAST_ENTRY:
+ return ucast;
+ default:
+ return -EINVAL;
+ }
+ }
/* Check if this is for a PF */
+ pf = rvu_get_pf(rvu->pdev, pcifunc);
if (pf && !(pcifunc & RVU_PFVF_FUNC_MASK)) {
/* Reserved entries exclude PF0 */
pf--;
int npc_get_bank(struct npc_mcam *mcam, int index)
{
+ struct rvu_hwinfo *hw = container_of(mcam, struct rvu_hwinfo, mcam);
int bank = index / mcam->banksize;
+ struct rvu *rvu = hw->rvu;
+
+ if (is_cn20k(rvu->pdev))
+ return bank;
/* 0,1 & 2,3 banks are combined for this keysize */
if (mcam->keysize == NPC_MCAM_KEY_X2)
u64 cfg;
index &= (mcam->banksize - 1);
- cfg = rvu_read64(rvu, blkaddr, NPC_AF_MCAMEX_BANKX_CFG(index, bank));
+ if (is_cn20k(rvu->pdev))
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(index,
+ bank));
+ else
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_CFG(index, bank));
+
return (cfg & 1);
}
int bank = npc_get_bank(mcam, index);
int actbank = bank;
+ if (is_cn20k(rvu->pdev)) {
+ if (index < 0 || index >= mcam->banksize * mcam->banks)
+ return;
+
+ return npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
+ }
+
index &= (mcam->banksize - 1);
for (; bank < (actbank + mcam->banks_per_entry); bank++) {
rvu_write64(rvu, blkaddr,
int blkaddr, u16 pf_func)
{
int bank, nixlf, index;
+ u64 reg;
/* get ucast entry rule entry index */
if (nix_get_nixlf(rvu, pf_func, &nixlf, NULL)) {
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
- return rvu_read64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
+ if (is_cn20k(rvu->pdev))
+ reg = NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0);
+ else
+ reg = NPC_AF_MCAMEX_BANKX_ACTION(index, bank);
+
+ return rvu_read64(rvu, blkaddr, reg);
}
static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam,
u64 cfg, sreg, dreg;
int bank, i;
+ if (is_cn20k(rvu->pdev))
+ return npc_cn20k_copy_mcam_entry(rvu, blkaddr, src, dest);
+
src &= (mcam->banksize - 1);
dest &= (mcam->banksize - 1);
int blkaddr, int index)
{
int bank = npc_get_bank(mcam, index);
+ u64 reg;
index &= (mcam->banksize - 1);
- return rvu_read64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
+
+ if (is_cn20k(rvu->pdev))
+ reg = NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0);
+ else
+ reg = NPC_AF_MCAMEX_BANKX_ACTION(index, bank);
+ return rvu_read64(rvu, blkaddr, reg);
}
void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, int index, u64 cfg)
{
int bank = npc_get_bank(mcam, index);
+ u64 reg;
index &= (mcam->banksize - 1);
- return rvu_write64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(index, bank), cfg);
+
+ if (is_cn20k(rvu->pdev))
+ reg = NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0);
+ else
+ reg = NPC_AF_MCAMEX_BANKX_ACTION(index, bank);
+
+ return rvu_write64(rvu, blkaddr, reg, cfg);
}
void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc,
mutex_lock(&mcam->lock);
for (index = 0; index < mcam->bmap_entries; index++) {
- if (mcam->entry2target_pffunc[index] == pcifunc) {
- update = true;
- /* update not needed for the rules added via ntuple filters */
- list_for_each_entry(rule, &mcam->mcam_rules, list) {
- if (rule->entry == index)
- update = false;
- }
- if (!update)
- continue;
- bank = npc_get_bank(mcam, index);
- actindex = index;
- entry = index & (mcam->banksize - 1);
-
- /* read vf flow entry enable status */
- enable = is_mcam_entry_enabled(rvu, mcam, blkaddr,
- actindex);
- /* disable before mcam entry update */
- npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex,
- false);
- /* update 'action' */
+ if (mcam->entry2target_pffunc[index] != pcifunc)
+ continue;
+ update = true;
+ /* update not needed for the rules added via ntuple filters */
+ list_for_each_entry(rule, &mcam->mcam_rules, list) {
+ if (rule->entry == index)
+ update = false;
+ }
+ if (!update)
+ continue;
+ bank = npc_get_bank(mcam, index);
+ actindex = index;
+ entry = index & (mcam->banksize - 1);
+
+ /* read vf flow entry enable status */
+ enable = is_mcam_entry_enabled(rvu, mcam, blkaddr,
+ actindex);
+ /* disable before mcam entry update */
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex,
+ false);
+
+ /* update 'action' */
+ if (is_cn20k(rvu->pdev))
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(entry,
+ bank,
+ 0),
+ rx_action);
+ else
rvu_write64(rvu, blkaddr,
NPC_AF_MCAMEX_BANKX_ACTION(entry, bank),
rx_action);
- if (enable)
- npc_enable_mcam_entry(rvu, mcam, blkaddr,
- actindex, true);
- }
+
+ if (enable)
+ npc_enable_mcam_entry(rvu, mcam, blkaddr,
+ actindex, true);
}
mutex_unlock(&mcam->lock);
}
struct npc_mcam *mcam = &rvu->hw->mcam;
struct rvu_hwinfo *hw = rvu->hw;
int bank, op_rss;
+ u64 reg;
if (!is_mcam_entry_enabled(rvu, mcam, blkaddr, mcam_index))
return;
bank = npc_get_bank(mcam, mcam_index);
mcam_index &= (mcam->banksize - 1);
+ if (is_cn20k(rvu->pdev))
+ reg = NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_index,
+ bank, 0);
+ else
+ reg = NPC_AF_MCAMEX_BANKX_ACTION(mcam_index, bank);
+
/* If Rx action is MCAST update only RSS algorithm index */
if (!op_rss) {
- *(u64 *)&action = rvu_read64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(mcam_index, bank));
+ *(u64 *)&action = rvu_read64(rvu, blkaddr, reg);
action.flow_key_alg = alg_idx;
}
- rvu_write64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(mcam_index, bank), *(u64 *)&action);
+ rvu_write64(rvu, blkaddr, reg, *(u64 *)&action);
}
void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
struct nix_rx_action action;
int blkaddr, index, bank;
struct rvu_pfvf *pfvf;
+ u64 reg;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
- *(u64 *)&action = rvu_read64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
+ if (is_cn20k(rvu->pdev))
+ reg = NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0);
+ else
+ reg = NPC_AF_MCAMEX_BANKX_ACTION(index, bank);
+
+ *(u64 *)&action = rvu_read64(rvu, blkaddr, reg);
/* Ignore if no action was set earlier */
if (!*(u64 *)&action)
return;
action.index = group;
action.flow_key_alg = alg_idx;
- rvu_write64(rvu, blkaddr,
- NPC_AF_MCAMEX_BANKX_ACTION(index, bank), *(u64 *)&action);
+ rvu_write64(rvu, blkaddr, reg, *(u64 *)&action);
+ /* update the VF flow rule action with the VF default entry action */
+ if (mcam_index < 0)
+ npc_update_vf_flow_entry(rvu, mcam, blkaddr, pcifunc,
+ *(u64 *)&action);
/* update the action change in default rule */
pfvf = rvu_get_pfvf(rvu, pcifunc);
int cntr;
u64 cfg;
- /* Actual number of MCAM entries vary by entry size */
cfg = (rvu_read64(rvu, blkaddr,
NPC_AF_INTFX_KEX_CFG(0)) >> 32) & 0x07;
- mcam->total_entries = (mcam->banks / BIT_ULL(cfg)) * mcam->banksize;
mcam->keysize = cfg;
/* Number of banks combined per MCAM entry */
if (is_cn20k(rvu->pdev)) {
+ /* In cn20k, x2 entries is allowed for x4 profile.
+ * set total_entries as 8192 * 2 and key size as x2.
+ */
+ mcam->total_entries = mcam->banks * mcam->banksize;
if (cfg == NPC_MCAM_KEY_X2)
mcam->banks_per_entry = 1;
else
mcam->banks_per_entry = 2;
+
+ rsvd = 0;
} else {
+ mcam->total_entries = (mcam->banks / BIT_ULL(cfg)) *
+ mcam->banksize;
+
if (cfg == NPC_MCAM_KEY_X4)
mcam->banks_per_entry = 4;
else if (cfg == NPC_MCAM_KEY_X2)
mcam->banks_per_entry = 2;
else
mcam->banks_per_entry = 1;
- }
- /* Reserve one MCAM entry for each of the NIX LF to
- * guarantee space to install default matching DMAC rule.
- * Also reserve 2 MCAM entries for each PF for default
- * channel based matching or 'bcast & promisc' matching to
- * support BCAST and PROMISC modes of operation for PFs.
- * PF0 is excluded.
- */
- rsvd = (nixlf_count * RSVD_MCAM_ENTRIES_PER_NIXLF) +
- ((rvu->hw->total_pfs - 1) * RSVD_MCAM_ENTRIES_PER_PF);
- if (mcam->total_entries <= rsvd) {
- dev_warn(rvu->dev,
- "Insufficient NPC MCAM size %d for pkt I/O, exiting\n",
- mcam->total_entries);
- return -ENOMEM;
+ /* Reserve one MCAM entry for each of the NIX LF to
+ * guarantee space to install default matching DMAC rule.
+ * Also reserve 2 MCAM entries for each PF for default
+ * channel based matching or 'bcast & promisc' matching to
+ * support BCAST and PROMISC modes of operation for PFs.
+ * PF0 is excluded.
+ */
+ rsvd = (nixlf_count * RSVD_MCAM_ENTRIES_PER_NIXLF) +
+ ((rvu->hw->total_pfs - 1) * RSVD_MCAM_ENTRIES_PER_PF);
+ if (mcam->total_entries <= rsvd) {
+ dev_warn(rvu->dev,
+ "Insufficient NPC MCAM size %d for pkt I/O, exiting\n",
+ mcam->total_entries);
+ return -ENOMEM;
+ }
}
mcam->bmap_entries = mcam->total_entries - rsvd;
- mcam->nixlf_offset = mcam->bmap_entries;
- mcam->pf_offset = mcam->nixlf_offset + nixlf_count;
+ /* cn20k does not need offsets to alloc mcam entries */
+ if (!is_cn20k(rvu->pdev)) {
+ mcam->nixlf_offset = mcam->bmap_entries;
+ mcam->pf_offset = mcam->nixlf_offset + nixlf_count;
+ }
/* Allocate bitmaps for managing MCAM entries */
mcam->bmap = bitmap_zalloc(mcam->bmap_entries, GFP_KERNEL);
* allocations and another 1/8th at the top for high priority
* allocations.
*/
- mcam->lprio_count = mcam->bmap_entries / 8;
- if (mcam->lprio_count > BITS_PER_LONG)
- mcam->lprio_count = round_down(mcam->lprio_count,
- BITS_PER_LONG);
- mcam->lprio_start = mcam->bmap_entries - mcam->lprio_count;
- mcam->hprio_count = mcam->lprio_count;
- mcam->hprio_end = mcam->hprio_count;
+ if (!is_cn20k(rvu->pdev)) {
+ mcam->lprio_count = mcam->bmap_entries / 8;
+ if (mcam->lprio_count > BITS_PER_LONG)
+ mcam->lprio_count = round_down(mcam->lprio_count,
+ BITS_PER_LONG);
+ mcam->lprio_start = mcam->bmap_entries - mcam->lprio_count;
+ mcam->hprio_count = mcam->lprio_count;
+ mcam->hprio_end = mcam->hprio_count;
+ }
/* Allocate bitmap for managing MCAM counters and memory
* for saving counter to RVU PFFUNC allocation mapping.
struct npc_mcam *mcam = &rvu->hw->mcam;
struct rvu_hwinfo *hw = rvu->hw;
u64 nibble_ena, rx_kex, tx_kex;
- u64 *keyx_cfg;
+ u64 *keyx_cfg, reg;
u8 intf;
if (is_cn20k(rvu->pdev)) {
keyx_cfg = mkex_extr->keyx_cfg;
- goto skip_miss_cntr;
+ } else {
+ keyx_cfg = mkex->keyx_cfg;
+ /* Reserve last counter for MCAM RX miss action which is set to
+ * drop packet. This way we will know how many pkts didn't
+ * match any MCAM entry.
+ */
+ mcam->counters.max--;
+ mcam->rx_miss_act_cntr = mcam->counters.max;
}
- keyx_cfg = mkex->keyx_cfg;
-
- /* Reserve last counter for MCAM RX miss action which is set to
- * drop packet. This way we will know how many pkts didn't match
- * any MCAM entry.
- */
- mcam->counters.max--;
- mcam->rx_miss_act_cntr = mcam->counters.max;
-
-skip_miss_cntr:
rx_kex = keyx_cfg[NIX_INTF_RX];
tx_kex = keyx_cfg[NIX_INTF_TX];
rx_kex);
if (is_cn20k(rvu->pdev))
- continue;
+ reg = NPC_AF_INTFX_MISS_ACTX(intf, 0);
+ else
+ reg = NPC_AF_INTFX_MISS_ACT(intf);
/* If MCAM lookup doesn't result in a match, drop the received
* packet. And map this action to a counter to count dropped
* packets.
*/
- rvu_write64(rvu, blkaddr,
- NPC_AF_INTFX_MISS_ACT(intf), NIX_RX_ACTIONOP_DROP);
+ rvu_write64(rvu, blkaddr, reg, NIX_RX_ACTIONOP_DROP);
+
+ if (is_cn20k(rvu->pdev))
+ continue;
/* NPC_AF_INTFX_MISS_STAT_ACT[14:12] - counter[11:9]
* NPC_AF_INTFX_MISS_STAT_ACT[8:0] - counter[8:0]
rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(intf),
tx_kex);
+ if (is_cn20k(rvu->pdev))
+ reg = NPC_AF_INTFX_MISS_ACTX(intf, 0);
+ else
+ reg = NPC_AF_INTFX_MISS_ACT(intf);
+
/* Set TX miss action to UCAST_DEFAULT i.e
* transmit the packet on NIX LF SQ's default channel.
*/
- rvu_write64(rvu, blkaddr,
- NPC_AF_INTFX_MISS_ACT(intf),
- NIX_TX_ACTIONOP_UCAST_DEFAULT);
+ rvu_write64(rvu, blkaddr, reg, NIX_TX_ACTIONOP_UCAST_DEFAULT);
}
}
/* Set mapping and increment counter's refcnt */
mcam->entry2cntr_map[entry] = cntr;
mcam->cntr_refcnt[cntr]++;
+
+ if (is_cn20k(rvu->pdev))
+ return;
+
/* Enable stats */
rvu_write64(rvu, blkaddr,
NPC_AF_MCAMEX_BANKX_STAT_ACT(index, bank),
int blkaddr, u16 pcifunc)
{
u16 index, cntr;
+ int rc;
/* Scan all MCAM entries and free the ones mapped to 'pcifunc' */
for (index = 0; index < mcam->bmap_entries; index++) {
blkaddr, index,
cntr);
mcam->entry2target_pffunc[index] = 0x0;
+ if (is_cn20k(rvu->pdev)) {
+ rc = npc_cn20k_idx_free(rvu, &index, 1);
+ if (rc)
+ dev_err(rvu->dev,
+ "Failed to free mcam idx=%u pcifunc=%#x\n",
+ index, pcifunc);
+ }
}
}
}
struct npc_mcam_alloc_entry_req *req,
struct npc_mcam_alloc_entry_rsp *rsp)
{
+ struct rvu_hwinfo *hw = container_of(mcam, struct rvu_hwinfo, mcam);
u16 entry_list[NPC_MAX_NONCONTIG_ENTRIES];
u16 fcnt, hp_fcnt, lp_fcnt;
+ struct rvu *rvu = hw->rvu;
u16 start, end, index;
int entry, next_start;
bool reverse = false;
unsigned long *bmap;
+ int ret, limit = 0;
u16 max_contig;
+ if (!is_cn20k(rvu->pdev))
+ goto not_cn20k;
+
+ /* The below table is being followed during allocation,
+ *
+ * 1. ref_entry == 0 && prio == HIGH && count == 1 : user wants to
+ * allocate 0th index
+ * 2. ref_entry == 0 && prio == HIGH && count > 1 : Invalid request
+ * 3. ref_entry == 0 && prio == LOW && count >= 1 : limit = 0
+ * 4. ref_entry != 0 && prio == HIGH && count >= 1 : limit = 0
+ * 5. ref_entry != 0 && prio == LOW && count >=1 : limit = Max
+ * (X2 2*8192, X4 8192)
+ */
+ if (req->ref_entry && req->ref_prio == NPC_MCAM_LOWER_PRIO) {
+ if (req->kw_type == NPC_MCAM_KEY_X2)
+ limit = 2 * mcam->bmap_entries;
+ else
+ limit = mcam->bmap_entries;
+ }
+
+ ret = npc_cn20k_ref_idx_alloc(rvu, pcifunc, req->kw_type,
+ req->ref_prio, rsp->entry_list,
+ req->ref_entry, limit,
+ req->contig, req->count);
+
+ if (ret) {
+ rsp->count = 0;
+ return NPC_MCAM_ALLOC_FAILED;
+ }
+
+ rsp->count = req->count;
+ if (req->contig)
+ rsp->entry = rsp->entry_list[0];
+
+ /* cn20k, entries allocation algorithm is different.
+ * This common API updates some bitmap on usage etc, which
+ * will be used by other functions. So update those for
+ * cn20k as well.
+ */
+
+ mutex_lock(&mcam->lock);
+ /* Mark the allocated entries as used and set nixlf mapping */
+ for (entry = 0; entry < rsp->count; entry++) {
+ index = rsp->entry_list[entry];
+ npc_mcam_set_bit(mcam, index);
+ mcam->entry2pfvf_map[index] = pcifunc;
+ mcam->entry2cntr_map[index] = NPC_MCAM_INVALID_MAP;
+ }
+
+ /* cn20k, free count is provided thru different mbox message.
+ * one counter to indicate free x2 slots and free x4 slots
+ * does not provide any useful information to the user.
+ */
+ rsp->free_count = -1;
+ mutex_unlock(&mcam->lock);
+
+ return 0;
+
+not_cn20k:
mutex_lock(&mcam->lock);
/* Check if there are any free entries */
npc_unmap_mcam_entry_and_cntr(rvu, mcam, blkaddr,
req->entry, cntr);
+ if (is_cn20k(rvu->pdev)) {
+ rc = npc_cn20k_idx_free(rvu, &req->entry, 1);
+ if (rc)
+ dev_err(rvu->dev,
+ "Failed to free index=%u\n",
+ req->entry);
+ }
+
goto exit;
free_all: