[NPC_MCAM_KEY_X4] = "X4",
};
+static const char *npc_dft_rule_name[NPC_DFT_RULE_MAX_ID] = {
+ [NPC_DFT_RULE_PROMISC_ID] = "Promisc",
+ [NPC_DFT_RULE_MCAST_ID] = "Mcast",
+ [NPC_DFT_RULE_BCAST_ID] = "Bcast",
+ [NPC_DFT_RULE_UCAST_ID] = "Ucast",
+};
+
#define KEX_EXTR_CFG(bytesm1, hdr_ofs, ena, key_ofs) \
(((bytesm1) << 16) | ((hdr_ofs) << 8) | ((ena) << 7) | \
((key_ofs) & 0x3F))
+#define NPC_DFT_RULE_ID_MK(pcifunc, id) \
+ ((pcifunc) | FIELD_PREP(GENMASK_ULL(31, 16), id))
+
+#define NPC_DFT_RULE_ID_2_PCIFUNC(rid) \
+ FIELD_GET(GENMASK_ULL(15, 0), rid)
+
+#define NPC_DFT_RULE_ID_2_ID(rid) \
+ FIELD_GET(GENMASK_ULL(31, 16), rid)
+
+#define NPC_DFT_RULE_PRIO 127
+
static const char cn20k_def_pfl_name[] = "default";
static struct npc_mcam_kex_extr npc_mkex_extr_default = {
return cnt;
}
+int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
+ u16 *mcast, u16 *promisc, u16 *ucast)
+{
+ u16 *ptr[4] = {promisc, mcast, bcast, ucast};
+ unsigned long idx;
+ bool set = false;
+ void *val;
+ int i, j;
+
+ if (!npc_priv.init_done)
+ return 0;
+
+ if (is_lbk_vf(rvu, pcifunc)) {
+ if (!ptr[0])
+ return -EINVAL;
+
+ idx = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_PROMISC_ID);
+ val = xa_load(&npc_priv.xa_pf2dfl_rmap, idx);
+ if (!val) {
+ pr_debug("%s: Failed to find %s index for pcifunc=%#x\n",
+ __func__,
+ npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID],
+ pcifunc);
+
+ *ptr[0] = USHRT_MAX;
+ return -ESRCH;
+ }
+
+ *ptr[0] = xa_to_value(val);
+ return 0;
+ }
+
+ if (is_vf(pcifunc)) {
+ if (!ptr[3])
+ return -EINVAL;
+
+ idx = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_UCAST_ID);
+ val = xa_load(&npc_priv.xa_pf2dfl_rmap, idx);
+ if (!val) {
+ pr_debug("%s: Failed to find %s index for pcifunc=%#x\n",
+ __func__,
+ npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID],
+ pcifunc);
+
+ *ptr[3] = USHRT_MAX;
+ return -ESRCH;
+ }
+
+ *ptr[3] = xa_to_value(val);
+ return 0;
+ }
+
+ for (i = NPC_DFT_RULE_START_ID, j = 0; i < NPC_DFT_RULE_MAX_ID; i++,
+ j++) {
+ if (!ptr[j])
+ continue;
+
+ idx = NPC_DFT_RULE_ID_MK(pcifunc, i);
+ val = xa_load(&npc_priv.xa_pf2dfl_rmap, idx);
+ if (!val) {
+ pr_debug("%s: Failed to find %s index for pcifunc=%#x\n",
+ __func__,
+ npc_dft_rule_name[i], pcifunc);
+
+ *ptr[j] = USHRT_MAX;
+ continue;
+ }
+
+ *ptr[j] = xa_to_value(val);
+ set = true;
+ }
+
+ return set ? 0 : -ESRCH;
+}
+
+static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
+{
+ return is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, pcifunc)) ||
+ is_lbk_vf(rvu, pcifunc);
+}
+
+void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
+{
+ struct npc_mcam_free_entry_req free_req = { 0 };
+ unsigned long index;
+ struct msg_rsp rsp;
+ u16 ptr[4];
+ int rc, i;
+ void *map;
+
+ if (!npc_priv.init_done)
+ return;
+
+ if (!npc_is_cgx_or_lbk(rvu, pcifunc)) {
+ dev_dbg(rvu->dev,
+ "%s: dft rule allocation is only for cgx mapped device, pcifunc=%#x\n",
+ __func__, pcifunc);
+ return;
+ }
+
+ rc = npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &ptr[0], &ptr[1],
+ &ptr[2], &ptr[3]);
+ if (rc)
+ return;
+
+ /* LBK */
+ if (is_lbk_vf(rvu, pcifunc)) {
+ index = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_PROMISC_ID);
+ map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
+ if (!map)
+ dev_dbg(rvu->dev,
+ "%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
+ __func__,
+ npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID],
+ pcifunc);
+
+ goto free_rules;
+ }
+
+ /* VF */
+ if (is_vf(pcifunc)) {
+ index = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_UCAST_ID);
+ map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
+ if (!map)
+ dev_dbg(rvu->dev,
+ "%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
+ __func__,
+ npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID],
+ pcifunc);
+
+ goto free_rules;
+ }
+
+ /* PF */
+ for (i = NPC_DFT_RULE_START_ID; i < NPC_DFT_RULE_MAX_ID; i++) {
+ index = NPC_DFT_RULE_ID_MK(pcifunc, i);
+ map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
+ if (!map)
+ dev_dbg(rvu->dev,
+ "%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
+ __func__, npc_dft_rule_name[i],
+ pcifunc);
+ }
+
+free_rules:
+
+ free_req.hdr.pcifunc = pcifunc;
+ free_req.all = 1;
+ rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
+ if (rc)
+ dev_err(rvu->dev,
+ "%s: Error deleting default entries (pcifunc=%#x\n",
+ __func__, pcifunc);
+}
+
+int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc)
+{
+ struct npc_mcam_free_entry_req free_req = { 0 };
+ u16 mcam_idx[4] = { 0 }, pf_ucast, pf_pcifunc;
+ struct npc_mcam_alloc_entry_req req = { 0 };
+ struct npc_mcam_alloc_entry_rsp rsp = { 0 };
+ int ret, eidx, i, k, pf, cnt;
+ struct rvu_pfvf *pfvf;
+ unsigned long index;
+ struct msg_rsp free_rsp;
+ u16 b, m, p, u;
+
+ if (!npc_priv.init_done)
+ return 0;
+
+ if (!npc_is_cgx_or_lbk(rvu, pcifunc)) {
+ dev_dbg(rvu->dev,
+ "%s: dft rule allocation is only for cgx mapped device, pcifunc=%#x\n",
+ __func__, pcifunc);
+ return 0;
+ }
+
+ /* Check if default rules are already alloced for this pcifunc */
+ ret = npc_cn20k_dft_rules_idx_get(rvu, pcifunc, &b, &m, &p, &u);
+ if (!ret) {
+ dev_dbg(rvu->dev,
+ "%s: default rules are already installed (pcifunc=%#x)\n",
+ __func__, pcifunc);
+ dev_dbg(rvu->dev,
+ "%s: bcast(%u) mcast(%u) promisc(%u) ucast(%u)\n",
+ __func__, b, m, p, u);
+ return 0;
+ }
+
+ /* Set ref index as lowest priority index */
+ eidx = 2 * npc_priv.bank_depth - 1;
+
+ /* Install only UCAST for VF */
+ cnt = is_vf(pcifunc) ? 1 : ARRAY_SIZE(mcam_idx);
+
+ /* For VF pcifunc, allocate default mcam indexes by taking
+ * ref as PF's ucast index.
+ */
+ if (is_vf(pcifunc)) {
+ pf = rvu_get_pf(rvu->pdev, pcifunc);
+ pf_pcifunc = pf << RVU_CN20K_PFVF_PF_SHIFT;
+
+ /* Get PF's ucast entry index */
+ ret = npc_cn20k_dft_rules_idx_get(rvu, pf_pcifunc, NULL,
+ NULL, NULL, &pf_ucast);
+
+ /* There is no PF rules installed; and VF installation comes
+ * first. PF may come later.
+ * TODO: Install PF rules before installing VF rules.
+ */
+
+ /* Set PF's ucast as ref entry */
+ if (!ret)
+ eidx = pf_ucast;
+ }
+
+ pfvf = rvu_get_pfvf(rvu, pcifunc);
+ pfvf->hw_prio = NPC_DFT_RULE_PRIO;
+
+ req.contig = false;
+ req.ref_prio = NPC_MCAM_HIGHER_PRIO;
+ req.ref_entry = eidx;
+ req.kw_type = NPC_MCAM_KEY_X2;
+ req.count = cnt;
+ req.hdr.pcifunc = pcifunc;
+
+ ret = rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &req, &rsp);
+
+ /* successfully allocated index */
+ if (!ret) {
+ /* Copy indexes to local array */
+ for (i = 0; i < cnt; i++)
+ mcam_idx[i] = rsp.entry_list[i];
+
+ goto chk_sanity;
+ }
+
+ /* If there is no slots available and request is for PF,
+ * return error.
+ */
+ if (!is_vf(pcifunc)) {
+ dev_err(rvu->dev,
+ "%s: Default index allocation failed for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return ret;
+ }
+
+ /* We could not find an index with higher priority index for VF.
+ * Find rule with lower priority index and set hardware priority
+ * as NPC_DFT_RULE_PRIO - 1 (higher hw priority)
+ */
+ req.contig = false;
+ req.kw_type = NPC_MCAM_KEY_X2;
+ req.count = cnt;
+ req.hdr.pcifunc = pcifunc;
+ req.ref_prio = NPC_MCAM_LOWER_PRIO;
+ req.ref_entry = eidx + 1;
+ ret = rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &req, &rsp);
+ if (ret) {
+ dev_err(rvu->dev,
+ "%s: Default index allocation failed for pcifunc=%#x\n",
+ __func__, pcifunc);
+ return ret;
+ }
+
+ /* Copy indexes to local array */
+ for (i = 0; i < cnt; i++)
+ mcam_idx[i] = rsp.entry_list[i];
+
+ pfvf->hw_prio = NPC_DFT_RULE_PRIO - 1;
+
+chk_sanity:
+ /* LBK */
+ if (is_lbk_vf(rvu, pcifunc)) {
+ index = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_PROMISC_ID);
+ ret = xa_insert(&npc_priv.xa_pf2dfl_rmap, index,
+ xa_mk_value(mcam_idx[0]), GFP_KERNEL);
+ if (ret) {
+ dev_err(rvu->dev,
+ "%s: Err to insert %s mcam idx to xarray pcifunc=%#x\n",
+ __func__,
+ npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID],
+ pcifunc);
+ goto err;
+ }
+
+ goto done;
+ }
+
+ /* VF */
+ if (is_vf(pcifunc)) {
+ index = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_UCAST_ID);
+ ret = xa_insert(&npc_priv.xa_pf2dfl_rmap, index,
+ xa_mk_value(mcam_idx[0]), GFP_KERNEL);
+ if (ret) {
+ dev_err(rvu->dev,
+ "%s: Err to insert %s mcam idx to xarray pcifunc=%#x\n",
+ __func__,
+ npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID],
+ pcifunc);
+ goto err;
+ }
+
+ goto done;
+ }
+
+ /* PF */
+ for (i = NPC_DFT_RULE_START_ID, k = 0; i < NPC_DFT_RULE_MAX_ID &&
+ k < cnt; i++, k++) {
+ index = NPC_DFT_RULE_ID_MK(pcifunc, i);
+ ret = xa_insert(&npc_priv.xa_pf2dfl_rmap, index,
+ xa_mk_value(mcam_idx[k]), GFP_KERNEL);
+ if (ret) {
+ dev_err(rvu->dev,
+ "%s: Err to insert %s mcam idx to xarray pcifunc=%#x\n",
+ __func__, npc_dft_rule_name[i],
+ pcifunc);
+ for (int p = NPC_DFT_RULE_START_ID; p < i; p++) {
+ index = NPC_DFT_RULE_ID_MK(pcifunc, p);
+ xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
+ }
+ goto err;
+ }
+ }
+
+done:
+ return 0;
+
+err:
+ free_req.hdr.pcifunc = pcifunc;
+ free_req.all = 1;
+ ret = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &free_rsp);
+ if (ret)
+ dev_err(rvu->dev,
+ "%s: Error deleting default entries (pcifunc=%#x\n",
+ __func__, pcifunc);
+
+ return -EFAULT;
+}
+
static int npc_priv_init(struct rvu *rvu)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
xa_init_flags(&npc_priv.xa_sb_free, XA_FLAGS_ALLOC);
xa_init_flags(&npc_priv.xa_idx2pf_map, XA_FLAGS_ALLOC);
xa_init_flags(&npc_priv.xa_pf_map, XA_FLAGS_ALLOC);
+ xa_init_flags(&npc_priv.xa_pf2dfl_rmap, XA_FLAGS_ALLOC);
if (npc_create_srch_order(num_subbanks))
goto fail1;
xa_destroy(&npc_priv.xa_sb_free);
xa_destroy(&npc_priv.xa_idx2pf_map);
xa_destroy(&npc_priv.xa_pf_map);
+ xa_destroy(&npc_priv.xa_pf2dfl_rmap);
kfree(npc_priv.sb);
npc_priv.sb = NULL;
return -ENOMEM;
xa_destroy(&npc_priv.xa_sb_free);
xa_destroy(&npc_priv.xa_idx2pf_map);
xa_destroy(&npc_priv.xa_pf_map);
+ xa_destroy(&npc_priv.xa_pf2dfl_rmap);
for (i = 0; i < npc_priv.pf_cnt; i++)
xa_destroy(&npc_priv.xa_pf2idx_map[i]);
req.match_id = action.match_id;
req.flow_key_alg = action.flow_key_alg;
+ if (is_cn20k(rvu->pdev))
+ req.hw_prio = pfvf->hw_prio;
+
rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
}
req.match_id = action.match_id;
req.flow_key_alg = flow_key_alg;
+ if (is_cn20k(rvu->pdev))
+ req.hw_prio = pfvf->hw_prio;
+
rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
}
req.hdr.pcifunc = 0; /* AF is requester */
req.vf = pcifunc;
+ if (is_cn20k(rvu->pdev))
+ req.hw_prio = pfvf->hw_prio;
+
rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
}
req.match_id = action.match_id;
req.flow_key_alg = flow_key_alg;
+ if (is_cn20k(rvu->pdev))
+ req.hw_prio = pfvf->hw_prio;
+
rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp);
}
{
u16 fcnt;
- if (req->priority == NPC_MCAM_HIGHER_PRIO)
+ if (req->ref_prio == NPC_MCAM_HIGHER_PRIO)
goto hprio;
/* For a low priority entry allocation
goto lprio_alloc;
/* Get the search range for priority allocation request */
- if (req->priority) {
+ if (req->ref_prio) {
npc_get_mcam_search_range_priority(mcam, req,
&start, &end, &reverse);
goto alloc;
* and not in mid zone.
*/
if (!(pcifunc & RVU_PFVF_FUNC_MASK) &&
- req->priority == NPC_MCAM_HIGHER_PRIO)
+ req->ref_prio == NPC_MCAM_HIGHER_PRIO)
end = req->ref_entry;
if (!(pcifunc & RVU_PFVF_FUNC_MASK) &&
- req->priority == NPC_MCAM_LOWER_PRIO)
+ req->ref_prio == NPC_MCAM_LOWER_PRIO)
start = req->ref_entry;
}
/* If allocating requested no of entries is unsucessful,
* expand the search range to full bitmap length and retry.
*/
- if (!req->priority && (rsp->count < req->count) &&
+ if (!req->ref_prio && rsp->count < req->count &&
((end - start) != mcam->bmap_entries)) {
reverse = true;
start = 0;
/* For priority entry allocation requests, if allocation is
* failed then expand search to max possible range and retry.
*/
- if (req->priority && rsp->count < req->count) {
- if (req->priority == NPC_MCAM_LOWER_PRIO &&
+ if (req->ref_prio && rsp->count < req->count) {
+ if (req->ref_prio == NPC_MCAM_LOWER_PRIO &&
(start != (req->ref_entry + 1))) {
start = req->ref_entry + 1;
end = mcam->bmap_entries;
reverse = false;
goto alloc;
- } else if ((req->priority == NPC_MCAM_HIGHER_PRIO) &&
+ } else if ((req->ref_prio == NPC_MCAM_HIGHER_PRIO) &&
((end - start) != req->ref_entry)) {
start = 0;
end = req->ref_entry;
/* ref_entry can't be '0' if requested priority is high.
* Can't be last entry if requested priority is low.
*/
- if ((!req->ref_entry && req->priority == NPC_MCAM_HIGHER_PRIO) ||
- ((req->ref_entry == mcam->bmap_entries) &&
- req->priority == NPC_MCAM_LOWER_PRIO))
+ if ((!req->ref_entry && req->ref_prio == NPC_MCAM_HIGHER_PRIO) ||
+ (req->ref_entry == mcam->bmap_entries &&
+ req->ref_prio == NPC_MCAM_LOWER_PRIO))
return NPC_MCAM_INVALID_REQ;
/* Since list of allocated indices needs to be sent to requester,
/* Try to allocate a MCAM entry */
entry_req.hdr.pcifunc = req->hdr.pcifunc;
entry_req.contig = true;
- entry_req.priority = req->priority;
+ entry_req.ref_prio = req->ref_prio;
entry_req.ref_entry = req->ref_entry;
entry_req.count = 1;