get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 97433,
    "url": "http://patchwork.dpdk.org/api/patches/97433/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20210827065717.1838258-16-andrew.rybchenko@oktetlabs.ru/",
    "project": {
        "id": 1,
        "url": "http://patchwork.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": "<20210827065717.1838258-16-andrew.rybchenko@oktetlabs.ru>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210827065717.1838258-16-andrew.rybchenko@oktetlabs.ru",
    "date": "2021-08-27T06:56:54",
    "name": "[15/38] net/sfc: add representor proxy port API",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "a8259d7bb83a812c20badf7ef4a95de800608cf7",
    "submitter": {
        "id": 2013,
        "url": "http://patchwork.dpdk.org/api/people/2013/?format=api",
        "name": "Andrew Rybchenko",
        "email": "Andrew.Rybchenko@oktetlabs.ru"
    },
    "delegate": {
        "id": 319,
        "url": "http://patchwork.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/20210827065717.1838258-16-andrew.rybchenko@oktetlabs.ru/mbox/",
    "series": [
        {
            "id": 18492,
            "url": "http://patchwork.dpdk.org/api/series/18492/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=18492",
            "date": "2021-08-27T06:56:39",
            "name": "net/sfc: support port representors",
            "version": 1,
            "mbox": "http://patchwork.dpdk.org/series/18492/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/97433/comments/",
    "check": "warning",
    "checks": "http://patchwork.dpdk.org/api/patches/97433/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 D84A9A0C43;\n\tFri, 27 Aug 2021 08:59:19 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id 3E4D24124D;\n\tFri, 27 Aug 2021 08:58:33 +0200 (CEST)",
            "from shelob.oktetlabs.ru (shelob.oktetlabs.ru [91.220.146.113])\n by mails.dpdk.org (Postfix) with ESMTP id C662F411D3\n for <dev@dpdk.org>; Fri, 27 Aug 2021 08:58:30 +0200 (CEST)",
            "by shelob.oktetlabs.ru (Postfix, from userid 122)\n id 9C4F57F6DE; Fri, 27 Aug 2021 09:58:30 +0300 (MSK)",
            "from aros.oktetlabs.ru (aros.oktetlabs.ru [192.168.38.17])\n by shelob.oktetlabs.ru (Postfix) with ESMTP id 6A3BC7F6E0;\n Fri, 27 Aug 2021 09:57:34 +0300 (MSK)"
        ],
        "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on shelob.oktetlabs.ru",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=0.8 required=5.0 tests=ALL_TRUSTED,\n DKIM_ADSP_DISCARD,\n URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2",
        "DKIM-Filter": "OpenDKIM Filter v2.11.0 shelob.oktetlabs.ru 6A3BC7F6E0",
        "Authentication-Results": "shelob.oktetlabs.ru/6A3BC7F6E0; dkim=none;\n dkim-atps=neutral",
        "From": "Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>",
        "To": "dev@dpdk.org",
        "Cc": "Igor Romanov <igor.romanov@oktetlabs.ru>,\n Andy Moreton <amoreton@xilinx.com>, Ivan Malov <ivan.malov@oktetlabs.ru>",
        "Date": "Fri, 27 Aug 2021 09:56:54 +0300",
        "Message-Id": "<20210827065717.1838258-16-andrew.rybchenko@oktetlabs.ru>",
        "X-Mailer": "git-send-email 2.30.2",
        "In-Reply-To": "<20210827065717.1838258-1-andrew.rybchenko@oktetlabs.ru>",
        "References": "<20210827065717.1838258-1-andrew.rybchenko@oktetlabs.ru>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[dpdk-dev] [PATCH 15/38] net/sfc: add representor proxy port API",
        "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",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Igor Romanov <igor.romanov@oktetlabs.ru>\n\nThe API is required to create and destroy representor proxy\nport assigned to representor.\n\nSigned-off-by: Igor Romanov <igor.romanov@oktetlabs.ru>\nSigned-off-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>\nReviewed-by: Andy Moreton <amoreton@xilinx.com>\nReviewed-by: Ivan Malov <ivan.malov@oktetlabs.ru>\n---\n drivers/net/sfc/sfc.c                |  12 +\n drivers/net/sfc/sfc.h                |   1 +\n drivers/net/sfc/sfc_ethdev.c         |   2 +\n drivers/net/sfc/sfc_repr.c           |  20 ++\n drivers/net/sfc/sfc_repr_proxy.c     | 320 ++++++++++++++++++++++++++-\n drivers/net/sfc/sfc_repr_proxy.h     |  30 +++\n drivers/net/sfc/sfc_repr_proxy_api.h |  29 +++\n 7 files changed, 412 insertions(+), 2 deletions(-)\n create mode 100644 drivers/net/sfc/sfc_repr_proxy_api.h",
    "diff": "diff --git a/drivers/net/sfc/sfc.c b/drivers/net/sfc/sfc.c\nindex 152234cb61..f79f4d5ffc 100644\n--- a/drivers/net/sfc/sfc.c\n+++ b/drivers/net/sfc/sfc.c\n@@ -1043,6 +1043,18 @@ sfc_attach(struct sfc_adapter *sa)\n \treturn rc;\n }\n \n+void\n+sfc_pre_detach(struct sfc_adapter *sa)\n+{\n+\tsfc_log_init(sa, \"entry\");\n+\n+\tSFC_ASSERT(!sfc_adapter_is_locked(sa));\n+\n+\tsfc_repr_proxy_pre_detach(sa);\n+\n+\tsfc_log_init(sa, \"done\");\n+}\n+\n void\n sfc_detach(struct sfc_adapter *sa)\n {\ndiff --git a/drivers/net/sfc/sfc.h b/drivers/net/sfc/sfc.h\nindex 628f32c13f..c3e92f3ab6 100644\n--- a/drivers/net/sfc/sfc.h\n+++ b/drivers/net/sfc/sfc.h\n@@ -376,6 +376,7 @@ uint32_t sfc_register_logtype(const struct rte_pci_addr *pci_addr,\n int sfc_probe(struct sfc_adapter *sa);\n void sfc_unprobe(struct sfc_adapter *sa);\n int sfc_attach(struct sfc_adapter *sa);\n+void sfc_pre_detach(struct sfc_adapter *sa);\n void sfc_detach(struct sfc_adapter *sa);\n int sfc_start(struct sfc_adapter *sa);\n void sfc_stop(struct sfc_adapter *sa);\ndiff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c\nindex 8308cbdfef..8578ba0765 100644\n--- a/drivers/net/sfc/sfc_ethdev.c\n+++ b/drivers/net/sfc/sfc_ethdev.c\n@@ -345,6 +345,8 @@ sfc_dev_close(struct rte_eth_dev *dev)\n \t\treturn 0;\n \t}\n \n+\tsfc_pre_detach(sa);\n+\n \tsfc_adapter_lock(sa);\n \tswitch (sa->state) {\n \tcase SFC_ETHDEV_STARTED:\ndiff --git a/drivers/net/sfc/sfc_repr.c b/drivers/net/sfc/sfc_repr.c\nindex 603a613ec6..f684b1d7ef 100644\n--- a/drivers/net/sfc/sfc_repr.c\n+++ b/drivers/net/sfc/sfc_repr.c\n@@ -19,6 +19,7 @@\n #include \"sfc_debug.h\"\n #include \"sfc_repr.h\"\n #include \"sfc_ethdev_state.h\"\n+#include \"sfc_repr_proxy_api.h\"\n #include \"sfc_switch.h\"\n \n /** Multi-process shared representor private data */\n@@ -285,6 +286,7 @@ static int\n sfc_repr_dev_close(struct rte_eth_dev *dev)\n {\n \tstruct sfc_repr *sr = sfc_repr_by_eth_dev(dev);\n+\tstruct sfc_repr_shared *srs = sfc_repr_shared_by_eth_dev(dev);\n \n \tsfcr_info(sr, \"entry\");\n \n@@ -306,6 +308,8 @@ sfc_repr_dev_close(struct rte_eth_dev *dev)\n \t * Rollback primary process sfc_repr_eth_dev_init() below.\n \t */\n \n+\t(void)sfc_repr_proxy_del_port(srs->pf_port_id, srs->repr_id);\n+\n \tdev->dev_ops = NULL;\n \n \tsfc_repr_unlock(sr);\n@@ -378,6 +382,18 @@ sfc_repr_eth_dev_init(struct rte_eth_dev *dev, void *init_params)\n \t\tgoto fail_mae_assign_switch_port;\n \t}\n \n+\tret = sfc_repr_proxy_add_port(repr_data->pf_port_id,\n+\t\t\t\t      repr_data->repr_id,\n+\t\t\t\t      dev->data->port_id,\n+\t\t\t\t      &repr_data->mport_sel);\n+\tif (ret != 0) {\n+\t\tSFC_GENERIC_LOG(ERR, \"%s() failed to add repr proxy port\",\n+\t\t\t\t__func__);\n+\t\tSFC_ASSERT(ret > 0);\n+\t\tret = -ret;\n+\t\tgoto fail_create_port;\n+\t}\n+\n \t/*\n \t * Allocate process private data from heap, since it should not\n \t * be located in shared memory allocated using rte_malloc() API.\n@@ -419,6 +435,10 @@ sfc_repr_eth_dev_init(struct rte_eth_dev *dev, void *init_params)\n \tfree(sr);\n \n fail_alloc_sr:\n+\t(void)sfc_repr_proxy_del_port(repr_data->pf_port_id,\n+\t\t\t\t      repr_data->repr_id);\n+\n+fail_create_port:\n fail_mae_assign_switch_port:\n \tSFC_GENERIC_LOG(ERR, \"%s() failed: %s\", __func__, rte_strerror(-ret));\n \treturn ret;\ndiff --git a/drivers/net/sfc/sfc_repr_proxy.c b/drivers/net/sfc/sfc_repr_proxy.c\nindex 6d3962304f..f64fa2efc7 100644\n--- a/drivers/net/sfc/sfc_repr_proxy.c\n+++ b/drivers/net/sfc/sfc_repr_proxy.c\n@@ -13,17 +13,191 @@\n #include \"sfc_log.h\"\n #include \"sfc_service.h\"\n #include \"sfc_repr_proxy.h\"\n+#include \"sfc_repr_proxy_api.h\"\n #include \"sfc.h\"\n \n+/**\n+ * Amount of time to wait for the representor proxy routine (which is\n+ * running on a service core) to handle a request sent via mbox.\n+ */\n+#define SFC_REPR_PROXY_MBOX_POLL_TIMEOUT_MS\t1000\n+\n+static struct sfc_repr_proxy *\n+sfc_repr_proxy_by_adapter(struct sfc_adapter *sa)\n+{\n+\treturn &sa->repr_proxy;\n+}\n+\n+static struct sfc_adapter *\n+sfc_get_adapter_by_pf_port_id(uint16_t pf_port_id)\n+{\n+\tstruct rte_eth_dev *dev;\n+\tstruct sfc_adapter *sa;\n+\n+\tSFC_ASSERT(pf_port_id < RTE_MAX_ETHPORTS);\n+\n+\tdev = &rte_eth_devices[pf_port_id];\n+\tsa = sfc_adapter_by_eth_dev(dev);\n+\n+\tsfc_adapter_lock(sa);\n+\n+\treturn sa;\n+}\n+\n+static void\n+sfc_put_adapter(struct sfc_adapter *sa)\n+{\n+\tsfc_adapter_unlock(sa);\n+}\n+\n+static int\n+sfc_repr_proxy_mbox_send(struct sfc_repr_proxy_mbox *mbox,\n+\t\t\t struct sfc_repr_proxy_port *port,\n+\t\t\t enum sfc_repr_proxy_mbox_op op)\n+{\n+\tconst unsigned int wait_ms = SFC_REPR_PROXY_MBOX_POLL_TIMEOUT_MS;\n+\tunsigned int i;\n+\n+\tmbox->op = op;\n+\tmbox->port = port;\n+\tmbox->ack = false;\n+\n+\t/*\n+\t * Release ordering enforces marker set after data is populated.\n+\t * Paired with acquire ordering in sfc_repr_proxy_mbox_handle().\n+\t */\n+\t__atomic_store_n(&mbox->write_marker, true, __ATOMIC_RELEASE);\n+\n+\t/*\n+\t * Wait for the representor routine to process the request.\n+\t * Give up on timeout.\n+\t */\n+\tfor (i = 0; i < wait_ms; i++) {\n+\t\t/*\n+\t\t * Paired with release ordering in sfc_repr_proxy_mbox_handle()\n+\t\t * on acknowledge write.\n+\t\t */\n+\t\tif (__atomic_load_n(&mbox->ack, __ATOMIC_ACQUIRE))\n+\t\t\tbreak;\n+\n+\t\trte_delay_ms(1);\n+\t}\n+\n+\tif (i == wait_ms) {\n+\t\tSFC_GENERIC_LOG(ERR,\n+\t\t\t\"%s() failed to wait for representor proxy routine ack\",\n+\t\t\t__func__);\n+\t\treturn ETIMEDOUT;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+sfc_repr_proxy_mbox_handle(struct sfc_repr_proxy *rp)\n+{\n+\tstruct sfc_repr_proxy_mbox *mbox = &rp->mbox;\n+\n+\t/*\n+\t * Paired with release ordering in sfc_repr_proxy_mbox_send()\n+\t * on marker set.\n+\t */\n+\tif (!__atomic_load_n(&mbox->write_marker, __ATOMIC_ACQUIRE))\n+\t\treturn;\n+\n+\tmbox->write_marker = false;\n+\n+\tswitch (mbox->op) {\n+\tcase SFC_REPR_PROXY_MBOX_ADD_PORT:\n+\t\tTAILQ_INSERT_TAIL(&rp->ports, mbox->port, entries);\n+\t\tbreak;\n+\tcase SFC_REPR_PROXY_MBOX_DEL_PORT:\n+\t\tTAILQ_REMOVE(&rp->ports, mbox->port, entries);\n+\t\tbreak;\n+\tdefault:\n+\t\tSFC_ASSERT(0);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * Paired with acquire ordering in sfc_repr_proxy_mbox_send()\n+\t * on acknowledge read.\n+\t */\n+\t__atomic_store_n(&mbox->ack, true, __ATOMIC_RELEASE);\n+}\n+\n static int32_t\n sfc_repr_proxy_routine(void *arg)\n {\n \tstruct sfc_repr_proxy *rp = arg;\n \n-\t/* Representor proxy boilerplate will be here */\n-\tRTE_SET_USED(rp);\n+\tsfc_repr_proxy_mbox_handle(rp);\n+\n+\treturn 0;\n+}\n+\n+static int\n+sfc_repr_proxy_ports_init(struct sfc_adapter *sa)\n+{\n+\tstruct sfc_repr_proxy *rp = &sa->repr_proxy;\n+\tint rc;\n+\n+\tsfc_log_init(sa, \"entry\");\n+\n+\trc = efx_mcdi_mport_alloc_alias(sa->nic, &rp->mport_alias, NULL);\n+\tif (rc != 0) {\n+\t\tsfc_err(sa, \"failed to alloc mport alias: %s\",\n+\t\t\trte_strerror(rc));\n+\t\tgoto fail_alloc_mport_alias;\n+\t}\n+\n+\tTAILQ_INIT(&rp->ports);\n+\n+\tsfc_log_init(sa, \"done\");\n \n \treturn 0;\n+\n+fail_alloc_mport_alias:\n+\n+\tsfc_log_init(sa, \"failed: %s\", rte_strerror(rc));\n+\treturn rc;\n+}\n+\n+void\n+sfc_repr_proxy_pre_detach(struct sfc_adapter *sa)\n+{\n+\tstruct sfc_repr_proxy *rp = &sa->repr_proxy;\n+\tbool close_ports[RTE_MAX_ETHPORTS] = {0};\n+\tstruct sfc_repr_proxy_port *port;\n+\tunsigned int i;\n+\n+\tSFC_ASSERT(!sfc_adapter_is_locked(sa));\n+\n+\tsfc_adapter_lock(sa);\n+\n+\tif (sfc_repr_available(sfc_sa2shared(sa))) {\n+\t\tTAILQ_FOREACH(port, &rp->ports, entries)\n+\t\t\tclose_ports[port->rte_port_id] = true;\n+\t} else {\n+\t\tsfc_log_init(sa, \"representors not supported - skip\");\n+\t}\n+\n+\tsfc_adapter_unlock(sa);\n+\n+\tfor (i = 0; i < RTE_DIM(close_ports); i++) {\n+\t\tif (close_ports[i]) {\n+\t\t\trte_eth_dev_stop(i);\n+\t\t\trte_eth_dev_close(i);\n+\t\t}\n+\t}\n+}\n+\n+static void\n+sfc_repr_proxy_ports_fini(struct sfc_adapter *sa)\n+{\n+\tstruct sfc_repr_proxy *rp = &sa->repr_proxy;\n+\n+\tefx_mae_mport_free(sa->nic, &rp->mport_alias);\n }\n \n int\n@@ -43,6 +217,10 @@ sfc_repr_proxy_attach(struct sfc_adapter *sa)\n \t\treturn 0;\n \t}\n \n+\trc = sfc_repr_proxy_ports_init(sa);\n+\tif (rc != 0)\n+\t\tgoto fail_ports_init;\n+\n \tcid = sfc_get_service_lcore(sa->socket_id);\n \tif (cid == RTE_MAX_LCORE && sa->socket_id != SOCKET_ID_ANY) {\n \t\t/* Warn and try to allocate on any NUMA node */\n@@ -96,6 +274,9 @@ sfc_repr_proxy_attach(struct sfc_adapter *sa)\n \t */\n \n fail_get_service_lcore:\n+\tsfc_repr_proxy_ports_fini(sa);\n+\n+fail_ports_init:\n \tsfc_log_init(sa, \"failed: %s\", rte_strerror(rc));\n \treturn rc;\n }\n@@ -115,6 +296,7 @@ sfc_repr_proxy_detach(struct sfc_adapter *sa)\n \n \trte_service_map_lcore_set(rp->service_id, rp->service_core_id, 0);\n \trte_service_component_unregister(rp->service_id);\n+\tsfc_repr_proxy_ports_fini(sa);\n \n \tsfc_log_init(sa, \"done\");\n }\n@@ -165,6 +347,8 @@ sfc_repr_proxy_start(struct sfc_adapter *sa)\n \t\tgoto fail_runstate_set;\n \t}\n \n+\trp->started = true;\n+\n \tsfc_log_init(sa, \"done\");\n \n \treturn 0;\n@@ -210,5 +394,137 @@ sfc_repr_proxy_stop(struct sfc_adapter *sa)\n \n \t/* Service lcore may be shared and we never stop it */\n \n+\trp->started = false;\n+\n+\tsfc_log_init(sa, \"done\");\n+}\n+\n+static struct sfc_repr_proxy_port *\n+sfc_repr_proxy_find_port(struct sfc_repr_proxy *rp, uint16_t repr_id)\n+{\n+\tstruct sfc_repr_proxy_port *port;\n+\n+\tTAILQ_FOREACH(port, &rp->ports, entries) {\n+\t\tif (port->repr_id == repr_id)\n+\t\t\treturn port;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+int\n+sfc_repr_proxy_add_port(uint16_t pf_port_id, uint16_t repr_id,\n+\t\t\tuint16_t rte_port_id, const efx_mport_sel_t *mport_sel)\n+{\n+\tstruct sfc_repr_proxy_port *port;\n+\tstruct sfc_repr_proxy *rp;\n+\tstruct sfc_adapter *sa;\n+\tint rc;\n+\n+\tsa = sfc_get_adapter_by_pf_port_id(pf_port_id);\n+\trp = sfc_repr_proxy_by_adapter(sa);\n+\n+\tsfc_log_init(sa, \"entry\");\n+\tTAILQ_FOREACH(port, &rp->ports, entries) {\n+\t\tif (port->rte_port_id == rte_port_id) {\n+\t\t\trc = EEXIST;\n+\t\t\tsfc_err(sa, \"%s() failed: port exists\", __func__);\n+\t\t\tgoto fail_port_exists;\n+\t\t}\n+\t}\n+\n+\tport = rte_zmalloc(\"sfc-repr-proxy-port\", sizeof(*port),\n+\t\t\t   sa->socket_id);\n+\tif (port == NULL) {\n+\t\trc = ENOMEM;\n+\t\tsfc_err(sa, \"failed to alloc memory for proxy port\");\n+\t\tgoto fail_alloc_port;\n+\t}\n+\n+\trc = efx_mae_mport_id_by_selector(sa->nic, mport_sel,\n+\t\t\t\t\t  &port->egress_mport);\n+\tif (rc != 0) {\n+\t\tsfc_err(sa,\n+\t\t\t\"failed get MAE mport id by selector (repr_id %u): %s\",\n+\t\t\trepr_id, rte_strerror(rc));\n+\t\tgoto fail_mport_id;\n+\t}\n+\n+\tport->rte_port_id = rte_port_id;\n+\tport->repr_id = repr_id;\n+\n+\tif (rp->started) {\n+\t\trc = sfc_repr_proxy_mbox_send(&rp->mbox, port,\n+\t\t\t\t\t      SFC_REPR_PROXY_MBOX_ADD_PORT);\n+\t\tif (rc != 0) {\n+\t\t\tsfc_err(sa, \"failed to add proxy port %u\",\n+\t\t\t\tport->repr_id);\n+\t\t\tgoto fail_port_add;\n+\t\t}\n+\t} else {\n+\t\tTAILQ_INSERT_TAIL(&rp->ports, port, entries);\n+\t}\n+\n+\tsfc_log_init(sa, \"done\");\n+\tsfc_put_adapter(sa);\n+\n+\treturn 0;\n+\n+fail_port_add:\n+fail_mport_id:\n+\trte_free(port);\n+fail_alloc_port:\n+fail_port_exists:\n+\tsfc_log_init(sa, \"failed: %s\", rte_strerror(rc));\n+\tsfc_put_adapter(sa);\n+\n+\treturn rc;\n+}\n+\n+int\n+sfc_repr_proxy_del_port(uint16_t pf_port_id, uint16_t repr_id)\n+{\n+\tstruct sfc_repr_proxy_port *port;\n+\tstruct sfc_repr_proxy *rp;\n+\tstruct sfc_adapter *sa;\n+\tint rc;\n+\n+\tsa = sfc_get_adapter_by_pf_port_id(pf_port_id);\n+\trp = sfc_repr_proxy_by_adapter(sa);\n+\n+\tsfc_log_init(sa, \"entry\");\n+\n+\tport = sfc_repr_proxy_find_port(rp, repr_id);\n+\tif (port == NULL) {\n+\t\tsfc_err(sa, \"failed: no such port\");\n+\t\trc = ENOENT;\n+\t\tgoto fail_no_port;\n+\t}\n+\n+\tif (rp->started) {\n+\t\trc = sfc_repr_proxy_mbox_send(&rp->mbox, port,\n+\t\t\t\t\t      SFC_REPR_PROXY_MBOX_DEL_PORT);\n+\t\tif (rc != 0) {\n+\t\t\tsfc_err(sa, \"failed to remove proxy port %u\",\n+\t\t\t\tport->repr_id);\n+\t\t\tgoto fail_port_remove;\n+\t\t}\n+\t} else {\n+\t\tTAILQ_REMOVE(&rp->ports, port, entries);\n+\t}\n+\n+\trte_free(port);\n+\n \tsfc_log_init(sa, \"done\");\n+\n+\tsfc_put_adapter(sa);\n+\n+\treturn 0;\n+\n+fail_port_remove:\n+fail_no_port:\n+\tsfc_log_init(sa, \"failed: %s\", rte_strerror(rc));\n+\tsfc_put_adapter(sa);\n+\n+\treturn rc;\n }\ndiff --git a/drivers/net/sfc/sfc_repr_proxy.h b/drivers/net/sfc/sfc_repr_proxy.h\nindex 953b9922c8..e4a6213c10 100644\n--- a/drivers/net/sfc/sfc_repr_proxy.h\n+++ b/drivers/net/sfc/sfc_repr_proxy.h\n@@ -12,6 +12,8 @@\n \n #include <stdint.h>\n \n+#include \"efx.h\"\n+\n #ifdef __cplusplus\n extern \"C\" {\n #endif\n@@ -24,14 +26,42 @@ extern \"C\" {\n #define SFC_REPR_PROXY_NB_TXQ_MIN\t(1)\n #define SFC_REPR_PROXY_NB_TXQ_MAX\t(1)\n \n+struct sfc_repr_proxy_port {\n+\tTAILQ_ENTRY(sfc_repr_proxy_port)\tentries;\n+\tuint16_t\t\t\t\trepr_id;\n+\tuint16_t\t\t\t\trte_port_id;\n+\tefx_mport_id_t\t\t\t\tegress_mport;\n+};\n+\n+enum sfc_repr_proxy_mbox_op {\n+\tSFC_REPR_PROXY_MBOX_ADD_PORT,\n+\tSFC_REPR_PROXY_MBOX_DEL_PORT,\n+};\n+\n+struct sfc_repr_proxy_mbox {\n+\tstruct sfc_repr_proxy_port\t*port;\n+\tenum sfc_repr_proxy_mbox_op\top;\n+\n+\tbool\t\t\t\twrite_marker;\n+\tbool\t\t\t\tack;\n+};\n+\n+TAILQ_HEAD(sfc_repr_proxy_ports, sfc_repr_proxy_port);\n+\n struct sfc_repr_proxy {\n \tuint32_t\t\t\tservice_core_id;\n \tuint32_t\t\t\tservice_id;\n+\tefx_mport_id_t\t\t\tmport_alias;\n+\tstruct sfc_repr_proxy_ports\tports;\n+\tbool\t\t\t\tstarted;\n+\n+\tstruct sfc_repr_proxy_mbox\tmbox;\n };\n \n struct sfc_adapter;\n \n int sfc_repr_proxy_attach(struct sfc_adapter *sa);\n+void sfc_repr_proxy_pre_detach(struct sfc_adapter *sa);\n void sfc_repr_proxy_detach(struct sfc_adapter *sa);\n int sfc_repr_proxy_start(struct sfc_adapter *sa);\n void sfc_repr_proxy_stop(struct sfc_adapter *sa);\ndiff --git a/drivers/net/sfc/sfc_repr_proxy_api.h b/drivers/net/sfc/sfc_repr_proxy_api.h\nnew file mode 100644\nindex 0000000000..af9009ca3c\n--- /dev/null\n+++ b/drivers/net/sfc/sfc_repr_proxy_api.h\n@@ -0,0 +1,29 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ *\n+ * Copyright(c) 2019-2021 Xilinx, Inc.\n+ * Copyright(c) 2019 Solarflare Communications Inc.\n+ *\n+ * This software was jointly developed between OKTET Labs (under contract\n+ * for Solarflare) and Solarflare Communications, Inc.\n+ */\n+\n+#ifndef _SFC_REPR_PROXY_API_H\n+#define _SFC_REPR_PROXY_API_H\n+\n+#include <stdint.h>\n+\n+#include \"efx.h\"\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+int sfc_repr_proxy_add_port(uint16_t pf_port_id, uint16_t repr_id,\n+\t\t\t    uint16_t rte_port_id,\n+\t\t\t    const efx_mport_sel_t *mport_set);\n+int sfc_repr_proxy_del_port(uint16_t pf_port_id, uint16_t repr_id);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+#endif  /* _SFC_REPR_PROXY_API_H */\n",
    "prefixes": [
        "15/38"
    ]
}