Skip to content

Commit

Permalink
octeontx2-af: Allow mkex profile without DMAC and add L2M/L2B header …
Browse files Browse the repository at this point in the history
…extraction support

[ Upstream commit 2cee640 ]

1. It is possible to have custom mkex profiles which do not extract
DMAC at all into the key. Hence allow mkex profiles which do not
have DMAC to be loaded into MCAM hardware. This patch also adds
debugging prints needed to identify profiles with wrong
configuration.

2. If a mkex profile set "l2l3mb" field for Rx interface,
then Rx multicast and broadcast entry should be configured.

Signed-off-by: Suman Ghosh <sumang@marvell.com>
Link: https://lore.kernel.org/r/20221031090856.1404303-1-sumang@marvell.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Stable-dep-of: 406bed1 ("octeontx2-af: Update/Fix NPC field hash extract feature")
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Suman Ghosh authored and gregkh committed May 17, 2023
1 parent 14504aa commit bd9234d
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 18 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/marvell/octeontx2/af/npc.h
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ struct rvu_npc_mcam_rule {
bool vfvlan_cfg;
u16 chan;
u16 chan_mask;
u8 lxmb;
};

#endif /* NPC_H */
6 changes: 6 additions & 0 deletions drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2759,6 +2759,12 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
for_each_set_bit(bit, (unsigned long *)&rule->features, 64) {
seq_printf(s, "\t%s ", npc_get_field_name(bit));
switch (bit) {
case NPC_LXMB:
if (rule->lxmb == 1)
seq_puts(s, "\tL2M nibble is set\n");
else
seq_puts(s, "\tL2B nibble is set\n");
break;
case NPC_DMAC:
seq_printf(s, "%pM ", rule->packet.dmac);
seq_printf(s, "mask %pM\n", rule->mask.dmac);
Expand Down
81 changes: 63 additions & 18 deletions drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static const char * const npc_flow_names[] = {
[NPC_DPORT_UDP] = "udp destination port",
[NPC_SPORT_SCTP] = "sctp source port",
[NPC_DPORT_SCTP] = "sctp destination port",
[NPC_LXMB] = "Mcast/Bcast header ",
[NPC_UNKNOWN] = "unknown",
};

Expand Down Expand Up @@ -340,8 +341,10 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
vlan_tag2 = &key_fields[NPC_VLAN_TAG2];

/* if key profile programmed does not extract Ethertype at all */
if (!etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws)
if (!etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws) {
dev_err(rvu->dev, "mkex: Ethertype is not extracted.\n");
goto vlan_tci;
}

/* if key profile programmed extracts Ethertype from one layer */
if (etype_ether->nr_kws && !etype_tag1->nr_kws && !etype_tag2->nr_kws)
Expand All @@ -354,35 +357,45 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
/* if key profile programmed extracts Ethertype from multiple layers */
if (etype_ether->nr_kws && etype_tag1->nr_kws) {
for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
if (etype_ether->kw_mask[i] != etype_tag1->kw_mask[i])
if (etype_ether->kw_mask[i] != etype_tag1->kw_mask[i]) {
dev_err(rvu->dev, "mkex: Etype pos is different for untagged and tagged pkts.\n");
goto vlan_tci;
}
}
key_fields[NPC_ETYPE] = *etype_tag1;
}
if (etype_ether->nr_kws && etype_tag2->nr_kws) {
for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
if (etype_ether->kw_mask[i] != etype_tag2->kw_mask[i])
if (etype_ether->kw_mask[i] != etype_tag2->kw_mask[i]) {
dev_err(rvu->dev, "mkex: Etype pos is different for untagged and double tagged pkts.\n");
goto vlan_tci;
}
}
key_fields[NPC_ETYPE] = *etype_tag2;
}
if (etype_tag1->nr_kws && etype_tag2->nr_kws) {
for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
if (etype_tag1->kw_mask[i] != etype_tag2->kw_mask[i])
if (etype_tag1->kw_mask[i] != etype_tag2->kw_mask[i]) {
dev_err(rvu->dev, "mkex: Etype pos is different for tagged and double tagged pkts.\n");
goto vlan_tci;
}
}
key_fields[NPC_ETYPE] = *etype_tag2;
}

/* check none of higher layers overwrite Ethertype */
start_lid = key_fields[NPC_ETYPE].layer_mdata.lid + 1;
if (npc_check_overlap(rvu, blkaddr, NPC_ETYPE, start_lid, intf))
if (npc_check_overlap(rvu, blkaddr, NPC_ETYPE, start_lid, intf)) {
dev_err(rvu->dev, "mkex: Ethertype is overwritten by higher layers.\n");
goto vlan_tci;
}
*features |= BIT_ULL(NPC_ETYPE);
vlan_tci:
/* if key profile does not extract outer vlan tci at all */
if (!vlan_tag1->nr_kws && !vlan_tag2->nr_kws)
if (!vlan_tag1->nr_kws && !vlan_tag2->nr_kws) {
dev_err(rvu->dev, "mkex: Outer vlan tci is not extracted.\n");
goto done;
}

/* if key profile extracts outer vlan tci from one layer */
if (vlan_tag1->nr_kws && !vlan_tag2->nr_kws)
Expand All @@ -393,15 +406,19 @@ static void npc_handle_multi_layer_fields(struct rvu *rvu, int blkaddr, u8 intf)
/* if key profile extracts outer vlan tci from multiple layers */
if (vlan_tag1->nr_kws && vlan_tag2->nr_kws) {
for (i = 0; i < NPC_MAX_KWS_IN_KEY; i++) {
if (vlan_tag1->kw_mask[i] != vlan_tag2->kw_mask[i])
if (vlan_tag1->kw_mask[i] != vlan_tag2->kw_mask[i]) {
dev_err(rvu->dev, "mkex: Out vlan tci pos is different for tagged and double tagged pkts.\n");
goto done;
}
}
key_fields[NPC_OUTER_VID] = *vlan_tag2;
}
/* check none of higher layers overwrite outer vlan tci */
start_lid = key_fields[NPC_OUTER_VID].layer_mdata.lid + 1;
if (npc_check_overlap(rvu, blkaddr, NPC_OUTER_VID, start_lid, intf))
if (npc_check_overlap(rvu, blkaddr, NPC_OUTER_VID, start_lid, intf)) {
dev_err(rvu->dev, "mkex: Outer vlan tci is overwritten by higher layers.\n");
goto done;
}
*features |= BIT_ULL(NPC_OUTER_VID);
done:
return;
Expand Down Expand Up @@ -522,6 +539,10 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf)
if (npc_check_field(rvu, blkaddr, NPC_LB, intf))
*features |= BIT_ULL(NPC_VLAN_ETYPE_CTAG) |
BIT_ULL(NPC_VLAN_ETYPE_STAG);

/* for L2M/L2B/L3M/L3B, check if the type is present in the key */
if (npc_check_field(rvu, blkaddr, NPC_LXMB, intf))
*features |= BIT_ULL(NPC_LXMB);
}

/* Scan key extraction profile and record how fields of our interest
Expand Down Expand Up @@ -598,16 +619,6 @@ static int npc_scan_verify_kex(struct rvu *rvu, int blkaddr)
dev_err(rvu->dev, "Channel cannot be overwritten\n");
return -EINVAL;
}
/* DMAC should be present in key for unicast filter to work */
if (!npc_is_field_present(rvu, NPC_DMAC, NIX_INTF_RX)) {
dev_err(rvu->dev, "DMAC not present in Key\n");
return -EINVAL;
}
/* check that none of the fields overwrite DMAC */
if (npc_check_overlap(rvu, blkaddr, NPC_DMAC, 0, NIX_INTF_RX)) {
dev_err(rvu->dev, "DMAC cannot be overwritten\n");
return -EINVAL;
}

npc_set_features(rvu, blkaddr, NIX_INTF_TX);
npc_set_features(rvu, blkaddr, NIX_INTF_RX);
Expand Down Expand Up @@ -850,6 +861,11 @@ static void npc_update_flow(struct rvu *rvu, struct mcam_entry *entry,
npc_update_entry(rvu, NPC_LE, entry, NPC_LT_LE_ESP,
0, ~0ULL, 0, intf);

if (features & BIT_ULL(NPC_LXMB)) {
output->lxmb = is_broadcast_ether_addr(pkt->dmac) ? 2 : 1;
npc_update_entry(rvu, NPC_LXMB, entry, output->lxmb, 0,
output->lxmb, 0, intf);
}
#define NPC_WRITE_FLOW(field, member, val_lo, val_hi, mask_lo, mask_hi) \
do { \
if (features & BIT_ULL((field))) { \
Expand Down Expand Up @@ -1152,6 +1168,7 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
rule->chan_mask = write_req.entry_data.kw_mask[0] & NPC_KEX_CHAN_MASK;
rule->chan = write_req.entry_data.kw[0] & NPC_KEX_CHAN_MASK;
rule->chan &= rule->chan_mask;
rule->lxmb = dummy.lxmb;
if (is_npc_intf_tx(req->intf))
rule->intf = pfvf->nix_tx_intf;
else
Expand Down Expand Up @@ -1214,6 +1231,34 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
if (!is_npc_interface_valid(rvu, req->intf))
return NPC_FLOW_INTF_INVALID;

/* If DMAC is not extracted in MKEX, rules installed by AF
* can rely on L2MB bit set by hardware protocol checker for
* broadcast and multicast addresses.
*/
if (npc_check_field(rvu, blkaddr, NPC_DMAC, req->intf))
goto process_flow;

if (is_pffunc_af(req->hdr.pcifunc)) {
if (is_unicast_ether_addr(req->packet.dmac)) {
dev_err(rvu->dev,
"%s: mkex profile does not support ucast flow\n",
__func__);
return NPC_FLOW_NOT_SUPPORTED;
}

if (!npc_is_field_present(rvu, NPC_LXMB, req->intf)) {
dev_err(rvu->dev,
"%s: mkex profile does not support bcast/mcast flow",
__func__);
return NPC_FLOW_NOT_SUPPORTED;
}

/* Modify feature to use LXMB instead of DMAC */
req->features &= ~BIT_ULL(NPC_DMAC);
req->features |= BIT_ULL(NPC_LXMB);
}

process_flow:
if (from_vf && req->default_rule)
return NPC_FLOW_VF_PERM_DENIED;

Expand Down

0 comments on commit bd9234d

Please sign in to comment.