#include "roc_api.h"
#include "roc_priv.h"
+int
+roc_npc_vtag_actions_get(struct roc_npc *roc_npc)
+{
+ struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+
+ return npc->vtag_strip_actions;
+}
+
+int
+roc_npc_vtag_actions_sub_return(struct roc_npc *roc_npc, uint32_t count)
+{
+ struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+
+ npc->vtag_strip_actions -= count;
+ return npc->vtag_strip_actions;
+}
+
int
roc_npc_mcam_free_counter(struct roc_npc *roc_npc, uint16_t ctr_id)
{
/* FIXME: change to reading in AF from NPC_AF_CONST1/2
* MCAM_BANK_DEPTH(_EXT) * MCAM_BANKS
*/
- if (roc_model_is_cn10k())
+ if (roc_model_is_cn10k() || roc_model_is_cn98xx())
return 16 * 1024; /* MCAM_BANKS = 4, BANK_DEPTH_EXT = 4096 */
else
return 4 * 1024; /* MCAM_BANKS = 4, BANK_DEPTH_EXT = 1024 */
const struct roc_npc_action_mark *act_mark;
const struct roc_npc_action_queue *act_q;
const struct roc_npc_action_vf *vf_act;
+ bool vlan_insert_action = false;
int sel_act, req_act = 0;
uint16_t pf_func, vf_id;
int errcode = 0;
req_act |= ROC_NPC_ACTION_TYPE_SEC;
rq = 0;
break;
+ case ROC_NPC_ACTION_TYPE_VLAN_STRIP:
+ req_act |= ROC_NPC_ACTION_TYPE_VLAN_STRIP;
+ break;
+ case ROC_NPC_ACTION_TYPE_VLAN_INSERT:
+ req_act |= ROC_NPC_ACTION_TYPE_VLAN_INSERT;
+ break;
+ case ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT:
+ req_act |= ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT;
+ break;
+ case ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT:
+ req_act |= ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT;
+ break;
default:
errcode = NPC_ERR_ACTION_NOTSUP;
goto err_exit;
}
}
+ if (req_act & (ROC_NPC_ACTION_TYPE_VLAN_INSERT |
+ ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT |
+ ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT))
+ vlan_insert_action = true;
+
+ if ((req_act & (ROC_NPC_ACTION_TYPE_VLAN_INSERT |
+ ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT |
+ ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT)) ==
+ ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
+ plt_err("PCP insert action can't be supported alone");
+ errcode = NPC_ERR_ACTION_NOTSUP;
+ goto err_exit;
+ }
+
+ /* Both STRIP and INSERT actions are not supported */
+ if (vlan_insert_action && (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP)) {
+ errcode = NPC_ERR_ACTION_NOTSUP;
+ goto err_exit;
+ }
+
/* Check if actions specified are compatible */
if (attr->egress) {
- /* Only DROP/COUNT is supported */
- if (!(req_act & ROC_NPC_ACTION_TYPE_DROP)) {
+ if (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
+ plt_err("VLAN pop action is not supported on Egress");
+ errcode = NPC_ERR_ACTION_NOTSUP;
+ goto err_exit;
+ }
+
+ if (req_act &
+ ~(ROC_NPC_ACTION_TYPE_VLAN_INSERT |
+ ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT |
+ ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT |
+ ROC_NPC_ACTION_TYPE_DROP | ROC_NPC_ACTION_TYPE_COUNT)) {
+ plt_err("Only VLAN insert, drop, count supported on Egress");
+ errcode = NPC_ERR_ACTION_NOTSUP;
+ goto err_exit;
+ }
+
+ if (vlan_insert_action &&
+ (req_act & ROC_NPC_ACTION_TYPE_DROP)) {
+ plt_err("Both VLAN insert and drop actions cannot be supported");
errcode = NPC_ERR_ACTION_NOTSUP;
goto err_exit;
- } else if (req_act & ~(ROC_NPC_ACTION_TYPE_DROP |
- ROC_NPC_ACTION_TYPE_COUNT)) {
+ }
+
+ if (req_act & ROC_NPC_ACTION_TYPE_DROP) {
+ flow->npc_action = NIX_TX_ACTIONOP_DROP;
+ } else if ((req_act & ROC_NPC_ACTION_TYPE_COUNT) ||
+ vlan_insert_action) {
+ flow->npc_action = NIX_TX_ACTIONOP_UCAST_DEFAULT;
+ } else {
+ plt_err("Unsupported action for egress");
errcode = NPC_ERR_ACTION_NOTSUP;
goto err_exit;
}
- flow->npc_action = NIX_TX_ACTIONOP_DROP;
+
goto set_pf_func;
+ } else {
+ if (vlan_insert_action) {
+ errcode = NPC_ERR_ACTION_NOTSUP;
+ goto err_exit;
+ }
}
/* We have already verified the attr, this is ingress.
goto err_exit;
}
+ if (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP)
+ npc->vtag_strip_actions++;
+
/* Set NIX_RX_ACTIONOP */
- if (req_act & (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
+ if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
+ /* Only VLAN action is provided */
+ flow->npc_action = NIX_RX_ACTIONOP_UCAST;
+ } else if (req_act &
+ (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
flow->npc_action = NIX_RX_ACTIONOP_UCAST;
if (req_act & ROC_NPC_ACTION_TYPE_QUEUE)
flow->npc_action |= (uint64_t)rq << 20;
return npc_program_mcam(npc, &parse_state, 0);
}
+int
+npc_rss_free_grp_get(struct npc *npc, uint32_t *pos)
+{
+ struct plt_bitmap *bmap = npc->rss_grp_entries;
+
+ for (*pos = 0; *pos < ROC_NIX_RSS_GRPS; ++*pos) {
+ if (!plt_bitmap_get(bmap, *pos))
+ break;
+ }
+ return *pos < ROC_NIX_RSS_GRPS ? 0 : -1;
+}
+
+int
+npc_rss_action_configure(struct roc_npc *roc_npc,
+ const struct roc_npc_action_rss *rss, uint8_t *alg_idx,
+ uint32_t *rss_grp, uint32_t mcam_id)
+{
+ struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+ struct roc_nix *roc_nix = roc_npc->roc_nix;
+ struct nix *nix = roc_nix_to_nix_priv(roc_nix);
+ uint32_t flowkey_cfg, rss_grp_idx, i, rem;
+ uint8_t key[ROC_NIX_RSS_KEY_LEN];
+ const uint8_t *key_ptr;
+ uint8_t flowkey_algx;
+ uint16_t *reta;
+ int rc;
+
+ rc = npc_rss_free_grp_get(npc, &rss_grp_idx);
+ /* RSS group :0 is not usable for flow rss action */
+ if (rc < 0 || rss_grp_idx == 0)
+ return -ENOSPC;
+
+ for (i = 0; i < rss->queue_num; i++) {
+ if (rss->queue[i] >= nix->nb_rx_queues) {
+ plt_err("queue id > max number of queues");
+ return -EINVAL;
+ }
+ }
+
+ *rss_grp = rss_grp_idx;
+
+ if (rss->key == NULL) {
+ roc_nix_rss_key_default_fill(roc_nix, key);
+ key_ptr = key;
+ } else {
+ key_ptr = rss->key;
+ }
+
+ roc_nix_rss_key_set(roc_nix, key_ptr);
+
+ /* If queue count passed in the rss action is less than
+ * HW configured reta size, replicate rss action reta
+ * across HW reta table.
+ */
+ reta = nix->reta[rss_grp_idx];
+
+ if (rss->queue_num > nix->reta_sz) {
+ plt_err("too many queues for RSS context");
+ return -ENOTSUP;
+ }
+
+ for (i = 0; i < (nix->reta_sz / rss->queue_num); i++)
+ memcpy(reta + i * rss->queue_num, rss->queue,
+ sizeof(uint16_t) * rss->queue_num);
+
+ rem = nix->reta_sz % rss->queue_num;
+ if (rem)
+ memcpy(&reta[i * rss->queue_num], rss->queue,
+ rem * sizeof(uint16_t));
+
+ rc = roc_nix_rss_reta_set(roc_nix, *rss_grp, reta);
+ if (rc) {
+ plt_err("Failed to init rss table rc = %d", rc);
+ return rc;
+ }
+
+ flowkey_cfg = roc_npc->flowkey_cfg_state;
+
+ rc = roc_nix_rss_flowkey_set(roc_nix, &flowkey_algx, flowkey_cfg,
+ *rss_grp, mcam_id);
+ if (rc) {
+ plt_err("Failed to set rss hash function rc = %d", rc);
+ return rc;
+ }
+
+ *alg_idx = flowkey_algx;
+
+ plt_bitmap_set(npc->rss_grp_entries, *rss_grp);
+
+ return 0;
+}
+
+int
+npc_rss_action_program(struct roc_npc *roc_npc,
+ const struct roc_npc_action actions[],
+ struct roc_npc_flow *flow)
+{
+ const struct roc_npc_action_rss *rss;
+ uint32_t rss_grp;
+ uint8_t alg_idx;
+ int rc;
+
+ for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
+ if (actions->type == ROC_NPC_ACTION_TYPE_RSS) {
+ rss = (const struct roc_npc_action_rss *)actions->conf;
+ rc = npc_rss_action_configure(roc_npc, rss, &alg_idx,
+ &rss_grp, flow->mcam_id);
+ if (rc)
+ return rc;
+
+ flow->npc_action &= (~(0xfULL));
+ flow->npc_action |= NIX_RX_ACTIONOP_RSS;
+ flow->npc_action |=
+ ((uint64_t)(alg_idx & NPC_RSS_ACT_ALG_MASK)
+ << NPC_RSS_ACT_ALG_OFFSET) |
+ ((uint64_t)(rss_grp & NPC_RSS_ACT_GRP_MASK)
+ << NPC_RSS_ACT_GRP_OFFSET);
+ break;
+ }
+ }
+ return 0;
+}
+
+int
+roc_npc_mark_actions_get(struct roc_npc *roc_npc)
+{
+ struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+
+ return npc->mark_actions;
+}
+
+int
+roc_npc_mark_actions_sub_return(struct roc_npc *roc_npc, uint32_t count)
+{
+ struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+
+ npc->mark_actions -= count;
+ return npc->mark_actions;
+}
+
+static int
+npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
+{
+ struct roc_nix *roc_nix = roc_npc->roc_nix;
+ struct nix_vtag_config *vtag_cfg;
+ struct nix_vtag_config_rsp *rsp;
+ struct mbox *mbox;
+ struct nix *nix;
+ int rc = 0;
+
+ union {
+ uint64_t reg;
+ struct nix_tx_vtag_action_s act;
+ } tx_vtag_action;
+
+ nix = roc_nix_to_nix_priv(roc_nix);
+ mbox = (&nix->dev)->mbox;
+
+ tx_vtag_action.reg = flow->vtag_action;
+ vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+
+ if (vtag_cfg == NULL)
+ return -ENOSPC;
+
+ vtag_cfg->cfg_type = VTAG_TX;
+ vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
+ vtag_cfg->tx.vtag0_idx = tx_vtag_action.act.vtag0_def;
+ vtag_cfg->tx.free_vtag0 = true;
+
+ if (flow->vtag_insert_count == 2) {
+ vtag_cfg->tx.vtag1_idx = tx_vtag_action.act.vtag1_def;
+ vtag_cfg->tx.free_vtag1 = true;
+ }
+
+ rc = mbox_process_msg(mbox, (void *)&rsp);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int
+npc_vtag_insert_action_parse(const struct roc_npc_action actions[],
+ struct roc_npc_flow *flow,
+ struct npc_action_vtag_info *vlan_info,
+ int *parsed_cnt)
+{
+ bool vlan_id_found = false, ethtype_found = false, pcp_found = false;
+ int count = 0;
+
+ *parsed_cnt = 0;
+
+ /* This function parses parameters of one VLAN. When a parameter is
+ * found repeated, it treats it as the end of first VLAN's parameters
+ * and returns. The caller calls again to parse the parameters of the
+ * second VLAN.
+ */
+
+ for (; count < NPC_ACTION_MAX_VLAN_PARAMS; count++, actions++) {
+ if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
+ if (vlan_id_found)
+ return 0;
+
+ const struct roc_npc_action_of_set_vlan_vid *vtag =
+ (const struct roc_npc_action_of_set_vlan_vid *)
+ actions->conf;
+
+ vlan_info->vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
+
+ if (vlan_info->vlan_id > 0xfff) {
+ plt_err("Invalid vlan_id for set vlan action");
+ return -EINVAL;
+ }
+
+ flow->vtag_insert_enabled = true;
+ (*parsed_cnt)++;
+ vlan_id_found = true;
+ } else if (actions->type ==
+ ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT) {
+ if (ethtype_found)
+ return 0;
+
+ const struct roc_npc_action_of_push_vlan *ethtype =
+ (const struct roc_npc_action_of_push_vlan *)
+ actions->conf;
+ vlan_info->vlan_ethtype =
+ plt_be_to_cpu_16(ethtype->ethertype);
+ if (vlan_info->vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
+ vlan_info->vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
+ plt_err("Invalid ethtype specified for push"
+ " vlan action");
+ return -EINVAL;
+ }
+ flow->vtag_insert_enabled = true;
+ (*parsed_cnt)++;
+ ethtype_found = true;
+ } else if (actions->type ==
+ ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
+ if (pcp_found)
+ return 0;
+ const struct roc_npc_action_of_set_vlan_pcp *pcp =
+ (const struct roc_npc_action_of_set_vlan_pcp *)
+ actions->conf;
+ vlan_info->vlan_pcp = pcp->vlan_pcp;
+ if (vlan_info->vlan_pcp > 0x7) {
+ plt_err("Invalid PCP value for pcp action");
+ return -EINVAL;
+ }
+ flow->vtag_insert_enabled = true;
+ (*parsed_cnt)++;
+ pcp_found = true;
+ } else {
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int
+npc_vtag_insert_action_configure(struct mbox *mbox, struct roc_npc_flow *flow,
+ struct npc_action_vtag_info *vlan_info)
+{
+ struct nix_vtag_config *vtag_cfg;
+ struct nix_vtag_config_rsp *rsp;
+ int rc = 0;
+
+ union {
+ uint64_t reg;
+ struct nix_tx_vtag_action_s act;
+ } tx_vtag_action;
+
+ vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+
+ if (vtag_cfg == NULL)
+ return -ENOSPC;
+
+ vtag_cfg->cfg_type = VTAG_TX;
+ vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
+ vtag_cfg->tx.vtag0 =
+ ((vlan_info[0].vlan_ethtype << 16) |
+ (vlan_info[0].vlan_pcp << 13) | vlan_info[0].vlan_id);
+
+ vtag_cfg->tx.cfg_vtag0 = 1;
+
+ if (flow->vtag_insert_count == 2) {
+ vtag_cfg->tx.vtag1 =
+ ((vlan_info[1].vlan_ethtype << 16) |
+ (vlan_info[1].vlan_pcp << 13) | vlan_info[1].vlan_id);
+
+ vtag_cfg->tx.cfg_vtag1 = 1;
+ }
+
+ rc = mbox_process_msg(mbox, (void *)&rsp);
+ if (rc)
+ return rc;
+
+ if (rsp->vtag0_idx < 0 ||
+ ((flow->vtag_insert_count == 2) && (rsp->vtag1_idx < 0))) {
+ plt_err("Failed to config TX VTAG action");
+ return -EINVAL;
+ }
+
+ tx_vtag_action.reg = 0;
+ tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
+ tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
+ tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
+ tx_vtag_action.act.vtag0_relptr = NIX_TX_VTAGACTION_VTAG0_RELPTR;
+
+ if (flow->vtag_insert_count == 2) {
+ tx_vtag_action.act.vtag1_def = rsp->vtag1_idx;
+ tx_vtag_action.act.vtag1_lid = NPC_LID_LA;
+ tx_vtag_action.act.vtag1_op = NIX_TX_VTAGOP_INSERT;
+ /* NIX_TX_VTAG_ACTION_S
+ * If Vtag 0 is inserted, hardware adjusts the Vtag 1 byte
+ * offset accordingly. Thus, if the two offsets are equal in
+ * the structure, hardware inserts Vtag 1 immediately after
+ * Vtag 0 in the packet.
+ */
+ tx_vtag_action.act.vtag1_relptr =
+ NIX_TX_VTAGACTION_VTAG0_RELPTR;
+ }
+
+ flow->vtag_action = tx_vtag_action.reg;
+
+ return 0;
+}
+
+static int
+npc_vtag_strip_action_configure(struct mbox *mbox,
+ const struct roc_npc_action actions[],
+ struct roc_npc_flow *flow, int *strip_cnt)
+{
+ struct nix_vtag_config *vtag_cfg;
+ uint64_t rx_vtag_action = 0;
+ int count = 0, rc = 0;
+
+ *strip_cnt = 0;
+
+ for (; count < NPC_ACTION_MAX_VLANS_STRIPPED; count++, actions++) {
+ if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
+ (*strip_cnt)++;
+ }
+
+ vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+
+ if (vtag_cfg == NULL)
+ return -ENOSPC;
+
+ vtag_cfg->cfg_type = VTAG_RX;
+ vtag_cfg->rx.strip_vtag = 1;
+ /* Always capture */
+ vtag_cfg->rx.capture_vtag = 1;
+ vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
+ vtag_cfg->rx.vtag_type = 0;
+
+ rc = mbox_process(mbox);
+ if (rc)
+ return rc;
+
+ rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
+ rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
+ rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
+
+ if (*strip_cnt == 2) {
+ rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 47);
+ rx_vtag_action |= ((uint64_t)NPC_LID_LB << 40);
+ rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR << 32;
+ }
+ flow->vtag_action = rx_vtag_action;
+
+ return 0;
+}
+
+static int
+npc_vtag_action_program(struct roc_npc *roc_npc,
+ const struct roc_npc_action actions[],
+ struct roc_npc_flow *flow)
+{
+ bool vlan_strip_parsed = false, vlan_insert_parsed = false;
+ const struct roc_npc_action *insert_actions;
+ struct roc_nix *roc_nix = roc_npc->roc_nix;
+ struct npc_action_vtag_info vlan_info[2];
+ int parsed_cnt = 0, strip_cnt = 0;
+ int tot_vlan_params = 0;
+ struct mbox *mbox;
+ struct nix *nix;
+ int i, rc;
+
+ nix = roc_nix_to_nix_priv(roc_nix);
+ mbox = (&nix->dev)->mbox;
+
+ memset(vlan_info, 0, sizeof(vlan_info));
+
+ flow->vtag_insert_enabled = false;
+
+ for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
+ if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
+ if (vlan_strip_parsed) {
+ plt_err("Incorrect VLAN strip actions");
+ return -EINVAL;
+ }
+ rc = npc_vtag_strip_action_configure(mbox, actions,
+ flow, &strip_cnt);
+ if (rc)
+ return rc;
+
+ if (strip_cnt == 2)
+ actions++;
+
+ vlan_strip_parsed = true;
+ } else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT ||
+ actions->type ==
+ ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT ||
+ actions->type ==
+ ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
+ if (vlan_insert_parsed) {
+ plt_err("Incorrect VLAN insert actions");
+ return -EINVAL;
+ }
+
+ insert_actions = actions;
+
+ for (i = 0; i < 2; i++) {
+ rc = npc_vtag_insert_action_parse(
+ insert_actions, flow, &vlan_info[i],
+ &parsed_cnt);
+
+ if (rc)
+ return rc;
+
+ if (parsed_cnt) {
+ insert_actions += parsed_cnt;
+ tot_vlan_params += parsed_cnt;
+ flow->vtag_insert_count++;
+ }
+ }
+ actions += tot_vlan_params - 1;
+ vlan_insert_parsed = true;
+ }
+ }
+
+ if (flow->vtag_insert_enabled) {
+ rc = npc_vtag_insert_action_configure(mbox, flow, vlan_info);
+
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
struct roc_npc_flow *
roc_npc_flow_create(struct roc_npc *roc_npc, const struct roc_npc_attr *attr,
const struct roc_npc_item_info pattern[],
struct npc_flow_list *list;
int rc;
+ npc->channel = roc_npc->channel;
+
flow = plt_zmalloc(sizeof(*flow), 0);
if (flow == NULL) {
*errcode = NPC_ERR_NO_MEM;
goto err_exit;
}
+ rc = npc_vtag_action_program(roc_npc, actions, flow);
+ if (rc != 0) {
+ *errcode = rc;
+ goto err_exit;
+ }
+
parse_state.is_vf = !roc_nix_is_pf(roc_npc->roc_nix);
rc = npc_program_mcam(npc, &parse_state, 1);
goto err_exit;
}
+ rc = npc_rss_action_program(roc_npc, actions, flow);
+ if (rc != 0) {
+ *errcode = rc;
+ goto set_rss_failed;
+ }
+
list = &npc->flow_list[flow->priority];
/* List in ascending order of mcam entries */
TAILQ_FOREACH(flow_iter, list, next) {
TAILQ_INSERT_TAIL(list, flow, next);
return flow;
+set_rss_failed:
+ rc = npc_mcam_free_entry(npc, flow->mcam_id);
+ if (rc != 0) {
+ *errcode = rc;
+ plt_free(flow);
+ return NULL;
+ }
err_exit:
plt_free(flow);
return NULL;
}
+int
+npc_rss_group_free(struct npc *npc, struct roc_npc_flow *flow)
+{
+ uint32_t rss_grp;
+
+ if ((flow->npc_action & 0xF) == NIX_RX_ACTIONOP_RSS) {
+ rss_grp = (flow->npc_action >> NPC_RSS_ACT_GRP_OFFSET) &
+ NPC_RSS_ACT_GRP_MASK;
+ if (rss_grp == 0 || rss_grp >= npc->rss_grps)
+ return -EINVAL;
+
+ plt_bitmap_clear(npc->rss_grp_entries, rss_grp);
+ }
+
+ return 0;
+}
+
int
roc_npc_flow_destroy(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
{
struct npc *npc = roc_npc_to_npc_priv(roc_npc);
struct plt_bitmap *bmap;
- uint16_t match_id;
int rc;
- match_id = (flow->npc_action >> NPC_RX_ACT_MATCH_OFFSET) &
- NPC_RX_ACT_MATCH_MASK;
+ rc = npc_rss_group_free(npc, flow);
+ if (rc != 0) {
+ plt_err("Failed to free rss action rc = %d", rc);
+ return rc;
+ }
- if (match_id && match_id < NPC_ACTION_FLAG_DEFAULT) {
- if (npc->mark_actions == 0)
- return NPC_ERR_PARAM;
+ if (flow->vtag_insert_enabled) {
+ rc = npc_vtag_cfg_delete(roc_npc, flow);
+ if (rc != 0)
+ return rc;
}
rc = npc_mcam_free_entry(npc, flow->mcam_id);
plt_free(flow);
return 0;
}
+
+void
+roc_npc_flow_dump(FILE *file, struct roc_npc *roc_npc)
+{
+ struct npc *npc = roc_npc_to_npc_priv(roc_npc);
+ struct roc_npc_flow *flow_iter;
+ struct npc_flow_list *list;
+ uint32_t max_prio, i;
+
+ max_prio = npc->flow_max_priority;
+
+ for (i = 0; i < max_prio; i++) {
+ list = &npc->flow_list[i];
+
+ /* List in ascending order of mcam entries */
+ TAILQ_FOREACH(flow_iter, list, next) {
+ roc_npc_flow_mcam_dump(file, roc_npc, flow_iter);
+ }
+ }
+}