#include "cn20k/npc.h"
#include "cn20k/reg.h"
+#include "rvu_npc.h"
static struct npc_priv_t npc_priv = {
.num_banks = MAX_NUM_BANKS,
[NPC_MCAM_KEY_X4] = "X4",
};
+static void npc_config_kpmcam(struct rvu *rvu, int blkaddr,
+ const struct npc_kpu_profile_cam *kpucam,
+ int kpm, int entry)
+{
+ struct npc_kpu_cam cam0 = {0};
+ struct npc_kpu_cam cam1 = {0};
+
+ cam1.state = kpucam->state & kpucam->state_mask;
+ cam1.dp0_data = kpucam->dp0 & kpucam->dp0_mask;
+ cam1.dp1_data = kpucam->dp1 & kpucam->dp1_mask;
+ cam1.dp2_data = kpucam->dp2 & kpucam->dp2_mask;
+
+ cam0.state = ~kpucam->state & kpucam->state_mask;
+ cam0.dp0_data = ~kpucam->dp0 & kpucam->dp0_mask;
+ cam0.dp1_data = ~kpucam->dp1 & kpucam->dp1_mask;
+ cam0.dp2_data = ~kpucam->dp2 & kpucam->dp2_mask;
+
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRYX_CAMX(kpm, entry, 0), *(u64 *)&cam0);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRYX_CAMX(kpm, entry, 1), *(u64 *)&cam1);
+}
+
+static void
+npc_config_kpmaction(struct rvu *rvu, int blkaddr,
+ const struct npc_kpu_profile_action *kpuaction,
+ int kpm, int entry, bool pkind)
+{
+ struct npc_kpm_action0 action0 = {0};
+ struct npc_kpu_action1 action1 = {0};
+ u64 reg;
+
+ action1.errlev = kpuaction->errlev;
+ action1.errcode = kpuaction->errcode;
+ action1.dp0_offset = kpuaction->dp0_offset;
+ action1.dp1_offset = kpuaction->dp1_offset;
+ action1.dp2_offset = kpuaction->dp2_offset;
+
+ if (pkind)
+ reg = NPC_AF_PKINDX_ACTION1(entry);
+ else
+ reg = NPC_AF_KPMX_ENTRYX_ACTION1(kpm, entry);
+
+ rvu_write64(rvu, blkaddr, reg, *(u64 *)&action1);
+
+ action0.byp_count = kpuaction->bypass_count & 0x7;
+ action0.capture_ena = kpuaction->cap_ena & 1;
+ action0.parse_done = kpuaction->parse_done & 1;
+ action0.next_state = kpuaction->next_state & 0xf;
+ action0.capture_lid = kpuaction->lid & 0x7;
+
+ /* Parser functionality will work correctly even though
+ * upper flag bits are silently discarded
+ */
+ action0.capture_ltype = kpuaction->ltype & 0xf;
+ action0.capture_flags = kpuaction->flags & 0xf;
+ action0.ptr_advance = kpuaction->ptr_advance;
+
+ action0.var_len_offset = kpuaction->offset;
+ action0.var_len_mask = kpuaction->mask;
+ action0.var_len_right = kpuaction->right & 1;
+ action0.var_len_shift = kpuaction->shift & 1;
+
+ if (pkind)
+ reg = NPC_AF_PKINDX_ACTION0(entry);
+ else
+ reg = NPC_AF_KPMX_ENTRYX_ACTION0(kpm, entry);
+
+ rvu_write64(rvu, blkaddr, reg, *(u64 *)&action0);
+}
+
+static void
+npc_program_single_kpm_profile(struct rvu *rvu, int blkaddr,
+ int kpm, int start_entry,
+ const struct npc_kpu_profile *profile)
+{
+ int entry, num_entries, max_entries;
+ u64 idx;
+
+ if (profile->cam_entries != profile->action_entries) {
+ dev_err(rvu->dev,
+ "kpm%d: CAM and action entries [%d != %d] not equal\n",
+ kpm, profile->cam_entries, profile->action_entries);
+
+ WARN(1, "Fatal error\n");
+ return;
+ }
+
+ max_entries = rvu->hw->npc_kpu_entries / 2;
+ entry = start_entry;
+ /* Program CAM match entries for previous kpm extracted data */
+ num_entries = min_t(int, profile->cam_entries, max_entries);
+ for (idx = 0; entry < num_entries + start_entry; entry++, idx++)
+ npc_config_kpmcam(rvu, blkaddr, &profile->cam[idx],
+ kpm, entry);
+
+ entry = start_entry;
+ /* Program this kpm's actions */
+ num_entries = min_t(int, profile->action_entries, max_entries);
+ for (idx = 0; entry < num_entries + start_entry; entry++, idx++)
+ npc_config_kpmaction(rvu, blkaddr, &profile->action[idx],
+ kpm, entry, false);
+}
+
+static void
+npc_enable_kpm_entry(struct rvu *rvu, int blkaddr, int kpm, int num_entries)
+{
+ u64 entry_mask;
+
+ entry_mask = npc_enable_mask(num_entries);
+ /* Disable first KPU_MAX_CST_ENT entries for built-in profile */
+ if (!rvu->kpu.custom)
+ entry_mask |= GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 0), entry_mask);
+ if (num_entries <= 64) {
+ /* Disable all the entries in W1, W2 and W3 */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 1),
+ npc_enable_mask(0));
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 2),
+ npc_enable_mask(0));
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 3),
+ npc_enable_mask(0));
+ return;
+ }
+
+ num_entries = num_entries - 64;
+ entry_mask = npc_enable_mask(num_entries);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 1), entry_mask);
+ if (num_entries <= 64) {
+ /* Disable all the entries in W2 and W3 */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 2),
+ npc_enable_mask(0));
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 3),
+ npc_enable_mask(0));
+ return;
+ }
+
+ num_entries = num_entries - 64;
+ entry_mask = npc_enable_mask(num_entries);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 2), entry_mask);
+ if (num_entries <= 64) {
+ /* Disable all the entries in W3 */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 3),
+ npc_enable_mask(0));
+ return;
+ }
+
+ num_entries = num_entries - 64;
+ entry_mask = npc_enable_mask(num_entries);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(kpm, 3), entry_mask);
+}
+
+#define KPU_OFFSET 8
+static void npc_program_kpm_profile(struct rvu *rvu, int blkaddr, int num_kpms)
+{
+ const struct npc_kpu_profile *profile1, *profile2;
+ int idx, total_cam_entries;
+
+ for (idx = 0; idx < num_kpms; idx++) {
+ profile1 = &rvu->kpu.kpu[idx];
+ npc_program_single_kpm_profile(rvu, blkaddr, idx, 0, profile1);
+ profile2 = &rvu->kpu.kpu[idx + KPU_OFFSET];
+ npc_program_single_kpm_profile(rvu, blkaddr, idx,
+ profile1->cam_entries,
+ profile2);
+ total_cam_entries = profile1->cam_entries +
+ profile2->cam_entries;
+ npc_enable_kpm_entry(rvu, blkaddr, idx, total_cam_entries);
+ rvu_write64(rvu, blkaddr, NPC_AF_KPMX_PASS2_OFFSET(idx),
+ profile1->cam_entries);
+ /* Enable the KPUs associated with this KPM */
+ rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x01);
+ rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx + KPU_OFFSET),
+ 0x01);
+ }
+}
+
+void npc_cn20k_parser_profile_init(struct rvu *rvu, int blkaddr)
+{
+ struct rvu_hwinfo *hw = rvu->hw;
+ int num_pkinds, idx;
+
+ /* Disable all KPMs and their entries */
+ for (idx = 0; idx < hw->npc_kpms; idx++) {
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(idx, 0), ~0ULL);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(idx, 1), ~0ULL);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(idx, 2), ~0ULL);
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_KPMX_ENTRY_DISX(idx, 3), ~0ULL);
+ }
+
+ for (idx = 0; idx < hw->npc_kpus; idx++)
+ rvu_write64(rvu, blkaddr, NPC_AF_KPUX_CFG(idx), 0x00);
+
+ /* Load and customize KPU profile. */
+ npc_load_kpu_profile(rvu);
+
+ /* Configure KPU and KPM mapping for second pass */
+ rvu_write64(rvu, blkaddr, NPC_AF_KPM_PASS2_CFG, 0x76543210);
+
+ /* First program IKPU profile i.e PKIND configs.
+ * Check HW max count to avoid configuring junk or
+ * writing to unsupported CSR addresses.
+ */
+ num_pkinds = rvu->kpu.pkinds;
+ num_pkinds = min_t(int, hw->npc_pkinds, num_pkinds);
+
+ for (idx = 0; idx < num_pkinds; idx++)
+ npc_config_kpmaction(rvu, blkaddr, &rvu->kpu.ikpu[idx],
+ 0, idx, true);
+
+ /* Program KPM CAM and Action profiles */
+ npc_program_kpm_profile(rvu, blkaddr, hw->npc_kpms);
+}
+
struct npc_priv_t *npc_priv_get(void)
{
return &npc_priv;
#include "npc_profile.h"
#include "rvu_npc_hash.h"
#include "cn20k/npc.h"
+#include "rvu_npc.h"
#define RSVD_MCAM_ENTRIES_PER_PF 3 /* Broadcast, Promisc and AllMulticast */
#define RSVD_MCAM_ENTRIES_PER_NIXLF 1 /* Ucast for LFs */
iounmap(mkex_prfl_addr);
}
-static void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
- const struct npc_kpu_profile_action *kpuaction,
- int kpu, int entry, bool pkind)
+void npc_config_kpuaction(struct rvu *rvu, int blkaddr,
+ const struct npc_kpu_profile_action *kpuaction,
+ int kpu, int entry, bool pkind)
{
struct npc_kpu_action0 action0 = {0};
struct npc_kpu_action1 action1 = {0};
NPC_AF_KPUX_ENTRYX_CAMX(kpu, entry, 1), *(u64 *)&cam1);
}
-static inline u64 enable_mask(int count)
+u64 npc_enable_mask(int count)
{
return (((count) < 64) ? ~(BIT_ULL(count) - 1) : (0x00ULL));
}
/* Enable all programmed entries */
num_entries = min_t(int, profile->action_entries, profile->cam_entries);
- entry_mask = enable_mask(num_entries);
+ entry_mask = npc_enable_mask(num_entries);
/* Disable first KPU_MAX_CST_ENT entries for built-in profile */
if (!rvu->kpu.custom)
entry_mask |= GENMASK_ULL(KPU_MAX_CST_ENT - 1, 0);
if (num_entries > 64) {
rvu_write64(rvu, blkaddr,
NPC_AF_KPUX_ENTRY_DISX(kpu, 1),
- enable_mask(num_entries - 64));
+ npc_enable_mask(num_entries - 64));
}
/* Enable this KPU */
return ret;
}
-static void npc_load_kpu_profile(struct rvu *rvu)
+void npc_load_kpu_profile(struct rvu *rvu)
{
struct npc_kpu_profile_adapter *profile = &rvu->kpu;
const char *kpu_profile = rvu->kpu_pfl_name;
mcam->keysize = cfg;
/* Number of banks combined per MCAM entry */
- 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;
+ if (is_cn20k(rvu->pdev)) {
+ if (cfg == NPC_MCAM_KEY_X2)
+ mcam->banks_per_entry = 1;
+ else
+ mcam->banks_per_entry = 2;
+ } else {
+ 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.
hw->npc_pkinds = (npc_const1 >> 12) & 0xFFULL;
hw->npc_kpu_entries = npc_const1 & 0xFFFULL;
hw->npc_kpus = (npc_const >> 8) & 0x1FULL;
+ /* For Cn20k silicon, check if enhanced parser
+ * is present, then set the NUM_KPMS = NUM_KPUS / 2 and
+ * number of LDATA extractors per KEX.
+ */
+ if (is_cn20k(rvu->pdev)) {
+ if (!(npc_const1 & BIT_ULL(62))) {
+ WARN(1, "Enhanced parser is not supported\n");
+ return;
+ }
+ hw->npc_kpms = hw->npc_kpus / 2;
+ hw->npc_kex_extr = (npc_const1 >> 36) & 0x3FULL;
+ }
+
hw->npc_intfs = npc_const & 0xFULL;
hw->npc_counters = (npc_const >> 48) & 0xFFFFULL;
return -ENOMEM;
/* Configure KPU profile */
- npc_parser_profile_init(rvu, blkaddr);
+ if (is_cn20k(rvu->pdev))
+ npc_cn20k_parser_profile_init(rvu, blkaddr);
+ else
+ npc_parser_profile_init(rvu, blkaddr);
/* Config Outer L2, IPv4's NPC layer info */
rvu_write64(rvu, blkaddr, NPC_AF_PCK_DEF_OL2,