From: Wenjing Qiao <wenjing.q...@intel.com>

Add TDI implementation to a flow engine.

Signed-off-by: Wenjing Qiao <wenjing.q...@intel.com>
---
 doc/guides/nics/cpfl.rst                |   10 +
 doc/guides/nics/features/cpfl.ini       |    1 +
 drivers/net/cpfl/cpfl_ethdev.h          |    8 +
 drivers/net/cpfl/cpfl_flow.c            |    5 +-
 drivers/net/cpfl/cpfl_flow.h            |    1 +
 drivers/net/cpfl/cpfl_flow_engine_fxp.c |   12 -
 drivers/net/cpfl/cpfl_flow_parser.c     |    8 +
 drivers/net/cpfl/cpfl_fxp_rule.h        |   12 +
 drivers/net/cpfl/cpfl_tdi.c             | 1282 +++++++++++++++++++++++
 drivers/net/cpfl/cpfl_tdi.h             |  123 +++
 drivers/net/cpfl/meson.build            |    1 +
 11 files changed, 1450 insertions(+), 13 deletions(-)
 create mode 100644 drivers/net/cpfl/cpfl_tdi.c
 create mode 100644 drivers/net/cpfl/cpfl_tdi.h

diff --git a/doc/guides/nics/cpfl.rst b/doc/guides/nics/cpfl.rst
index 9b7a99c894..591bd496e6 100644
--- a/doc/guides/nics/cpfl.rst
+++ b/doc/guides/nics/cpfl.rst
@@ -213,6 +213,16 @@ low level hardware resources.
       flow create X ingress group M pattern eth dst is 00:01:00:00:03:14 / 
ipv4 src is 192.168.0.1 \
       dst is 192.168.0.2 / tcp / end actions port_representor port_id Y / end
 
+#. Create one flow for TDI engine to forward ETH-IPV4-TCP from I/O port to a 
local(CPF's) vport. Flow should
+   be created on vport X. Group M should be table id. Prog name N should be 
action id. Prog arguments
+   port_representor Y means forward packet to local vport Y::
+
+   .. code-block:: console
+
+      flow create X ingress group M pattern prog key is 0x00 / prog key is 
0x000100000314 / prog key
+      is 0x001122334455 / prog key is 0xC0A80001 / prog key is 0xC0A80002 / 
prog key is 0x1451 / prog key
+      is 0x157C / end actions prog name N arguments port_representor Y  end / 
end
+
 #. Send a matched packet, and it should be displayed on PMD::
 
    .. code-block:: console
diff --git a/doc/guides/nics/features/cpfl.ini 
b/doc/guides/nics/features/cpfl.ini
index 4eadaca6e7..85b8011a54 100644
--- a/doc/guides/nics/features/cpfl.ini
+++ b/doc/guides/nics/features/cpfl.ini
@@ -33,6 +33,7 @@ tcp                  = Y
 udp                  = Y
 vlan                 = Y
 vxlan                = Y
+flex                 = Y
 
 [rte_flow actions]
 count                = Y
diff --git a/drivers/net/cpfl/cpfl_ethdev.h b/drivers/net/cpfl/cpfl_ethdev.h
index e580f80f2f..7dfa4a0183 100644
--- a/drivers/net/cpfl/cpfl_ethdev.h
+++ b/drivers/net/cpfl/cpfl_ethdev.h
@@ -185,10 +185,18 @@ struct cpfl_repr {
        bool func_up; /* If the represented function is up */
 };
 
+struct cpfl_tdi_table_node;
+TAILQ_HEAD(cpfl_tdi_table_list, cpfl_tdi_table_node);
+
+struct cpfl_tdi_action_node;
+TAILQ_HEAD(cpfl_tdi_action_list, cpfl_tdi_action_node);
+
 struct cpfl_flow_parser {
        struct cpfl_flow_js_parser *fixed_parser;
        struct cpfl_tdi_program *p4_parser;
        bool is_p4_parser;
+       struct cpfl_tdi_table_list tdi_table_list;
+       struct cpfl_tdi_action_list tdi_action_list;
 };
 
 struct cpfl_metadata_chunk {
diff --git a/drivers/net/cpfl/cpfl_flow.c b/drivers/net/cpfl/cpfl_flow.c
index 1c4131da2c..15c7cc6d8b 100644
--- a/drivers/net/cpfl/cpfl_flow.c
+++ b/drivers/net/cpfl/cpfl_flow.c
@@ -6,6 +6,7 @@
 
 #include "cpfl_flow.h"
 #include "cpfl_flow_parser.h"
+#include "cpfl_tdi.h"
 #include "cpfl_tdi_parser.h"
 
 TAILQ_HEAD(cpfl_flow_engine_list, cpfl_flow_engine);
@@ -338,8 +339,10 @@ cpfl_flow_uninit(struct cpfl_adapter_ext *ad)
        if (ad->flow_parser.fixed_parser)
                cpfl_parser_destroy(ad->flow_parser.fixed_parser);
 
-       if (ad->flow_parser.p4_parser)
+       if (ad->flow_parser.p4_parser) {
+               cpfl_tdi_free_table_list(&ad->flow_parser);
                cpfl_tdi_program_destroy(ad->flow_parser.p4_parser);
+       }
 
        cpfl_flow_engine_uninit(ad);
 }
diff --git a/drivers/net/cpfl/cpfl_flow.h b/drivers/net/cpfl/cpfl_flow.h
index 1bde847763..1de9c25b17 100644
--- a/drivers/net/cpfl/cpfl_flow.h
+++ b/drivers/net/cpfl/cpfl_flow.h
@@ -15,6 +15,7 @@ extern const struct rte_flow_ops cpfl_flow_ops;
 enum cpfl_flow_engine_type {
        CPFL_FLOW_ENGINE_NONE = 0,
        CPFL_FLOW_ENGINE_FXP,
+       CPFL_FLOW_ENGINE_TDI,
 };
 
 typedef int (*engine_init_t)(struct cpfl_adapter_ext *ad);
diff --git a/drivers/net/cpfl/cpfl_flow_engine_fxp.c 
b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
index f269ff97e1..6a5e7ed770 100644
--- a/drivers/net/cpfl/cpfl_flow_engine_fxp.c
+++ b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
@@ -27,23 +27,11 @@
 #include "cpfl_fxp_rule.h"
 #include "cpfl_flow_parser.h"
 
-#define CPFL_COOKIE_DEF                0x1000
-#define CPFL_MOD_COOKIE_DEF    0x1237561
 #define CPFL_PREC_DEF          1
 #define CPFL_PREC_SET          5
 #define CPFL_TYPE_ID           3
 #define CPFL_OFFSET            0x0a
-#define CPFL_HOST_ID_DEF       0
 #define CPFL_PF_NUM_DEF                0
-#define CPFL_PORT_NUM_DEF      0
-#define CPFL_RESP_REQ_DEF      2
-#define CPFL_PIN_TO_CACHE_DEF  0
-#define CPFL_CLEAR_MIRROR_1ST_STATE_DEF        0
-#define CPFL_FIXED_FETCH_DEF   0
-#define CPFL_PTI_DEF           0
-#define CPFL_MOD_OBJ_SIZE_DEF  0
-#define CPFL_PIN_MOD_CONTENT_DEF       0
-
 #define CPFL_MAX_MOD_CONTENT_INDEX     256
 #define CPFL_MAX_MR_ACTION_NUM 8
 
diff --git a/drivers/net/cpfl/cpfl_flow_parser.c 
b/drivers/net/cpfl/cpfl_flow_parser.c
index e7f8a8a6cc..a3572e32d5 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.c
+++ b/drivers/net/cpfl/cpfl_flow_parser.c
@@ -6,6 +6,7 @@
 
 #include "cpfl_flow_parser.h"
 #include "cpfl_tdi_parser.h"
+#include "cpfl_tdi.h"
 
 static enum rte_flow_item_type
 cpfl_get_item_type_by_str(const char *type)
@@ -976,6 +977,13 @@ cpfl_parser_create(struct cpfl_flow_parser *flow_parser, 
const char *filename)
                flow_parser->p4_parser = prog;
                flow_parser->fixed_parser = NULL;
                flow_parser->is_p4_parser = true;
+
+               ret = cpfl_tdi_build(flow_parser);
+               if (ret != 0) {
+                       PMD_INIT_LOG(ERR, "Failed to build tdi program %s", 
filename);
+                       rte_free(prog);
+                       return -EINVAL;
+               }
        } else {
                PMD_DRV_LOG(NOTICE, "flow parser mode is fixed function mode.");
                parser = rte_zmalloc("flow_parser", sizeof(struct 
cpfl_flow_js_parser), 0);
diff --git a/drivers/net/cpfl/cpfl_fxp_rule.h b/drivers/net/cpfl/cpfl_fxp_rule.h
index ed757b80b1..f089155353 100644
--- a/drivers/net/cpfl/cpfl_fxp_rule.h
+++ b/drivers/net/cpfl/cpfl_fxp_rule.h
@@ -9,6 +9,18 @@
 
 #define CPFL_MAX_KEY_LEN 128
 #define CPFL_MAX_RULE_ACTIONS 32
+#define CPFL_RESP_REQ_DEF      2
+#define CPFL_PIN_TO_CACHE_DEF  0
+#define CPFL_CLEAR_MIRROR_1ST_STATE_DEF        0
+#define CPFL_FIXED_FETCH_DEF   0
+#define CPFL_PTI_DEF           0
+#define CPFL_MOD_OBJ_SIZE_DEF  0
+#define CPFL_PIN_MOD_CONTENT_DEF       0
+#define CPFL_HOST_ID_DEF       0
+#define CPFL_PORT_NUM_DEF      0
+#define CPFL_VSI_DEF   0
+#define CPFL_COOKIE_DEF                0x1000
+#define CPFL_MOD_COOKIE_DEF    0x1237561
 
 struct cpfl_sem_rule_info {
        uint16_t prof_id;
diff --git a/drivers/net/cpfl/cpfl_tdi.c b/drivers/net/cpfl/cpfl_tdi.c
new file mode 100644
index 0000000000..ac681ecc01
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi.c
@@ -0,0 +1,1282 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#include <rte_hash_crc.h>
+#include <rte_tailq.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "cpfl_actions.h"
+#include "cpfl_flow.h"
+#include "cpfl_fxp_rule.h"
+#include "cpfl_tdi.h"
+#include "cpfl_tdi_parser.h"
+#include "rte_branch_prediction.h"
+#include "rte_common.h"
+#include "rte_flow.h"
+
+#define CPFL_NO_FWD 0
+uint64_t cpfl_tdi_rule_cookie = CPFL_COOKIE_DEF;
+
+/*help function to do left shift on a byte array */
+static void
+cpfl_tdi_shift_left(uint8_t *buf, int length, uint32_t shift_amount)
+{
+       uint32_t i;
+       int j;
+       uint32_t carry = 0;
+
+       if (shift_amount == 0)
+               return;
+
+       for (i = 0; i < shift_amount; i += 8) {
+               for (j = 0; j < length; j++) {
+                       uint32_t temp = (buf[j] << (shift_amount - i)) | carry;
+
+                       carry = (temp >> 8) & 0xff;
+                       buf[j] = temp & 0xff;
+               }
+       }
+}
+
+/* help function to init a mask array with bit_width */
+static void
+cpfl_tdi_init_msk_buf(uint8_t *buf, int length, uint32_t bit_width)
+{
+       uint32_t i;
+
+       memset(buf, 0, length);
+       for (i = 0; i < bit_width; i++) {
+               cpfl_tdi_shift_left(buf, length, 1);
+               buf[0] += 1;
+       }
+}
+
+/* help function to OR a byte array with value and mask */
+static void
+cpfl_tdi_or_buf(uint8_t *buf, int length, uint8_t *values, uint8_t *mask)
+{
+       int i;
+
+       for (i = 0; i < length; i++)
+               buf[i] = (values[i] & mask[i]) | (buf[i] & ~mask[i]);
+}
+
+static uint32_t
+cpfl_tdi_to_action_code(struct cpfl_tdi_hw_action *ha,
+                       uint8_t *val,
+                       enum cpfl_act_fwd_type fwd_type)
+{
+       switch (ha->action_code) {
+       case CPFL_TDI_ACTION_CODE_SET1A_24b:
+               switch (ha->index) {
+               case 0: /* mod addr */
+                       return cpfl_act_mod_addr(ha->prec, (uint32_t)*val).data;
+               case 8: /* todo */
+                       break;
+               default:
+                       PMD_DRV_LOG(WARNING, "Unsupported SET1A_24b index %d", 
ha->index);
+                       break;
+               }
+               break;
+       case CPFL_TDI_ACTION_CODE_SET1_16b:
+               switch (ha->index) {
+               case 2: /* set vsi */
+                       if (fwd_type == CPFL_ACT_FWD_VSI)
+                               return cpfl_act_fwd_vsi(0, ha->prec, 
CPFL_PE_LAN, (uint16_t)*val)
+                                   .data;
+                       else if (fwd_type == CPFL_ACT_FWD_PORT)
+                               return cpfl_act_fwd_port(0, ha->prec, 
CPFL_PE_LAN, (uint16_t)*val)
+                                   .data;
+                       else
+                               PMD_DRV_LOG(WARNING, "Unsupported fwd type %d", 
fwd_type);
+                       break;
+               default:
+                       PMD_DRV_LOG(WARNING, "Unsupported SET1_16b index %d", 
ha->index);
+                       break;
+               }
+               break;
+       case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+               switch (ha->setmd_action_code) {
+               case CPFL_TDI_SETMD_ACTION_CODE_SET_16b:
+                       return cpfl_act_set_md16(ha->index, ha->prec, 
ha->type_id, ha->offset,
+                                                (uint16_t)*val)
+                           .data;
+               case CPFL_TDI_SETMD_ACTION_CODE_SET_32b_AUX: /* todo */
+                       break;
+               default:
+                       PMD_DRV_LOG(WARNING, "Unsupported SET1b_24b setmd code 
%d",
+                                   ha->setmd_action_code);
+                       break;
+               }
+               break;
+       default:
+               PMD_DRV_LOG(WARNING, "Unsupported action code %d", 
ha->action_code);
+               break;
+       }
+
+       return 0;
+}
+
+static void
+cpfl_tdi_pack_sem_entry(struct cpfl_tdi_rule_info *rinfo,
+                       struct cpfl_tdi_ma_hardware_block *hb,
+                       enum cpfl_tdi_table_entry_op op,
+                       struct idpf_dma_mem *dma,
+                       struct idpf_ctlq_msg *msg)
+{
+       union cpfl_rule_cfg_pkt_record *blob;
+       struct cpfl_rule_cfg_data cfg = {0};
+       uint16_t cfg_ctrl;
+       enum cpfl_ctlq_rule_cfg_opc opc = 0;
+       const struct cpfl_tdi_table_key_obj *key = &rinfo->kobj;
+       const struct cpfl_tdi_action_obj *action = &rinfo->aobj;
+
+       blob = (void *)dma->va;
+       memset(blob, 0, sizeof(*blob));
+
+       cfg_ctrl = CPFL_GET_MEV_SEM_RULE_CFG_CTRL(hb->profile[0], 
hb->sem.sub_profile, 0, 0);
+
+       switch (op) {
+       case CPFL_TDI_TABLE_ENTRY_OP_ADD:
+               cpfl_prep_sem_rule_blob(key->buf, key->buf_len, action->buf, 
action->buf_len,
+                                       cfg_ctrl, blob);
+               opc = cpfl_ctlq_sem_add_rule;
+               break;
+       case CPFL_TDI_TABLE_ENTRY_OP_DEL:
+               cpfl_prep_sem_rule_blob(key->buf, key->buf_len, NULL, 0, 
cfg_ctrl, blob);
+               opc = cpfl_ctlq_sem_del_rule;
+               break;
+       case CPFL_TDI_TABLE_ENTRY_OP_QRY:
+               cpfl_prep_sem_rule_blob(key->buf, key->buf_len, NULL, 0, 
cfg_ctrl, blob);
+               opc = cpfl_ctlq_sem_query_rule;
+               break;
+       default:
+               PMD_DRV_LOG(ERR, "Unknown ops, this is a bug.");
+               break;
+       }
+
+       cpfl_fill_rule_cfg_data_common(opc,
+                                      rinfo->cookie,
+                                      rinfo->vsi,
+                                      rinfo->port_num,
+                                      rinfo->host_id,
+                                      0, /* time_sel */
+                                      0, /* time_sel_val */
+                                      0, /* cache_wr_thru */
+                                      rinfo->resp_req,
+                                      sizeof(union cpfl_rule_cfg_pkt_record),
+                                      dma,
+                                      &cfg.common);
+
+       cpfl_prep_rule_desc(&cfg, msg);
+}
+
+static void
+cpfl_tdi_pack_mod_entry(struct cpfl_tdi_rule_info *rinfo,
+                       enum cpfl_tdi_table_entry_op op,
+                       struct idpf_dma_mem *dma,
+                       struct idpf_ctlq_msg *msg)
+{
+       union cpfl_rule_cfg_pkt_record *blob;
+       struct cpfl_rule_cfg_data cfg = {0};
+       uint32_t mod_index;
+       enum cpfl_ctlq_rule_cfg_opc opc = 0;
+       const struct cpfl_tdi_table_key_obj *key = &rinfo->kobj;
+       const struct cpfl_tdi_action_obj *action = &rinfo->aobj;
+
+       blob = (void *)dma->va;
+       memset(blob, 0, sizeof(*blob));
+
+       mod_index = *(const uint32_t *)&key->buf[0];
+
+       switch (op) {
+       case CPFL_TDI_TABLE_ENTRY_OP_ADD:
+               cpfl_fill_rule_mod_content(CPFL_MOD_OBJ_SIZE_DEF, 
CPFL_PIN_MOD_CONTENT_DEF,
+                                          mod_index, &cfg.ext.mod_content);
+
+               memcpy(blob->mod_blob, action->buf, action->buf_len);
+               opc = cpfl_ctlq_mod_add_update_rule;
+               break;
+       case CPFL_TDI_TABLE_ENTRY_OP_QRY:
+               opc = cpfl_ctlq_mod_query_rule;
+               break;
+       default:
+               break;
+       }
+
+       cpfl_fill_rule_cfg_data_common(opc,
+                                      CPFL_MOD_COOKIE_DEF,
+                                      0, /* vsi_id not used for mod */
+                                      CPFL_PORT_NUM_DEF,
+                                      0,
+                                      0,           /* time_sel */
+                                      0,                           /* 
time_sel_val */
+                                      0,                           /* 
cache_wr_thru */
+                                      CPFL_RESP_REQ_DEF,
+                                      sizeof(union cpfl_rule_cfg_pkt_record),
+                                      dma,
+                                      &cfg.common);
+
+       cpfl_prep_rule_desc(&cfg, msg);
+}
+
+static int
+cpfl_tdi_rule_process(struct cpfl_itf *itf,
+                     struct idpf_ctlq_info *tx_cq,
+                     struct idpf_ctlq_info *rx_cq,
+                     struct cpfl_tdi_rule_info *rinfo,
+                     int rule_num,
+                     enum cpfl_tdi_table_entry_op op)
+{
+       const struct cpfl_tdi_table_key_obj *kobj;
+       struct idpf_hw *hw = &itf->adapter->base.hw;
+       struct cpfl_tdi_ma_hardware_block *hb;
+       const struct cpfl_tdi_table *table;
+       int ret = 0;
+
+       if (rule_num == 0)
+               return 0;
+
+       kobj = &rinfo->kobj;
+
+       table = kobj->tnode->table;
+       if (table->match_attributes.hardware_block_num == 0) {
+               PMD_DRV_LOG(ERR, "No valid hardware block be specified");
+               return -EINVAL;
+       }
+       hb = &table->match_attributes.hardware_blocks[0];
+       switch (hb->hw_block) {
+       case CPFL_TDI_HW_BLOCK_SEM:
+               cpfl_tdi_pack_sem_entry(rinfo, hb, op, &itf->dma[0], 
&itf->msg[0]);
+               break;
+       case CPFL_TDI_HW_BLOCK_MOD:
+               if (op == CPFL_TDI_TABLE_ENTRY_OP_DEL)
+                       /* do nothing */
+                       return 0;
+               cpfl_tdi_pack_mod_entry(rinfo, op, &itf->dma[0], &itf->msg[0]);
+               break;
+       default:
+               PMD_DRV_LOG(ERR, "Unsupported hardware block %d", hb->hw_block);
+               return -EINVAL;
+       }
+
+       ret = cpfl_send_ctlq_msg(hw, tx_cq, 1, itf->msg);
+       if (ret != 0) {
+               PMD_DRV_LOG(ERR, "Failed to send control message");
+               return -EINVAL;
+       }
+
+       ret = cpfl_receive_ctlq_msg(hw, rx_cq, 1, itf->msg);
+       if (ret) {
+               PMD_INIT_LOG(ERR, "Failed to update rule");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int
+cpfl_tdi_fxp_rule_create(struct rte_eth_dev *dev,
+                        struct rte_flow *flow,
+                        void *meta,
+                        struct rte_flow_error *error)
+{
+       struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+       struct cpfl_adapter_ext *ad = itf->adapter;
+       int ret;
+       uint32_t cpq_id = 0;
+       struct cpfl_vport *vport;
+       struct cpfl_repr *repr;
+       struct cpfl_tdi_rule_info *rinfo = meta;
+
+       if (!rinfo)
+               goto err;
+
+       if (itf->type == CPFL_ITF_TYPE_VPORT) {
+               vport = (struct cpfl_vport *)itf;
+               /* Every vport has one pair control queues configured to handle 
message.
+                * Even index is tx queue and odd index is rx queue.
+                */
+               cpq_id = vport->base.devarg_id * 2;
+       } else if (itf->type == CPFL_ITF_TYPE_REPRESENTOR) {
+               repr = (struct cpfl_repr *)itf;
+               cpq_id = ((repr->repr_id.pf_id + repr->repr_id.vf_id) & 
(CPFL_TX_CFGQ_NUM - 1)) * 2;
+       } else {
+               rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, 
NULL,
+                                  "fail to find correct control queue");
+               return -rte_errno;
+       }
+
+       ret = cpfl_tdi_rule_process(itf, ad->ctlqp[cpq_id], ad->ctlqp[cpq_id + 
1], rinfo, 1,
+                                   CPFL_TDI_TABLE_ENTRY_OP_ADD);
+       if (ret)
+               goto err;
+
+       flow->rule = rinfo;
+
+       return 0;
+
+err:
+       return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, 
NULL,
+                                 "cpfl filter create flow fail");
+}
+
+static int
+cpfl_tdi_fxp_rule_destroy(struct rte_eth_dev *dev,
+                         struct rte_flow *flow,
+                         struct rte_flow_error *error)
+{
+       struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+       struct cpfl_adapter_ext *ad = itf->adapter;
+       struct cpfl_vport *vport;
+       struct cpfl_repr *repr;
+       struct cpfl_tdi_rule_info *rinfo = (struct cpfl_tdi_rule_info 
*)flow->rule;
+       int ret = 0;
+       uint32_t cpq_id = 0;
+
+       if (itf->type == CPFL_ITF_TYPE_VPORT) {
+               vport = (struct cpfl_vport *)itf;
+               cpq_id = vport->base.devarg_id * 2;
+       } else if (itf->type == CPFL_ITF_TYPE_REPRESENTOR) {
+               repr = (struct cpfl_repr *)itf;
+               cpq_id = ((repr->repr_id.pf_id + repr->repr_id.vf_id) & 
(CPFL_TX_CFGQ_NUM - 1)) * 2;
+       } else {
+               rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, 
NULL,
+                                  "fail to find correct control queue");
+               ret = -rte_errno;
+               goto err;
+       }
+
+       ret = cpfl_tdi_rule_process(itf, ad->ctlqp[cpq_id], ad->ctlqp[cpq_id + 
1], rinfo, 1,
+                                   CPFL_TDI_TABLE_ENTRY_OP_DEL);
+       if (ret)
+               goto err;
+
+err:
+       rte_free(rinfo);
+       flow->rule = NULL;
+       return ret;
+}
+
+void
+cpfl_tdi_free_table_list(struct cpfl_flow_parser *flow_parser)
+{
+       struct cpfl_tdi_table_node *node;
+
+       while ((node = TAILQ_FIRST(&flow_parser->tdi_table_list))) {
+               TAILQ_REMOVE(&flow_parser->tdi_table_list, node, next);
+               rte_free(node);
+       }
+}
+
+static int
+cpfl_tdi_build_table_list(struct cpfl_flow_parser *flow_parser)
+{
+       struct cpfl_tdi_program *prog = flow_parser->p4_parser;
+       int i;
+
+       TAILQ_INIT(&flow_parser->tdi_table_list);
+
+       for (i = 0; i < prog->table_num; i++) {
+               struct cpfl_tdi_table *table = &prog->tables[i];
+               struct cpfl_tdi_table_node *node;
+
+               node = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_table_node), 0);
+               if (node == NULL)
+                       return -ENOMEM;
+
+               node->table = table;
+               TAILQ_INSERT_TAIL(&flow_parser->tdi_table_list, node, next);
+       }
+
+       return 0;
+}
+
+static void
+cpfl_tdi_build_hw_action_buf(struct cpfl_tdi_action_node *node)
+{
+       int i, j;
+
+       for (i = 0; i < node->format->hw_action_num; i++) {
+               struct cpfl_tdi_hw_action *ha = 
&node->format->hw_actions_list[i];
+               struct cpfl_tdi_hw_action_parameter *hap = &ha->parameters[0];
+               uint32_t msk = UINT32_MAX;
+               uint32_t action_code = 0;
+               uint16_t offset;
+               uint16_t size;
+
+               switch (ha->action_code) {
+               case CPFL_TDI_ACTION_CODE_SET10_1b:
+               case CPFL_TDI_ACTION_CODE_SET1_16b:
+               case CPFL_TDI_ACTION_CODE_SET1A_24b:
+               case CPFL_TDI_ACTION_CODE_SET1B_24b:
+                       offset = node->buf_len;
+                       size = 4;
+                       node->buf_len += 4; /* 32 bit action encode */
+                       break;
+               default:
+                       continue;
+               }
+
+               if (ha->parameter_num == 0) {
+                       switch (ha->action_code) {
+                       case CPFL_TDI_ACTION_CODE_SET10_1b:
+                               switch (ha->index) {
+                               case 0: /* drop */
+                                       action_code = CPFL_ACT_MAKE_1B(ha->prec,
+                                                                      
CPFL_ACT_1B_OP_DROP,
+                                                                      
ha->value & ha->mask);
+                                       break;
+                               default:
+                                       continue;
+                               }
+                               break;
+                       case CPFL_TDI_ACTION_CODE_SET1A_24b:
+                               switch (ha->index) {
+                               case 9: /* mod profile */
+                                       action_code =
+                                           cpfl_act_mod_profile(ha->prec, 
ha->mod_profile, 0, 0, 0,
+                                                                
CPFL_ACT_MOD_PROFILE_PREFETCH_256B)
+                                               .data;
+                                       break;
+                               case 8: /* queue */
+                                       /* todo */
+                                       break;
+                               default:
+                                       break;
+                               }
+                               break;
+                       case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+                               switch (ha->setmd_action_code) {
+                               case CPFL_TDI_SETMD_ACTION_CODE_SET_8b:
+                                       action_code =
+                                           cpfl_act_set_md8(ha->index, 
ha->prec, ha->type_id,
+                                                            ha->offset, 
ha->value, ha->mask)
+                                               .data;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               break;
+                       default:
+                               continue;
+                       }
+
+                       memcpy(&node->init_buf[offset], &action_code, 4);
+                       memcpy(&node->query_msk[offset], &msk, 4);
+                       continue;
+               } else {
+                       uint32_t code_msk = 0;
+                       uint32_t dummy = 0;
+                       uint32_t action_code =
+                           cpfl_tdi_to_action_code(ha, (void *)&dummy, 
CPFL_NO_FWD);
+
+                       switch (ha->action_code) {
+                       case CPFL_TDI_ACTION_CODE_SET10_1b:
+                               code_msk = ~CPFL_ACT_1B_VAL_M;
+                               break;
+                       case CPFL_TDI_ACTION_CODE_SET1_16b:
+                               code_msk = ~CPFL_ACT_16B_VAL_M;
+                               break;
+                       case CPFL_TDI_ACTION_CODE_SET1A_24b:
+                               code_msk = ~CPFL_ACT_24B_A_VAL_M;
+                               break;
+                       case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+                               code_msk = ~CPFL_ACT_24B_B_VAL_M;
+                               break;
+                       default:
+                               continue;
+                       }
+
+                       memcpy(&node->init_buf[offset], &action_code, 4);
+                       memcpy(&node->query_msk[offset], &code_msk, 4);
+               }
+
+               /* only check the first parameter */
+               for (j = 0; j < node->format->immediate_field_num; j++) {
+                       struct cpfl_tdi_immediate_field *imf = 
&node->format->immediate_fields[j];
+
+                       if (imf->param_handle == hap->param_handle) {
+                               node->params[j].id = imf->param_handle;
+                               node->params[j].offset = offset;
+                               node->params[j].size = size;
+                       }
+               }
+       }
+}
+
+static void
+cpfl_tdi_build_mod_content_format_buf(struct cpfl_tdi_action_node *node)
+{
+       int i, j;
+       uint8_t val_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+       uint8_t msk_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+
+       for (i = 0; i < node->format->mod_content_format.mod_field_num; i++) {
+               struct cpfl_tdi_mod_field *mf = 
&node->format->mod_content_format.mod_fields[i];
+               uint16_t size = (uint16_t)((mf->start_bit_offset + 
mf->bit_width) >> 3);
+
+               node->buf_len += size;
+
+               if (mf->type == CPFL_TDI_MOD_FIELD_TYPE_CONSTANT) {
+                       memcpy(val_buf, mf->value, size);
+                       cpfl_tdi_shift_left(val_buf, size, 
mf->start_bit_offset);
+                       cpfl_tdi_init_msk_buf(msk_buf, size, mf->bit_width);
+                       cpfl_tdi_shift_left(msk_buf, size, 
mf->start_bit_offset);
+                       cpfl_tdi_or_buf(&node->init_buf[mf->byte_array_index], 
size, val_buf,
+                                       msk_buf);
+                       continue;
+               }
+
+               for (j = 0; j < node->format->immediate_field_num; j++) {
+                       struct cpfl_tdi_immediate_field *imf = 
&node->format->immediate_fields[j];
+
+                       if (imf->param_handle == mf->param_handle) {
+                               node->params[j].id = imf->param_handle;
+                               node->params[j].offset = mf->byte_array_index;
+                               node->params[j].size = size;
+                               break;
+                       }
+               }
+       }
+}
+
+static void
+cpfl_tdi_build_action_params(struct cpfl_tdi_action_node *node)
+{
+       node->buf_len = 0;
+       /* build mod content layout */
+       if (node->format->mod_content_format.mod_field_num > 0) {
+               cpfl_tdi_build_mod_content_format_buf(node);
+               /* build action buffer layout */
+       } else if (node->format->hw_action_num > 0) {
+               cpfl_tdi_build_hw_action_buf(node);
+       }
+}
+
+static void
+cpfl_tdi_free_action_list(struct cpfl_flow_parser *flow_parser)
+{
+       struct cpfl_tdi_action_node *action;
+
+       while ((action = TAILQ_FIRST(&flow_parser->tdi_action_list))) {
+               TAILQ_REMOVE(&flow_parser->tdi_action_list, action, next);
+               rte_free(action);
+       }
+}
+
+static int
+cpfl_tdi_build_action_list(struct cpfl_flow_parser *flow_parser)
+{
+#define _HASH_TABLE_NAME_SIZE 32
+#define _HASH_TABLE_ENTRY_SIZE 1024
+       struct cpfl_tdi_program *prog = flow_parser->p4_parser;
+       char hname[_HASH_TABLE_NAME_SIZE];
+       struct rte_hash *ht;
+       int ret = 0;
+       int i, j, k;
+
+       snprintf(hname, _HASH_TABLE_NAME_SIZE, "cpfl_tdi_action_hash");
+
+       struct rte_hash_parameters params = {
+           .name = hname,
+           .entries = _HASH_TABLE_ENTRY_SIZE,
+           .key_len = sizeof(uint32_t),
+           .hash_func = rte_hash_crc,
+           .hash_func_init_val = 0,
+           .socket_id = SOCKET_ID_ANY,
+           .extra_flag = 0,
+       };
+
+       ht = rte_hash_create(&params);
+
+       if (ht == NULL) {
+               PMD_INIT_LOG(ERR, "Failed to create hash table %s", hname);
+               return -EINVAL;
+       }
+
+       TAILQ_INIT(&flow_parser->tdi_action_list);
+
+       for (i = 0; i < prog->table_num; i++) {
+               struct cpfl_tdi_table *table = &prog->tables[i];
+
+               for (j = 0; j < table->action_num; j++) {
+                       struct cpfl_tdi_action *action = &table->actions[j];
+                       uint32_t handle = action->handle;
+                       struct cpfl_tdi_action_node *node;
+
+                       /* skip if already exist */
+                       if (rte_hash_lookup(ht, &handle) >= 0)
+                               continue;
+
+                       node = rte_zmalloc(NULL, sizeof(struct 
cpfl_tdi_action_node), 0);
+                       if (node == NULL) {
+                               ret = -ENOMEM;
+                               goto err;
+                       }
+
+                       node->action = action;
+                       ret = rte_hash_add_key_data(ht, &handle, node);
+                       if (ret != 0)
+                               goto err;
+
+                       TAILQ_INSERT_TAIL(&flow_parser->tdi_action_list, node, 
next);
+               }
+
+               for (j = 0; j < table->match_attributes.hardware_block_num; 
j++) {
+                       struct cpfl_tdi_ma_hardware_block *hb =
+                           &table->match_attributes.hardware_blocks[j];
+
+                       for (k = 0; k < hb->action_format_num; k++) {
+                               struct cpfl_tdi_action_format *format = 
&hb->action_format[k];
+                               uint32_t handle = format->action_handle;
+                               struct cpfl_tdi_action_node *node = NULL;
+
+                               if (rte_hash_lookup_data(ht, &handle, (void 
**)&node) >= 0) {
+                                       node->hw_block_type = hb->hw_block;
+                                       if (node->format == NULL) {
+                                               node->format = format;
+                                               
cpfl_tdi_build_action_params(node);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       rte_hash_free(ht);
+
+       return 0;
+
+err:
+
+       rte_hash_free(ht);
+       cpfl_tdi_free_action_list(flow_parser);
+       return ret;
+}
+
+static int
+cpfl_tdi_table_info_get(struct rte_eth_dev *dev,
+                       uint32_t table_id,
+                       struct cpfl_tdi_table_node **table_node)
+{
+       struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+       struct cpfl_adapter_ext *adapter = itf->adapter;
+       struct cpfl_tdi_table_node *node;
+       void *temp;
+       int i;
+
+       RTE_TAILQ_FOREACH_SAFE(node, &adapter->flow_parser.tdi_table_list, 
next, temp)
+       {
+               const struct cpfl_tdi_table *table = node->table;
+
+               if (table->handle != table_id)
+                       continue;
+
+               if (table->match_key_field_num > CPFL_TDI_KEY_FIELD_NUM_MAX) {
+                       PMD_DRV_LOG(ERR, "Too many fields (%d) in tdi table %s",
+                                   table->match_key_field_num, table->name);
+                       goto err;
+               }
+
+               if (table->action_num > CPFL_TDI_ACTION_SPEC_NUM_MAX) {
+                       PMD_DRV_LOG(ERR, "Too many action types (%d) in tdi 
table %s",
+                                   table->action_num, table->name);
+                       goto err;
+               }
+
+               /* match_key_field first */
+               if (table->match_key_format_num == 0) {
+                       node->buf_len = 0;
+                       for (i = 0; i < table->match_key_field_num; i++) {
+                               struct cpfl_tdi_match_key_field *field =
+                                   &table->match_key_fields[i];
+                               uint32_t size = (uint16_t)(field->bit_width >> 
3);
+
+                               node->params[i].id = field->index;
+                               node->params[i].offset =
+                                   node->buf_len; /* equal with 
field->position */
+                               node->params[i].size = size;
+                               node->buf_len += size;
+                       }
+               } else {
+                       for (i = 0; i < table->match_key_format_num; i++) {
+                               struct cpfl_tdi_match_key_format *format =
+                                   &table->match_key_format[i];
+
+                               node->buf_len =
+                                   format->byte_array_index + 
(uint16_t)(format->bit_width >> 3);
+                               node->params[i].id = format->match_key_handle;
+                               node->params[i].offset = 
format->byte_array_index;
+                               node->params[i].size = 
(uint16_t)(format->bit_width >> 3);
+                       }
+               }
+               *table_node = node;
+
+               return 0;
+       }
+
+err:
+       return -EINVAL;
+}
+
+static int
+cpfl_tdi_table_key_node_init(struct rte_eth_dev *dev __rte_unused,
+                            struct cpfl_tdi_table_node *node,
+                            struct cpfl_tdi_table_key_obj *kobj)
+{
+       kobj->tnode = node;
+       kobj->buf_len = node->buf_len;
+       kobj->sem.pin_to_cache = CPFL_PIN_TO_CACHE_DEF;
+       kobj->sem.fixed_fetch = CPFL_FIXED_FETCH_DEF;
+       return 0;
+}
+
+static int
+cpfl_tdi_table_key_create(struct rte_eth_dev *dev,
+                         uint32_t table_id,
+                         struct cpfl_tdi_table_node **table_node,
+                         struct cpfl_tdi_table_key_obj *kobj)
+{
+       int ret;
+
+       if (!kobj)
+               return -EINVAL;
+
+       ret = cpfl_tdi_table_info_get(dev, table_id, table_node);
+       if (ret != 0)
+               return -EINVAL;
+
+       ret = cpfl_tdi_table_key_node_init(dev, *table_node, kobj);
+       if (ret != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int
+cpfl_tdi_table_key_field_info_get(__rte_unused struct rte_eth_dev *dev,
+                                 struct cpfl_tdi_table_node *node,
+                                 uint32_t field_id,
+                                 struct cpfl_tdi_table_key_field_info 
**key_field_info)
+{
+       const struct cpfl_tdi_table *table = node->table;
+       int i, j;
+
+       for (i = 0; i < table->match_key_field_num; i++) {
+               struct cpfl_tdi_match_key_field *field = 
&table->match_key_fields[i];
+               struct cpfl_tdi_table_key_field_info *tkfinfo;
+
+               if (field->index != field_id)
+                       continue;
+
+               tkfinfo = rte_zmalloc(NULL, sizeof(struct 
cpfl_tdi_table_key_field_info), 0);
+               if (tkfinfo == NULL)
+                       return -ENOMEM;
+
+               tkfinfo->field = field;
+               tkfinfo->param = node->params[i];
+               *key_field_info = tkfinfo;
+
+               /* adjust byte width */
+               for (j = 0; j < table->match_key_format_num; j++) {
+                       struct cpfl_tdi_match_key_format *format = 
&table->match_key_format[j];
+
+                       if (format->match_key_handle != field_id)
+                               continue;
+                       tkfinfo->format = format;
+                       return 0;
+               }
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int
+_cpfl_tdi_table_key_field_set(struct rte_eth_dev *dev __rte_unused,
+                             struct cpfl_tdi_table_key_obj *kobj,
+                             struct cpfl_tdi_table_key_field_info *tkfinfo,
+                             const uint8_t *value,
+                             uint16_t size)
+{
+       struct cpfl_tdi_param_info *pi = &tkfinfo->param;
+       uint8_t *target = &kobj->buf[pi->offset];
+
+       memcpy(target, value, size);
+
+       /* Need to fix as this will overwrite. */
+       if (tkfinfo->format != NULL)
+               cpfl_tdi_shift_left(target, pi->size, 
tkfinfo->format->start_bit_offset);
+
+       return 0;
+}
+
+static int
+cpfl_tdi_table_key_field_set(struct rte_eth_dev *dev,
+                            struct cpfl_tdi_table_node *table_node,
+                            struct cpfl_tdi_table_key_obj *kobj,
+                            uint32_t field_id,
+                            const uint8_t *value,
+                            uint16_t size)
+{
+       struct cpfl_tdi_table_key_field_info *key_field_info;
+       int ret;
+
+       if (!kobj || !value)
+               return -EINVAL;
+
+       ret = cpfl_tdi_table_key_field_info_get(dev, table_node, field_id, 
&key_field_info);
+       if (ret != 0)
+               return -EINVAL;
+
+       if (key_field_info->field->match_type != CPFL_TDI_MATCH_TYPE_EXACT)
+               return -EINVAL;
+
+       if (unlikely(key_field_info->field->is_vsi)) {
+               struct cpfl_itf *src_itf;
+               uint16_t vsi_id, port_id;
+               uint8_t ids[2];
+
+               if (size != 1 && size != 2) /* input port id should be 8/16 
bits */
+                       return -EINVAL;
+               port_id = size == 1 ? value[0] : value[0] << 8 | value[1];
+               src_itf = cpfl_get_itf_by_port_id(port_id);
+               if (!src_itf)
+                       return -EINVAL;
+               vsi_id = cpfl_get_vsi_id(src_itf);
+               if (vsi_id == CPFL_INVALID_HW_ID)
+                       return -EINVAL;
+               ids[0] = (uint8_t)vsi_id;
+               ids[1] = (uint8_t)vsi_id >> 8;
+
+               ret = _cpfl_tdi_table_key_field_set(dev, kobj, key_field_info, 
ids, size);
+               if (ret != 0)
+                       return -EINVAL;
+       } else {
+               ret = _cpfl_tdi_table_key_field_set(dev, kobj, key_field_info, 
value, size);
+               if (ret != 0)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+cpfl_tdi_action_spec_info_get(struct rte_eth_dev *dev,
+                             uint32_t spec_id,
+                             struct cpfl_tdi_action_node **action_node)
+{
+       struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+       struct cpfl_adapter_ext *adapter = itf->adapter;
+       struct cpfl_tdi_action_node *node;
+       void *temp;
+
+       RTE_TAILQ_FOREACH_SAFE(node, &adapter->flow_parser.tdi_action_list, 
next, temp)
+       {
+               if (node->action->handle != spec_id)
+                       continue;
+               *action_node = node;
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int
+cpfl_tdi_action_obj_init(struct rte_eth_dev *dev __rte_unused,
+                        struct cpfl_tdi_table_node *tnode,
+                        struct cpfl_tdi_action_node *anode,
+                        struct cpfl_tdi_action_obj *aobj)
+{
+       aobj->table = tnode->table;
+       aobj->node = anode;
+       aobj->buf_len = anode->buf_len;
+
+       memcpy(aobj->buf, anode->init_buf, anode->buf_len);
+
+       return 0;
+}
+
+static inline bool __rte_unused
+verify_action(struct cpfl_tdi_table_node *table_node, uint32_t spec_id)
+{
+       int i;
+       const struct cpfl_tdi_table *table = table_node->table;
+
+       for (i = 0; i < table->action_num; i++)
+               if (spec_id == table->actions[i].handle)
+                       return true;
+
+       return false;
+}
+
+static int
+cpfl_tdi_action_node_get_by_spec_id(struct rte_eth_dev *dev,
+                                   uint32_t table_id __rte_unused,
+                                   uint32_t spec_id,
+                                   struct cpfl_tdi_action_node **action_node)
+{
+       return cpfl_tdi_action_spec_info_get(dev, spec_id, action_node);
+}
+
+static int
+cpfl_tdi_action_spec_field_info_get(struct rte_eth_dev *dev __rte_unused,
+                                   struct cpfl_tdi_action_node *anode,
+                                   uint32_t field_id,
+                                   struct cpfl_tdi_action_spec_field_info 
**info)
+{
+       int ret = -EINVAL;
+       int i, j;
+
+       if (anode->format == NULL)
+               goto err;
+
+       for (i = 0; i < anode->format->immediate_field_num; i++) {
+               struct cpfl_tdi_immediate_field *field = 
&anode->format->immediate_fields[i];
+               struct cpfl_tdi_action_spec_field_info *asfinfo;
+
+               if (field->param_handle != field_id)
+                       continue;
+
+               asfinfo = rte_malloc(NULL, sizeof(struct 
cpfl_tdi_action_spec_field_info), 0);
+               if (asfinfo == NULL) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               asfinfo->field = field;
+               asfinfo->param = anode->params[i];
+
+               for (j = 0; j < 
anode->format->mod_content_format.mod_field_num; j++) {
+                       struct cpfl_tdi_mod_field *mod_field =
+                           &anode->format->mod_content_format.mod_fields[j];
+
+                       if (mod_field->type != 
CPFL_TDI_MOD_FIELD_TYPE_PARAMETER)
+                               continue;
+
+                       if (mod_field->param_handle != field_id)
+                               continue;
+
+                       asfinfo->mod_field = mod_field;
+               }
+
+               for (i = 0; i < anode->format->hw_action_num; i++) {
+                       struct cpfl_tdi_hw_action *hw_action = 
&anode->format->hw_actions_list[i];
+
+                       if (hw_action->parameter_num == 0)
+                               continue;
+
+                       if (hw_action->parameters[0].param_handle != field_id)
+                               continue;
+
+                       asfinfo->hw_action = hw_action;
+               }
+
+               *info = asfinfo;
+
+               return 0;
+       }
+       PMD_DRV_LOG(WARNING, "No immediate_field_num!!!");
+err:
+       return ret;
+}
+
+static int
+_cpfl_tdi_action_field_set(struct rte_eth_dev *dev __rte_unused,
+                          struct cpfl_tdi_action_obj *aobj,
+                          struct cpfl_tdi_action_spec_field_info *asfinfo,
+                          const uint8_t *value,
+                          uint16_t size,
+                          enum cpfl_act_fwd_type fwd_type)
+{
+       struct cpfl_tdi_action_node *node = aobj->node;
+       struct cpfl_tdi_param_info *pi = &asfinfo->param;
+       uint8_t val_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+       uint8_t msk_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+
+       memcpy(val_buf, value, size);
+
+       if (node->format->mod_content_format.mod_field_num > 0) {
+               struct cpfl_tdi_mod_field *mf = asfinfo->mod_field;
+
+               cpfl_tdi_shift_left(val_buf, pi->size, mf->start_bit_offset);
+               cpfl_tdi_init_msk_buf(msk_buf, pi->size, mf->bit_width);
+               cpfl_tdi_shift_left(msk_buf, pi->size, mf->start_bit_offset);
+               cpfl_tdi_or_buf(&aobj->buf[pi->offset], pi->size, val_buf, 
msk_buf);
+       } else {
+               struct cpfl_tdi_hw_action *ha = asfinfo->hw_action;
+               uint32_t action_code = cpfl_tdi_to_action_code(ha, val_buf, 
fwd_type);
+
+               memcpy(&aobj->buf[pi->offset], &action_code, 4);
+       }
+
+       return 0;
+}
+
+static int
+cpfl_tdi_action_field_set(struct rte_eth_dev *dev,
+                         struct cpfl_tdi_action_obj *aobj,
+                         struct cpfl_tdi_action_node *action_node,
+                         uint32_t field_id,
+                         const struct rte_flow_action_prog_argument *arg)
+{
+       struct cpfl_tdi_action_spec_field_info *asfinfo;
+       enum rte_flow_action_type action_type;
+       /* used when action is PORT_REPRESENTOR type */
+       struct cpfl_itf *dst_itf;
+       uint16_t dev_id; /* vsi id */
+       uint16_t port_id;
+       uint8_t value;
+       bool is_vsi;
+       int ret;
+       enum cpfl_act_fwd_type fwd_type;
+
+       if (!aobj || !arg)
+               return -EINVAL;
+
+       ret = cpfl_tdi_action_spec_field_info_get(dev, action_node, field_id, 
&asfinfo);
+       if (ret != 0)
+               return -EINVAL;
+
+       if (!strcmp(arg->name, "port_representor"))
+               action_type = RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR;
+       else if (!strcmp(arg->name, "represented_port"))
+               action_type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT;
+       else
+               return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, 
arg->value, arg->size,
+                                                 CPFL_NO_FWD);
+
+       if (arg->size != 1 && arg->size != 2) /* input port_id should be 8/16 
bits */
+               return -EINVAL;
+
+       port_id = arg->size == 1 ? arg->value[0] : arg->value[0] << 8 | 
arg->value[1];
+       dst_itf = cpfl_get_itf_by_port_id(port_id);
+       if (!dst_itf)
+               goto err;
+
+       is_vsi = (action_type == RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR ||
+                 dst_itf->type == CPFL_ITF_TYPE_REPRESENTOR);
+       if (is_vsi)
+               dev_id = cpfl_get_vsi_id(dst_itf);
+       else
+               dev_id = cpfl_get_port_id(dst_itf);
+
+       if (dev_id == CPFL_INVALID_HW_ID)
+               goto err;
+
+       value = (uint8_t)dev_id;
+       fwd_type = is_vsi ? CPFL_ACT_FWD_VSI : CPFL_ACT_FWD_PORT;
+
+       return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, &value, 
arg->size, fwd_type);
+err:
+       PMD_DRV_LOG(ERR, "Can not get dev id.");
+       return -EINVAL;
+}
+
+int
+cpfl_tdi_build(struct cpfl_flow_parser *flow_parser)
+{
+       int ret;
+
+       ret = cpfl_tdi_build_table_list(flow_parser);
+       if (ret != 0) {
+               PMD_INIT_LOG(ERR, "Failed to build tdi table list");
+               return ret;
+       }
+
+       ret = cpfl_tdi_build_action_list(flow_parser);
+       if (ret != 0) {
+               PMD_INIT_LOG(ERR, "Failed to build tdi action list");
+               cpfl_tdi_free_table_list(flow_parser);
+               return ret;
+       }
+
+       return 0;
+}
+
+static bool
+cpfl_flow_items_all_is_flex(const struct rte_flow_item pattern[])
+{
+       int i;
+
+       for (i = 0; pattern[i].type != RTE_FLOW_ITEM_TYPE_END; i++) {
+               if (pattern[i].type != RTE_FLOW_ITEM_TYPE_FLEX)
+                       return false;
+       }
+       return true;
+}
+
+static void
+cpfl_fill_rinfo_default_value(struct cpfl_tdi_rule_info *rinfo)
+{
+       if (cpfl_tdi_rule_cookie == ~0llu)
+               cpfl_tdi_rule_cookie = CPFL_COOKIE_DEF;
+       rinfo->cookie = cpfl_tdi_rule_cookie++;
+       rinfo->host_id = CPFL_HOST_ID_DEF;
+       rinfo->port_num = CPFL_PORT_NUM_DEF;
+       rinfo->resp_req = CPFL_RESP_REQ_DEF;
+       rinfo->vsi = CPFL_VSI_DEF;
+       rinfo->clear_mirror_1st_state = CPFL_CLEAR_MIRROR_1ST_STATE_DEF;
+}
+
+static int
+cpfl_tdi_parse_pattern(struct rte_eth_dev *dev,
+                      const struct rte_flow_item pattern[],
+                      uint32_t table_id,
+                      struct cpfl_tdi_table_node **table_node,
+                      struct cpfl_tdi_table_key_obj *kobj)
+{
+       const struct rte_flow_item_flex *flex;
+       int i, ret;
+
+       /* Create the key */
+       ret = cpfl_tdi_table_key_create(dev, table_id, table_node, kobj);
+       if (ret) {
+               PMD_INIT_LOG(ERR, "Failed to create table key obj.");
+               return -EINVAL;
+       }
+
+       for (i = 0; pattern[i].type != RTE_FLOW_ITEM_TYPE_END; i++) {
+               if (pattern[i].type != RTE_FLOW_ITEM_TYPE_FLEX) {
+                       PMD_INIT_LOG(ERR, "All pattern type should be 
RTE_FLOW_ITEM_TYPE_FLEX.");
+                       return -EINVAL;
+               }
+               flex = pattern[i].spec;
+               /* Set the key fields */
+               ret = cpfl_tdi_table_key_field_set(dev, *table_node, kobj, i, 
flex->pattern,
+                                                  flex->length);
+               if (ret) {
+                       PMD_INIT_LOG(ERR, "Failed to set table key field.");
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+static int
+cpfl_tdi_parse_action(struct rte_eth_dev *dev,
+                     const struct rte_flow_action actions[],
+                     uint32_t table_id,
+                     struct cpfl_tdi_table_node *table_node,
+                     struct cpfl_tdi_action_node **action_node,
+                     struct cpfl_tdi_action_obj *aobj)
+{
+       const struct rte_flow_action_prog *prog;
+       const struct rte_flow_action_prog_argument *arg;
+       uint32_t action_spec_id;
+       int i, ret;
+       uint32_t j;
+
+       for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
+               if (actions[i].type != RTE_FLOW_ACTION_TYPE_PROG)
+                       continue;
+
+               prog = actions[i].conf;
+               action_spec_id = atoi(prog->name);
+               /* Get action node */
+               ret =
+                   cpfl_tdi_action_node_get_by_spec_id(dev, table_id, 
action_spec_id, action_node);
+               if (ret) {
+                       PMD_INIT_LOG(ERR, "Failed to get action node.");
+                       return -EINVAL;
+               }
+
+               ret = cpfl_tdi_action_obj_init(dev, table_node, *action_node, 
aobj);
+               if (ret != 0) {
+                       PMD_INIT_LOG(ERR, "Failed to init action obj.");
+                       return -EINVAL;
+               }
+
+               for (j = 0; j < prog->args_num; j++) {
+                       arg = &prog->args[j];
+                       /* Set the action fields */
+                       ret = cpfl_tdi_action_field_set(dev, aobj, 
*action_node, j, arg);
+                       if (ret) {
+                               PMD_INIT_LOG(ERR, "Failed to set action 
field.");
+                               return -EINVAL;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int
+cpfl_tdi_parse_pattern_action(struct rte_eth_dev *dev,
+                             const struct rte_flow_attr *attr,
+                             const struct rte_flow_item pattern[],
+                             const struct rte_flow_action actions[],
+                             void **meta)
+{
+       struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+       struct cpfl_adapter_ext *adapter = itf->adapter;
+       int ret;
+       struct cpfl_tdi_rule_info *rinfo;
+       struct cpfl_tdi_table_node *table_node;
+       struct cpfl_tdi_action_node *action_node;
+       struct cpfl_tdi_table_key_obj *kobj;
+       struct cpfl_tdi_action_obj *aobj;
+       uint32_t table_id = attr->group;
+
+       if (!adapter->flow_parser.is_p4_parser || 
!cpfl_flow_items_all_is_flex(pattern))
+               return -EINVAL;
+
+       rinfo = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_rule_info), 0);
+       if (!rinfo)
+               return -ENOMEM;
+
+       kobj = &rinfo->kobj;
+       aobj = &rinfo->aobj;
+       memset(kobj, 0, sizeof(struct cpfl_tdi_table_key_obj));
+       memset(aobj, 0, sizeof(struct cpfl_tdi_action_obj));
+
+       ret = cpfl_tdi_parse_pattern(dev, pattern, table_id, &table_node, kobj);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Invalid pattern");
+               rte_free(rinfo);
+               return -EINVAL;
+       }
+
+       ret = cpfl_tdi_parse_action(dev, actions, table_id, table_node, 
&action_node, aobj);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Invalid action");
+               rte_free(rinfo);
+               return -EINVAL;
+       }
+
+       cpfl_fill_rinfo_default_value(rinfo);
+       if (!meta)
+               rte_free(rinfo);
+       else
+               *meta = rinfo;
+
+       return 0;
+}
+
+static int
+cpfl_tdi_fxp_init(struct cpfl_adapter_ext *ad __rte_unused)
+{
+       return 0;
+}
+
+static void
+cpfl_tdi_fxp_uninit(struct cpfl_adapter_ext *ad __rte_unused)
+{
+}
+
+static struct cpfl_flow_engine cpfl_tdi_engine = {
+       .type = CPFL_FLOW_ENGINE_TDI,
+       .init = cpfl_tdi_fxp_init,
+       .uninit = cpfl_tdi_fxp_uninit,
+       .create = cpfl_tdi_fxp_rule_create,
+       .destroy = cpfl_tdi_fxp_rule_destroy,
+       .parse_pattern_action = cpfl_tdi_parse_pattern_action,
+};
+
+RTE_INIT(cpfl_sw_engine_init)
+{
+       struct cpfl_flow_engine *engine = &cpfl_tdi_engine;
+
+       cpfl_flow_engine_register(engine);
+}
diff --git a/drivers/net/cpfl/cpfl_tdi.h b/drivers/net/cpfl/cpfl_tdi.h
new file mode 100644
index 0000000000..c7b8c38657
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#ifndef _CPFL_TDI_H_
+#define _CPFL_TDI_H_
+
+#include "cpfl_ethdev.h"
+#include "cpfl_fxp_rule.h"
+#include "cpfl_tdi_parser.h"
+
+#define CPFL_TDI_KEY_FIELD_NUM_MAX 256 /* Max number of key field in a table. 
*/
+#define CPFL_TDI_ACTION_SPEC_NUM_MAX 64 /* Max number of action spec in a 
table. */
+#define CPFL_TDI_ACTION_PARAMETER_NUM_MAX 16
+#define CPFL_TDI_ACTION_BUF_SIZE_MAX 256
+#define CPFL_TDI_TABLE_KEY_FIELD_MAX 32
+#define CPFL_TDI_MAX_TABLE_KEY_SIZE 128
+
+/**
+ *
+ * Table entry operation type.
+ */
+
+enum cpfl_tdi_table_entry_op {
+       CPFL_TDI_TABLE_ENTRY_OP_ADD, /* Add an entry */
+       CPFL_TDI_TABLE_ENTRY_OP_DEL, /* Delete an entry */
+       CPFL_TDI_TABLE_ENTRY_OP_QRY, /* Query an entry */
+};
+
+/**
+ * Table key match type.
+ *
+ * To specify the key match type of a table.
+ */
+enum cpfl_tdi_table_key_match_type {
+       CPFL_TDI_TABLE_KEY_MATCH_TYPE_EXACT,    /**< Exact match. */
+       CPFL_TDI_TABLE_KEY_MATCH_TYPE_WILDCARD, /**< Wildcard match. */
+       CPFL_TDI_TABLE_KEY_MATCH_TYPE_RANGE,    /**< Range match. */
+       CPFL_TDI_TABLE_KEY_MATCH_TYPE_LPM,      /**< longest prefix match. */
+};
+
+struct cpfl_tdi_param_info {
+       uint32_t id;
+       uint16_t offset;
+       uint16_t size;
+};
+
+struct cpfl_tdi_action_spec_field_info {
+       struct cpfl_tdi_immediate_field *field;
+       struct cpfl_tdi_param_info param;
+       struct cpfl_tdi_mod_field *mod_field;
+       struct cpfl_tdi_hw_action *hw_action;
+};
+
+struct cpfl_tdi_table_key_field_info {
+       struct cpfl_tdi_match_key_field *field;
+       struct cpfl_tdi_match_key_format *format;
+       struct cpfl_tdi_param_info param;
+};
+
+struct cpfl_tdi_action_node {
+       TAILQ_ENTRY(cpfl_tdi_action_node) next;
+       enum cpfl_tdi_hw_block hw_block_type;
+       const struct cpfl_tdi_action *action;
+       const struct cpfl_tdi_action_format *format;
+       uint32_t buf_len;
+       struct cpfl_tdi_param_info params[CPFL_TDI_ACTION_PARAMETER_NUM_MAX];
+       uint8_t init_buf[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+       uint8_t query_msk[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+};
+
+struct cpfl_tdi_table_node {
+       TAILQ_ENTRY(cpfl_tdi_table_node) next;
+       const struct cpfl_tdi_table *table;
+       struct cpfl_tdi_action_node **actions;
+       uint16_t buf_len;
+       struct cpfl_tdi_param_info params[CPFL_TDI_TABLE_KEY_FIELD_MAX];
+};
+
+struct cpfl_tdi_table_key_obj {
+       uint16_t buf_len;
+       uint8_t buf[CPFL_TDI_MAX_TABLE_KEY_SIZE];
+       const struct cpfl_tdi_table_node *tnode;
+       union {
+               struct {
+                       uint16_t prof_id;
+                       uint8_t sub_prof_id;
+                       uint8_t pin_to_cache;
+                       uint8_t fixed_fetch;
+               } sem;
+               struct {
+                       uint32_t mod_index;
+                       uint8_t pin_mod_content;
+                       uint8_t mod_obj_size;
+               } mod;
+       };
+};
+
+struct cpfl_tdi_action_obj {
+       const struct cpfl_tdi_table *table;
+       struct cpfl_tdi_action_node *node;
+       uint16_t buf_len;
+       uint8_t buf[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+};
+
+TAILQ_HEAD(tdi_table_key_obj_list, tdi_table_key_obj);
+TAILQ_HEAD(tdi_action_obj_list, tdi_action_obj);
+
+struct cpfl_tdi_rule_info {
+       enum cpfl_rule_type type;
+       struct cpfl_tdi_table_key_obj kobj;
+       struct cpfl_tdi_action_obj aobj;
+       uint64_t cookie;
+       uint8_t host_id;
+       uint8_t port_num;
+       uint8_t resp_req;
+       /* vsi is used for lem and lpm rules */
+       uint16_t vsi;
+       uint8_t clear_mirror_1st_state;
+};
+
+void cpfl_tdi_free_table_list(struct cpfl_flow_parser *flow_parser);
+int cpfl_tdi_build(struct cpfl_flow_parser *flow_parser);
+#endif
diff --git a/drivers/net/cpfl/meson.build b/drivers/net/cpfl/meson.build
index f948033f1f..a2e5c9d25b 100644
--- a/drivers/net/cpfl/meson.build
+++ b/drivers/net/cpfl/meson.build
@@ -48,6 +48,7 @@ if dpdk_conf.has('RTE_HAS_JANSSON')
             'cpfl_flow_parser.c',
             'cpfl_fxp_rule.c',
             'cpfl_tdi_parser.c',
+            'cpfl_tdi.c',
     )
     ext_deps += jansson_dep
 endif
-- 
2.34.1


Reply via email to