kex_cap.bit.dip_addr = npc_is_kex_enabled(npc, NPC_LID_LC, NPC_LT_LC_IP,
14 * 8, 4 * 8);
/* IP6 SIP: offset 8B, len 16B */
- kex_cap.bit.sip6_addr = npc_is_kex_enabled(
- npc, NPC_LID_LC, NPC_LT_LC_IP6, 8 * 8, 16 * 8);
+ kex_cap.bit.sip6_addr = npc_is_kex_enabled(npc, NPC_LID_LC, NPC_LT_LC_IP6,
+ 8 * 8, 16 * 8);
/* IP6 DIP: offset 24B, len 16B */
kex_cap.bit.dip6_addr = npc_is_kex_enabled(
npc, NPC_LID_LC, NPC_LT_LC_IP6, 24 * 8, 16 * 8);
/* Custom L3 frame: varied offset and lengths */
kex_cap.bit.custom_l3 =
npc_is_kex_enabled(npc, NPC_LID_LC, NPC_LT_LC_CUSTOM0, 0, 0);
- kex_cap.bit.custom_l3 |=
- npc_is_kex_enabled(npc, NPC_LID_LC, NPC_LT_LC_CUSTOM1, 0, 0);
+ kex_cap.bit.custom_l3 |= (uint64_t)npc_is_kex_enabled(npc, NPC_LID_LC,
+ NPC_LT_LC_CUSTOM1, 0, 0);
/* SCTP sport : offset 0B, len 2B */
kex_cap.bit.sctp_sport = npc_is_kex_enabled(
npc, NPC_LID_LD, NPC_LT_LD_SCTP, 0 * 8, 2 * 8);
return rc;
}
+static void
+npc_mcam_set_channel(struct roc_npc_flow *flow,
+ struct npc_mcam_write_entry_req *req, uint16_t channel,
+ uint16_t chan_mask, bool is_second_pass)
+{
+ uint16_t chan = 0, mask = 0;
+
+ req->entry_data.kw[0] &= ~(GENMASK(11, 0));
+ req->entry_data.kw_mask[0] &= ~(GENMASK(11, 0));
+ flow->mcam_data[0] &= ~(GENMASK(11, 0));
+ flow->mcam_mask[0] &= ~(GENMASK(11, 0));
+
+ if (is_second_pass) {
+ chan = (channel | NIX_CHAN_CPT_CH_START);
+ mask = (chan_mask | NIX_CHAN_CPT_CH_START);
+ } else {
+ /*
+ * Clear bits 10 & 11 corresponding to CPT
+ * channel. By default, rules should match
+ * both first pass packets and second pass
+ * packets from CPT.
+ */
+ chan = (channel & NIX_CHAN_CPT_X2P_MASK);
+ mask = (chan_mask & NIX_CHAN_CPT_X2P_MASK);
+ }
+
+ req->entry_data.kw[0] |= (uint64_t)chan;
+ req->entry_data.kw_mask[0] |= (uint64_t)mask;
+ flow->mcam_data[0] |= (uint64_t)chan;
+ flow->mcam_mask[0] |= (uint64_t)mask;
+}
+
int
npc_mcam_alloc_and_write(struct npc *npc, struct roc_npc_flow *flow,
struct npc_parse_state *pst)
if (flow->nix_intf == NIX_INTF_RX) {
if (inl_dev && inl_dev->is_multi_channel &&
(flow->npc_action & NIX_RX_ACTIONOP_UCAST_IPSEC)) {
- req->entry_data.kw[0] |= (uint64_t)inl_dev->channel;
- req->entry_data.kw_mask[0] |=
- (uint64_t)inl_dev->chan_mask;
pf_func = nix_inl_dev_pffunc_get();
req->entry_data.action &= ~(GENMASK(19, 4));
req->entry_data.action |= (uint64_t)pf_func << 4;
-
flow->npc_action &= ~(GENMASK(19, 4));
flow->npc_action |= (uint64_t)pf_func << 4;
- flow->mcam_data[0] |= (uint64_t)inl_dev->channel;
- flow->mcam_mask[0] |= (uint64_t)inl_dev->chan_mask;
+
+ npc_mcam_set_channel(flow, req, inl_dev->channel,
+ inl_dev->chan_mask, false);
+ } else if (npc->is_sdp_link) {
+ npc_mcam_set_channel(flow, req, npc->sdp_channel,
+ npc->sdp_channel_mask,
+ pst->is_second_pass_rule);
} else {
- req->entry_data.kw[0] |= (uint64_t)npc->channel;
- req->entry_data.kw_mask[0] |= (BIT_ULL(12) - 1);
- flow->mcam_data[0] |= (uint64_t)npc->channel;
- flow->mcam_mask[0] |= (BIT_ULL(12) - 1);
+ npc_mcam_set_channel(flow, req, npc->channel,
+ (BIT_ULL(12) - 1),
+ pst->is_second_pass_rule);
}
} else {
uint16_t pf_func = (flow->npc_action >> 4) & 0xffff;
return 0;
}
+static void
+npc_set_vlan_ltype(struct npc_parse_state *pst)
+{
+ uint64_t val, mask;
+ uint8_t lb_offset;
+
+ lb_offset =
+ __builtin_popcount(pst->npc->keyx_supp_nmask[pst->nix_intf] &
+ ((1ULL << NPC_LTYPE_LB_OFFSET) - 1));
+ lb_offset *= 4;
+
+ mask = ~((0xfULL << lb_offset));
+ pst->flow->mcam_data[0] &= mask;
+ pst->flow->mcam_mask[0] &= mask;
+ /* NPC_LT_LB_CTAG: 0b0010, NPC_LT_LB_STAG_QINQ: 0b0011
+ * Set LB layertype/mask as 0b0010/0b1110 to match both.
+ */
+ val = ((uint64_t)(NPC_LT_LB_CTAG & NPC_LT_LB_STAG_QINQ)) << lb_offset;
+ pst->flow->mcam_data[0] |= val;
+ pst->flow->mcam_mask[0] |= (0xeULL << lb_offset);
+}
+
+static void
+npc_set_ipv6ext_ltype_mask(struct npc_parse_state *pst)
+{
+ uint8_t lc_offset, lcflag_offset;
+ uint64_t val, mask;
+
+ lc_offset =
+ __builtin_popcount(pst->npc->keyx_supp_nmask[pst->nix_intf] &
+ ((1ULL << NPC_LTYPE_LC_OFFSET) - 1));
+ lc_offset *= 4;
+
+ mask = ~((0xfULL << lc_offset));
+ pst->flow->mcam_data[0] &= mask;
+ pst->flow->mcam_mask[0] &= mask;
+ /* NPC_LT_LC_IP6: 0b0100, NPC_LT_LC_IP6_EXT: 0b0101
+ * Set LC layertype/mask as 0b0100/0b1110 to match both.
+ */
+ val = ((uint64_t)(NPC_LT_LC_IP6 & NPC_LT_LC_IP6_EXT)) << lc_offset;
+ pst->flow->mcam_data[0] |= val;
+ pst->flow->mcam_mask[0] |= (0xeULL << lc_offset);
+
+ /* If LC LFLAG is non-zero, set the LC LFLAG mask to 0xF. In general
+ * case flag mask is set same as the value in data. For example, to
+ * match 3 VLANs, flags have to match a range of values. But, for IPv6
+ * extended attributes matching, we need an exact match. Hence, set the
+ * mask as 0xF. This is done only if LC LFLAG value is non-zero,
+ * because for AH and ESP, LC LFLAG is zero and we don't want to match
+ * zero in LFLAG.
+ */
+ lcflag_offset =
+ __builtin_popcount(pst->npc->keyx_supp_nmask[pst->nix_intf] &
+ ((1ULL << NPC_LFLAG_LC_OFFSET) - 1));
+ lcflag_offset *= 4;
+
+ mask = (0xfULL << lcflag_offset);
+ val = pst->flow->mcam_data[0] & mask;
+ if (val)
+ pst->flow->mcam_mask[0] |= mask;
+}
+
int
npc_program_mcam(struct npc *npc, struct npc_parse_state *pst, bool mcam_alloc)
{
if (layer_info) {
for (idx = 0; idx <= 2; idx++) {
if (layer_info & (1 << idx)) {
- if (idx == 2)
+ if (idx == 2) {
data = lt;
- else if (idx == 1)
+ mask = 0xf;
+ } else if (idx == 1) {
data = ((flags >> 4) & 0xf);
- else
+ mask = ((flags >> 4) & 0xf);
+ } else {
data = (flags & 0xf);
+ mask = (flags & 0xf);
+ }
if (data_off >= 64) {
data_off = 0;
}
key_data[index] |=
((uint64_t)data << data_off);
- mask = 0xf;
+
if (lt == 0)
mask = 0;
key_mask[index] |=
memcpy(pst->flow->mcam_data, key_data, key_len);
memcpy(pst->flow->mcam_mask, key_mask, key_len);
- if (pst->is_vf) {
+ if (pst->set_vlan_ltype_mask)
+ npc_set_vlan_ltype(pst);
+
+ if (pst->set_ipv6ext_ltype_mask)
+ npc_set_ipv6ext_ltype_mask(pst);
+
+ if (pst->is_vf && pst->flow->nix_intf == NIX_INTF_RX) {
(void)mbox_alloc_msg_npc_read_base_steer_rule(npc->mbox);
rc = mbox_process_msg(npc->mbox, (void *)&base_rule_rsp);
if (rc) {
return 0;
}
+int
+npc_flow_enable_all_entries(struct npc *npc, bool enable)
+{
+ struct npc_flow_list *list;
+ struct roc_npc_flow *flow;
+ int rc = 0, idx;
+
+ /* Free any MCAM counters and delete flow list */
+ for (idx = 0; idx < npc->flow_max_priority; idx++) {
+ list = &npc->flow_list[idx];
+ TAILQ_FOREACH(flow, list, next) {
+ flow->enable = enable;
+ rc = npc_mcam_write_entry(npc, flow);
+ if (rc)
+ return rc;
+ }
+ }
+ return rc;
+}
+
int
npc_flow_free_all_resources(struct npc *npc)
{