get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/45056/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 45056,
    "url": "https://patches.dpdk.org/api/patches/45056/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1537465276-77264-3-git-send-email-nikhil.rao@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1537465276-77264-3-git-send-email-nikhil.rao@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1537465276-77264-3-git-send-email-nikhil.rao@intel.com",
    "date": "2018-09-20T17:41:14",
    "name": "[v4,3/5] eventdev: add eth Tx adapter implementation",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "e9e211ba9e7ad5fae13525082ca0e7a2b820366e",
    "submitter": {
        "id": 528,
        "url": "https://patches.dpdk.org/api/people/528/?format=api",
        "name": "Rao, Nikhil",
        "email": "nikhil.rao@intel.com"
    },
    "delegate": {
        "id": 310,
        "url": "https://patches.dpdk.org/api/users/310/?format=api",
        "username": "jerin",
        "first_name": "Jerin",
        "last_name": "Jacob",
        "email": "jerinj@marvell.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1537465276-77264-3-git-send-email-nikhil.rao@intel.com/mbox/",
    "series": [
        {
            "id": 1426,
            "url": "https://patches.dpdk.org/api/series/1426/?format=api",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=1426",
            "date": "2018-09-20T17:41:12",
            "name": "[v4,1/5] eventdev: add eth Tx adapter APIs",
            "version": 4,
            "mbox": "https://patches.dpdk.org/series/1426/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/45056/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/45056/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 376B61B141;\n\tThu, 20 Sep 2018 19:42:33 +0200 (CEST)",
            "from mga18.intel.com (mga18.intel.com [134.134.136.126])\n\tby dpdk.org (Postfix) with ESMTP id 08A4B1B123\n\tfor <dev@dpdk.org>; Thu, 20 Sep 2018 19:42:29 +0200 (CEST)",
            "from orsmga006.jf.intel.com ([10.7.209.51])\n\tby orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t20 Sep 2018 10:42:29 -0700",
            "from unknown (HELO localhost.localdomain.localdomain)\n\t([10.224.122.193])\n\tby orsmga006.jf.intel.com with ESMTP; 20 Sep 2018 10:42:26 -0700"
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.54,281,1534834800\"; d=\"scan'208\";a=\"75970119\"",
        "From": "Nikhil Rao <nikhil.rao@intel.com>",
        "To": "jerin.jacob@caviumnetworks.com, olivier.matz@6wind.com,\n\tmarko.kovacevic@intel.com, john.mcnamara@intel.com",
        "Cc": "dev@dpdk.org,\n\tNikhil Rao <nikhil.rao@intel.com>",
        "Date": "Thu, 20 Sep 2018 23:11:14 +0530",
        "Message-Id": "<1537465276-77264-3-git-send-email-nikhil.rao@intel.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1537465276-77264-1-git-send-email-nikhil.rao@intel.com>",
        "References": "<1535694069-88757-1-git-send-email-nikhil.rao@intel.com>\n\t<1537465276-77264-1-git-send-email-nikhil.rao@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v4 3/5] eventdev: add eth Tx adapter\n\timplementation",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch implements the Tx adapter APIs by invoking the\ncorresponding eventdev PMD callbacks and also provides\nthe common rte_service function based implementation when\nthe eventdev PMD support is absent.\n\nSigned-off-by: Nikhil Rao <nikhil.rao@intel.com>\n---\n config/rte_config.h                            |    1 +\n lib/librte_eventdev/rte_event_eth_tx_adapter.c | 1138 ++++++++++++++++++++++++\n config/common_base                             |    2 +-\n lib/librte_eventdev/Makefile                   |    2 +\n lib/librte_eventdev/meson.build                |    6 +-\n lib/librte_eventdev/rte_eventdev_version.map   |   12 +\n 6 files changed, 1158 insertions(+), 3 deletions(-)\n create mode 100644 lib/librte_eventdev/rte_event_eth_tx_adapter.c",
    "diff": "diff --git a/config/rte_config.h b/config/rte_config.h\nindex ee84f04..73e71af 100644\n--- a/config/rte_config.h\n+++ b/config/rte_config.h\n@@ -69,6 +69,7 @@\n #define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32\n #define RTE_EVENT_ETH_INTR_RING_SIZE 1024\n #define RTE_EVENT_CRYPTO_ADAPTER_MAX_INSTANCE 32\n+#define RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE 32\n \n /* rawdev defines */\n #define RTE_RAWDEV_MAX_DEVS 10\ndiff --git a/lib/librte_eventdev/rte_event_eth_tx_adapter.c b/lib/librte_eventdev/rte_event_eth_tx_adapter.c\nnew file mode 100644\nindex 0000000..aae0378\n--- /dev/null\n+++ b/lib/librte_eventdev/rte_event_eth_tx_adapter.c\n@@ -0,0 +1,1138 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Intel Corporation.\n+ */\n+#include <rte_spinlock.h>\n+#include <rte_service_component.h>\n+#include <rte_ethdev.h>\n+\n+#include \"rte_eventdev_pmd.h\"\n+#include \"rte_event_eth_tx_adapter.h\"\n+\n+#define TXA_BATCH_SIZE\t\t32\n+#define TXA_SERVICE_NAME_LEN\t32\n+#define TXA_MEM_NAME_LEN\t32\n+#define TXA_FLUSH_THRESHOLD\t1024\n+#define TXA_RETRY_CNT\t\t100\n+#define TXA_MAX_NB_TX\t\t128\n+#define TXA_INVALID_DEV_ID\tINT32_C(-1)\n+#define TXA_INVALID_SERVICE_ID\tINT64_C(-1)\n+\n+#define txa_evdev(id) (&rte_eventdevs[txa_dev_id_array[(id)]])\n+\n+#define txa_dev_caps_get(id) txa_evdev((id))->dev_ops->eth_tx_adapter_caps_get\n+\n+#define txa_dev_adapter_create(t) txa_evdev(t)->dev_ops->eth_tx_adapter_create\n+\n+#define txa_dev_adapter_create_ext(t) \\\n+\t\t\t\ttxa_evdev(t)->dev_ops->eth_tx_adapter_create\n+\n+#define txa_dev_adapter_free(t) txa_evdev(t)->dev_ops->eth_tx_adapter_free\n+\n+#define txa_dev_queue_add(id) txa_evdev(id)->dev_ops->eth_tx_adapter_queue_add\n+\n+#define txa_dev_queue_del(t) txa_evdev(t)->dev_ops->eth_tx_adapter_queue_del\n+\n+#define txa_dev_start(t) txa_evdev(t)->dev_ops->eth_tx_adapter_start\n+\n+#define txa_dev_stop(t) txa_evdev(t)->dev_ops->eth_tx_adapter_stop\n+\n+#define txa_dev_stats_reset(t) txa_evdev(t)->dev_ops->eth_tx_adapter_stats_reset\n+\n+#define txa_dev_stats_get(t) txa_evdev(t)->dev_ops->eth_tx_adapter_stats_get\n+\n+#define RTE_EVENT_ETH_TX_ADAPTER_ID_VALID_OR_ERR_RET(id, retval) \\\n+do { \\\n+\tif (!txa_valid_id(id)) { \\\n+\t\tRTE_EDEV_LOG_ERR(\"Invalid eth Rx adapter id = %d\", id); \\\n+\t\treturn retval; \\\n+\t} \\\n+} while (0)\n+\n+#define TXA_CHECK_OR_ERR_RET(id) \\\n+do {\\\n+\tint ret; \\\n+\tRTE_EVENT_ETH_TX_ADAPTER_ID_VALID_OR_ERR_RET((id), -EINVAL); \\\n+\tret = txa_init(); \\\n+\tif (ret != 0) \\\n+\t\treturn ret; \\\n+\tif (!txa_adapter_exist((id))) \\\n+\t\treturn -EINVAL; \\\n+} while (0)\n+\n+/* Tx retry callback structure */\n+struct txa_retry {\n+\t/* Ethernet port id */\n+\tuint16_t port_id;\n+\t/* Tx queue */\n+\tuint16_t tx_queue;\n+\t/* Adapter ID */\n+\tuint8_t id;\n+};\n+\n+/* Per queue structure */\n+struct txa_service_queue_info {\n+\t/* Queue has been added */\n+\tuint8_t added;\n+\t/* Retry callback argument */\n+\tstruct txa_retry txa_retry;\n+\t/* Tx buffer */\n+\tstruct rte_eth_dev_tx_buffer *tx_buf;\n+};\n+\n+/* PMD private structure */\n+struct txa_service_data {\n+\t/* Max mbufs processed in any service function invocation */\n+\tuint32_t max_nb_tx;\n+\t/* Number of Tx queues in adapter */\n+\tuint32_t nb_queues;\n+\t/*  Synchronization with data path */\n+\trte_spinlock_t tx_lock;\n+\t/* Event port ID */\n+\tuint8_t port_id;\n+\t/* Event device identifier */\n+\tuint8_t eventdev_id;\n+\t/* Highest port id supported + 1 */\n+\tuint16_t dev_count;\n+\t/* Loop count to flush Tx buffers */\n+\tint loop_cnt;\n+\t/* Per ethernet device structure */\n+\tstruct txa_service_ethdev *txa_ethdev;\n+\t/* Statistics */\n+\tstruct rte_event_eth_tx_adapter_stats stats;\n+\t/* Adapter Identifier */\n+\tuint8_t id;\n+\t/* Conf arg must be freed */\n+\tuint8_t conf_free;\n+\t/* Configuration callback */\n+\trte_event_eth_tx_adapter_conf_cb conf_cb;\n+\t/* Configuration callback argument */\n+\tvoid *conf_arg;\n+\t/* socket id */\n+\tint socket_id;\n+\t/* Per adapter EAL service */\n+\tint64_t service_id;\n+\t/* Memory allocation name */\n+\tchar mem_name[TXA_MEM_NAME_LEN];\n+} __rte_cache_aligned;\n+\n+/* Per eth device structure */\n+struct txa_service_ethdev {\n+\t/* Pointer to ethernet device */\n+\tstruct rte_eth_dev *dev;\n+\t/* Number of queues added */\n+\tuint16_t nb_queues;\n+\t/* PMD specific queue data */\n+\tvoid *queues;\n+};\n+\n+/* Array of adapter instances, initialized with event device id\n+ * when adapter is created\n+ */\n+static int *txa_dev_id_array;\n+\n+/* Array of pointers to service implementation data */\n+static struct txa_service_data **txa_service_data_array;\n+\n+static int32_t txa_service_func(void *args);\n+static int txa_service_adapter_create_ext(uint8_t id,\n+\t\t\tstruct rte_eventdev *dev,\n+\t\t\trte_event_eth_tx_adapter_conf_cb conf_cb,\n+\t\t\tvoid *conf_arg);\n+static int txa_service_queue_del(uint8_t id,\n+\t\t\t\tconst struct rte_eth_dev *dev,\n+\t\t\t\tint32_t tx_queue_id);\n+\n+static int\n+txa_adapter_exist(uint8_t id)\n+{\n+\treturn txa_dev_id_array[id] != TXA_INVALID_DEV_ID;\n+}\n+\n+static inline int\n+txa_valid_id(uint8_t id)\n+{\n+\treturn id < RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE;\n+}\n+\n+static void *\n+txa_memzone_array_get(const char *name, unsigned int elt_size, int nb_elems)\n+{\n+\tconst struct rte_memzone *mz;\n+\tunsigned int sz;\n+\n+\tsz = elt_size * nb_elems;\n+\tsz = RTE_ALIGN(sz, RTE_CACHE_LINE_SIZE);\n+\n+\tmz = rte_memzone_lookup(name);\n+\tif (mz == NULL) {\n+\t\tmz = rte_memzone_reserve_aligned(name, sz, rte_socket_id(), 0,\n+\t\t\t\t\t\t RTE_CACHE_LINE_SIZE);\n+\t\tif (mz == NULL) {\n+\t\t\tRTE_EDEV_LOG_ERR(\"failed to reserve memzone\"\n+\t\t\t\t\t\" name = %s err = %\"\n+\t\t\t\t\tPRId32, name, rte_errno);\n+\t\t\treturn NULL;\n+\t\t}\n+\t}\n+\n+\treturn  mz->addr;\n+}\n+\n+static int\n+txa_dev_id_array_init(void)\n+{\n+\tif (txa_dev_id_array == NULL) {\n+\t\tint i;\n+\n+\t\ttxa_dev_id_array = txa_memzone_array_get(\"txa_adapter_array\",\n+\t\t\t\t\tsizeof(int),\n+\t\t\t\t\tRTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE);\n+\t\tif (txa_dev_id_array == NULL)\n+\t\t\treturn -ENOMEM;\n+\n+\t\tfor (i = 0; i < RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE; i++)\n+\t\t\ttxa_dev_id_array[i] = TXA_INVALID_DEV_ID;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+txa_init(void)\n+{\n+\treturn txa_dev_id_array_init();\n+}\n+\n+static int\n+txa_service_data_init(void)\n+{\n+\tif (txa_service_data_array == NULL) {\n+\t\ttxa_service_data_array =\n+\t\t\t\ttxa_memzone_array_get(\"txa_service_data_array\",\n+\t\t\t\t\tsizeof(int),\n+\t\t\t\t\tRTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE);\n+\t\tif (txa_service_data_array == NULL)\n+\t\t\treturn -ENOMEM;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static inline struct txa_service_data *\n+txa_service_id_to_data(uint8_t id)\n+{\n+\treturn txa_service_data_array[id];\n+}\n+\n+static inline struct txa_service_queue_info *\n+txa_service_queue(struct txa_service_data *txa, uint16_t port_id,\n+\t\tuint16_t tx_queue_id)\n+{\n+\tstruct txa_service_queue_info *tqi;\n+\n+\tif (unlikely(txa->txa_ethdev == NULL || txa->dev_count < port_id + 1))\n+\t\treturn NULL;\n+\n+\ttqi = txa->txa_ethdev[port_id].queues;\n+\n+\treturn likely(tqi != NULL) ? tqi + tx_queue_id : NULL;\n+}\n+\n+static int\n+txa_service_conf_cb(uint8_t __rte_unused id, uint8_t dev_id,\n+\t\tstruct rte_event_eth_tx_adapter_conf *conf, void *arg)\n+{\n+\tint ret;\n+\tstruct rte_eventdev *dev;\n+\tstruct rte_event_port_conf *pc;\n+\tstruct rte_event_dev_config dev_conf;\n+\tint started;\n+\tuint8_t port_id;\n+\n+\tpc = arg;\n+\tdev = &rte_eventdevs[dev_id];\n+\tdev_conf = dev->data->dev_conf;\n+\n+\tstarted = dev->data->dev_started;\n+\tif (started)\n+\t\trte_event_dev_stop(dev_id);\n+\n+\tport_id = dev_conf.nb_event_ports;\n+\tdev_conf.nb_event_ports += 1;\n+\n+\tret = rte_event_dev_configure(dev_id, &dev_conf);\n+\tif (ret) {\n+\t\tRTE_EDEV_LOG_ERR(\"failed to configure event dev %u\",\n+\t\t\t\t\t\tdev_id);\n+\t\tif (started) {\n+\t\t\tif (rte_event_dev_start(dev_id))\n+\t\t\t\treturn -EIO;\n+\t\t}\n+\t\treturn ret;\n+\t}\n+\n+\tpc->disable_implicit_release = 0;\n+\tret = rte_event_port_setup(dev_id, port_id, pc);\n+\tif (ret) {\n+\t\tRTE_EDEV_LOG_ERR(\"failed to setup event port %u\\n\",\n+\t\t\t\t\tport_id);\n+\t\tif (started) {\n+\t\t\tif (rte_event_dev_start(dev_id))\n+\t\t\t\treturn -EIO;\n+\t\t}\n+\t\treturn ret;\n+\t}\n+\n+\tconf->event_port_id = port_id;\n+\tconf->max_nb_tx = TXA_MAX_NB_TX;\n+\tif (started)\n+\t\tret = rte_event_dev_start(dev_id);\n+\treturn ret;\n+}\n+\n+static int\n+txa_service_ethdev_alloc(struct txa_service_data *txa)\n+{\n+\tstruct txa_service_ethdev *txa_ethdev;\n+\tuint16_t i, dev_count;\n+\n+\tdev_count = rte_eth_dev_count_avail();\n+\tif (txa->txa_ethdev && dev_count == txa->dev_count)\n+\t\treturn 0;\n+\n+\ttxa_ethdev = rte_zmalloc_socket(txa->mem_name,\n+\t\t\t\t\tdev_count * sizeof(*txa_ethdev),\n+\t\t\t\t\t0,\n+\t\t\t\t\ttxa->socket_id);\n+\tif (txa_ethdev == NULL) {\n+\t\tRTE_EDEV_LOG_ERR(\"Failed to alloc txa::txa_ethdev \");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tif (txa->dev_count)\n+\t\tmemcpy(txa_ethdev, txa->txa_ethdev,\n+\t\t\ttxa->dev_count * sizeof(*txa_ethdev));\n+\n+\tRTE_ETH_FOREACH_DEV(i) {\n+\t\tif (i == dev_count)\n+\t\t\tbreak;\n+\t\ttxa_ethdev[i].dev = &rte_eth_devices[i];\n+\t}\n+\n+\ttxa->txa_ethdev = txa_ethdev;\n+\ttxa->dev_count = dev_count;\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_queue_array_alloc(struct txa_service_data *txa,\n+\t\t\tuint16_t port_id)\n+{\n+\tstruct txa_service_queue_info *tqi;\n+\tuint16_t nb_queue;\n+\tint ret;\n+\n+\tret = txa_service_ethdev_alloc(txa);\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\tif (txa->txa_ethdev[port_id].queues)\n+\t\treturn 0;\n+\n+\tnb_queue = txa->txa_ethdev[port_id].dev->data->nb_tx_queues;\n+\ttqi = rte_zmalloc_socket(txa->mem_name,\n+\t\t\t\tnb_queue *\n+\t\t\t\tsizeof(struct txa_service_queue_info), 0,\n+\t\t\t\ttxa->socket_id);\n+\tif (tqi == NULL)\n+\t\treturn -ENOMEM;\n+\ttxa->txa_ethdev[port_id].queues = tqi;\n+\treturn 0;\n+}\n+\n+static void\n+txa_service_queue_array_free(struct txa_service_data *txa,\n+\t\t\tuint16_t port_id)\n+{\n+\tstruct txa_service_ethdev *txa_ethdev;\n+\tstruct txa_service_queue_info *tqi;\n+\n+\ttxa_ethdev = &txa->txa_ethdev[port_id];\n+\tif (txa->txa_ethdev == NULL || txa_ethdev->nb_queues != 0)\n+\t\treturn;\n+\n+\ttqi = txa_ethdev->queues;\n+\ttxa_ethdev->queues = NULL;\n+\trte_free(tqi);\n+\n+\tif (txa->nb_queues == 0) {\n+\t\trte_free(txa->txa_ethdev);\n+\t\ttxa->txa_ethdev = NULL;\n+\t}\n+}\n+\n+static void\n+txa_service_unregister(struct txa_service_data *txa)\n+{\n+\tif (txa->service_id != TXA_INVALID_SERVICE_ID) {\n+\t\trte_service_component_runstate_set(txa->service_id, 0);\n+\t\twhile (rte_service_may_be_active(txa->service_id))\n+\t\t\trte_pause();\n+\t\trte_service_component_unregister(txa->service_id);\n+\t}\n+\ttxa->service_id = TXA_INVALID_SERVICE_ID;\n+}\n+\n+static int\n+txa_service_register(struct txa_service_data *txa)\n+{\n+\tint ret;\n+\tstruct rte_service_spec service;\n+\tstruct rte_event_eth_tx_adapter_conf conf;\n+\n+\tif (txa->service_id != TXA_INVALID_SERVICE_ID)\n+\t\treturn 0;\n+\n+\tmemset(&service, 0, sizeof(service));\n+\tsnprintf(service.name, TXA_SERVICE_NAME_LEN, \"txa_%d\", txa->id);\n+\tservice.socket_id = txa->socket_id;\n+\tservice.callback = txa_service_func;\n+\tservice.callback_userdata = txa;\n+\tservice.capabilities = RTE_SERVICE_CAP_MT_SAFE;\n+\tret = rte_service_component_register(&service,\n+\t\t\t\t\t(uint32_t *)&txa->service_id);\n+\tif (ret) {\n+\t\tRTE_EDEV_LOG_ERR(\"failed to register service %s err = %\"\n+\t\t\t\t PRId32, service.name, ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = txa->conf_cb(txa->id, txa->eventdev_id, &conf, txa->conf_arg);\n+\tif (ret) {\n+\t\ttxa_service_unregister(txa);\n+\t\treturn ret;\n+\t}\n+\n+\trte_service_component_runstate_set(txa->service_id, 1);\n+\ttxa->port_id = conf.event_port_id;\n+\ttxa->max_nb_tx = conf.max_nb_tx;\n+\treturn 0;\n+}\n+\n+static struct rte_eth_dev_tx_buffer *\n+txa_service_tx_buf_alloc(struct txa_service_data *txa,\n+\t\t\tconst struct rte_eth_dev *dev)\n+{\n+\tstruct rte_eth_dev_tx_buffer *tb;\n+\tuint16_t port_id;\n+\n+\tport_id = dev->data->port_id;\n+\ttb = rte_zmalloc_socket(txa->mem_name,\n+\t\t\t\tRTE_ETH_TX_BUFFER_SIZE(TXA_BATCH_SIZE),\n+\t\t\t\t0,\n+\t\t\t\trte_eth_dev_socket_id(port_id));\n+\tif (tb == NULL)\n+\t\tRTE_EDEV_LOG_ERR(\"Failed to allocate memory for tx buffer\");\n+\treturn tb;\n+}\n+\n+static int\n+txa_service_is_queue_added(struct txa_service_data *txa,\n+\t\t\tconst struct rte_eth_dev *dev,\n+\t\t\tuint16_t tx_queue_id)\n+{\n+\tstruct txa_service_queue_info *tqi;\n+\n+\ttqi = txa_service_queue(txa, dev->data->port_id, tx_queue_id);\n+\treturn tqi && tqi->added;\n+}\n+\n+static int\n+txa_service_ctrl(uint8_t id, int start)\n+{\n+\tint ret;\n+\tstruct txa_service_data *txa;\n+\n+\ttxa = txa_service_id_to_data(id);\n+\tif (txa->service_id == TXA_INVALID_SERVICE_ID)\n+\t\treturn 0;\n+\n+\tret = rte_service_runstate_set(txa->service_id, start);\n+\tif (ret == 0 && !start) {\n+\t\twhile (rte_service_may_be_active(txa->service_id))\n+\t\t\trte_pause();\n+\t}\n+\treturn ret;\n+}\n+\n+static void\n+txa_service_buffer_retry(struct rte_mbuf **pkts, uint16_t unsent,\n+\t\t\tvoid *userdata)\n+{\n+\tstruct txa_retry *tr;\n+\tstruct txa_service_data *data;\n+\tstruct rte_event_eth_tx_adapter_stats *stats;\n+\tuint16_t sent = 0;\n+\tunsigned int retry = 0;\n+\tuint16_t i, n;\n+\n+\ttr = (struct txa_retry *)(uintptr_t)userdata;\n+\tdata = txa_service_id_to_data(tr->id);\n+\tstats = &data->stats;\n+\n+\tdo {\n+\t\tn = rte_eth_tx_burst(tr->port_id, tr->tx_queue,\n+\t\t\t       &pkts[sent], unsent - sent);\n+\n+\t\tsent += n;\n+\t} while (sent != unsent && retry++ < TXA_RETRY_CNT);\n+\n+\tfor (i = sent; i < unsent; i++)\n+\t\trte_pktmbuf_free(pkts[i]);\n+\n+\tstats->tx_retry += retry;\n+\tstats->tx_packets += sent;\n+\tstats->tx_dropped += unsent - sent;\n+}\n+\n+static void\n+txa_service_tx(struct txa_service_data *txa, struct rte_event *ev,\n+\tuint32_t n)\n+{\n+\tuint32_t i;\n+\tuint16_t nb_tx;\n+\tstruct rte_event_eth_tx_adapter_stats *stats;\n+\n+\tstats = &txa->stats;\n+\n+\tnb_tx = 0;\n+\tfor (i = 0; i < n; i++) {\n+\t\tstruct rte_mbuf *m;\n+\t\tuint16_t port;\n+\t\tuint16_t queue;\n+\t\tstruct txa_service_queue_info *tqi;\n+\n+\t\tm = ev[i].mbuf;\n+\t\tport = m->port;\n+\t\tqueue = rte_event_eth_tx_adapter_txq_get(m);\n+\n+\t\ttqi = txa_service_queue(txa, port, queue);\n+\t\tif (unlikely(tqi == NULL || !tqi->added)) {\n+\t\t\trte_pktmbuf_free(m);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tnb_tx += rte_eth_tx_buffer(port, queue, tqi->tx_buf, m);\n+\t}\n+\n+\tstats->tx_packets += nb_tx;\n+}\n+\n+static int32_t\n+txa_service_func(void *args)\n+{\n+\tstruct txa_service_data *txa = args;\n+\tuint8_t dev_id;\n+\tuint8_t port;\n+\tuint16_t n;\n+\tuint32_t nb_tx, max_nb_tx;\n+\tstruct rte_event ev[TXA_BATCH_SIZE];\n+\n+\tdev_id = txa->eventdev_id;\n+\tmax_nb_tx = txa->max_nb_tx;\n+\tport = txa->port_id;\n+\n+\tif (txa->nb_queues == 0)\n+\t\treturn 0;\n+\n+\tif (!rte_spinlock_trylock(&txa->tx_lock))\n+\t\treturn 0;\n+\n+\tfor (nb_tx = 0; nb_tx < max_nb_tx; nb_tx += n) {\n+\n+\t\tn = rte_event_dequeue_burst(dev_id, port, ev, RTE_DIM(ev), 0);\n+\t\tif (!n)\n+\t\t\tbreak;\n+\t\ttxa_service_tx(txa, ev, n);\n+\t}\n+\n+\tif ((txa->loop_cnt++ & (TXA_FLUSH_THRESHOLD - 1)) == 0) {\n+\n+\t\tstruct txa_service_ethdev *tdi;\n+\t\tstruct txa_service_queue_info *tqi;\n+\t\tstruct rte_eth_dev *dev;\n+\t\tuint16_t i;\n+\n+\t\ttdi = txa->txa_ethdev;\n+\t\tnb_tx = 0;\n+\n+\t\tRTE_ETH_FOREACH_DEV(i) {\n+\t\t\tuint16_t q;\n+\n+\t\t\tif (i == txa->dev_count)\n+\t\t\t\tbreak;\n+\n+\t\t\tdev = tdi[i].dev;\n+\t\t\tif (tdi[i].nb_queues == 0)\n+\t\t\t\tcontinue;\n+\t\t\tfor (q = 0; q < dev->data->nb_tx_queues; q++) {\n+\n+\t\t\t\ttqi = txa_service_queue(txa, i, q);\n+\t\t\t\tif (unlikely(tqi == NULL || !tqi->added))\n+\t\t\t\t\tcontinue;\n+\n+\t\t\t\tnb_tx += rte_eth_tx_buffer_flush(i, q,\n+\t\t\t\t\t\t\ttqi->tx_buf);\n+\t\t\t}\n+\t\t}\n+\n+\t\ttxa->stats.tx_packets += nb_tx;\n+\t}\n+\trte_spinlock_unlock(&txa->tx_lock);\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_adapter_create(uint8_t id, struct rte_eventdev *dev,\n+\t\t\tstruct rte_event_port_conf *port_conf)\n+{\n+\tstruct txa_service_data *txa;\n+\tstruct rte_event_port_conf *cb_conf;\n+\tint ret;\n+\n+\tcb_conf = rte_malloc(NULL, sizeof(*cb_conf), 0);\n+\tif (cb_conf == NULL)\n+\t\treturn -ENOMEM;\n+\n+\t*cb_conf = *port_conf;\n+\tret = txa_service_adapter_create_ext(id, dev, txa_service_conf_cb,\n+\t\t\t\t\tcb_conf);\n+\tif (ret) {\n+\t\trte_free(cb_conf);\n+\t\treturn ret;\n+\t}\n+\n+\ttxa = txa_service_id_to_data(id);\n+\ttxa->conf_free = 1;\n+\treturn ret;\n+}\n+\n+static int\n+txa_service_adapter_create_ext(uint8_t id, struct rte_eventdev *dev,\n+\t\t\trte_event_eth_tx_adapter_conf_cb conf_cb,\n+\t\t\tvoid *conf_arg)\n+{\n+\tstruct txa_service_data *txa;\n+\tint socket_id;\n+\tchar mem_name[TXA_SERVICE_NAME_LEN];\n+\tint ret;\n+\n+\tif (conf_cb == NULL)\n+\t\treturn -EINVAL;\n+\n+\tsocket_id = dev->data->socket_id;\n+\tsnprintf(mem_name, TXA_MEM_NAME_LEN,\n+\t\t\"rte_event_eth_txa_%d\",\n+\t\tid);\n+\n+\tret = txa_service_data_init();\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\ttxa = rte_zmalloc_socket(mem_name,\n+\t\t\t\tsizeof(*txa),\n+\t\t\t\tRTE_CACHE_LINE_SIZE, socket_id);\n+\tif (txa == NULL) {\n+\t\tRTE_EDEV_LOG_ERR(\"failed to get mem for tx adapter\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\ttxa->id = id;\n+\ttxa->eventdev_id = dev->data->dev_id;\n+\ttxa->socket_id = socket_id;\n+\tstrncpy(txa->mem_name, mem_name, TXA_SERVICE_NAME_LEN);\n+\ttxa->conf_cb = conf_cb;\n+\ttxa->conf_arg = conf_arg;\n+\ttxa->service_id = TXA_INVALID_SERVICE_ID;\n+\trte_spinlock_init(&txa->tx_lock);\n+\ttxa_service_data_array[id] = txa;\n+\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_event_port_get(uint8_t id, uint8_t *port)\n+{\n+\tstruct txa_service_data *txa;\n+\n+\ttxa = txa_service_id_to_data(id);\n+\tif (txa->service_id == TXA_INVALID_SERVICE_ID)\n+\t\treturn -ENODEV;\n+\n+\t*port = txa->port_id;\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_adapter_free(uint8_t id)\n+{\n+\tstruct txa_service_data *txa;\n+\n+\ttxa = txa_service_id_to_data(id);\n+\tif (txa->nb_queues) {\n+\t\tRTE_EDEV_LOG_ERR(\"%\" PRIu16 \" Tx queues not deleted\",\n+\t\t\t\ttxa->nb_queues);\n+\t\treturn -EBUSY;\n+\t}\n+\n+\tif (txa->conf_free)\n+\t\trte_free(txa->conf_arg);\n+\trte_free(txa);\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_queue_add(uint8_t id,\n+\t\t__rte_unused struct rte_eventdev *dev,\n+\t\tconst struct rte_eth_dev *eth_dev,\n+\t\tint32_t tx_queue_id)\n+{\n+\tstruct txa_service_data *txa;\n+\tstruct txa_service_ethdev *tdi;\n+\tstruct txa_service_queue_info *tqi;\n+\tstruct rte_eth_dev_tx_buffer *tb;\n+\tstruct txa_retry *txa_retry;\n+\tint ret;\n+\n+\ttxa = txa_service_id_to_data(id);\n+\n+\tif (tx_queue_id == -1) {\n+\t\tint nb_queues;\n+\t\tuint16_t i, j;\n+\t\tuint16_t *qdone;\n+\n+\t\tnb_queues = eth_dev->data->nb_tx_queues;\n+\t\tif (txa->dev_count > eth_dev->data->port_id) {\n+\t\t\ttdi = &txa->txa_ethdev[eth_dev->data->port_id];\n+\t\t\tnb_queues -= tdi->nb_queues;\n+\t\t}\n+\n+\t\tqdone = rte_zmalloc(txa->mem_name,\n+\t\t\t\tnb_queues * sizeof(*qdone), 0);\n+\t\tj = 0;\n+\t\tfor (i = 0; i < nb_queues; i++) {\n+\t\t\tif (txa_service_is_queue_added(txa, eth_dev, i))\n+\t\t\t\tcontinue;\n+\t\t\tret = txa_service_queue_add(id, dev, eth_dev, i);\n+\t\t\tif (ret == 0)\n+\t\t\t\tqdone[j++] = i;\n+\t\t\telse\n+\t\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (i != nb_queues) {\n+\t\t\tfor (i = 0; i < j; i++)\n+\t\t\t\ttxa_service_queue_del(id, eth_dev, qdone[i]);\n+\t\t}\n+\t\trte_free(qdone);\n+\t\treturn ret;\n+\t}\n+\n+\tret = txa_service_register(txa);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\trte_spinlock_lock(&txa->tx_lock);\n+\n+\tif (txa_service_is_queue_added(txa, eth_dev, tx_queue_id)) {\n+\t\trte_spinlock_unlock(&txa->tx_lock);\n+\t\treturn 0;\n+\t}\n+\n+\tret = txa_service_queue_array_alloc(txa, eth_dev->data->port_id);\n+\tif (ret)\n+\t\tgoto err_unlock;\n+\n+\ttb = txa_service_tx_buf_alloc(txa, eth_dev);\n+\tif (tb == NULL)\n+\t\tgoto err_unlock;\n+\n+\ttdi = &txa->txa_ethdev[eth_dev->data->port_id];\n+\ttqi = txa_service_queue(txa, eth_dev->data->port_id, tx_queue_id);\n+\n+\ttxa_retry = &tqi->txa_retry;\n+\ttxa_retry->id = txa->id;\n+\ttxa_retry->port_id = eth_dev->data->port_id;\n+\ttxa_retry->tx_queue = tx_queue_id;\n+\n+\trte_eth_tx_buffer_init(tb, TXA_BATCH_SIZE);\n+\trte_eth_tx_buffer_set_err_callback(tb,\n+\t\ttxa_service_buffer_retry, txa_retry);\n+\n+\ttqi->tx_buf = tb;\n+\ttqi->added = 1;\n+\ttdi->nb_queues++;\n+\ttxa->nb_queues++;\n+\n+err_unlock:\n+\tif (txa->nb_queues == 0) {\n+\t\ttxa_service_queue_array_free(txa,\n+\t\t\t\t\teth_dev->data->port_id);\n+\t\ttxa_service_unregister(txa);\n+\t}\n+\n+\trte_spinlock_unlock(&txa->tx_lock);\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_queue_del(uint8_t id,\n+\t\tconst struct rte_eth_dev *dev,\n+\t\tint32_t tx_queue_id)\n+{\n+\tstruct txa_service_data *txa;\n+\tstruct txa_service_queue_info *tqi;\n+\tstruct rte_eth_dev_tx_buffer *tb;\n+\tuint16_t port_id;\n+\n+\tif (tx_queue_id == -1) {\n+\t\tuint16_t i;\n+\t\tint ret;\n+\n+\t\tfor (i = 0; i < dev->data->nb_tx_queues; i++) {\n+\t\t\tret = txa_service_queue_del(id, dev, i);\n+\t\t\tif (ret != 0)\n+\t\t\t\tbreak;\n+\t\t}\n+\t\treturn ret;\n+\t}\n+\n+\ttxa = txa_service_id_to_data(id);\n+\tport_id = dev->data->port_id;\n+\n+\ttqi = txa_service_queue(txa, port_id, tx_queue_id);\n+\tif (tqi == NULL || !tqi->added)\n+\t\treturn 0;\n+\n+\ttb = tqi->tx_buf;\n+\ttqi->added = 0;\n+\ttqi->tx_buf = NULL;\n+\trte_free(tb);\n+\ttxa->nb_queues--;\n+\ttxa->txa_ethdev[port_id].nb_queues--;\n+\n+\ttxa_service_queue_array_free(txa, port_id);\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_id_get(uint8_t id, uint32_t *service_id)\n+{\n+\tstruct txa_service_data *txa;\n+\n+\ttxa = txa_service_id_to_data(id);\n+\tif (txa->service_id == TXA_INVALID_SERVICE_ID)\n+\t\treturn -ESRCH;\n+\n+\tif (service_id == NULL)\n+\t\treturn -EINVAL;\n+\n+\t*service_id = txa->service_id;\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_start(uint8_t id)\n+{\n+\treturn txa_service_ctrl(id, 1);\n+}\n+\n+static int\n+txa_service_stats_get(uint8_t id,\n+\t\tstruct rte_event_eth_tx_adapter_stats *stats)\n+{\n+\tstruct txa_service_data *txa;\n+\n+\ttxa = txa_service_id_to_data(id);\n+\t*stats = txa->stats;\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_stats_reset(uint8_t id)\n+{\n+\tstruct txa_service_data *txa;\n+\n+\ttxa = txa_service_id_to_data(id);\n+\tmemset(&txa->stats, 0, sizeof(txa->stats));\n+\treturn 0;\n+}\n+\n+static int\n+txa_service_stop(uint8_t id)\n+{\n+\treturn txa_service_ctrl(id, 0);\n+}\n+\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_create(uint8_t id, uint8_t dev_id,\n+\t\t\t\tstruct rte_event_port_conf *port_conf)\n+{\n+\tstruct rte_eventdev *dev;\n+\tint ret;\n+\n+\tif (port_conf == NULL)\n+\t\treturn -EINVAL;\n+\n+\tRTE_EVENT_ETH_TX_ADAPTER_ID_VALID_OR_ERR_RET(id, -EINVAL);\n+\tRTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);\n+\n+\tdev = &rte_eventdevs[dev_id];\n+\n+\tret = txa_init();\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\tif (txa_adapter_exist(id))\n+\t\treturn -EEXIST;\n+\n+\ttxa_dev_id_array[id] = dev_id;\n+\tif (txa_dev_adapter_create(id))\n+\t\tret = txa_dev_adapter_create(id)(id, dev);\n+\n+\tif (ret != 0) {\n+\t\ttxa_dev_id_array[id] = TXA_INVALID_DEV_ID;\n+\t\treturn ret;\n+\t}\n+\n+\tret = txa_service_adapter_create(id, dev, port_conf);\n+\tif (ret != 0) {\n+\t\tif (txa_dev_adapter_free(id))\n+\t\t\ttxa_dev_adapter_free(id)(id, dev);\n+\t\ttxa_dev_id_array[id] = TXA_INVALID_DEV_ID;\n+\t\treturn ret;\n+\t}\n+\n+\ttxa_dev_id_array[id] = dev_id;\n+\treturn 0;\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_create_ext(uint8_t id, uint8_t dev_id,\n+\t\t\t\trte_event_eth_tx_adapter_conf_cb conf_cb,\n+\t\t\t\tvoid *conf_arg)\n+{\n+\tstruct rte_eventdev *dev;\n+\tint ret;\n+\n+\tRTE_EVENT_ETH_TX_ADAPTER_ID_VALID_OR_ERR_RET(id, -EINVAL);\n+\tRTE_EVENTDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);\n+\n+\tret = txa_init();\n+\tif (ret != 0)\n+\t\treturn ret;\n+\n+\tif (txa_adapter_exist(id))\n+\t\treturn -EINVAL;\n+\n+\tdev = &rte_eventdevs[dev_id];\n+\n+\ttxa_dev_id_array[id] = dev_id;\n+\tif (txa_dev_adapter_create_ext(id))\n+\t\tret = txa_dev_adapter_create_ext(id)(id, dev);\n+\n+\tif (ret != 0) {\n+\t\ttxa_dev_id_array[id] = TXA_INVALID_DEV_ID;\n+\t\treturn ret;\n+\t}\n+\n+\tret = txa_service_adapter_create_ext(id, dev, conf_cb, conf_arg);\n+\tif (ret != 0) {\n+\t\tif (txa_dev_adapter_free(id))\n+\t\t\ttxa_dev_adapter_free(id)(id, dev);\n+\t\ttxa_dev_id_array[id] = TXA_INVALID_DEV_ID;\n+\t\treturn ret;\n+\t}\n+\n+\ttxa_dev_id_array[id] = dev_id;\n+\treturn 0;\n+}\n+\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_event_port_get(uint8_t id, uint8_t *event_port_id)\n+{\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\treturn txa_service_event_port_get(id, event_port_id);\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_free(uint8_t id)\n+{\n+\tint ret;\n+\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\tret = txa_dev_adapter_free(id) ?\n+\t\ttxa_dev_adapter_free(id)(id, txa_evdev(id)) :\n+\t\t0;\n+\n+\tif (ret == 0)\n+\t\tret = txa_service_adapter_free(id);\n+\ttxa_dev_id_array[id] = TXA_INVALID_DEV_ID;\n+\n+\treturn ret;\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_queue_add(uint8_t id,\n+\t\t\t\tuint16_t eth_dev_id,\n+\t\t\t\tint32_t queue)\n+{\n+\tstruct rte_eth_dev *eth_dev;\n+\tint ret;\n+\tuint32_t caps;\n+\n+\tRTE_ETH_VALID_PORTID_OR_ERR_RET(eth_dev_id, -EINVAL);\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\teth_dev = &rte_eth_devices[eth_dev_id];\n+\tif (queue != -1 && (uint16_t)queue >= eth_dev->data->nb_tx_queues) {\n+\t\tRTE_EDEV_LOG_ERR(\"Invalid tx queue_id %\" PRIu16,\n+\t\t\t\t(uint16_t)queue);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tcaps = 0;\n+\tif (txa_dev_caps_get(id))\n+\t\ttxa_dev_caps_get(id)(txa_evdev(id), eth_dev, &caps);\n+\n+\tif (caps & RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT)\n+\t\tret =  txa_dev_queue_add(id) ?\n+\t\t\t\t\ttxa_dev_queue_add(id)(id,\n+\t\t\t\t\t\t\ttxa_evdev(id),\n+\t\t\t\t\t\t\teth_dev,\n+\t\t\t\t\t\t\tqueue) : 0;\n+\telse\n+\t\tret = txa_service_queue_add(id, txa_evdev(id), eth_dev, queue);\n+\n+\treturn ret;\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_queue_del(uint8_t id,\n+\t\t\t\tuint16_t eth_dev_id,\n+\t\t\t\tint32_t queue)\n+{\n+\tstruct rte_eth_dev *eth_dev;\n+\tint ret;\n+\tuint32_t caps;\n+\n+\tRTE_ETH_VALID_PORTID_OR_ERR_RET(eth_dev_id, -EINVAL);\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\teth_dev = &rte_eth_devices[eth_dev_id];\n+\tif (queue != -1 && (uint16_t)queue >= eth_dev->data->nb_tx_queues) {\n+\t\tRTE_EDEV_LOG_ERR(\"Invalid tx queue_id %\" PRIu16,\n+\t\t\t\t(uint16_t)queue);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tcaps = 0;\n+\n+\tif (txa_dev_caps_get(id))\n+\t\ttxa_dev_caps_get(id)(txa_evdev(id), eth_dev, &caps);\n+\n+\tif (caps & RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT)\n+\t\tret =  txa_dev_queue_del(id) ?\n+\t\t\t\t\ttxa_dev_queue_del(id)(id, txa_evdev(id),\n+\t\t\t\t\t\t\teth_dev,\n+\t\t\t\t\t\t\tqueue) : 0;\n+\telse\n+\t\tret = txa_service_queue_del(id, eth_dev, queue);\n+\n+\treturn ret;\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_service_id_get(uint8_t id, uint32_t *service_id)\n+{\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\treturn txa_service_id_get(id, service_id);\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_start(uint8_t id)\n+{\n+\tint ret;\n+\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\tret = txa_dev_start(id) ? txa_dev_start(id)(id, txa_evdev(id)) : 0;\n+\tif (ret == 0)\n+\t\tret = txa_service_start(id);\n+\treturn ret;\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_stats_get(uint8_t id,\n+\t\t\t\tstruct rte_event_eth_tx_adapter_stats *stats)\n+{\n+\tint ret;\n+\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\tif (stats == NULL)\n+\t\treturn -EINVAL;\n+\n+\t*stats = (struct rte_event_eth_tx_adapter_stats){0};\n+\n+\tret = txa_dev_stats_get(id) ?\n+\t\t\ttxa_dev_stats_get(id)(id, txa_evdev(id), stats) : 0;\n+\n+\tif (ret == 0 && txa_service_id_get(id, NULL) != ESRCH) {\n+\t\tif (txa_dev_stats_get(id)) {\n+\t\t\tstruct rte_event_eth_tx_adapter_stats service_stats;\n+\n+\t\t\tret = txa_service_stats_get(id, &service_stats);\n+\t\t\tif (ret == 0) {\n+\t\t\t\tstats->tx_retry += service_stats.tx_retry;\n+\t\t\t\tstats->tx_packets += service_stats.tx_packets;\n+\t\t\t\tstats->tx_dropped += service_stats.tx_dropped;\n+\t\t\t}\n+\t\t} else\n+\t\t\tret = txa_service_stats_get(id, stats);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_stats_reset(uint8_t id)\n+{\n+\tint ret;\n+\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\tret = txa_dev_stats_reset(id) ?\n+\t\ttxa_dev_stats_reset(id)(id, txa_evdev(id)) : 0;\n+\tif (ret == 0)\n+\t\tret = txa_service_stats_reset(id);\n+\treturn ret;\n+}\n+\n+int __rte_experimental\n+rte_event_eth_tx_adapter_stop(uint8_t id)\n+{\n+\tint ret;\n+\n+\tTXA_CHECK_OR_ERR_RET(id);\n+\n+\tret = txa_dev_stop(id) ? txa_dev_stop(id)(id,  txa_evdev(id)) : 0;\n+\tif (ret == 0)\n+\t\tret = txa_service_stop(id);\n+\treturn ret;\n+}\ndiff --git a/config/common_base b/config/common_base\nindex 86e3833..f00b4bc 100644\n--- a/config/common_base\n+++ b/config/common_base\n@@ -602,7 +602,7 @@ CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64\n CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32\n CONFIG_RTE_EVENT_ETH_INTR_RING_SIZE=1024\n CONFIG_RTE_EVENT_CRYPTO_ADAPTER_MAX_INSTANCE=32\n-\n+CONFIG_RTE_EVENT_ETH_TX_ADAPTER_MAX_INSTANCE=32\n #\n # Compile PMD for skeleton event device\n #\ndiff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile\nindex 47f599a..424ff35 100644\n--- a/lib/librte_eventdev/Makefile\n+++ b/lib/librte_eventdev/Makefile\n@@ -28,6 +28,7 @@ SRCS-y += rte_event_ring.c\n SRCS-y += rte_event_eth_rx_adapter.c\n SRCS-y += rte_event_timer_adapter.c\n SRCS-y += rte_event_crypto_adapter.c\n+SRCS-y += rte_event_eth_tx_adapter.c\n \n # export include files\n SYMLINK-y-include += rte_eventdev.h\n@@ -39,6 +40,7 @@ SYMLINK-y-include += rte_event_eth_rx_adapter.h\n SYMLINK-y-include += rte_event_timer_adapter.h\n SYMLINK-y-include += rte_event_timer_adapter_pmd.h\n SYMLINK-y-include += rte_event_crypto_adapter.h\n+SYMLINK-y-include += rte_event_eth_tx_adapter.h\n \n # versioning export map\n EXPORT_MAP := rte_eventdev_version.map\ndiff --git a/lib/librte_eventdev/meson.build b/lib/librte_eventdev/meson.build\nindex 3cbaf29..47989e7 100644\n--- a/lib/librte_eventdev/meson.build\n+++ b/lib/librte_eventdev/meson.build\n@@ -14,7 +14,8 @@ sources = files('rte_eventdev.c',\n \t\t'rte_event_ring.c',\n \t\t'rte_event_eth_rx_adapter.c',\n \t\t'rte_event_timer_adapter.c',\n-\t\t'rte_event_crypto_adapter.c')\n+\t\t'rte_event_crypto_adapter.c',\n+\t\t'rte_event_eth_tx_adapter.c')\n headers = files('rte_eventdev.h',\n \t\t'rte_eventdev_pmd.h',\n \t\t'rte_eventdev_pmd_pci.h',\n@@ -23,5 +24,6 @@ headers = files('rte_eventdev.h',\n \t\t'rte_event_eth_rx_adapter.h',\n \t\t'rte_event_timer_adapter.h',\n \t\t'rte_event_timer_adapter_pmd.h',\n-\t\t'rte_event_crypto_adapter.h')\n+\t\t'rte_event_crypto_adapter.h',\n+\t\t'rte_event_eth_tx_adapter.h')\n deps += ['ring', 'ethdev', 'hash', 'mempool', 'mbuf', 'timer', 'cryptodev']\ndiff --git a/lib/librte_eventdev/rte_eventdev_version.map b/lib/librte_eventdev/rte_eventdev_version.map\nindex 12835e9..19c1494 100644\n--- a/lib/librte_eventdev/rte_eventdev_version.map\n+++ b/lib/librte_eventdev/rte_eventdev_version.map\n@@ -96,6 +96,18 @@ EXPERIMENTAL {\n \trte_event_crypto_adapter_stats_reset;\n \trte_event_crypto_adapter_stop;\n \trte_event_eth_rx_adapter_cb_register;\n+\trte_event_eth_tx_adapter_caps_get;\n+\trte_event_eth_tx_adapter_create;\n+\trte_event_eth_tx_adapter_create_ext;\n+\trte_event_eth_tx_adapter_event_port_get;\n+\trte_event_eth_tx_adapter_free;\n+\trte_event_eth_tx_adapter_queue_add;\n+\trte_event_eth_tx_adapter_queue_del;\n+\trte_event_eth_tx_adapter_service_id_get;\n+\trte_event_eth_tx_adapter_start;\n+\trte_event_eth_tx_adapter_stats_get;\n+\trte_event_eth_tx_adapter_stats_reset;\n+\trte_event_eth_tx_adapter_stop;\n \trte_event_timer_adapter_caps_get;\n \trte_event_timer_adapter_create;\n \trte_event_timer_adapter_create_ext;\n",
    "prefixes": [
        "v4",
        "3/5"
    ]
}