net/mlx5: add C++ include guard to public header
[dpdk.git] / drivers / net / cnxk / cn10k_rte_flow.c
index b04de6a..529fb0e 100644 (file)
@@ -6,6 +6,121 @@
 #include "cn10k_ethdev.h"
 #include "cn10k_rx.h"
 
+static int
+cn10k_mtr_connect(struct rte_eth_dev *eth_dev, uint32_t mtr_id)
+{
+       return nix_mtr_connect(eth_dev, mtr_id);
+}
+
+static int
+cn10k_mtr_destroy(struct rte_eth_dev *eth_dev, uint32_t mtr_id)
+{
+       struct rte_mtr_error mtr_error;
+
+       return nix_mtr_destroy(eth_dev, mtr_id, &mtr_error);
+}
+
+static int
+cn10k_mtr_configure(struct rte_eth_dev *eth_dev,
+                   const struct rte_flow_action actions[])
+{
+       uint32_t mtr_id = 0xffff, prev_mtr_id = 0xffff, next_mtr_id = 0xffff;
+       const struct rte_flow_action_meter *mtr_conf;
+       const struct rte_flow_action_queue *q_conf;
+       const struct rte_flow_action_rss *rss_conf;
+       struct cnxk_mtr_policy_node *policy;
+       bool is_mtr_act = false;
+       int tree_level = 0;
+       int rc = -EINVAL, i;
+
+       for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
+               if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
+                       mtr_conf = (const struct rte_flow_action_meter
+                                           *)(actions[i].conf);
+                       mtr_id = mtr_conf->mtr_id;
+                       is_mtr_act = true;
+               }
+               if (actions[i].type == RTE_FLOW_ACTION_TYPE_QUEUE) {
+                       q_conf = (const struct rte_flow_action_queue
+                                         *)(actions[i].conf);
+                       if (is_mtr_act)
+                               nix_mtr_rq_update(eth_dev, mtr_id, 1,
+                                                 &q_conf->index);
+               }
+               if (actions[i].type == RTE_FLOW_ACTION_TYPE_RSS) {
+                       rss_conf = (const struct rte_flow_action_rss
+                                           *)(actions[i].conf);
+                       if (is_mtr_act)
+                               nix_mtr_rq_update(eth_dev, mtr_id,
+                                                 rss_conf->queue_num,
+                                                 rss_conf->queue);
+               }
+       }
+
+       if (!is_mtr_act)
+               return rc;
+
+       prev_mtr_id = mtr_id;
+       next_mtr_id = mtr_id;
+       while (next_mtr_id != 0xffff) {
+               rc = nix_mtr_validate(eth_dev, next_mtr_id);
+               if (rc)
+                       return rc;
+
+               rc = nix_mtr_policy_act_get(eth_dev, next_mtr_id, &policy);
+               if (rc)
+                       return rc;
+
+               rc = nix_mtr_color_action_validate(eth_dev, mtr_id,
+                                                  &prev_mtr_id, &next_mtr_id,
+                                                  policy, &tree_level);
+               if (rc)
+                       return rc;
+       }
+
+       return nix_mtr_configure(eth_dev, mtr_id);
+}
+
+static int
+cn10k_rss_action_validate(struct rte_eth_dev *eth_dev,
+                         const struct rte_flow_attr *attr,
+                         const struct rte_flow_action *act)
+{
+       const struct rte_flow_action_rss *rss;
+
+       if (act == NULL)
+               return -EINVAL;
+
+       rss = (const struct rte_flow_action_rss *)act->conf;
+
+       if (attr->egress) {
+               plt_err("No support of RSS in egress");
+               return -EINVAL;
+       }
+
+       if (eth_dev->data->dev_conf.rxmode.mq_mode != RTE_ETH_MQ_RX_RSS) {
+               plt_err("multi-queue mode is disabled");
+               return -ENOTSUP;
+       }
+
+       if (!rss || !rss->queue_num) {
+               plt_err("no valid queues");
+               return -EINVAL;
+       }
+
+       if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+               plt_err("non-default RSS hash functions are not supported");
+               return -ENOTSUP;
+       }
+
+       if (rss->key_len && rss->key_len > ROC_NIX_RSS_KEY_LEN) {
+               plt_err("RSS hash key too large");
+               return -ENOTSUP;
+       }
+
+       return 0;
+}
+
 struct rte_flow *
 cn10k_flow_create(struct rte_eth_dev *eth_dev, const struct rte_flow_attr *attr,
                  const struct rte_flow_item pattern[],
@@ -13,13 +128,74 @@ cn10k_flow_create(struct rte_eth_dev *eth_dev, const struct rte_flow_attr *attr,
                  struct rte_flow_error *error)
 {
        struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
+       const struct rte_flow_action *action_rss = NULL;
+       const struct rte_flow_action_meter *mtr = NULL;
+       const struct rte_flow_action *act_q = NULL;
        int mark_actions = 0, vtag_actions = 0;
        struct roc_npc *npc = &dev->npc;
        struct roc_npc_flow *flow;
+       uint32_t req_act = 0;
+       int i, rc;
+
+       for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
+               if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER)
+                       req_act |= ROC_NPC_ACTION_TYPE_METER;
+
+               if (actions[i].type == RTE_FLOW_ACTION_TYPE_QUEUE) {
+                       req_act |= ROC_NPC_ACTION_TYPE_QUEUE;
+                       act_q = &actions[i];
+               }
+               if (actions[i].type == RTE_FLOW_ACTION_TYPE_RSS) {
+                       req_act |= ROC_NPC_ACTION_TYPE_RSS;
+                       action_rss = &actions[i];
+               }
+       }
+
+       if (req_act & ROC_NPC_ACTION_TYPE_METER) {
+               if ((req_act & ROC_NPC_ACTION_TYPE_RSS) &&
+                   ((req_act & ROC_NPC_ACTION_TYPE_QUEUE))) {
+                       return NULL;
+               }
+               if (req_act & ROC_NPC_ACTION_TYPE_RSS) {
+                       rc = cn10k_rss_action_validate(eth_dev, attr,
+                                                      action_rss);
+                       if (rc)
+                               return NULL;
+               } else if (req_act & ROC_NPC_ACTION_TYPE_QUEUE) {
+                       const struct rte_flow_action_queue *act_queue;
+                       act_queue = (const struct rte_flow_action_queue *)
+                                           act_q->conf;
+                       if (act_queue->index > eth_dev->data->nb_rx_queues)
+                               return NULL;
+               } else {
+                       return NULL;
+               }
+       }
+       for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
+               if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
+                       mtr = (const struct rte_flow_action_meter *)actions[i]
+                                     .conf;
+                       rc = cn10k_mtr_configure(eth_dev, actions);
+                       if (rc) {
+                               rte_flow_error_set(error, rc,
+                                       RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                       "Failed to configure mtr ");
+                               return NULL;
+                       }
+                       break;
+               }
+       }
 
        flow = cnxk_flow_create(eth_dev, attr, pattern, actions, error);
-       if (!flow)
+       if (!flow) {
+               if (mtr)
+                       nix_mtr_chain_reset(eth_dev, mtr->mtr_id);
+
                return NULL;
+       } else {
+               if (mtr)
+                       cn10k_mtr_connect(eth_dev, mtr->mtr_id);
+       }
 
        mark_actions = roc_npc_mark_actions_get(npc);
 
@@ -46,6 +222,8 @@ cn10k_flow_destroy(struct rte_eth_dev *eth_dev, struct rte_flow *rte_flow,
        struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
        int mark_actions = 0, vtag_actions = 0;
        struct roc_npc *npc = &dev->npc;
+       uint32_t mtr_id;
+       int rc;
 
        mark_actions = roc_npc_mark_actions_get(npc);
        if (mark_actions) {
@@ -68,5 +246,15 @@ cn10k_flow_destroy(struct rte_eth_dev *eth_dev, struct rte_flow *rte_flow,
                }
        }
 
-       return cnxk_flow_destroy(eth_dev, flow, error);
+       mtr_id = flow->mtr_id;
+       rc = cnxk_flow_destroy(eth_dev, flow, error);
+       if (!rc && mtr_id != ROC_NIX_MTR_ID_INVALID) {
+               rc = cn10k_mtr_destroy(eth_dev, mtr_id);
+               if (rc) {
+                       rte_flow_error_set(error, ENXIO,
+                               RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                               "Meter attached to this flow does not exist");
+               }
+       }
+       return rc;
 }