get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 97429,
    "url": "http://patchwork.dpdk.org/api/patches/97429/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/20210827065717.1838258-12-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-12-andrew.rybchenko@oktetlabs.ru>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20210827065717.1838258-12-andrew.rybchenko@oktetlabs.ru",
    "date": "2021-08-27T06:56:50",
    "name": "[11/38] net/sfc: add port representors infrastructure",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "bf9c80c6f00fe83015761c155e85d0e2f5fe0f85",
    "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-12-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/97429/comments/",
    "check": "success",
    "checks": "http://patchwork.dpdk.org/api/patches/97429/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 81A2CA0C43;\n\tFri, 27 Aug 2021 08:58:54 +0200 (CEST)",
            "from [217.70.189.124] (localhost [127.0.0.1])\n\tby mails.dpdk.org (Postfix) with ESMTP id D92404128B;\n\tFri, 27 Aug 2021 08:58:09 +0200 (CEST)",
            "from shelob.oktetlabs.ru (shelob.oktetlabs.ru [91.220.146.113])\n by mails.dpdk.org (Postfix) with ESMTP id C150641289\n for <dev@dpdk.org>; Fri, 27 Aug 2021 08:58:07 +0200 (CEST)",
            "by shelob.oktetlabs.ru (Postfix, from userid 122)\n id 8FAC47F6D3; Fri, 27 Aug 2021 09:58:07 +0300 (MSK)",
            "from aros.oktetlabs.ru (aros.oktetlabs.ru [192.168.38.17])\n by shelob.oktetlabs.ru (Postfix) with ESMTP id F13707F6DB;\n Fri, 27 Aug 2021 09:57:33 +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 F13707F6DB",
        "Authentication-Results": "shelob.oktetlabs.ru/F13707F6DB; 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:50 +0300",
        "Message-Id": "<20210827065717.1838258-12-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 11/38] net/sfc: add port representors\n infrastructure",
        "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\nProvide minimal implementation for port representors that only can be\nconfigured and can provide device information.\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 doc/guides/nics/sfc_efx.rst  |  13 +-\n drivers/net/sfc/meson.build  |   1 +\n drivers/net/sfc/sfc_ethdev.c | 156 +++++++++++-\n drivers/net/sfc/sfc_kvargs.c |   1 +\n drivers/net/sfc/sfc_kvargs.h |   2 +\n drivers/net/sfc/sfc_repr.c   | 458 +++++++++++++++++++++++++++++++++++\n drivers/net/sfc/sfc_repr.h   |  36 +++\n drivers/net/sfc/sfc_switch.h |   5 +\n 8 files changed, 663 insertions(+), 9 deletions(-)\n create mode 100644 drivers/net/sfc/sfc_repr.c\n create mode 100644 drivers/net/sfc/sfc_repr.h",
    "diff": "diff --git a/doc/guides/nics/sfc_efx.rst b/doc/guides/nics/sfc_efx.rst\nindex d66cb76dab..4719031508 100644\n--- a/doc/guides/nics/sfc_efx.rst\n+++ b/doc/guides/nics/sfc_efx.rst\n@@ -74,6 +74,8 @@ SFC EFX PMD has support for:\n \n - SR-IOV PF\n \n+- Port representors (see :ref: switch_representation)\n+\n \n Non-supported Features\n ----------------------\n@@ -382,7 +384,16 @@ boolean parameters value.\n   software virtual switch (for example, Open vSwitch) makes the decision.\n   Software virtual switch may install MAE rules to pass established traffic\n   flows via hardware and offload software datapath as the result.\n-  Default is legacy.\n+  Default is legacy, unless representors are specified, in which case switchdev\n+  is chosen.\n+\n+- ``representor`` parameter [list]\n+\n+  Instantiate port representor Ethernet devices for specified Virtual\n+  Functions list.\n+\n+  It is a standard parameter whose format is described in\n+  :ref:`ethernet_device_standard_device_arguments`.\n \n - ``rx_datapath`` [auto|efx|ef10|ef10_essb] (default **auto**)\n \ndiff --git a/drivers/net/sfc/meson.build b/drivers/net/sfc/meson.build\nindex 4fc2063f7a..98365e9e73 100644\n--- a/drivers/net/sfc/meson.build\n+++ b/drivers/net/sfc/meson.build\n@@ -98,4 +98,5 @@ sources = files(\n         'sfc_ef100_tx.c',\n         'sfc_service.c',\n         'sfc_repr_proxy.c',\n+        'sfc_repr.c',\n )\ndiff --git a/drivers/net/sfc/sfc_ethdev.c b/drivers/net/sfc/sfc_ethdev.c\nindex ff762bb90b..8308cbdfef 100644\n--- a/drivers/net/sfc/sfc_ethdev.c\n+++ b/drivers/net/sfc/sfc_ethdev.c\n@@ -28,6 +28,7 @@\n #include \"sfc_flow.h\"\n #include \"sfc_dp.h\"\n #include \"sfc_dp_rx.h\"\n+#include \"sfc_repr.h\"\n #include \"sfc_sw_stats.h\"\n \n #define SFC_XSTAT_ID_INVALID_VAL  UINT64_MAX\n@@ -1908,6 +1909,10 @@ static const struct eth_dev_ops sfc_eth_dev_ops = {\n \t.pool_ops_supported\t\t= sfc_pool_ops_supported,\n };\n \n+struct sfc_ethdev_init_data {\n+\tuint16_t\t\tnb_representors;\n+};\n+\n /**\n  * Duplicate a string in potentially shared memory required for\n  * multi-process support.\n@@ -2189,7 +2194,7 @@ sfc_register_dp(void)\n }\n \n static int\n-sfc_parse_switch_mode(struct sfc_adapter *sa)\n+sfc_parse_switch_mode(struct sfc_adapter *sa, bool has_representors)\n {\n \tconst char *switch_mode = NULL;\n \tint rc;\n@@ -2201,9 +2206,9 @@ sfc_parse_switch_mode(struct sfc_adapter *sa)\n \tif (rc != 0)\n \t\tgoto fail_kvargs;\n \n-\t/* Check representors when supported */\n-\tif (switch_mode == NULL ||\n-\t    strcasecmp(switch_mode, SFC_KVARG_SWITCH_MODE_LEGACY) == 0) {\n+\tif (switch_mode == NULL) {\n+\t\tsa->switchdev = has_representors;\n+\t} else if (strcasecmp(switch_mode, SFC_KVARG_SWITCH_MODE_LEGACY) == 0) {\n \t\tsa->switchdev = false;\n \t} else if (strcasecmp(switch_mode,\n \t\t\t      SFC_KVARG_SWITCH_MODE_SWITCHDEV) == 0) {\n@@ -2227,10 +2232,11 @@ sfc_parse_switch_mode(struct sfc_adapter *sa)\n }\n \n static int\n-sfc_eth_dev_init(struct rte_eth_dev *dev)\n+sfc_eth_dev_init(struct rte_eth_dev *dev, void *init_params)\n {\n \tstruct sfc_adapter_shared *sas = sfc_adapter_shared_by_eth_dev(dev);\n \tstruct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);\n+\tstruct sfc_ethdev_init_data *init_data = init_params;\n \tuint32_t logtype_main;\n \tstruct sfc_adapter *sa;\n \tint rc;\n@@ -2312,7 +2318,7 @@ sfc_eth_dev_init(struct rte_eth_dev *dev)\n \tsfc_adapter_lock_init(sa);\n \tsfc_adapter_lock(sa);\n \n-\trc = sfc_parse_switch_mode(sa);\n+\trc = sfc_parse_switch_mode(sa, init_data->nb_representors > 0);\n \tif (rc != 0)\n \t\tgoto fail_switch_mode;\n \n@@ -2402,11 +2408,145 @@ static const struct rte_pci_id pci_id_sfc_efx_map[] = {\n \t{ .vendor_id = 0 /* sentinel */ }\n };\n \n+static int\n+sfc_parse_rte_devargs(const char *args, struct rte_eth_devargs *devargs)\n+{\n+\tstruct rte_eth_devargs eth_da = { .nb_representor_ports = 0 };\n+\tint rc;\n+\n+\tif (args != NULL) {\n+\t\trc = rte_eth_devargs_parse(args, &eth_da);\n+\t\tif (rc != 0) {\n+\t\t\tSFC_GENERIC_LOG(ERR,\n+\t\t\t\t\t\"Failed to parse generic devargs '%s'\",\n+\t\t\t\t\targs);\n+\t\t\treturn rc;\n+\t\t}\n+\t}\n+\n+\t*devargs = eth_da;\n+\n+\treturn 0;\n+}\n+\n+static int\n+sfc_eth_dev_create(struct rte_pci_device *pci_dev,\n+\t\t   struct sfc_ethdev_init_data *init_data,\n+\t\t   struct rte_eth_dev **devp)\n+{\n+\tstruct rte_eth_dev *dev;\n+\tint rc;\n+\n+\trc = rte_eth_dev_create(&pci_dev->device, pci_dev->device.name,\n+\t\t\t\tsizeof(struct sfc_adapter_shared),\n+\t\t\t\teth_dev_pci_specific_init, pci_dev,\n+\t\t\t\tsfc_eth_dev_init, init_data);\n+\tif (rc != 0) {\n+\t\tSFC_GENERIC_LOG(ERR, \"Failed to create sfc ethdev '%s'\",\n+\t\t\t\tpci_dev->device.name);\n+\t\treturn rc;\n+\t}\n+\n+\tdev = rte_eth_dev_allocated(pci_dev->device.name);\n+\tif (dev == NULL) {\n+\t\tSFC_GENERIC_LOG(ERR, \"Failed to find allocated sfc ethdev '%s'\",\n+\t\t\t\tpci_dev->device.name);\n+\t\treturn -ENODEV;\n+\t}\n+\n+\t*devp = dev;\n+\n+\treturn 0;\n+}\n+\n+static int\n+sfc_eth_dev_create_representors(struct rte_eth_dev *dev,\n+\t\t\t\tconst struct rte_eth_devargs *eth_da)\n+{\n+\tstruct sfc_adapter *sa;\n+\tunsigned int i;\n+\tint rc;\n+\n+\tif (eth_da->nb_representor_ports == 0)\n+\t\treturn 0;\n+\n+\tsa = sfc_adapter_by_eth_dev(dev);\n+\n+\tif (!sa->switchdev) {\n+\t\tsfc_err(sa, \"cannot create representors in non-switchdev mode\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (!sfc_repr_available(sfc_sa2shared(sa))) {\n+\t\tsfc_err(sa, \"cannot create representors: unsupported\");\n+\n+\t\treturn -ENOTSUP;\n+\t}\n+\n+\tfor (i = 0; i < eth_da->nb_representor_ports; ++i) {\n+\t\tconst efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic);\n+\t\tefx_mport_sel_t mport_sel;\n+\n+\t\trc = efx_mae_mport_by_pcie_function(encp->enc_pf,\n+\t\t\t\teth_da->representor_ports[i], &mport_sel);\n+\t\tif (rc != 0) {\n+\t\t\tsfc_err(sa,\n+\t\t\t\t\"failed to get representor %u m-port: %s - ignore\",\n+\t\t\t\teth_da->representor_ports[i],\n+\t\t\t\trte_strerror(-rc));\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\trc = sfc_repr_create(dev, eth_da->representor_ports[i],\n+\t\t\t\t     sa->mae.switch_domain_id, &mport_sel);\n+\t\tif (rc != 0) {\n+\t\t\tsfc_err(sa, \"cannot create representor %u: %s - ignore\",\n+\t\t\t\teth_da->representor_ports[i],\n+\t\t\t\trte_strerror(-rc));\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int sfc_eth_dev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \tstruct rte_pci_device *pci_dev)\n {\n-\treturn rte_eth_dev_pci_generic_probe(pci_dev,\n-\t\tsizeof(struct sfc_adapter_shared), sfc_eth_dev_init);\n+\tstruct sfc_ethdev_init_data init_data;\n+\tstruct rte_eth_devargs eth_da;\n+\tstruct rte_eth_dev *dev;\n+\tint rc;\n+\n+\tif (pci_dev->device.devargs != NULL) {\n+\t\trc = sfc_parse_rte_devargs(pci_dev->device.devargs->args,\n+\t\t\t\t\t   &eth_da);\n+\t\tif (rc != 0)\n+\t\t\treturn rc;\n+\t} else {\n+\t\tmemset(&eth_da, 0, sizeof(eth_da));\n+\t}\n+\n+\tinit_data.nb_representors = eth_da.nb_representor_ports;\n+\n+\tif (eth_da.nb_representor_ports > 0 &&\n+\t    rte_eal_process_type() != RTE_PROC_PRIMARY) {\n+\t\tSFC_GENERIC_LOG(ERR,\n+\t\t\t\"Create representors from secondary process not supported, dev '%s'\",\n+\t\t\tpci_dev->device.name);\n+\t\treturn -ENOTSUP;\n+\t}\n+\n+\trc = sfc_eth_dev_create(pci_dev, &init_data, &dev);\n+\tif (rc != 0)\n+\t\treturn rc;\n+\n+\trc = sfc_eth_dev_create_representors(dev, &eth_da);\n+\tif (rc != 0) {\n+\t\t(void)rte_eth_dev_destroy(dev, sfc_eth_dev_uninit);\n+\t\treturn rc;\n+\t}\n+\n+\treturn 0;\n }\n \n static int sfc_eth_dev_pci_remove(struct rte_pci_device *pci_dev)\ndiff --git a/drivers/net/sfc/sfc_kvargs.c b/drivers/net/sfc/sfc_kvargs.c\nindex cd16213637..783cb43ae6 100644\n--- a/drivers/net/sfc/sfc_kvargs.c\n+++ b/drivers/net/sfc/sfc_kvargs.c\n@@ -23,6 +23,7 @@ sfc_kvargs_parse(struct sfc_adapter *sa)\n \tstruct rte_devargs *devargs = eth_dev->device->devargs;\n \tconst char **params = (const char *[]){\n \t\tSFC_KVARG_SWITCH_MODE,\n+\t\tSFC_KVARG_REPRESENTOR,\n \t\tSFC_KVARG_STATS_UPDATE_PERIOD_MS,\n \t\tSFC_KVARG_PERF_PROFILE,\n \t\tSFC_KVARG_RX_DATAPATH,\ndiff --git a/drivers/net/sfc/sfc_kvargs.h b/drivers/net/sfc/sfc_kvargs.h\nindex 8e34ec92a2..2226f2b3d9 100644\n--- a/drivers/net/sfc/sfc_kvargs.h\n+++ b/drivers/net/sfc/sfc_kvargs.h\n@@ -26,6 +26,8 @@ extern \"C\" {\n \t\"[\" SFC_KVARG_SWITCH_MODE_LEGACY \"|\" \\\n \t    SFC_KVARG_SWITCH_MODE_SWITCHDEV \"]\"\n \n+#define SFC_KVARG_REPRESENTOR\t\t\"representor\"\n+\n #define SFC_KVARG_PERF_PROFILE\t\t\"perf_profile\"\n \n #define SFC_KVARG_PERF_PROFILE_AUTO\t\t\"auto\"\ndiff --git a/drivers/net/sfc/sfc_repr.c b/drivers/net/sfc/sfc_repr.c\nnew file mode 100644\nindex 0000000000..603a613ec6\n--- /dev/null\n+++ b/drivers/net/sfc/sfc_repr.c\n@@ -0,0 +1,458 @@\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+#include <stdint.h>\n+\n+#include <rte_ethdev.h>\n+#include <rte_malloc.h>\n+#include <ethdev_driver.h>\n+\n+#include \"efx.h\"\n+\n+#include \"sfc_log.h\"\n+#include \"sfc_debug.h\"\n+#include \"sfc_repr.h\"\n+#include \"sfc_ethdev_state.h\"\n+#include \"sfc_switch.h\"\n+\n+/** Multi-process shared representor private data */\n+struct sfc_repr_shared {\n+\tuint16_t\t\tpf_port_id;\n+\tuint16_t\t\trepr_id;\n+\tuint16_t\t\tswitch_domain_id;\n+\tuint16_t\t\tswitch_port_id;\n+};\n+\n+/** Primary process representor private data */\n+struct sfc_repr {\n+\t/**\n+\t * PMD setup and configuration is not thread safe. Since it is not\n+\t * performance sensitive, it is better to guarantee thread-safety\n+\t * and add device level lock. Adapter control operations which\n+\t * change its state should acquire the lock.\n+\t */\n+\trte_spinlock_t\t\t\tlock;\n+\tenum sfc_ethdev_state\t\tstate;\n+};\n+\n+#define sfcr_err(sr, ...) \\\n+\tdo {\t\t\t\t\t\t\t\t\\\n+\t\tconst struct sfc_repr *_sr = (sr);\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\\\n+\t\t(void)_sr;\t\t\t\t\t\t\\\n+\t\tSFC_GENERIC_LOG(ERR, __VA_ARGS__);\t\t\t\\\n+\t} while (0)\n+\n+#define sfcr_info(sr, ...) \\\n+\tdo {\t\t\t\t\t\t\t\t\\\n+\t\tconst struct sfc_repr *_sr = (sr);\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\\\n+\t\t(void)_sr;\t\t\t\t\t\t\\\n+\t\tSFC_GENERIC_LOG(INFO,\t\t\t\t\t\\\n+\t\t\t\tRTE_FMT(\"%s() \"\t\t\t\t\\\n+\t\t\t\tRTE_FMT_HEAD(__VA_ARGS__ ,),\t\t\\\n+\t\t\t\t__func__,\t\t\t\t\\\n+\t\t\t\tRTE_FMT_TAIL(__VA_ARGS__ ,)));\t\t\\\n+\t} while (0)\n+\n+static inline struct sfc_repr_shared *\n+sfc_repr_shared_by_eth_dev(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct sfc_repr_shared *srs = eth_dev->data->dev_private;\n+\n+\treturn srs;\n+}\n+\n+static inline struct sfc_repr *\n+sfc_repr_by_eth_dev(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct sfc_repr *sr = eth_dev->process_private;\n+\n+\treturn sr;\n+}\n+\n+/*\n+ * Add wrapper functions to acquire/release lock to be able to remove or\n+ * change the lock in one place.\n+ */\n+\n+static inline void\n+sfc_repr_lock_init(struct sfc_repr *sr)\n+{\n+\trte_spinlock_init(&sr->lock);\n+}\n+\n+#ifdef RTE_LIBRTE_SFC_EFX_DEBUG\n+\n+static inline int\n+sfc_repr_lock_is_locked(struct sfc_repr *sr)\n+{\n+\treturn rte_spinlock_is_locked(&sr->lock);\n+}\n+\n+#endif\n+\n+static inline void\n+sfc_repr_lock(struct sfc_repr *sr)\n+{\n+\trte_spinlock_lock(&sr->lock);\n+}\n+\n+static inline void\n+sfc_repr_unlock(struct sfc_repr *sr)\n+{\n+\trte_spinlock_unlock(&sr->lock);\n+}\n+\n+static inline void\n+sfc_repr_lock_fini(__rte_unused struct sfc_repr *sr)\n+{\n+\t/* Just for symmetry of the API */\n+}\n+\n+static int\n+sfc_repr_check_conf(struct sfc_repr *sr, uint16_t nb_rx_queues,\n+\t\t    const struct rte_eth_conf *conf)\n+{\n+\tconst struct rte_eth_rss_conf *rss_conf;\n+\tint ret = 0;\n+\n+\tsfcr_info(sr, \"entry\");\n+\n+\tif (conf->link_speeds != 0) {\n+\t\tsfcr_err(sr, \"specific link speeds not supported\");\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tswitch (conf->rxmode.mq_mode) {\n+\tcase ETH_MQ_RX_RSS:\n+\t\tif (nb_rx_queues != 1) {\n+\t\t\tsfcr_err(sr, \"Rx RSS is not supported with %u queues\",\n+\t\t\t\t nb_rx_queues);\n+\t\t\tret = -EINVAL;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\trss_conf = &conf->rx_adv_conf.rss_conf;\n+\t\tif (rss_conf->rss_key != NULL || rss_conf->rss_key_len != 0 ||\n+\t\t    rss_conf->rss_hf != 0) {\n+\t\t\tsfcr_err(sr, \"Rx RSS configuration is not supported\");\n+\t\t\tret = -EINVAL;\n+\t\t}\n+\t\tbreak;\n+\tcase ETH_MQ_RX_NONE:\n+\t\tbreak;\n+\tdefault:\n+\t\tsfcr_err(sr, \"Rx mode MQ modes other than RSS not supported\");\n+\t\tret = -EINVAL;\n+\t\tbreak;\n+\t}\n+\n+\tif (conf->txmode.mq_mode != ETH_MQ_TX_NONE) {\n+\t\tsfcr_err(sr, \"Tx mode MQ modes not supported\");\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tif (conf->lpbk_mode != 0) {\n+\t\tsfcr_err(sr, \"loopback not supported\");\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tif (conf->dcb_capability_en != 0) {\n+\t\tsfcr_err(sr, \"priority-based flow control not supported\");\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tif (conf->fdir_conf.mode != RTE_FDIR_MODE_NONE) {\n+\t\tsfcr_err(sr, \"Flow Director not supported\");\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tif (conf->intr_conf.lsc != 0) {\n+\t\tsfcr_err(sr, \"link status change interrupt not supported\");\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tif (conf->intr_conf.rxq != 0) {\n+\t\tsfcr_err(sr, \"receive queue interrupt not supported\");\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tif (conf->intr_conf.rmv != 0) {\n+\t\tsfcr_err(sr, \"remove interrupt not supported\");\n+\t\tret = -EINVAL;\n+\t}\n+\n+\tsfcr_info(sr, \"done %d\", ret);\n+\n+\treturn ret;\n+}\n+\n+\n+static int\n+sfc_repr_configure(struct sfc_repr *sr, uint16_t nb_rx_queues,\n+\t\t   const struct rte_eth_conf *conf)\n+{\n+\tint ret;\n+\n+\tsfcr_info(sr, \"entry\");\n+\n+\tSFC_ASSERT(sfc_repr_lock_is_locked(sr));\n+\n+\tret = sfc_repr_check_conf(sr, nb_rx_queues, conf);\n+\tif (ret != 0)\n+\t\tgoto fail_check_conf;\n+\n+\tsr->state = SFC_ETHDEV_CONFIGURED;\n+\n+\tsfcr_info(sr, \"done\");\n+\n+\treturn 0;\n+\n+fail_check_conf:\n+\tsfcr_info(sr, \"failed %s\", rte_strerror(-ret));\n+\treturn ret;\n+}\n+\n+static int\n+sfc_repr_dev_configure(struct rte_eth_dev *dev)\n+{\n+\tstruct sfc_repr *sr = sfc_repr_by_eth_dev(dev);\n+\tstruct rte_eth_dev_data *dev_data = dev->data;\n+\tint ret;\n+\n+\tsfcr_info(sr, \"entry n_rxq=%u n_txq=%u\",\n+\t\t  dev_data->nb_rx_queues, dev_data->nb_tx_queues);\n+\n+\tsfc_repr_lock(sr);\n+\tswitch (sr->state) {\n+\tcase SFC_ETHDEV_CONFIGURED:\n+\t\t/* FALLTHROUGH */\n+\tcase SFC_ETHDEV_INITIALIZED:\n+\t\tret = sfc_repr_configure(sr, dev_data->nb_rx_queues,\n+\t\t\t\t\t &dev_data->dev_conf);\n+\t\tbreak;\n+\tdefault:\n+\t\tsfcr_err(sr, \"unexpected adapter state %u to configure\",\n+\t\t\t sr->state);\n+\t\tret = -EINVAL;\n+\t\tbreak;\n+\t}\n+\tsfc_repr_unlock(sr);\n+\n+\tsfcr_info(sr, \"done %s\", rte_strerror(-ret));\n+\n+\treturn ret;\n+}\n+\n+static int\n+sfc_repr_dev_infos_get(struct rte_eth_dev *dev,\n+\t\t       struct rte_eth_dev_info *dev_info)\n+{\n+\tstruct sfc_repr_shared *srs = sfc_repr_shared_by_eth_dev(dev);\n+\n+\tdev_info->device = dev->device;\n+\n+\tdev_info->max_rx_queues = SFC_REPR_RXQ_MAX;\n+\tdev_info->max_tx_queues = SFC_REPR_TXQ_MAX;\n+\tdev_info->default_rxconf.rx_drop_en = 1;\n+\tdev_info->switch_info.domain_id = srs->switch_domain_id;\n+\tdev_info->switch_info.port_id = srs->switch_port_id;\n+\n+\treturn 0;\n+}\n+\n+static void\n+sfc_repr_close(struct sfc_repr *sr)\n+{\n+\tSFC_ASSERT(sfc_repr_lock_is_locked(sr));\n+\n+\tSFC_ASSERT(sr->state == SFC_ETHDEV_CONFIGURED);\n+\tsr->state = SFC_ETHDEV_CLOSING;\n+\n+\t/* Put representor close actions here */\n+\n+\tsr->state = SFC_ETHDEV_INITIALIZED;\n+}\n+\n+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+\n+\tsfcr_info(sr, \"entry\");\n+\n+\tsfc_repr_lock(sr);\n+\tswitch (sr->state) {\n+\tcase SFC_ETHDEV_CONFIGURED:\n+\t\tsfc_repr_close(sr);\n+\t\tSFC_ASSERT(sr->state == SFC_ETHDEV_INITIALIZED);\n+\t\t/* FALLTHROUGH */\n+\tcase SFC_ETHDEV_INITIALIZED:\n+\t\tbreak;\n+\tdefault:\n+\t\tsfcr_err(sr, \"unexpected adapter state %u on close\", sr->state);\n+\t\tbreak;\n+\t}\n+\n+\t/*\n+\t * Cleanup all resources.\n+\t * Rollback primary process sfc_repr_eth_dev_init() below.\n+\t */\n+\n+\tdev->dev_ops = NULL;\n+\n+\tsfc_repr_unlock(sr);\n+\tsfc_repr_lock_fini(sr);\n+\n+\tsfcr_info(sr, \"done\");\n+\n+\tfree(sr);\n+\n+\treturn 0;\n+}\n+\n+static const struct eth_dev_ops sfc_repr_dev_ops = {\n+\t.dev_configure\t\t\t= sfc_repr_dev_configure,\n+\t.dev_close\t\t\t= sfc_repr_dev_close,\n+\t.dev_infos_get\t\t\t= sfc_repr_dev_infos_get,\n+};\n+\n+\n+struct sfc_repr_init_data {\n+\tuint16_t\t\tpf_port_id;\n+\tuint16_t\t\trepr_id;\n+\tuint16_t\t\tswitch_domain_id;\n+\tefx_mport_sel_t\t\tmport_sel;\n+};\n+\n+static int\n+sfc_repr_assign_mae_switch_port(uint16_t switch_domain_id,\n+\t\t\t\tconst struct sfc_mae_switch_port_request *req,\n+\t\t\t\tuint16_t *switch_port_id)\n+{\n+\tint rc;\n+\n+\trc = sfc_mae_assign_switch_port(switch_domain_id, req, switch_port_id);\n+\n+\tSFC_ASSERT(rc >= 0);\n+\treturn -rc;\n+}\n+\n+static int\n+sfc_repr_eth_dev_init(struct rte_eth_dev *dev, void *init_params)\n+{\n+\tconst struct sfc_repr_init_data *repr_data = init_params;\n+\tstruct sfc_repr_shared *srs = sfc_repr_shared_by_eth_dev(dev);\n+\tstruct sfc_mae_switch_port_request switch_port_request;\n+\tefx_mport_sel_t ethdev_mport_sel;\n+\tstruct sfc_repr *sr;\n+\tint ret;\n+\n+\t/*\n+\t * Currently there is no mport we can use for representor's\n+\t * ethdev. Use an invalid one for now. This way representors\n+\t * can be instantiated.\n+\t */\n+\tefx_mae_mport_invalid(&ethdev_mport_sel);\n+\n+\tmemset(&switch_port_request, 0, sizeof(switch_port_request));\n+\tswitch_port_request.type = SFC_MAE_SWITCH_PORT_REPRESENTOR;\n+\tswitch_port_request.ethdev_mportp = &ethdev_mport_sel;\n+\tswitch_port_request.entity_mportp = &repr_data->mport_sel;\n+\tswitch_port_request.ethdev_port_id = dev->data->port_id;\n+\n+\tret = sfc_repr_assign_mae_switch_port(repr_data->switch_domain_id,\n+\t\t\t\t\t      &switch_port_request,\n+\t\t\t\t\t      &srs->switch_port_id);\n+\tif (ret != 0) {\n+\t\tSFC_GENERIC_LOG(ERR,\n+\t\t\t\"%s() failed to assign MAE switch port (domain id %u)\",\n+\t\t\t__func__, repr_data->switch_domain_id);\n+\t\tgoto fail_mae_assign_switch_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+\t */\n+\tsr = calloc(1, sizeof(*sr));\n+\tif (sr == NULL) {\n+\t\tret = -ENOMEM;\n+\t\tgoto fail_alloc_sr;\n+\t}\n+\n+\tsfc_repr_lock_init(sr);\n+\tsfc_repr_lock(sr);\n+\n+\tdev->process_private = sr;\n+\n+\tsrs->pf_port_id = repr_data->pf_port_id;\n+\tsrs->repr_id = repr_data->repr_id;\n+\tsrs->switch_domain_id = repr_data->switch_domain_id;\n+\n+\tdev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR;\n+\tdev->data->representor_id = srs->repr_id;\n+\tdev->data->parent_port_id = srs->pf_port_id;\n+\n+\tdev->data->mac_addrs = rte_zmalloc(\"sfcr\", RTE_ETHER_ADDR_LEN, 0);\n+\tif (dev->data->mac_addrs == NULL) {\n+\t\tret = -ENOMEM;\n+\t\tgoto fail_mac_addrs;\n+\t}\n+\n+\tdev->dev_ops = &sfc_repr_dev_ops;\n+\n+\tsr->state = SFC_ETHDEV_INITIALIZED;\n+\tsfc_repr_unlock(sr);\n+\n+\treturn 0;\n+\n+fail_mac_addrs:\n+\tsfc_repr_unlock(sr);\n+\tfree(sr);\n+\n+fail_alloc_sr:\n+fail_mae_assign_switch_port:\n+\tSFC_GENERIC_LOG(ERR, \"%s() failed: %s\", __func__, rte_strerror(-ret));\n+\treturn ret;\n+}\n+\n+int\n+sfc_repr_create(struct rte_eth_dev *parent, uint16_t representor_id,\n+\t\tuint16_t switch_domain_id, const efx_mport_sel_t *mport_sel)\n+{\n+\tstruct sfc_repr_init_data repr_data;\n+\tchar name[RTE_ETH_NAME_MAX_LEN];\n+\tint ret;\n+\n+\tif (snprintf(name, sizeof(name), \"net_%s_representor_%u\",\n+\t\t     parent->device->name, representor_id) >=\n+\t\t\t(int)sizeof(name)) {\n+\t\tSFC_GENERIC_LOG(ERR, \"%s() failed name too long\", __func__);\n+\t\treturn -ENAMETOOLONG;\n+\t}\n+\n+\tmemset(&repr_data, 0, sizeof(repr_data));\n+\trepr_data.pf_port_id = parent->data->port_id;\n+\trepr_data.repr_id = representor_id;\n+\trepr_data.switch_domain_id = switch_domain_id;\n+\trepr_data.mport_sel = *mport_sel;\n+\n+\tret = rte_eth_dev_create(parent->device, name,\n+\t\t\t\t  sizeof(struct sfc_repr_shared),\n+\t\t\t\t  NULL, NULL,\n+\t\t\t\t  sfc_repr_eth_dev_init, &repr_data);\n+\tif (ret != 0)\n+\t\tSFC_GENERIC_LOG(ERR, \"%s() failed to create device\", __func__);\n+\n+\tSFC_GENERIC_LOG(INFO, \"%s() done: %s\", __func__, rte_strerror(-ret));\n+\n+\treturn ret;\n+}\ndiff --git a/drivers/net/sfc/sfc_repr.h b/drivers/net/sfc/sfc_repr.h\nnew file mode 100644\nindex 0000000000..1347206006\n--- /dev/null\n+++ b/drivers/net/sfc/sfc_repr.h\n@@ -0,0 +1,36 @@\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_H\n+#define _SFC_REPR_H\n+\n+#include <stdint.h>\n+\n+#include <rte_ethdev.h>\n+\n+#include \"efx.h\"\n+\n+#ifdef __cplusplus\n+extern \"C\" {\n+#endif\n+\n+/** Max count of the representor Rx queues */\n+#define SFC_REPR_RXQ_MAX\t1\n+\n+/** Max count of the representor Tx queues */\n+#define SFC_REPR_TXQ_MAX\t1\n+\n+int sfc_repr_create(struct rte_eth_dev *parent, uint16_t representor_id,\n+\t\t    uint16_t switch_domain_id,\n+\t\t    const efx_mport_sel_t *mport_sel);\n+\n+#ifdef __cplusplus\n+}\n+#endif\n+#endif  /* _SFC_REPR_H */\ndiff --git a/drivers/net/sfc/sfc_switch.h b/drivers/net/sfc/sfc_switch.h\nindex 84a02a61f8..a1a2ab9848 100644\n--- a/drivers/net/sfc/sfc_switch.h\n+++ b/drivers/net/sfc/sfc_switch.h\n@@ -27,6 +27,11 @@ enum sfc_mae_switch_port_type {\n \t * and thus refers to its underlying PCIe function\n \t */\n \tSFC_MAE_SWITCH_PORT_INDEPENDENT = 0,\n+\t/**\n+\t * The switch port is operated by a representor RTE ethdev\n+\t * and thus refers to the represented PCIe function\n+\t */\n+\tSFC_MAE_SWITCH_PORT_REPRESENTOR,\n };\n \n struct sfc_mae_switch_port_request {\n",
    "prefixes": [
        "11/38"
    ]
}