get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 133893,
    "url": "http://patches.dpdk.org/api/patches/133893/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20231106131128.33499-7-fengchengwen@huawei.com/",
    "project": {
        "id": 1,
        "url": "http://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": "<20231106131128.33499-7-fengchengwen@huawei.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20231106131128.33499-7-fengchengwen@huawei.com",
    "date": "2023-11-06T13:11:26",
    "name": "[v3,6/7] app/testpmd: extract event handling to event.c",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "011d90a37929d773cc61ad0b60f2fb7fd09cd886",
    "submitter": {
        "id": 2146,
        "url": "http://patches.dpdk.org/api/people/2146/?format=api",
        "name": "fengchengwen",
        "email": "fengchengwen@huawei.com"
    },
    "delegate": {
        "id": 319,
        "url": "http://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20231106131128.33499-7-fengchengwen@huawei.com/mbox/",
    "series": [
        {
            "id": 30169,
            "url": "http://patches.dpdk.org/api/series/30169/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=30169",
            "date": "2023-11-06T13:11:23",
            "name": "fix race-condition of proactive error handling mode",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/30169/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/133893/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/133893/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "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])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 03203432B0;\n\tMon,  6 Nov 2023 14:14:45 +0100 (CET)",
            "from mails.dpdk.org (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id C070040A70;\n\tMon,  6 Nov 2023 14:14:20 +0100 (CET)",
            "from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187])\n by mails.dpdk.org (Postfix) with ESMTP id 75252402BA\n for <dev@dpdk.org>; Mon,  6 Nov 2023 14:14:13 +0100 (CET)",
            "from dggpeml100024.china.huawei.com (unknown [172.30.72.56])\n by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4SPBd90LYTzvQYC;\n Mon,  6 Nov 2023 21:14:05 +0800 (CST)",
            "from localhost.localdomain (10.50.165.33) by\n dggpeml100024.china.huawei.com (7.185.36.115) with Microsoft SMTP Server\n (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id\n 15.1.2507.31; Mon, 6 Nov 2023 21:14:11 +0800"
        ],
        "From": "Chengwen Feng <fengchengwen@huawei.com>",
        "To": "<thomas@monjalon.net>, <ferruh.yigit@amd.com>,\n <konstantin.ananyev@huawei.com>, <ajit.khaparde@broadcom.com>, Aman Singh\n <aman.deep.singh@intel.com>, Yuying Zhang <yuying.zhang@intel.com>",
        "CC": "<dev@dpdk.org>, <andrew.rybchenko@oktetlabs.ru>,\n <kalesh-anakkur.purayil@broadcom.com>, <Honnappa.Nagarahalli@arm.com>",
        "Subject": "[PATCH v3 6/7] app/testpmd: extract event handling to event.c",
        "Date": "Mon, 6 Nov 2023 13:11:26 +0000",
        "Message-ID": "<20231106131128.33499-7-fengchengwen@huawei.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20231106131128.33499-1-fengchengwen@huawei.com>",
        "References": "<20230301030610.49468-1-fengchengwen@huawei.com>\n <20231106131128.33499-1-fengchengwen@huawei.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[10.50.165.33]",
        "X-ClientProxiedBy": "dggems703-chm.china.huawei.com (10.3.19.180) To\n dggpeml100024.china.huawei.com (7.185.36.115)",
        "X-CFilter-Loop": "Reflected",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <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 <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org"
    },
    "content": "This patch extract event handling (including eth-event and dev-event)\nto a new file 'event.c'.\n\nSigned-off-by: Chengwen Feng <fengchengwen@huawei.com>\nAcked-by: Huisong Li <lihuisong@huawei.com>\n---\n app/test-pmd/event.c      | 390 ++++++++++++++++++++++++++++++++++++++\n app/test-pmd/meson.build  |   1 +\n app/test-pmd/parameters.c |  36 +---\n app/test-pmd/testpmd.c    | 327 +-------------------------------\n app/test-pmd/testpmd.h    |   6 +\n 5 files changed, 407 insertions(+), 353 deletions(-)\n create mode 100644 app/test-pmd/event.c",
    "diff": "diff --git a/app/test-pmd/event.c b/app/test-pmd/event.c\nnew file mode 100644\nindex 0000000000..8393e105d7\n--- /dev/null\n+++ b/app/test-pmd/event.c\n@@ -0,0 +1,390 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2023 HiSilicon Limited\n+ */\n+\n+#include <stdint.h>\n+\n+#include <rte_alarm.h>\n+#include <rte_ethdev.h>\n+#include <rte_dev.h>\n+#include <rte_log.h>\n+#ifdef RTE_NET_MLX5\n+#include \"mlx5_testpmd.h\"\n+#endif\n+\n+#include \"testpmd.h\"\n+\n+/* Pretty printing of ethdev events */\n+static const char * const eth_event_desc[] = {\n+\t[RTE_ETH_EVENT_UNKNOWN] = \"unknown\",\n+\t[RTE_ETH_EVENT_INTR_LSC] = \"link state change\",\n+\t[RTE_ETH_EVENT_QUEUE_STATE] = \"queue state\",\n+\t[RTE_ETH_EVENT_INTR_RESET] = \"reset\",\n+\t[RTE_ETH_EVENT_VF_MBOX] = \"VF mbox\",\n+\t[RTE_ETH_EVENT_IPSEC] = \"IPsec\",\n+\t[RTE_ETH_EVENT_MACSEC] = \"MACsec\",\n+\t[RTE_ETH_EVENT_INTR_RMV] = \"device removal\",\n+\t[RTE_ETH_EVENT_NEW] = \"device probed\",\n+\t[RTE_ETH_EVENT_DESTROY] = \"device released\",\n+\t[RTE_ETH_EVENT_FLOW_AGED] = \"flow aged\",\n+\t[RTE_ETH_EVENT_RX_AVAIL_THRESH] = \"RxQ available descriptors threshold reached\",\n+\t[RTE_ETH_EVENT_ERR_RECOVERING] = \"error recovering\",\n+\t[RTE_ETH_EVENT_RECOVERY_SUCCESS] = \"error recovery successful\",\n+\t[RTE_ETH_EVENT_RECOVERY_FAILED] = \"error recovery failed\",\n+\t[RTE_ETH_EVENT_MAX] = NULL,\n+};\n+\n+/*\n+ * Display or mask ether events\n+ * Default to all events except VF_MBOX\n+ */\n+uint32_t event_print_mask = (UINT32_C(1) << RTE_ETH_EVENT_UNKNOWN) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_INTR_LSC) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_QUEUE_STATE) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_IPSEC) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_MACSEC) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_ERR_RECOVERING) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_SUCCESS) |\n+\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_FAILED);\n+\n+int\n+get_event_name_mask(const char *name, uint32_t *mask)\n+{\n+\tif (!strcmp(name, \"unknown\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_UNKNOWN;\n+\telse if (!strcmp(name, \"intr_lsc\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_LSC;\n+\telse if (!strcmp(name, \"queue_state\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_QUEUE_STATE;\n+\telse if (!strcmp(name, \"intr_reset\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET;\n+\telse if (!strcmp(name, \"vf_mbox\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_VF_MBOX;\n+\telse if (!strcmp(name, \"ipsec\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_IPSEC;\n+\telse if (!strcmp(name, \"macsec\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_MACSEC;\n+\telse if (!strcmp(name, \"intr_rmv\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV;\n+\telse if (!strcmp(name, \"dev_probed\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_NEW;\n+\telse if (!strcmp(name, \"dev_released\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_DESTROY;\n+\telse if (!strcmp(name, \"flow_aged\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED;\n+\telse if (!strcmp(name, \"err_recovering\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_ERR_RECOVERING;\n+\telse if (!strcmp(name, \"recovery_success\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_SUCCESS;\n+\telse if (!strcmp(name, \"recovery_failed\"))\n+\t\t*mask = UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_FAILED;\n+\telse if (!strcmp(name, \"all\"))\n+\t\t*mask = ~UINT32_C(0);\n+\telse\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+static void\n+rmv_port_callback(void *arg)\n+{\n+\tint need_to_start = 0;\n+\tint org_no_link_check = no_link_check;\n+\tportid_t port_id = (intptr_t)arg;\n+\tstruct rte_eth_dev_info dev_info;\n+\tint ret;\n+\n+\tRTE_ETH_VALID_PORTID_OR_RET(port_id);\n+\n+\tif (!test_done && port_is_forwarding(port_id)) {\n+\t\tneed_to_start = 1;\n+\t\tstop_packet_forwarding();\n+\t}\n+\tno_link_check = 1;\n+\tstop_port(port_id);\n+\tno_link_check = org_no_link_check;\n+\n+\tret = eth_dev_info_get_print_err(port_id, &dev_info);\n+\tif (ret != 0)\n+\t\tTESTPMD_LOG(ERR,\n+\t\t\t\"Failed to get device info for port %d, not detaching\\n\",\n+\t\t\tport_id);\n+\telse {\n+\t\tstruct rte_device *device = dev_info.device;\n+\t\tclose_port(port_id);\n+\t\tdetach_device(device); /* might be already removed or have more ports */\n+\t}\n+\tif (need_to_start)\n+\t\tstart_packet_forwarding(0);\n+}\n+\n+static int need_start_when_recovery_over;\n+\n+static bool\n+has_port_in_err_recovering(void)\n+{\n+\tstruct rte_port *port;\n+\tportid_t pid;\n+\n+\tRTE_ETH_FOREACH_DEV(pid) {\n+\t\tport = &ports[pid];\n+\t\tif (port->err_recovering)\n+\t\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n+static void\n+err_recovering_callback(portid_t port_id)\n+{\n+\tif (!has_port_in_err_recovering())\n+\t\tprintf(\"Please stop executing any commands until recovery result events are received!\\n\");\n+\n+\tports[port_id].err_recovering = 1;\n+\tports[port_id].recover_failed = 0;\n+\n+\t/* To simplify implementation, stop forwarding regardless of whether the port is used. */\n+\tif (!test_done) {\n+\t\tprintf(\"Stop packet forwarding because some ports are in error recovering!\\n\");\n+\t\tstop_packet_forwarding();\n+\t\tneed_start_when_recovery_over = 1;\n+\t}\n+}\n+\n+static void\n+recover_success_callback(portid_t port_id)\n+{\n+\tports[port_id].err_recovering = 0;\n+\tif (has_port_in_err_recovering())\n+\t\treturn;\n+\n+\tif (need_start_when_recovery_over) {\n+\t\tprintf(\"Recovery success! Restart packet forwarding!\\n\");\n+\t\tstart_packet_forwarding(0);\n+\t\tneed_start_when_recovery_over = 0;\n+\t} else {\n+\t\tprintf(\"Recovery success!\\n\");\n+\t}\n+}\n+\n+static void\n+recover_failed_callback(portid_t port_id)\n+{\n+\tstruct rte_port *port;\n+\tportid_t pid;\n+\n+\tports[port_id].err_recovering = 0;\n+\tports[port_id].recover_failed = 1;\n+\tif (has_port_in_err_recovering())\n+\t\treturn;\n+\n+\tneed_start_when_recovery_over = 0;\n+\tprintf(\"The ports:\");\n+\tRTE_ETH_FOREACH_DEV(pid) {\n+\t\tport = &ports[pid];\n+\t\tif (port->recover_failed)\n+\t\t\tprintf(\" %u\", pid);\n+\t}\n+\tprintf(\" recovery failed! Please remove them!\\n\");\n+}\n+\n+/* This function is used by the interrupt thread */\n+static int\n+eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,\n+\t\t  void *ret_param)\n+{\n+\tRTE_SET_USED(param);\n+\tRTE_SET_USED(ret_param);\n+\n+\tif (type >= RTE_ETH_EVENT_MAX) {\n+\t\tfprintf(stderr,\n+\t\t\t\"\\nPort %\" PRIu16 \": %s called upon invalid event %d\\n\",\n+\t\t\tport_id, __func__, type);\n+\t\tfflush(stderr);\n+\t} else if (event_print_mask & (UINT32_C(1) << type)) {\n+\t\tprintf(\"\\nPort %\" PRIu16 \": %s event\\n\", port_id,\n+\t\t\teth_event_desc[type]);\n+\t\tfflush(stdout);\n+\t}\n+\n+\tswitch (type) {\n+\tcase RTE_ETH_EVENT_NEW:\n+\t\tports[port_id].need_setup = 1;\n+\t\tports[port_id].port_status = RTE_PORT_HANDLING;\n+\t\tbreak;\n+\tcase RTE_ETH_EVENT_INTR_RMV:\n+\t\tif (port_id_is_invalid(port_id, DISABLED_WARN))\n+\t\t\tbreak;\n+\t\tif (rte_eal_alarm_set(100000,\n+\t\t\t\trmv_port_callback, (void *)(intptr_t)port_id))\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"Could not set up deferred device removal\\n\");\n+\t\tbreak;\n+\tcase RTE_ETH_EVENT_DESTROY:\n+\t\tports[port_id].port_status = RTE_PORT_CLOSED;\n+\t\tprintf(\"Port %u is closed\\n\", port_id);\n+\t\tbreak;\n+\tcase RTE_ETH_EVENT_RX_AVAIL_THRESH: {\n+\t\tuint16_t rxq_id;\n+\t\tint ret;\n+\n+\t\t/* avail_thresh query API rewinds rxq_id, no need to check max RxQ num */\n+\t\tfor (rxq_id = 0; ; rxq_id++) {\n+\t\t\tret = rte_eth_rx_avail_thresh_query(port_id, &rxq_id,\n+\t\t\t\t\t\t\t    NULL);\n+\t\t\tif (ret <= 0)\n+\t\t\t\tbreak;\n+\t\t\tprintf(\"Received avail_thresh event, port: %u, rxq_id: %u\\n\",\n+\t\t\t       port_id, rxq_id);\n+\n+#ifdef RTE_NET_MLX5\n+\t\t\tmlx5_test_avail_thresh_event_handler(port_id, rxq_id);\n+#endif\n+\t\t}\n+\t\tbreak;\n+\t}\n+\tcase RTE_ETH_EVENT_ERR_RECOVERING:\n+\t\terr_recovering_callback(port_id);\n+\t\tbreak;\n+\tcase RTE_ETH_EVENT_RECOVERY_SUCCESS:\n+\t\trecover_success_callback(port_id);\n+\t\tbreak;\n+\tcase RTE_ETH_EVENT_RECOVERY_FAILED:\n+\t\trecover_failed_callback(port_id);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\treturn 0;\n+}\n+\n+int\n+register_eth_event_callback(void)\n+{\n+\tint ret;\n+\tenum rte_eth_event_type event;\n+\n+\tfor (event = RTE_ETH_EVENT_UNKNOWN;\n+\t\t\tevent < RTE_ETH_EVENT_MAX; event++) {\n+\t\tret = rte_eth_dev_callback_register(RTE_ETH_ALL,\n+\t\t\t\tevent,\n+\t\t\t\teth_event_callback,\n+\t\t\t\tNULL);\n+\t\tif (ret != 0) {\n+\t\t\tTESTPMD_LOG(ERR, \"Failed to register callback for \"\n+\t\t\t\t\t\"%s event\\n\", eth_event_desc[event]);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+unregister_eth_event_callback(void)\n+{\n+\tint ret;\n+\tenum rte_eth_event_type event;\n+\n+\tfor (event = RTE_ETH_EVENT_UNKNOWN;\n+\t\t\tevent < RTE_ETH_EVENT_MAX; event++) {\n+\t\tret = rte_eth_dev_callback_unregister(RTE_ETH_ALL,\n+\t\t\t\tevent,\n+\t\t\t\teth_event_callback,\n+\t\t\t\tNULL);\n+\t\tif (ret != 0) {\n+\t\t\tTESTPMD_LOG(ERR, \"Failed to unregister callback for \"\n+\t\t\t\t\t\"%s event\\n\", eth_event_desc[event]);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* This function is used by the interrupt thread */\n+static void\n+dev_event_callback(const char *device_name, enum rte_dev_event_type type,\n+\t\t\t     __rte_unused void *arg)\n+{\n+\tuint16_t port_id;\n+\tint ret;\n+\n+\tif (type >= RTE_DEV_EVENT_MAX) {\n+\t\tfprintf(stderr, \"%s called upon invalid event %d\\n\",\n+\t\t\t__func__, type);\n+\t\tfflush(stderr);\n+\t}\n+\n+\tswitch (type) {\n+\tcase RTE_DEV_EVENT_REMOVE:\n+\t\tRTE_LOG(DEBUG, EAL, \"The device: %s has been removed!\\n\",\n+\t\t\tdevice_name);\n+\t\tret = rte_eth_dev_get_port_by_name(device_name, &port_id);\n+\t\tif (ret) {\n+\t\t\tRTE_LOG(ERR, EAL, \"can not get port by device %s!\\n\",\n+\t\t\t\tdevice_name);\n+\t\t\treturn;\n+\t\t}\n+\t\t/*\n+\t\t * Because the user's callback is invoked in eal interrupt\n+\t\t * callback, the interrupt callback need to be finished before\n+\t\t * it can be unregistered when detaching device. So finish\n+\t\t * callback soon and use a deferred removal to detach device\n+\t\t * is need. It is a workaround, once the device detaching be\n+\t\t * moved into the eal in the future, the deferred removal could\n+\t\t * be deleted.\n+\t\t */\n+\t\tif (rte_eal_alarm_set(100000,\n+\t\t\t\trmv_port_callback, (void *)(intptr_t)port_id))\n+\t\t\tRTE_LOG(ERR, EAL,\n+\t\t\t\t\"Could not set up deferred device removal\\n\");\n+\t\tbreak;\n+\tcase RTE_DEV_EVENT_ADD:\n+\t\tRTE_LOG(ERR, EAL, \"The device: %s has been added!\\n\",\n+\t\t\tdevice_name);\n+\t\t/* TODO: After finish kernel driver binding,\n+\t\t * begin to attach port.\n+\t\t */\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+}\n+\n+int\n+register_dev_event_callback(void)\n+{\n+\tint ret;\n+\n+\tret = rte_dev_event_callback_register(NULL,\n+\t\tdev_event_callback, NULL);\n+\tif (ret != 0) {\n+\t\tRTE_LOG(ERR, EAL,\n+\t\t\t\"fail  to register device event callback\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+unregister_dev_event_callback(void)\n+{\n+\tint ret;\n+\n+\tret = rte_dev_event_callback_unregister(NULL,\n+\t\tdev_event_callback, NULL);\n+\tif (ret < 0) {\n+\t\tRTE_LOG(ERR, EAL,\n+\t\t\t\"fail to unregister device event callback.\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build\nindex 719f875be0..b7860f3ab0 100644\n--- a/app/test-pmd/meson.build\n+++ b/app/test-pmd/meson.build\n@@ -14,6 +14,7 @@ sources = files(\n         'cmd_flex_item.c',\n         'config.c',\n         'csumonly.c',\n+        'event.c',\n         'flowgen.c',\n         'icmpecho.c',\n         'ieee1588fwd.c',\ndiff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c\nindex a9ca58339d..504315da8b 100644\n--- a/app/test-pmd/parameters.c\n+++ b/app/test-pmd/parameters.c\n@@ -434,45 +434,19 @@ static int\n parse_event_printing_config(const char *optarg, int enable)\n {\n \tuint32_t mask = 0;\n+\tint ret;\n \n-\tif (!strcmp(optarg, \"unknown\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_UNKNOWN;\n-\telse if (!strcmp(optarg, \"intr_lsc\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_INTR_LSC;\n-\telse if (!strcmp(optarg, \"queue_state\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_QUEUE_STATE;\n-\telse if (!strcmp(optarg, \"intr_reset\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET;\n-\telse if (!strcmp(optarg, \"vf_mbox\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_VF_MBOX;\n-\telse if (!strcmp(optarg, \"ipsec\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_IPSEC;\n-\telse if (!strcmp(optarg, \"macsec\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_MACSEC;\n-\telse if (!strcmp(optarg, \"intr_rmv\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV;\n-\telse if (!strcmp(optarg, \"dev_probed\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_NEW;\n-\telse if (!strcmp(optarg, \"dev_released\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_DESTROY;\n-\telse if (!strcmp(optarg, \"flow_aged\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED;\n-\telse if (!strcmp(optarg, \"err_recovering\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_ERR_RECOVERING;\n-\telse if (!strcmp(optarg, \"recovery_success\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_SUCCESS;\n-\telse if (!strcmp(optarg, \"recovery_failed\"))\n-\t\tmask = UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_FAILED;\n-\telse if (!strcmp(optarg, \"all\"))\n-\t\tmask = ~UINT32_C(0);\n-\telse {\n+\tret = get_event_name_mask(optarg, &mask);\n+\tif (ret != 0) {\n \t\tfprintf(stderr, \"Invalid event: %s\\n\", optarg);\n \t\treturn -1;\n \t}\n+\n \tif (enable)\n \t\tevent_print_mask |= mask;\n \telse\n \t\tevent_print_mask &= ~mask;\n+\n \treturn 0;\n }\n \ndiff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c\nindex a45c411398..0831180f3b 100644\n--- a/app/test-pmd/testpmd.c\n+++ b/app/test-pmd/testpmd.c\n@@ -434,41 +434,6 @@ uint8_t clear_ptypes = true;\n /* Hairpin ports configuration mode. */\n uint32_t hairpin_mode;\n \n-/* Pretty printing of ethdev events */\n-static const char * const eth_event_desc[] = {\n-\t[RTE_ETH_EVENT_UNKNOWN] = \"unknown\",\n-\t[RTE_ETH_EVENT_INTR_LSC] = \"link state change\",\n-\t[RTE_ETH_EVENT_QUEUE_STATE] = \"queue state\",\n-\t[RTE_ETH_EVENT_INTR_RESET] = \"reset\",\n-\t[RTE_ETH_EVENT_VF_MBOX] = \"VF mbox\",\n-\t[RTE_ETH_EVENT_IPSEC] = \"IPsec\",\n-\t[RTE_ETH_EVENT_MACSEC] = \"MACsec\",\n-\t[RTE_ETH_EVENT_INTR_RMV] = \"device removal\",\n-\t[RTE_ETH_EVENT_NEW] = \"device probed\",\n-\t[RTE_ETH_EVENT_DESTROY] = \"device released\",\n-\t[RTE_ETH_EVENT_FLOW_AGED] = \"flow aged\",\n-\t[RTE_ETH_EVENT_RX_AVAIL_THRESH] = \"RxQ available descriptors threshold reached\",\n-\t[RTE_ETH_EVENT_ERR_RECOVERING] = \"error recovering\",\n-\t[RTE_ETH_EVENT_RECOVERY_SUCCESS] = \"error recovery successful\",\n-\t[RTE_ETH_EVENT_RECOVERY_FAILED] = \"error recovery failed\",\n-\t[RTE_ETH_EVENT_MAX] = NULL,\n-};\n-\n-/*\n- * Display or mask ether events\n- * Default to all events except VF_MBOX\n- */\n-uint32_t event_print_mask = (UINT32_C(1) << RTE_ETH_EVENT_UNKNOWN) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_INTR_LSC) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_QUEUE_STATE) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_IPSEC) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_MACSEC) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_ERR_RECOVERING) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_SUCCESS) |\n-\t\t\t    (UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_FAILED);\n /*\n  * Decide if all memory are locked for performance.\n  */\n@@ -700,12 +665,6 @@ eth_dev_set_mtu_mp(uint16_t port_id, uint16_t mtu)\n /* Forward function declarations */\n static void setup_attached_port(portid_t pi);\n static void check_all_ports_link_status(uint32_t port_mask);\n-static int eth_event_callback(portid_t port_id,\n-\t\t\t      enum rte_eth_event_type type,\n-\t\t\t      void *param, void *ret_param);\n-static void dev_event_callback(const char *device_name,\n-\t\t\t\tenum rte_dev_event_type type,\n-\t\t\t\tvoid *param);\n static void fill_xstats_display_info(void);\n \n /*\n@@ -3671,7 +3630,7 @@ setup_attached_port(portid_t pi)\n \tprintf(\"Done\\n\");\n }\n \n-static void\n+void\n detach_device(struct rte_device *dev)\n {\n \tportid_t sibling;\n@@ -3817,13 +3776,9 @@ pmd_test_exit(void)\n \t\t\treturn;\n \t\t}\n \n-\t\tret = rte_dev_event_callback_unregister(NULL,\n-\t\t\tdev_event_callback, NULL);\n-\t\tif (ret < 0) {\n-\t\t\tRTE_LOG(ERR, EAL,\n-\t\t\t\t\"fail to unregister device event callback.\\n\");\n+\t\tret = unregister_dev_event_callback();\n+\t\tif (ret != 0)\n \t\t\treturn;\n-\t\t}\n \n \t\tret = rte_dev_hotplug_handle_disable();\n \t\tif (ret) {\n@@ -3908,274 +3863,6 @@ check_all_ports_link_status(uint32_t port_mask)\n \t}\n }\n \n-static void\n-rmv_port_callback(void *arg)\n-{\n-\tint need_to_start = 0;\n-\tint org_no_link_check = no_link_check;\n-\tportid_t port_id = (intptr_t)arg;\n-\tstruct rte_eth_dev_info dev_info;\n-\tint ret;\n-\n-\tRTE_ETH_VALID_PORTID_OR_RET(port_id);\n-\n-\tif (!test_done && port_is_forwarding(port_id)) {\n-\t\tneed_to_start = 1;\n-\t\tstop_packet_forwarding();\n-\t}\n-\tno_link_check = 1;\n-\tstop_port(port_id);\n-\tno_link_check = org_no_link_check;\n-\n-\tret = eth_dev_info_get_print_err(port_id, &dev_info);\n-\tif (ret != 0)\n-\t\tTESTPMD_LOG(ERR,\n-\t\t\t\"Failed to get device info for port %d, not detaching\\n\",\n-\t\t\tport_id);\n-\telse {\n-\t\tstruct rte_device *device = dev_info.device;\n-\t\tclose_port(port_id);\n-\t\tdetach_device(device); /* might be already removed or have more ports */\n-\t}\n-\tif (need_to_start)\n-\t\tstart_packet_forwarding(0);\n-}\n-\n-static int need_start_when_recovery_over;\n-\n-static bool\n-has_port_in_err_recovering(void)\n-{\n-\tstruct rte_port *port;\n-\tportid_t pid;\n-\n-\tRTE_ETH_FOREACH_DEV(pid) {\n-\t\tport = &ports[pid];\n-\t\tif (port->err_recovering)\n-\t\t\treturn true;\n-\t}\n-\n-\treturn false;\n-}\n-\n-static void\n-err_recovering_callback(portid_t port_id)\n-{\n-\tif (!has_port_in_err_recovering())\n-\t\tprintf(\"Please stop executing any commands until recovery result events are received!\\n\");\n-\n-\tports[port_id].err_recovering = 1;\n-\tports[port_id].recover_failed = 0;\n-\n-\t/* To simplify implementation, stop forwarding regardless of whether the port is used. */\n-\tif (!test_done) {\n-\t\tprintf(\"Stop packet forwarding because some ports are in error recovering!\\n\");\n-\t\tstop_packet_forwarding();\n-\t\tneed_start_when_recovery_over = 1;\n-\t}\n-}\n-\n-static void\n-recover_success_callback(portid_t port_id)\n-{\n-\tports[port_id].err_recovering = 0;\n-\tif (has_port_in_err_recovering())\n-\t\treturn;\n-\n-\tif (need_start_when_recovery_over) {\n-\t\tprintf(\"Recovery success! Restart packet forwarding!\\n\");\n-\t\tstart_packet_forwarding(0);\n-\t\tneed_start_when_recovery_over = 0;\n-\t} else {\n-\t\tprintf(\"Recovery success!\\n\");\n-\t}\n-}\n-\n-static void\n-recover_failed_callback(portid_t port_id)\n-{\n-\tstruct rte_port *port;\n-\tportid_t pid;\n-\n-\tports[port_id].err_recovering = 0;\n-\tports[port_id].recover_failed = 1;\n-\tif (has_port_in_err_recovering())\n-\t\treturn;\n-\n-\tneed_start_when_recovery_over = 0;\n-\tprintf(\"The ports:\");\n-\tRTE_ETH_FOREACH_DEV(pid) {\n-\t\tport = &ports[pid];\n-\t\tif (port->recover_failed)\n-\t\t\tprintf(\" %u\", pid);\n-\t}\n-\tprintf(\" recovery failed! Please remove them!\\n\");\n-}\n-\n-/* This function is used by the interrupt thread */\n-static int\n-eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,\n-\t\t  void *ret_param)\n-{\n-\tRTE_SET_USED(param);\n-\tRTE_SET_USED(ret_param);\n-\n-\tif (type >= RTE_ETH_EVENT_MAX) {\n-\t\tfprintf(stderr,\n-\t\t\t\"\\nPort %\" PRIu16 \": %s called upon invalid event %d\\n\",\n-\t\t\tport_id, __func__, type);\n-\t\tfflush(stderr);\n-\t} else if (event_print_mask & (UINT32_C(1) << type)) {\n-\t\tprintf(\"\\nPort %\" PRIu16 \": %s event\\n\", port_id,\n-\t\t\teth_event_desc[type]);\n-\t\tfflush(stdout);\n-\t}\n-\n-\tswitch (type) {\n-\tcase RTE_ETH_EVENT_NEW:\n-\t\tports[port_id].need_setup = 1;\n-\t\tports[port_id].port_status = RTE_PORT_HANDLING;\n-\t\tbreak;\n-\tcase RTE_ETH_EVENT_INTR_RMV:\n-\t\tif (port_id_is_invalid(port_id, DISABLED_WARN))\n-\t\t\tbreak;\n-\t\tif (rte_eal_alarm_set(100000,\n-\t\t\t\trmv_port_callback, (void *)(intptr_t)port_id))\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"Could not set up deferred device removal\\n\");\n-\t\tbreak;\n-\tcase RTE_ETH_EVENT_DESTROY:\n-\t\tports[port_id].port_status = RTE_PORT_CLOSED;\n-\t\tprintf(\"Port %u is closed\\n\", port_id);\n-\t\tbreak;\n-\tcase RTE_ETH_EVENT_RX_AVAIL_THRESH: {\n-\t\tuint16_t rxq_id;\n-\t\tint ret;\n-\n-\t\t/* avail_thresh query API rewinds rxq_id, no need to check max RxQ num */\n-\t\tfor (rxq_id = 0; ; rxq_id++) {\n-\t\t\tret = rte_eth_rx_avail_thresh_query(port_id, &rxq_id,\n-\t\t\t\t\t\t\t    NULL);\n-\t\t\tif (ret <= 0)\n-\t\t\t\tbreak;\n-\t\t\tprintf(\"Received avail_thresh event, port: %u, rxq_id: %u\\n\",\n-\t\t\t       port_id, rxq_id);\n-\n-#ifdef RTE_NET_MLX5\n-\t\t\tmlx5_test_avail_thresh_event_handler(port_id, rxq_id);\n-#endif\n-\t\t}\n-\t\tbreak;\n-\t}\n-\tcase RTE_ETH_EVENT_ERR_RECOVERING:\n-\t\terr_recovering_callback(port_id);\n-\t\tbreak;\n-\tcase RTE_ETH_EVENT_RECOVERY_SUCCESS:\n-\t\trecover_success_callback(port_id);\n-\t\tbreak;\n-\tcase RTE_ETH_EVENT_RECOVERY_FAILED:\n-\t\trecover_failed_callback(port_id);\n-\t\tbreak;\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\treturn 0;\n-}\n-\n-static int\n-register_eth_event_callback(void)\n-{\n-\tint ret;\n-\tenum rte_eth_event_type event;\n-\n-\tfor (event = RTE_ETH_EVENT_UNKNOWN;\n-\t\t\tevent < RTE_ETH_EVENT_MAX; event++) {\n-\t\tret = rte_eth_dev_callback_register(RTE_ETH_ALL,\n-\t\t\t\tevent,\n-\t\t\t\teth_event_callback,\n-\t\t\t\tNULL);\n-\t\tif (ret != 0) {\n-\t\t\tTESTPMD_LOG(ERR, \"Failed to register callback for \"\n-\t\t\t\t\t\"%s event\\n\", eth_event_desc[event]);\n-\t\t\treturn -1;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int\n-unregister_eth_event_callback(void)\n-{\n-\tint ret;\n-\tenum rte_eth_event_type event;\n-\n-\tfor (event = RTE_ETH_EVENT_UNKNOWN;\n-\t\t\tevent < RTE_ETH_EVENT_MAX; event++) {\n-\t\tret = rte_eth_dev_callback_unregister(RTE_ETH_ALL,\n-\t\t\t\tevent,\n-\t\t\t\teth_event_callback,\n-\t\t\t\tNULL);\n-\t\tif (ret != 0) {\n-\t\t\tTESTPMD_LOG(ERR, \"Failed to unregister callback for \"\n-\t\t\t\t\t\"%s event\\n\", eth_event_desc[event]);\n-\t\t\treturn -1;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n-/* This function is used by the interrupt thread */\n-static void\n-dev_event_callback(const char *device_name, enum rte_dev_event_type type,\n-\t\t\t     __rte_unused void *arg)\n-{\n-\tuint16_t port_id;\n-\tint ret;\n-\n-\tif (type >= RTE_DEV_EVENT_MAX) {\n-\t\tfprintf(stderr, \"%s called upon invalid event %d\\n\",\n-\t\t\t__func__, type);\n-\t\tfflush(stderr);\n-\t}\n-\n-\tswitch (type) {\n-\tcase RTE_DEV_EVENT_REMOVE:\n-\t\tRTE_LOG(DEBUG, EAL, \"The device: %s has been removed!\\n\",\n-\t\t\tdevice_name);\n-\t\tret = rte_eth_dev_get_port_by_name(device_name, &port_id);\n-\t\tif (ret) {\n-\t\t\tRTE_LOG(ERR, EAL, \"can not get port by device %s!\\n\",\n-\t\t\t\tdevice_name);\n-\t\t\treturn;\n-\t\t}\n-\t\t/*\n-\t\t * Because the user's callback is invoked in eal interrupt\n-\t\t * callback, the interrupt callback need to be finished before\n-\t\t * it can be unregistered when detaching device. So finish\n-\t\t * callback soon and use a deferred removal to detach device\n-\t\t * is need. It is a workaround, once the device detaching be\n-\t\t * moved into the eal in the future, the deferred removal could\n-\t\t * be deleted.\n-\t\t */\n-\t\tif (rte_eal_alarm_set(100000,\n-\t\t\t\trmv_port_callback, (void *)(intptr_t)port_id))\n-\t\t\tRTE_LOG(ERR, EAL,\n-\t\t\t\t\"Could not set up deferred device removal\\n\");\n-\t\tbreak;\n-\tcase RTE_DEV_EVENT_ADD:\n-\t\tRTE_LOG(ERR, EAL, \"The device: %s has been added!\\n\",\n-\t\t\tdevice_name);\n-\t\t/* TODO: After finish kernel driver binding,\n-\t\t * begin to attach port.\n-\t\t */\n-\t\tbreak;\n-\tdefault:\n-\t\tbreak;\n-\t}\n-}\n-\n static void\n rxtx_port_config(portid_t pid)\n {\n@@ -4724,13 +4411,9 @@ main(int argc, char** argv)\n \t\t\treturn -1;\n \t\t}\n \n-\t\tret = rte_dev_event_callback_register(NULL,\n-\t\t\tdev_event_callback, NULL);\n-\t\tif (ret) {\n-\t\t\tRTE_LOG(ERR, EAL,\n-\t\t\t\t\"fail  to register device event callback\\n\");\n+\t\tret = register_dev_event_callback();\n+\t\tif (ret != 0)\n \t\t\treturn -1;\n-\t\t}\n \t}\n \n \tif (!no_device_start && start_port(RTE_PORT_ALL) != 0) {\ndiff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h\nindex b8a0a4715a..8d3fb3475d 100644\n--- a/app/test-pmd/testpmd.h\n+++ b/app/test-pmd/testpmd.h\n@@ -1109,6 +1109,11 @@ void set_nb_pkt_per_burst(uint16_t pkt_burst);\n char *list_pkt_forwarding_modes(void);\n char *list_pkt_forwarding_retry_modes(void);\n void set_pkt_forwarding_mode(const char *fwd_mode);\n+int get_event_name_mask(const char *name, uint32_t *mask);\n+int register_eth_event_callback(void);\n+int unregister_eth_event_callback(void);\n+int register_dev_event_callback(void);\n+int unregister_dev_event_callback(void);\n void start_packet_forwarding(int with_tx_first);\n void fwd_stats_display(void);\n void fwd_stats_reset(void);\n@@ -1128,6 +1133,7 @@ void stop_port(portid_t pid);\n void close_port(portid_t pid);\n void reset_port(portid_t pid);\n void attach_port(char *identifier);\n+void detach_device(struct rte_device *dev);\n void detach_devargs(char *identifier);\n void detach_port_device(portid_t port_id);\n int all_ports_stopped(void);\n",
    "prefixes": [
        "v3",
        "6/7"
    ]
}