#include "rvu_npc.h"
#include "cn20k/npc.h"
#include "cn20k/reg.h"
+#include "rvu_npc_fs.h"
static struct npc_priv_t npc_priv = {
.num_banks = MAX_NUM_BANKS,
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
bank));
- hw_prio = cfg & GENMASK_ULL(14, 8);
+ hw_prio = cfg & GENMASK_ULL(30, 24);
cfg = enable ? 1 : 0;
cfg |= hw_prio;
rvu_write64(rvu, blkaddr,
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CFG_EXT(mcam_idx,
bank));
- hw_prio = cfg & GENMASK_ULL(14, 8);
+ hw_prio = cfg & GENMASK_ULL(30, 24);
cfg = enable ? 1 : 0;
cfg |= hw_prio;
rvu_write64(rvu, blkaddr,
*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 |
- *-----------------------------------------------------------------------------|
+/*-------------------------------------------------------------------------
+ *Kex type| mcam | cam1 |cam0 | req_kwtype||<----- output > |
+ * in | | | | || | |
+ * profile| len | | | ||len | type |
+ *-------------------------------------------------------------------------
+ *X2 | 256 (X2) | 001b |110b | 0 ||X2 | X2 |
+ *------------------------------------------------------------------------|
+ *X4 | 256 (X2) | 000b |000b | 0 ||X2 | DYN |
+ *------------------------------------------------------------------------|
+ *X4 | 512 (X4) | 010b |101b | 0 ||X4 | X4 |
+ *------------------------------------------------------------------------|
+ *DYN | 256 (X2) | 000b |000b | 0 ||X2 | DYN |
+ *------------------------------------------------------------------------|
+ *DYN | 512 (X4) | 010b |101b | 0 ||X4 | X4 |
+ *------------------------------------------------------------------------|
+ *X4 | 256 (X2) | 000b |000b | X2 ||DYN | DYN |
+ *------------------------------------------------------------------------|
+ *DYNC | 256 (X2) | 000b |000b | X2 ||DYN | DYN |
+ *------------------------------------------------------------------------|
+ * X2 | 512 (X4) | xxxb |xxxb | X4 ||INVAL | INVAL |
+ *------------------------------------------------------------------------|
*/
static void npc_cn20k_config_kw_x2(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, int index, u8 intf,
struct cn20k_mcam_entry *entry,
- int bank, u8 kw_type, int kw)
+ int bank, u8 kw_type, int kw,
+ u8 req_kw_type)
{
u64 intf_ext = 0, intf_ext_mask = 0;
u8 tx_intf_mask = ~intf & 0x3;
kw_type_mask = 0;
}
+ /* Say, we need to write x2 keyword in an x4 subbank.
+ * req_kw_type will be x2, and kw_type will be x4.
+ * So in the case ignore kw bits in mcam.
+ */
+ if (kw_type == NPC_MCAM_KEY_X4 && req_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;
static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, int index, u8 intf,
struct cn20k_mcam_entry *entry,
- u8 kw_type)
+ u8 kw_type, u8 req_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);
+ entry, bank, kw_type,
+ kw, req_kw_type);
}
static void
struct npc_mcam *mcam = &rvu->hw->mcam;
u64 bank_cfg;
- bank_cfg = (u64)hw_prio << 8;
+ bank_cfg = (u64)hw_prio << 24;
if (enable)
bank_cfg |= 0x1;
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)
+ bool enable, u8 hw_prio, u8 req_kw_type)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
int mcam_idx = index % mcam->banksize;
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);
+ bank, kw_type, kw, req_kw_type);
/* Set 'action' */
rvu_write64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
bank, 0),
entry->action);
+ /* Set 'action2' for inline receive */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 2),
+ entry->action2);
+
/* 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);
+ mcam_idx, intf, entry,
+ kw_type, req_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, 1),
entry->vtag_action);
+
+ /* Set 'action2' for inline receive */
+ rvu_write64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(mcam_idx,
+ bank, 2),
+ entry->action2);
}
set_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;
+ *hw_prio = (bank_cfg & GENMASK_ULL(30, 24)) >> 24;
if (kw_type == NPC_MCAM_KEY_X2) {
cam1 = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CAMX_W0_EXT(index,
npc_cn20k_config_mcam_entry(rvu, blkaddr, req->entry, nix_intf,
&req->entry_data, req->enable_entry,
- req->hw_prio);
+ req->hw_prio, req->req_kw_type);
rc = 0;
exit:
npc_cn20k_config_mcam_entry(rvu, blkaddr, entry, nix_intf,
&req->entry_data, req->enable_entry,
- req->hw_prio);
+ req->hw_prio, req->req_kw_type);
mutex_unlock(&mcam->lock);
return 0;
}
+static int rvu_npc_get_base_steer_rule_type(struct rvu *rvu, u16 pcifunc)
+{
+ if (is_lbk_vf(rvu, pcifunc))
+ return NIXLF_PROMISC_ENTRY;
+
+ return NIXLF_UCAST_ENTRY;
+}
+
int rvu_mbox_handler_npc_cn20k_read_base_steer_rule(struct rvu *rvu,
struct msg_req *req,
struct npc_cn20k_mcam_read_base_rule_rsp *rsp)
u16 pcifunc = req->hdr.pcifunc;
u8 intf, enable, hw_prio;
struct rvu_pfvf *pfvf;
+ int rl_type;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
mutex_unlock(&mcam->lock);
goto out;
}
+
+ rl_type = rvu_npc_get_base_steer_rule_type(rvu, pcifunc);
+
/* Read the default ucast entry if there is no pkt steering rule */
- index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
- NIXLF_UCAST_ENTRY);
+ index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf, rl_type);
+ if (index < 0) {
+ mutex_unlock(&mcam->lock);
+ goto out;
+ }
+
read_entry:
/* Read the mcam entry */
npc_cn20k_read_mcam_entry(rvu, blkaddr, index,
return set ? 0 : -ESRCH;
}
+int rvu_mbox_handler_npc_get_pfl_info(struct rvu *rvu, struct msg_req *req,
+ struct npc_get_pfl_info_rsp *rsp)
+{
+ if (!is_cn20k(rvu->pdev)) {
+ dev_err(rvu->dev, "Mbox support is only for cn20k\n");
+ return -EOPNOTSUPP;
+ }
+
+ rsp->kw_type = npc_priv.kw;
+ rsp->x4_slots = npc_priv.bank_depth;
+ return 0;
+}
+
+int rvu_mbox_handler_npc_get_num_kws(struct rvu *rvu,
+ struct npc_get_num_kws_req *req,
+ struct npc_get_num_kws_rsp *rsp)
+{
+ struct rvu_npc_mcam_rule dummy = { 0 };
+ struct cn20k_mcam_entry cn20k_entry = { 0 };
+ struct mcam_entry_mdata mdata = { };
+ struct mcam_entry entry = { 0 };
+ struct npc_install_flow_req *fl;
+ int i, cnt = 0, blkaddr;
+
+ if (!is_cn20k(rvu->pdev)) {
+ dev_err(rvu->dev, "Mbox support is only for cn20k\n");
+ return -EOPNOTSUPP;
+ }
+
+ fl = &req->fl;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0) {
+ dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__);
+ return NPC_MCAM_INVALID_REQ;
+ }
+
+ npc_populate_mcam_mdata(rvu, &mdata, &cn20k_entry, &entry);
+
+ npc_update_flow(rvu, &mdata, fl->features, &fl->packet,
+ &fl->mask, &dummy, fl->intf, blkaddr);
+
+ /* Find the most significant word valid. Traverse from
+ * MSB to LSB, check if cam0 or cam1 is set
+ */
+ for (i = NPC_CN20K_MAX_KWS_IN_KEY - 1; i >= 0; i--) {
+ if (cn20k_entry.kw[i] || cn20k_entry.kw_mask[i]) {
+ cnt = i + 1;
+ break;
+ }
+ }
+
+ rsp->kws = cnt;
+
+ return 0;
+}
+
+int rvu_mbox_handler_npc_get_dft_rl_idxs(struct rvu *rvu, struct msg_req *req,
+ struct npc_get_dft_rl_idxs_rsp *rsp)
+{
+ u16 bcast, mcast, promisc, ucast;
+ u16 pcifunc;
+ int rc;
+
+ if (!is_cn20k(rvu->pdev)) {
+ dev_err(rvu->dev, "Mbox support is only for cn20k\n");
+ return -EOPNOTSUPP;
+ }
+
+ pcifunc = req->hdr.pcifunc;
+
+ rc = npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &bcast, &mcast,
+ &promisc, &ucast);
+ if (rc)
+ return rc;
+
+ rsp->bcast = bcast;
+ rsp->mcast = mcast;
+ rsp->promisc = promisc;
+ rsp->ucast = ucast;
+ return 0;
+}
+
static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
{
return is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, pcifunc)) ||
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 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,
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) \
u64 kw_mask[NPC_CN20K_MAX_KWS_IN_KEY];
u64 action;
u64 vtag_action;
+ u64 action2;
};
struct npc_cn20k_mcam_write_entry_req {
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 */
};
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 */
};
/* old counter value */
u16 cntr_val;
u8 hw_prio;
+ u8 req_kw_type; /* Key type to be written */
+ u8 alloc_entry; /* only for cn20k */
+ 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 {
if (!is_cn20k(rvu->pdev))
goto not_cn20k;
+ /* Only x2 or x4 key types are accepted */
+ if (req->kw_type != NPC_MCAM_KEY_X2 && req->kw_type != NPC_MCAM_KEY_X4)
+ return NPC_MCAM_INVALID_REQ;
+
/* The below table is being followed during allocation,
*
* 1. ref_entry == 0 && prio == HIGH && count == 1 : user wants to
~0ULL, 0, intf);
}
-static 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_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)
{
u64 dmac_mask = ether_addr_to_u64(mask->dmac);
u64 smac_mask = ether_addr_to_u64(mask->smac);
return 0;
}
-static void
+void
npc_populate_mcam_mdata(struct rvu *rvu,
struct mcam_entry_mdata *mdata,
struct cn20k_mcam_entry *cn20k_entry,
cn20k_wreq.intf = req->intf;
cn20k_wreq.enable_entry = (u8)enable;
cn20k_wreq.hw_prio = req->hw_prio;
+ cn20k_wreq.req_kw_type = req->req_kw_type;
update_rule:
return 0;
}
+static int
+rvu_npc_free_entry_for_flow_install(struct rvu *rvu, u16 pcifunc,
+ bool free_entry, int mcam_idx)
+{
+ struct npc_mcam_free_entry_req free_req = { 0 };
+ struct msg_rsp rsp;
+ int rc;
+
+ if (!free_entry)
+ return 0;
+
+ free_req.hdr.pcifunc = pcifunc;
+ free_req.entry = mcam_idx;
+ rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
+ return rc;
+}
+
+static int
+rvu_npc_alloc_entry_for_flow_install(struct rvu *rvu,
+ struct npc_install_flow_req *fl_req,
+ u16 *mcam_idx, u8 *kw_type,
+ bool *allocated)
+{
+ struct npc_mcam_alloc_entry_req entry_req;
+ struct npc_mcam_alloc_entry_rsp entry_rsp;
+ struct npc_get_num_kws_req kws_req;
+ struct npc_get_num_kws_rsp kws_rsp;
+ int off, kw_bits, rc;
+ u8 *src, *dst;
+
+ if (!is_cn20k(rvu->pdev)) {
+ *kw_type = -1;
+ return 0;
+ }
+
+ if (!fl_req->alloc_entry) {
+ *kw_type = -1;
+ return 0;
+ }
+
+ off = offsetof(struct npc_install_flow_req, packet);
+ dst = (u8 *)&kws_req.fl + off;
+ src = (u8 *)fl_req + off;
+ memcpy(dst, src, sizeof(struct npc_install_flow_req) - off);
+ rc = rvu_mbox_handler_npc_get_num_kws(rvu, &kws_req, &kws_rsp);
+ if (rc)
+ return rc;
+
+ kw_bits = kws_rsp.kws * 64;
+
+ *kw_type = NPC_MCAM_KEY_X2;
+ if (kw_bits > 256)
+ *kw_type = NPC_MCAM_KEY_X4;
+
+ memset(&entry_req, 0, sizeof(entry_req));
+ memset(&entry_rsp, 0, sizeof(entry_rsp));
+
+ entry_req.hdr.pcifunc = fl_req->hdr.pcifunc;
+ entry_req.ref_prio = fl_req->ref_prio;
+ entry_req.ref_entry = fl_req->ref_entry;
+ entry_req.kw_type = *kw_type;
+ entry_req.count = 1;
+ rc = rvu_mbox_handler_npc_mcam_alloc_entry(rvu,
+ &entry_req,
+ &entry_rsp);
+ if (rc)
+ return rc;
+
+ *mcam_idx = entry_rsp.entry_list[0];
+ *allocated = true;
+ return 0;
+}
+
int rvu_mbox_handler_npc_install_flow(struct rvu *rvu,
struct npc_install_flow_req *req,
struct npc_install_flow_rsp *rsp)
int blkaddr, nixlf, err;
struct rvu_pfvf *pfvf;
bool pf_set_vfs_mac = false;
+ bool allocated = false;
bool enable = true;
+ u8 kw_type;
u16 target;
- req->entry = npc_cn20k_vidx2idx(req->entry);
-
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0) {
dev_err(rvu->dev, "%s: NPC block not implemented\n", __func__);
if (!is_npc_interface_valid(rvu, req->intf))
return NPC_FLOW_INTF_INVALID;
+ err = rvu_npc_alloc_entry_for_flow_install(rvu, req, &req->entry,
+ &kw_type, &allocated);
+ if (err) {
+ dev_err(rvu->dev,
+ "%s: Error to alloc mcam entry for pcifunc=%#x\n",
+ __func__, req->hdr.pcifunc);
+ return err;
+ }
+
+ req->entry = npc_cn20k_vidx2idx(req->entry);
+
/* 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.
dev_warn(rvu->dev,
"%s: mkex profile does not support ucast flow\n",
__func__);
+ rvu_npc_free_entry_for_flow_install(rvu,
+ req->hdr.pcifunc,
+ allocated,
+ req->entry);
return NPC_FLOW_NOT_SUPPORTED;
}
dev_warn(rvu->dev,
"%s: mkex profile does not support bcast/mcast flow",
__func__);
+ rvu_npc_free_entry_for_flow_install(rvu,
+ req->hdr.pcifunc,
+ allocated,
+ req->entry);
return NPC_FLOW_NOT_SUPPORTED;
}
}
process_flow:
- if (from_vf && req->default_rule)
+ if (from_vf && req->default_rule) {
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return NPC_FLOW_VF_PERM_DENIED;
+ }
/* Each PF/VF info is maintained in struct rvu_pfvf.
* rvu_pfvf for the target PF/VF needs to be retrieved
req->chan_mask = 0xFFF;
err = npc_check_unsupported_flows(rvu, req->features, req->intf);
- if (err)
+ if (err) {
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return NPC_FLOW_NOT_SUPPORTED;
+ }
pfvf = rvu_get_pfvf(rvu, target);
/* Proceed if NIXLF is attached or not for TX rules */
err = nix_get_nixlf(rvu, target, &nixlf, NULL);
- if (err && is_npc_intf_rx(req->intf) && !pf_set_vfs_mac)
+ if (err && is_npc_intf_rx(req->intf) && !pf_set_vfs_mac) {
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return NPC_FLOW_NO_NIXLF;
+ }
/* don't enable rule when nixlf not attached or initialized */
if (!(is_nixlf_attached(rvu, target) &&
enable = true;
/* Do not allow requests from uninitialized VFs */
- if (from_vf && !enable)
+ if (from_vf && !enable) {
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return NPC_FLOW_VF_NOT_INIT;
+ }
/* PF sets VF mac & VF NIXLF is not attached, update the mac addr */
if (pf_set_vfs_mac && !enable) {
ether_addr_copy(pfvf->default_mac, req->packet.dmac);
ether_addr_copy(pfvf->mac_addr, req->packet.dmac);
set_bit(PF_SET_VF_MAC, &pfvf->flags);
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
return 0;
}
mutex_lock(&rswitch->switch_lock);
err = npc_install_flow(rvu, blkaddr, target, nixlf, pfvf,
req, rsp, enable, pf_set_vfs_mac);
+ if (err)
+ rvu_npc_free_entry_for_flow_install(rvu, req->hdr.pcifunc,
+ allocated, req->entry);
+
+ rsp->kw_type = kw_type;
+ rsp->entry = req->entry;
mutex_unlock(&rswitch->switch_lock);
return err;
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 */
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;
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);
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
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->ref_prio = NPC_MCAM_HIGHER_PRIO;
- req->ref_entry = flow_cfg->def_ent[0];
+ 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;
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 +
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)) {
}
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;
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)
{
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);
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;