From patchwork Fri Dec 22 10:08:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenjing Qiao X-Patchwork-Id: 135497 X-Patchwork-Delegate: qi.z.zhang@intel.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5A09E4375D; Fri, 22 Dec 2023 11:10:23 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 44BBE4025D; Fri, 22 Dec 2023 11:10:23 +0100 (CET) Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.20]) by mails.dpdk.org (Postfix) with ESMTP id EA8E54003C for ; Fri, 22 Dec 2023 11:10:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703239822; x=1734775822; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eCC5NRFKu9BNAwsCe44TiXkxfokxcrVOwfWFnYYZyIg=; b=fgOp061VHSeQ6PiqOTmVAobMkjF4yYbz6tgeFKUlBGgWQjwPuzs/H1ul aaGyJ/FTeizkvgLHC8WRLd73NtYEjphmjrEUZYVZ+rWi30tDwpP/CW+nG yXB52HjhgEpQTOmChJVlki8BTUeKzEqUm4V1Z7d0AfxB8xHPrQiY2NuUg cZ4pCW1AgumAJqBgpEYWilZE0Bjo9Nr0ByetyZo77AEucTZ64/rB76MIv gDF0aVm7e6LArTdy7Y0mNduE3G5NaYc3RVxNvlGI18HwTCwE7P5Li2s3D tWDuSwhWrA0AekclS2AWFp81IVadQYo3XcDM+P4Dwd1+bRs51qnsriNv2 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10931"; a="386525305" X-IronPort-AV: E=Sophos;i="6.04,296,1695711600"; d="scan'208";a="386525305" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Dec 2023 02:10:20 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10931"; a="920605426" X-IronPort-AV: E=Sophos;i="6.04,296,1695711600"; d="scan'208";a="920605426" Received: from dpdk-wenjing-02.sh.intel.com ([10.67.118.228]) by fmsmga001.fm.intel.com with ESMTP; 22 Dec 2023 02:10:18 -0800 From: wenjing.qiao@intel.com To: jingjing.wu@intel.com, beilei.xing@intel.com, qi.z.zhang@intel.com Cc: dev@dpdk.org, Wenjing Qiao Subject: [PATCH 2/2] net/cpfl: add TDI to flow engine Date: Fri, 22 Dec 2023 10:08:41 +0000 Message-Id: <20231222100837.260493-3-wenjing.qiao@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231222100837.260493-1-wenjing.qiao@intel.com> References: <20231222100837.260493-1-wenjing.qiao@intel.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Wenjing Qiao Add TDI implementation to a flow engine. Signed-off-by: Wenjing Qiao --- 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 | 1244 +++++++++++++++++++++++ drivers/net/cpfl/cpfl_tdi.h | 123 +++ drivers/net/cpfl/meson.build | 1 + 11 files changed, 1412 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..b7dd3e4764 --- /dev/null +++ b/drivers/net/cpfl/cpfl_tdi.c @@ -0,0 +1,1244 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Intel Corporation + */ +#include +#include +#include +#include +#include + +#include "cpfl_actions.h" +#include "cpfl_flow.h" +#include "cpfl_fxp_rule.h" +#include "cpfl_tdi.h" +#include "cpfl_tdi_parser.h" +#include "rte_common.h" +#include "rte_flow.h" + +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) +{ + 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 */ + return cpfl_act_fwd_vsi(0, ha->prec, CPFL_PE_LAN, (uint16_t)*val).data; + 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 */ + return cpfl_act_fwd_vsi(0, ha->prec, CPFL_PE_LAN, (uint16_t)*val).data; + 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); + + rte_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; + } + + rte_memcpy(&node->init_buf[offset], &action_code, 4); + rte_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); + + 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; + } + + rte_memcpy(&node->init_buf[offset], &action_code, 4); + rte_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) { + rte_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(¶ms); + + 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]; + + rte_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; + + 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; + + rte_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) +{ + 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}; + + rte_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); + + rte_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 */ + uint8_t value; + bool is_vsi; + int ret; + + 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); + + if (arg->size != 1) + return -EINVAL; + + dst_itf = cpfl_get_itf_by_port_id(arg->value[0]); + 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; + + return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, &value, arg->size); +err: + PMD_DRV_LOG(ERR, "Can not get dev id."); + return -EINVAL; + + return 0; +} + +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