get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 66132,
    "url": "http://patches.dpdk.org/api/patches/66132/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1582879102-17977-5-git-send-email-xiaojun.liu@silicom.co.il/",
    "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": "<1582879102-17977-5-git-send-email-xiaojun.liu@silicom.co.il>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1582879102-17977-5-git-send-email-xiaojun.liu@silicom.co.il",
    "date": "2020-02-28T08:38:21",
    "name": "[v1,4/5] net/fm10k: add flow interface and switch management",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "d5726bb481ba133466aebd8a7a8622c8b26ed5ae",
    "submitter": {
        "id": 1512,
        "url": "http://patches.dpdk.org/api/people/1512/?format=api",
        "name": "Xiaojun Liu",
        "email": "xiaojun.liu@silicom.co.il"
    },
    "delegate": {
        "id": 31221,
        "url": "http://patches.dpdk.org/api/users/31221/?format=api",
        "username": "yexl",
        "first_name": "xiaolong",
        "last_name": "ye",
        "email": "xiaolong.ye@intel.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1582879102-17977-5-git-send-email-xiaojun.liu@silicom.co.il/mbox/",
    "series": [
        {
            "id": 8723,
            "url": "http://patches.dpdk.org/api/series/8723/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=8723",
            "date": "2020-02-28T08:38:17",
            "name": "support fm10k switch management",
            "version": 1,
            "mbox": "http://patches.dpdk.org/series/8723/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/66132/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/66132/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 dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id B5A21A0561;\n\tFri, 28 Feb 2020 09:40:04 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id A76E81BFF7;\n\tFri, 28 Feb 2020 09:39:26 +0100 (CET)",
            "from EUR05-VI1-obe.outbound.protection.outlook.com\n (mail-vi1eur05on2090.outbound.protection.outlook.com [40.107.21.90])\n by dpdk.org (Postfix) with ESMTP id EBF5E1BFF5\n for <dev@dpdk.org>; Fri, 28 Feb 2020 09:39:22 +0100 (CET)",
            "from DB7PR04MB5196.eurprd04.prod.outlook.com (20.176.234.140) by\n DB7PR04MB5484.eurprd04.prod.outlook.com (20.178.106.147) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.2772.14; Fri, 28 Feb 2020 08:39:20 +0000",
            "from DB7PR04MB5196.eurprd04.prod.outlook.com\n ([fe80::a400:f6b9:34b1:ed]) by DB7PR04MB5196.eurprd04.prod.outlook.com\n ([fe80::a400:f6b9:34b1:ed%5]) with mapi id 15.20.2750.024; Fri, 28 Feb 2020\n 08:39:20 +0000",
            "from xj-desktop.net-perf.com (119.139.199.125) by\n HK2PR02CA0207.apcprd02.prod.outlook.com (2603:1096:201:20::19) with Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.2772.14 via Frontend Transport; Fri, 28 Feb 2020 08:39:18 +0000"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=ZtyZqs2ST+irJMKRhB3+WEM6LKg1MT7xlfqoeTUB7l3+z2zsbCMS1lkrKa/ppmk9T+rS0EwJPME1v+4MvDKXmBzhDXJ1IyvuoxyFHFpSn92iUps5Oq4A6Em31c0R2bHILlFJCzHXuWMoUwku+zh65coeUpy1PvZQVIDeeq20ubEH/po5TdaEte8CimH4+AksNZAUFnGJGupG+XYrr6rBR7ZAFUgsxO6Q1Mcu9ZN7zjTPpWFfne+btg+Qk4ns+mdlRac9HwCu5xBX5AdFxtYwy4P5zzU9iLFAmYJ+sDvKj65/mSkx07P5xvKhgvKfpAlKb++Ml1okxCweNUq7WqM3Dg==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=OY+uVzj63EOokmrvkOo4OXmqMbh5B4oVO/zannTQ0PQ=;\n b=cxZrRSR2zSqOOP0rI61u8PDfUyGGla050Xpmquqhnb6DHL2eOHiHsww35OY3SLM/z+XxbPFqBUFQ+z9mAByE5iE2BLcvechfjDUvbFhPe4i1udKvEOcTJQ7cv7+PSa2QFqcJKZlLJVJ1472C5H35GLZFMyFyaYOYmnI2EZ62fBuE/E+7NbmnpwTscBtHb0+1TULrRuv9sxUDUfhNJSyAYgKjqfnNE0Be0wunCod3ZasKsViYJrQTnkP01uQZJcPYW/MjyeacQi2umzS9VQHK7rSfEMeJyXNAlgTkHPeu/2DOBxEpDjkiMmAFUrvIAkxSIM7ajZ+mPsSzRWwcJybNYg==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass\n smtp.mailfrom=silicom.co.il; dmarc=pass action=none\n header.from=silicom.co.il; dkim=pass header.d=silicom.co.il; arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=SILICOMLTD.onmicrosoft.com; s=selector2-SILICOMLTD-onmicrosoft-com;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=OY+uVzj63EOokmrvkOo4OXmqMbh5B4oVO/zannTQ0PQ=;\n b=an/wniDON6+KrFFlwa4LFPMcoHTVqebXFgJ+6L1atBqOsYugZMDQRwGbTyCkKwQRcCSLmuyX5CVYXeltDTzp0hal9vpQD0ZeGtf+aRoEdpxsV2n8tTMCoQJM95evxkdEbD79j1jBsTImyMWKmy4oHArllx5EJarIdnvYz+aFCjg=",
        "Authentication-Results": "spf=none (sender IP is )\n smtp.mailfrom=xiaojun.liu@silicom.co.il;",
        "From": "Xiaojun Liu <xiaojun.liu@silicom.co.il>",
        "To": "xiao.w.wang@intel.com, qi.z.zhang@intel.com, ngai-mint.kwan@intel.com,\n jacob.e.keller@intel.com",
        "Cc": "dev@dpdk.org,\n\tXiaojun Liu <xiaojun.liu@silicom.co.il>",
        "Date": "Fri, 28 Feb 2020 16:38:21 +0800",
        "Message-Id": "<1582879102-17977-5-git-send-email-xiaojun.liu@silicom.co.il>",
        "X-Mailer": [
            "git-send-email 1.8.3.1",
            "git-send-email 1.8.3.1"
        ],
        "In-Reply-To": "<1582879102-17977-1-git-send-email-xiaojun.liu@silicom.co.il>",
        "References": "<1582207174-31037-2-git-send-email-xiaojun.liu@silicom.co.il>\n <1582879102-17977-1-git-send-email-xiaojun.liu@silicom.co.il>",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "HK2PR02CA0207.apcprd02.prod.outlook.com\n (2603:1096:201:20::19) To DB7PR04MB5196.eurprd04.prod.outlook.com\n (2603:10a6:10:1a::12)",
        "MIME-Version": "1.0",
        "X-MS-Exchange-MessageSentRepresentingType": "1",
        "X-Originating-IP": "[119.139.199.125]",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-Office365-Filtering-Correlation-Id": "527da915-0814-498b-5974-08d7bc29b47f",
        "X-MS-TrafficTypeDiagnostic": "DB7PR04MB5484:",
        "X-MS-Exchange-Transport-Forked": "True",
        "X-Microsoft-Antispam-PRVS": "\n <DB7PR04MB5484B544A686B82B5C830969BDE80@DB7PR04MB5484.eurprd04.prod.outlook.com>",
        "X-MS-Oob-TLC-OOBClassifiers": "OLM:175;",
        "X-Forefront-PRVS": "0327618309",
        "X-Forefront-Antispam-Report": "SFV:NSPM;\n SFS:(10019020)(376002)(136003)(346002)(366004)(396003)(39850400004)(189003)(199004)(86362001)(5660300002)(2906002)(6666004)(8936002)(107886003)(4326008)(956004)(44832011)(66946007)(66556008)(2616005)(8676002)(81156014)(81166006)(66476007)(316002)(478600001)(6506007)(36756003)(16526019)(52116002)(186003)(30864003)(26005)(6486002)(6512007)(579004)(559001);\n DIR:OUT; SFP:1102; SCL:1; SRVR:DB7PR04MB5484;\n H:DB7PR04MB5196.eurprd04.prod.outlook.com; FPR:; SPF:None; LANG:en;\n PTR:InfoNoRecords; MX:1; A:1;",
        "Received-SPF": "None (protection.outlook.com: silicom.co.il does not designate\n permitted sender hosts)",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n bL28/nEbHq6WSb+gMR37u0Q1p/hZCIFJ2As8mV7YLjfmvZJDZnNwzMNCWTjEaVw2J9zOTleFBIZpLcB+c2sjUqXFjUdWgP3rNWfhbEsOCmezrX5yIBBp6ztxWu/cMSTeoQmxLcSAY+jk+TqzpQhcpEg2y3qNHgu42b+gvHyl0HcVnxXUwhXYGVnXu9CXFdqrHflravy02DKDMGgv/Qqo6efKXk4EX/ywju6j2f+1jN5mK5U6G27Qa8YaEJTE6aa7OearRNXQKs+4U3DEHXuGprlwVCO1a+ab8N7/1nfAbp79O41temD7q53zd68BckscG3kxwELROZMUPumnT/TO3iY5CGIhz8gFYc6zZWlhlFJMqa5tOStxzKVPfYkVTiXdPJWYqGXyxEMoS+ygBY3eImuKtuh7FzRmiGMokKiKpPRR9TmQcUajxmAJzLA4Fp08",
        "X-MS-Exchange-AntiSpam-MessageData": "\n n73dIhFsnWXktI/Hnel0ollfFPNXxLMdoy83419sa6rftmKeS19w13pnxMvvwvp+Wznfw2hAYJbr6kkISSH844LtreVO+cu2ZCv8bD07xpuioFNLUde6H5EN3k9HNvGv67VCrMttVug8QzPcwlVCjw==",
        "X-OriginatorOrg": "silicom.co.il",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 527da915-0814-498b-5974-08d7bc29b47f",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "28 Feb 2020 08:39:20.6878 (UTC)",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "c9e326d8-ce47-4930-8612-cc99d3c87ad1",
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n i7Dm//7hVLI2D3dk5RSBlRQbguxvbfTjTyA1Aw5Ns83dBGb9qv7TB3WYkVxbdu4wU/jJks8z9/dSrQJ2EfI5MyNxfv1agrboDy/0dMvPdcA=",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DB7PR04MB5484",
        "Subject": "[dpdk-dev] [PATCH v1 4/5] net/fm10k: add flow interface and switch\n\tmanagement",
        "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 <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": "Add flow interface to support offload flow into HW.\nIt supports parse vlan and parse mpls, all these\ndata will be transferred to ffu data.\nAdd switch management, includes initialization,\nport mapping, epl port link, LED controller, interrupt handler.\nIt create 3 threads. One for interrupt handler, one for\nLED controller, one for statistics.\n\nTo enable the switch management, you need add\nCONFIG_RTE_FM10K_MANAGEMENT=y in\nconfig/common_linux when building.\n\nSigned-off-by: Xiaojun Liu <xiaojun.liu@silicom.co.il>\n---\n drivers/net/fm10k/Makefile              |    2 +\n drivers/net/fm10k/switch/fm10k_flow.c   |  872 ++++++++++++\n drivers/net/fm10k/switch/fm10k_flow.h   |   26 +\n drivers/net/fm10k/switch/fm10k_stats.c  |  128 ++\n drivers/net/fm10k/switch/fm10k_switch.c | 2376 +++++++++++++++++++++++++++++++\n 5 files changed, 3404 insertions(+)\n create mode 100644 drivers/net/fm10k/switch/fm10k_flow.c\n create mode 100644 drivers/net/fm10k/switch/fm10k_flow.h\n create mode 100644 drivers/net/fm10k/switch/fm10k_switch.c",
    "diff": "diff --git a/drivers/net/fm10k/Makefile b/drivers/net/fm10k/Makefile\nindex d4d2037..9a245c9 100644\n--- a/drivers/net/fm10k/Makefile\n+++ b/drivers/net/fm10k/Makefile\n@@ -91,6 +91,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_spico_code.c\n SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_config.c\n SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_ffu.c\n SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_stats.c\n+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_flow.c\n+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_switch.c\n endif\n ifeq ($(CONFIG_RTE_ARCH_X86), y)\n SRCS-$(CONFIG_RTE_LIBRTE_FM10K_INC_VECTOR) += fm10k_rxtx_vec.c\ndiff --git a/drivers/net/fm10k/switch/fm10k_flow.c b/drivers/net/fm10k/switch/fm10k_flow.c\nnew file mode 100644\nindex 0000000..353f021\n--- /dev/null\n+++ b/drivers/net/fm10k/switch/fm10k_flow.c\n@@ -0,0 +1,872 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2019   Silicom Ltd. Connectivity Solutions\n+ */\n+\n+#include <sys/queue.h>\n+#include <stdio.h>\n+#include <errno.h>\n+#include <stdint.h>\n+#include <string.h>\n+#include <unistd.h>\n+#include <stdarg.h>\n+\n+#include <rte_ether.h>\n+#include <rte_ethdev.h>\n+#include <rte_log.h>\n+#include <rte_malloc.h>\n+#include <rte_eth_ctrl.h>\n+#include <rte_tailq.h>\n+#include <rte_flow_driver.h>\n+\n+#include \"fm10k_flow.h\"\n+#include \"fm10k_switch.h\"\n+#include \"fm10k_ffu.h\"\n+#include \"fm10k_config.h\"\n+\n+\n+static int fm10k_flow_validate(struct rte_eth_dev *dev,\n+\t\t\t      const struct rte_flow_attr *attr,\n+\t\t\t      const struct rte_flow_item pattern[],\n+\t\t\t      const struct rte_flow_action actions[],\n+\t\t\t      struct rte_flow_error *error);\n+static struct rte_flow *fm10k_flow_create(struct rte_eth_dev *dev,\n+\t\t\t\t\t const struct rte_flow_attr *attr,\n+\t\t\t\t\t const struct rte_flow_item pattern[],\n+\t\t\t\t\t const struct rte_flow_action actions[],\n+\t\t\t\t\t struct rte_flow_error *error);\n+static int fm10k_flow_destroy(struct rte_eth_dev *dev,\n+\t\t\t     struct rte_flow *flow,\n+\t\t\t     struct rte_flow_error *error);\n+static int fm10k_flow_flush(struct rte_eth_dev *dev,\n+\t\t\t   struct rte_flow_error *error);\n+static int fm10k_flow_parse_attr(const struct rte_flow_attr *attr,\n+\t\t\t\tstruct rte_flow_error *error);\n+\n+const struct rte_flow_ops fm10k_flow_ops = {\n+\t.validate = fm10k_flow_validate,\n+\t.create = fm10k_flow_create,\n+\t.destroy = fm10k_flow_destroy,\n+\t.flush = fm10k_flow_flush,\n+};\n+\n+union fm10k_filter_t cons_filter;\n+enum rte_filter_type fm10k_cons_filter_type = RTE_ETH_FILTER_NONE;\n+\n+/**\n+ * MPLS filter configuration.\n+ */\n+enum fm10k_mpls_type {\n+\tFM10K_MPLS_TYPE_UNI,\n+\tFM10K_MPLS_TYPE_MULTI,\n+};\n+\n+enum fm10k_mpls_action {\n+\tFM10K_MPLS_ACTION_DROP,\n+\tFM10K_MPLS_ACTION_QUEUE,\n+};\n+\n+struct fm10k_mpls_filter_conf {\n+\tenum fm10k_mpls_type mpls_type; /**< mandatory for MPLS */\n+\tuint32_t mpls_header;     /**< MPLS header */\n+\tuint32_t mpls_header_mask;      /**< MPLS header mask */\n+\tenum fm10k_mpls_action mpls_action;\n+\tuint16_t queue;\n+\tuint8_t ffu_id;\n+\tuint8_t ffu_prio;\n+};\n+\n+/**\n+ * VLAN filter configuration.\n+ */\n+struct fm10k_vlan_filter_conf {\n+\tint ffu_id;\n+\tuint8_t ffu_prio;\n+\tuint8_t is_ingress;\n+\tuint8_t port;\n+\tuint8_t in_ext_port;\n+\tuint8_t out_ext_port;\n+\tuint16_t in_vlan;\n+\tuint16_t out_vlan;\n+};\n+\n+\n+union fm10k_filter_t {\n+\tstruct fm10k_mpls_filter_conf mpls_filter;\n+\tstruct fm10k_vlan_filter_conf vlan_filter;\n+};\n+\n+typedef int (*parse_filter_t)(struct rte_eth_dev *dev,\n+\t\t\t      const struct rte_flow_attr *attr,\n+\t\t\t      const struct rte_flow_item pattern[],\n+\t\t\t      const struct rte_flow_action actions[],\n+\t\t\t      struct rte_flow_error *error,\n+\t\t\t      union fm10k_filter_t *filter);\n+\n+struct fm10k_valid_pattern {\n+\tenum rte_flow_item_type *items;\n+\tparse_filter_t parse_filter;\n+};\n+\n+static enum rte_flow_item_type pattern_mpls_1[] = {\n+\tRTE_FLOW_ITEM_TYPE_ETH,\n+\tRTE_FLOW_ITEM_TYPE_MPLS,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_vlan_1[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_PHY_PORT,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static enum rte_flow_item_type pattern_vlan_2[] = {\n+\tRTE_FLOW_ITEM_TYPE_VLAN,\n+\tRTE_FLOW_ITEM_TYPE_PHY_PORT,\n+\tRTE_FLOW_ITEM_TYPE_PHY_PORT,\n+\tRTE_FLOW_ITEM_TYPE_END,\n+};\n+\n+static int fm10k_flow_parse_mpls_filter(struct rte_eth_dev *dev,\n+\t\t\t\t    const struct rte_flow_attr *attr,\n+\t\t\t\t    const struct rte_flow_item pattern[],\n+\t\t\t\t    const struct rte_flow_action actions[],\n+\t\t\t\t    struct rte_flow_error *error,\n+\t\t\t\t    union fm10k_filter_t *filter);\n+static int\n+fm10k_flow_parse_vlan_filter(struct rte_eth_dev *dev,\n+\t\t\t    const struct rte_flow_attr *attr,\n+\t\t\t    const struct rte_flow_item pattern[],\n+\t\t\t    const struct rte_flow_action actions[],\n+\t\t\t    struct rte_flow_error *error,\n+\t\t\t    union fm10k_filter_t *filter);\n+\n+static struct fm10k_valid_pattern fm10k_supported_patterns[] = {\n+\t/* MPLS */\n+\t{ pattern_mpls_1, fm10k_flow_parse_mpls_filter },\n+\t/* VLAN */\n+\t{ pattern_vlan_1, fm10k_flow_parse_vlan_filter },\n+\t/* VLAN */\n+\t{ pattern_vlan_2, fm10k_flow_parse_vlan_filter },\n+};\n+\n+static const struct rte_flow_action *\n+fm10k_next_item_of_action(const struct rte_flow_action *actions,\n+\t\tuint32_t *index)\n+{\n+\tstatic const struct rte_flow_action *act;\n+\n+\tact = actions + *index;\n+\twhile (act->type == RTE_FLOW_ACTION_TYPE_VOID) {\n+\t\t(*index)++;\n+\t\tact = actions + *index;\n+\t}\n+\treturn act;\n+}\n+\n+/* Find the first VOID or non-VOID item pointer */\n+static const struct rte_flow_item *\n+fm10k_find_first_item(const struct rte_flow_item *item, bool is_void)\n+{\n+\tbool is_find;\n+\n+\twhile (item->type != RTE_FLOW_ITEM_TYPE_END) {\n+\t\tif (is_void)\n+\t\t\tis_find = item->type == RTE_FLOW_ITEM_TYPE_VOID;\n+\t\telse\n+\t\t\tis_find = item->type != RTE_FLOW_ITEM_TYPE_VOID;\n+\t\tif (is_find)\n+\t\t\tbreak;\n+\t\titem++;\n+\t}\n+\treturn item;\n+}\n+\n+/* Skip all VOID items of the pattern */\n+static void\n+fm10k_pattern_skip_void_item(struct rte_flow_item *items,\n+\t\t\t    const struct rte_flow_item *pattern)\n+{\n+\tuint32_t cpy_count = 0;\n+\tconst struct rte_flow_item *pb = pattern, *pe = pattern;\n+\n+\tfor (;;) {\n+\t\t/* Find a non-void item first */\n+\t\tpb = fm10k_find_first_item(pb, false);\n+\t\tif (pb->type == RTE_FLOW_ITEM_TYPE_END) {\n+\t\t\tpe = pb;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Find a void item */\n+\t\tpe = fm10k_find_first_item(pb + 1, true);\n+\n+\t\tcpy_count = pe - pb;\n+\t\trte_memcpy(items, pb, sizeof(struct rte_flow_item) * cpy_count);\n+\n+\t\titems += cpy_count;\n+\n+\t\tif (pe->type == RTE_FLOW_ITEM_TYPE_END) {\n+\t\t\tpb = pe;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tpb = pe + 1;\n+\t}\n+\t/* Copy the END item. */\n+\trte_memcpy(items, pe, sizeof(struct rte_flow_item));\n+}\n+\n+/* Check if the pattern matches a supported item type array */\n+static bool\n+fm10k_match_pattern(enum rte_flow_item_type *item_array,\n+\t\t   struct rte_flow_item *pattern)\n+{\n+\tstruct rte_flow_item *item = pattern;\n+\n+\twhile ((*item_array == item->type) &&\n+\t       (*item_array != RTE_FLOW_ITEM_TYPE_END)) {\n+\t\titem_array++;\n+\t\titem++;\n+\t}\n+\n+\treturn (*item_array == RTE_FLOW_ITEM_TYPE_END &&\n+\t\titem->type == RTE_FLOW_ITEM_TYPE_END);\n+}\n+\n+/* Find if there's parse filter function matched */\n+static parse_filter_t\n+fm10k_find_parse_filter_func(struct rte_flow_item *pattern, uint32_t *idx)\n+{\n+\tparse_filter_t parse_filter = NULL;\n+\tuint8_t i = *idx;\n+\n+\tfor (; i < RTE_DIM(fm10k_supported_patterns); i++) {\n+\t\tif (fm10k_match_pattern(fm10k_supported_patterns[i].items,\n+\t\t\t\t\tpattern)) {\n+\t\t\tparse_filter = fm10k_supported_patterns[i].parse_filter;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t*idx = ++i;\n+\n+\treturn parse_filter;\n+}\n+\n+/* Parse attributes */\n+static int\n+fm10k_flow_parse_attr(const struct rte_flow_attr *attr,\n+\t\t     struct rte_flow_error *error)\n+{\n+\t/* Not supported */\n+\tif (attr->group) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR_GROUP,\n+\t\t\t\t   attr, \"Not support group.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * MPLS\n+ */\n+/* 1. Last in item should be NULL as range is not supported.\n+ * 2. Supported filter types: MPLS label.\n+ * 3. Mask of fields which need to be matched should be\n+ *    filled with 1.\n+ * 4. Mask of fields which needn't to be matched should be\n+ *    filled with 0.\n+ */\n+static int\n+fm10k_flow_parse_mpls_pattern(__rte_unused struct rte_eth_dev *dev,\n+\t\t\t     const struct rte_flow_item *pattern,\n+\t\t\t     struct rte_flow_error *error,\n+\t\t\t     struct fm10k_mpls_filter_conf *filter)\n+{\n+\tconst struct rte_flow_item *item = pattern;\n+\tconst struct rte_flow_item_mpls *mpls_spec;\n+\tconst struct rte_flow_item_mpls *mpls_mask;\n+\tconst struct rte_flow_item_eth *eth_spec;\n+\tenum rte_flow_item_type item_type;\n+\tconst uint8_t label_mask[3] = {0xFF, 0xFF, 0xF0};\n+\tuint32_t label_be = 0;\n+\tuint32_t be_mask = 0;\n+\n+\tfor (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (item->last) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Not support range\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t\titem_type = item->type;\n+\t\tswitch (item_type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_ETH:\n+\t\t\tif (!item->spec || item->mask) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"Invalid ETH item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\t\t\teth_spec =\n+\t\t\t\t(const struct rte_flow_item_eth *)item->spec;\n+\n+\t\t\tif (rte_be_to_cpu_16(eth_spec->type) == 0x8847) {\n+\t\t\t\tfilter->mpls_type = FM10K_MPLS_TYPE_UNI;\n+\t\t\t} else if (rte_be_to_cpu_16(eth_spec->type) == 0x8848) {\n+\t\t\t\tfilter->mpls_type = FM10K_MPLS_TYPE_MULTI;\n+\t\t\t} else {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\tRTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\titem, \"Invalid ETH item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tcase RTE_FLOW_ITEM_TYPE_MPLS:\n+\t\t\tmpls_spec =\n+\t\t\t\t(const struct rte_flow_item_mpls *)item->spec;\n+\t\t\tmpls_mask =\n+\t\t\t\t(const struct rte_flow_item_mpls *)item->mask;\n+\n+\t\t\tif (!mpls_spec || !mpls_mask) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"Invalid MPLS item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\n+\t\t\tif (memcmp(mpls_mask->label_tc_s, label_mask, 3)) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"Invalid MPLS label mask\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\t\t\trte_memcpy(((uint8_t *)&label_be + 1),\n+\t\t\t\t\tmpls_spec->label_tc_s, 3);\n+\t\t\trte_memcpy(((uint8_t *)&be_mask + 1),\n+\t\t\t\t\tmpls_mask->label_tc_s, 3);\n+\t\t\tfilter->mpls_header =\n+\t\t\t\t\trte_be_to_cpu_32(label_be) >> 4;\n+\t\t\tfilter->mpls_header_mask =\n+\t\t\t\t\trte_be_to_cpu_32(be_mask) >> 4;\n+\n+\t\t\tfm10k_cons_filter_type = RTE_ETH_FILTER_TUNNEL;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* MPLS action only supports QUEUE or DROP. */\n+static int\n+fm10k_flow_parse_mpls_action(const struct rte_flow_action *actions,\n+\t\t\t\t struct rte_flow_error *error,\n+\t\t\t\t struct fm10k_mpls_filter_conf *filter)\n+{\n+\tconst struct rte_flow_action *act;\n+\tconst struct rte_flow_action_queue *act_q;\n+\tuint32_t index = 0;\n+\n+\t/* Check if the first non-void action is QUEUE or DROP. */\n+\tact = fm10k_next_item_of_action(actions, &index);\n+\tif (act->type != RTE_FLOW_ACTION_TYPE_QUEUE &&\n+\t    act->type != RTE_FLOW_ACTION_TYPE_DROP) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t   act, \"Not supported action.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (act->type == RTE_FLOW_ACTION_TYPE_QUEUE) {\n+\t\tact_q = (const struct rte_flow_action_queue *)act->conf;\n+\t\tfilter->mpls_action = FM10K_MPLS_ACTION_QUEUE;\n+\t\tfilter->queue = act_q->index;\n+\t} else {\n+\t\tfilter->mpls_action = FM10K_MPLS_ACTION_DROP;\n+\t}\n+\n+\t/* Check if the next non-void item is END */\n+\tindex++;\n+\tact = fm10k_next_item_of_action(actions, &index);\n+\tif (act->type != RTE_FLOW_ACTION_TYPE_END) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t   act, \"Not supported action.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+fm10k_flow_parse_mpls_filter(struct rte_eth_dev *dev,\n+\t\t\t    const struct rte_flow_attr *attr,\n+\t\t\t    const struct rte_flow_item pattern[],\n+\t\t\t    const struct rte_flow_action actions[],\n+\t\t\t    struct rte_flow_error *error,\n+\t\t\t    union fm10k_filter_t *filter)\n+{\n+\tstruct fm10k_mpls_filter_conf *mpls_filter =\n+\t\t&filter->mpls_filter;\n+\tint ret;\n+\n+\tret = fm10k_flow_parse_mpls_pattern(dev, pattern,\n+\t\t\t\t\t   error, mpls_filter);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = fm10k_flow_parse_mpls_action(actions, error, mpls_filter);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = fm10k_flow_parse_attr(attr, error);\n+\treturn ret;\n+}\n+\n+\n+/*\n+ * VLAN\n+ */\n+static int\n+fm10k_flow_parse_vlan_pattern(__rte_unused struct rte_eth_dev *dev,\n+\t\t\t     const struct rte_flow_item *pattern,\n+\t\t\t     struct rte_flow_error *error,\n+\t\t\t     struct fm10k_vlan_filter_conf *filter)\n+{\n+\tconst struct rte_flow_item *item = pattern;\n+\tconst struct rte_flow_item_vlan *vlan_spec;\n+\tconst struct rte_flow_item_phy_port *pp_spec;\n+\tenum rte_flow_item_type item_type;\n+\n+\tPMD_INIT_LOG(DEBUG, \"Parse vlan pattern ffu id %d\", filter->ffu_id);\n+\n+\tfor (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {\n+\t\tif (item->last) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   item,\n+\t\t\t\t\t   \"Not support range\");\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t\titem_type = item->type;\n+\t\tswitch (item_type) {\n+\t\tcase RTE_FLOW_ITEM_TYPE_VLAN:\n+\t\t\tvlan_spec =\n+\t\t\t\t(const struct rte_flow_item_vlan *)item->spec;\n+\n+\t\t\tif (!vlan_spec) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"Invalid VLAN item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase RTE_FLOW_ITEM_TYPE_PHY_PORT:\n+\t\t\tpp_spec =\n+\t\t\t(const struct rte_flow_item_phy_port *)item->spec;\n+\t\t\tif (!pp_spec) {\n+\t\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t\t   item,\n+\t\t\t\t\t\t   \"Invalid PHY PORT item\");\n+\t\t\t\treturn -rte_errno;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+static int\n+fm10k_flow_parse_vlan_action(struct rte_eth_dev *dev,\n+\t\t\t\t const struct rte_flow_action *actions,\n+\t\t\t\t struct rte_flow_error *error,\n+\t\t\t\t struct fm10k_vlan_filter_conf *filter)\n+{\n+\tconst struct rte_flow_action *act;\n+\tuint32_t index = 0;\n+\n+\tPMD_INIT_LOG(DEBUG, \"Parse vlan action name %s ffu id %d\",\n+\t\t\tdev->device->name, filter->ffu_id);\n+\n+\t/* Check if the first non-void action is QUEUE or DROP. */\n+\tact = fm10k_next_item_of_action(actions, &index);\n+\tif (act->type != RTE_FLOW_ACTION_TYPE_MARK) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t   act, \"Not supported action.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tindex++;\n+\tact = fm10k_next_item_of_action(actions, &index);\n+\tif (act->type != RTE_FLOW_ACTION_TYPE_MARK &&\n+\t\tact->type != RTE_FLOW_ACTION_TYPE_END) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t   act, \"Not supported action.\");\n+\t\treturn -rte_errno;\n+\t}\n+\tif (act->type == RTE_FLOW_ACTION_TYPE_END)\n+\t\treturn 0;\n+\n+\tindex++;\n+\t/* Check if the next non-void item is END */\n+\tact = fm10k_next_item_of_action(actions, &index);\n+\tif (act->type != RTE_FLOW_ACTION_TYPE_END) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,\n+\t\t\t\t   act, \"Not supported action.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+fm10k_flow_parse_vlan_filter(struct rte_eth_dev *dev,\n+\t\t\t    const struct rte_flow_attr *attr,\n+\t\t\t    const struct rte_flow_item pattern[],\n+\t\t\t    const struct rte_flow_action actions[],\n+\t\t\t    struct rte_flow_error *error,\n+\t\t\t    union fm10k_filter_t *filter)\n+{\n+\tint ret;\n+\tstruct fm10k_vlan_filter_conf *vlan_filter =\n+\t\t&filter->vlan_filter;\n+\n+\tret = fm10k_flow_parse_vlan_pattern(dev, pattern,\n+\t\t\t\t\t   error, vlan_filter);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = fm10k_flow_parse_vlan_action(dev, actions, error, vlan_filter);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (attr->ingress)\n+\t\tvlan_filter->is_ingress = 1;\n+\telse if (attr->egress)\n+\t\tvlan_filter->is_ingress = 0;\n+\tvlan_filter->ffu_prio = attr->priority;\n+\n+\tret = fm10k_flow_parse_attr(attr, error);\n+\treturn ret;\n+}\n+\n+/*\n+ *\n+ */\n+static int\n+fm10k_flow_validate(struct rte_eth_dev *dev,\n+\t\t   const struct rte_flow_attr *attr,\n+\t\t   const struct rte_flow_item pattern[],\n+\t\t   const struct rte_flow_action actions[],\n+\t\t   struct rte_flow_error *error)\n+{\n+\tstruct rte_flow_item *items; /* internal pattern w/o VOID items */\n+\tparse_filter_t parse_filter;\n+\tuint32_t item_num = 0; /* non-void item number of pattern*/\n+\tuint32_t i = 0;\n+\tbool flag = false;\n+\tint ret = -1;\n+\n+\tif (!pattern) {\n+\t\trte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_NUM,\n+\t\t\t\t   NULL, \"NULL pattern.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (!actions) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ACTION_NUM,\n+\t\t\t\t   NULL, \"NULL action.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\tif (!attr) {\n+\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_ATTR,\n+\t\t\t\t   NULL, \"NULL attribute.\");\n+\t\treturn -rte_errno;\n+\t}\n+\n+\t/* Get the non-void item number of pattern */\n+\twhile ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {\n+\t\tif ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID)\n+\t\t\titem_num++;\n+\t\ti++;\n+\t}\n+\titem_num++;\n+\n+\titems = rte_zmalloc(\"fm10k_pattern\",\n+\t\t\t    item_num * sizeof(struct rte_flow_item), 0);\n+\tif (!items) {\n+\t\trte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ITEM_NUM,\n+\t\t\t\t   NULL, \"No memory for PMD internal items.\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tfm10k_pattern_skip_void_item(items, pattern);\n+\n+\ti = 0;\n+\tdo {\n+\t\tparse_filter = fm10k_find_parse_filter_func(items, &i);\n+\t\tif (!parse_filter && !flag) {\n+\t\t\trte_flow_error_set(error, EINVAL,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_ITEM,\n+\t\t\t\t\t   pattern, \"Unsupported pattern\");\n+\t\t\trte_free(items);\n+\t\t\treturn -rte_errno;\n+\t\t}\n+\t\tif (parse_filter)\n+\t\t\tret = parse_filter(dev, attr, items, actions,\n+\t\t\t\t\t   error, &cons_filter);\n+\t\tflag = true;\n+\t} while ((ret < 0) && (i < RTE_DIM(fm10k_supported_patterns)));\n+\n+\trte_free(items);\n+\n+\treturn ret;\n+}\n+\n+static struct fm10k_cfg_flow *\n+fm10k_flow_cfg_transfer(struct rte_eth_dev *dev,\n+\t\t const struct rte_flow_attr *attr,\n+\t\t const struct rte_flow_item pattern[],\n+\t\t const struct rte_flow_action actions[],\n+\t\t struct rte_flow_error *error)\n+{\n+\tint i;\n+\tu8 port_id;\n+\tint set_port_num = 0, set_vlan_num = 0;\n+\tu16 fw_port_id = 0, bp_port_id = 0;\n+\tu16 filter_vlan_id = 0, fw_vlan_id = 0, bp_vlan_id = 0;\n+\tstruct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);\n+\tstruct fm10k_cfg_flow *cf;\n+\n+\tcf = rte_zmalloc(\"fm10k_rule\", sizeof(struct fm10k_cfg_flow), 0);\n+\tif (!cf) {\n+\t\trte_flow_error_set(error, ENOMEM,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t   \"Failed to allocate memory\");\n+\t\treturn NULL;\n+\t}\n+\tmemset(cf, 0, sizeof(struct fm10k_cfg_flow));\n+\n+\tport_id = fm10k_switch_dpdk_port_no_get(hw);\n+\tfor (i = 0; i < 4; i++)\t{\n+\t\tif (pattern[i].type == RTE_FLOW_ITEM_TYPE_VLAN) {\n+\t\t\tfilter_vlan_id =\n+\t\t\t\trte_be_to_cpu_16\n+\t\t\t\t(((const struct rte_flow_item_vlan *)\n+\t\t\t\tpattern[i].spec)->tci);\n+\t\t} else if (pattern[i].type == RTE_FLOW_ITEM_TYPE_PHY_PORT) {\n+\t\t\tif (set_port_num)\n+\t\t\t\tbp_port_id =\n+\t\t\t\t\t((const struct rte_flow_item_phy_port *)\n+\t\t\t\t\tpattern[i].spec)->index;\n+\t\t\telse\n+\t\t\t\tfw_port_id =\n+\t\t\t\t\t((const struct rte_flow_item_phy_port *)\n+\t\t\t\t\tpattern[i].spec)->index;\n+\t\t\tset_port_num++;\n+\t\t} else if (pattern[i].type == RTE_FLOW_ITEM_TYPE_END) {\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < 3; i++)\t{\n+\t\tif (actions[i].type == RTE_FLOW_ACTION_TYPE_MARK) {\n+\t\t\tif (set_vlan_num)\n+\t\t\t\tbp_vlan_id =\n+\t\t\t\t\t((const struct rte_flow_action_mark *)\n+\t\t\t\t\tactions[i].conf)->id;\n+\t\t\telse\n+\t\t\t\tfw_vlan_id =\n+\t\t\t\t\t((const struct rte_flow_action_mark *)\n+\t\t\t\t\tactions[i].conf)->id;\n+\t\t\tset_vlan_num++;\n+\t\t} else if (actions[i].type == RTE_FLOW_ACTION_TYPE_END) {\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (attr->ingress && !attr->egress)\t{\n+\t\t/* this port is DPDK port and it is destination port */\n+\t\tcf->src_port.port_type = FM10K_CONFIG_FLOW_EXT_PORT;\n+\t\tcf->src_port.port_no = fw_port_id;\n+\t\tcf->src_port.vlan_id = filter_vlan_id;\n+\t\tcf->fw_port[0].port_type = FM10K_CONFIG_FLOW_DPDK_PORT;\n+\t\tcf->fw_port[0].port_no = port_id;\n+\t\tcf->fw_port[0].vlan_id = fw_vlan_id;\n+\t} else if (!attr->ingress && attr->egress) {\n+\t\t/* this port is DPDK port and it is source port */\n+\t\tcf->src_port.port_type = FM10K_CONFIG_FLOW_DPDK_PORT;\n+\t\tcf->src_port.port_no = port_id;\n+\t\tcf->src_port.vlan_id = filter_vlan_id;\n+\t\tcf->fw_port[0].port_type = FM10K_CONFIG_FLOW_EXT_PORT;\n+\t\tcf->fw_port[0].port_no = fw_port_id;\n+\t\tcf->fw_port[0].vlan_id = fw_vlan_id;\n+\t} else if (!attr->ingress && !attr->egress) {\n+\t\t/* two ports are external port */\n+\t\tcf->src_port.port_type = FM10K_CONFIG_FLOW_EXT_PORT;\n+\t\tcf->src_port.port_no = port_id;\n+\t\tcf->src_port.vlan_id = filter_vlan_id;\n+\t\tcf->fw_port[0].port_type = FM10K_CONFIG_FLOW_EXT_PORT;\n+\t\tcf->fw_port[0].port_no = fw_port_id;\n+\t\tcf->fw_port[0].vlan_id = fw_vlan_id;\n+\t} else {\n+\t\t/* two ports are DPDK port */\n+\t\tcf->src_port.port_type = FM10K_CONFIG_FLOW_DPDK_PORT;\n+\t\tcf->src_port.port_no = port_id;\n+\t\tcf->src_port.vlan_id = filter_vlan_id;\n+\t\tcf->fw_port[0].port_type = FM10K_CONFIG_FLOW_DPDK_PORT;\n+\t\tcf->fw_port[0].port_no = fw_port_id;\n+\t\tcf->fw_port[0].vlan_id = fw_vlan_id;\n+\t}\n+\n+\tif (set_port_num == 2 && set_vlan_num == 2)\t{\n+\t\tcf->fw_port[1].port_type = FM10K_CONFIG_FLOW_EXT_PORT;\n+\t\tcf->fw_port[1].port_no = bp_port_id;\n+\t\tcf->fw_port[1].vlan_id = bp_vlan_id;\n+\t}\n+\n+\treturn cf;\n+}\n+\n+\n+static struct rte_flow *\n+fm10k_flow_create(struct rte_eth_dev *dev,\n+\t\t const struct rte_flow_attr *attr,\n+\t\t const struct rte_flow_item pattern[],\n+\t\t const struct rte_flow_action actions[],\n+\t\t struct rte_flow_error *error)\n+{\n+\tstruct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);\n+\tstruct rte_flow *flow;\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\tstruct fm10k_cfg_flow *cf;\n+\tint ret;\n+\n+\tflow = rte_zmalloc(\"fm10k_flow\", sizeof(struct rte_flow), 0);\n+\tif (!flow) {\n+\t\trte_flow_error_set(error, ENOMEM,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t   \"Failed to allocate memory\");\n+\t\treturn flow;\n+\t}\n+\n+\tret = fm10k_flow_validate(dev, attr, pattern, actions, error);\n+\tif (ret < 0)\n+\t\treturn NULL;\n+\n+\tcf = fm10k_flow_cfg_transfer(dev, attr, pattern, actions, error);\n+\tif (!cf)\n+\t\tgoto free_flow;\n+\n+\tflow->rule = cf;\n+\tfm10k_ffu_flow_enable(sw, cf);\n+\tfm10k_config_flow_list_add_tail(fm10k_config_flowset_current_get(), cf);\n+\n+\tTAILQ_INSERT_TAIL((struct fm10k_flow_list *)\n+\t\t\tfm10k_switch_dpdk_port_flow_list_get(hw), flow, node);\n+\treturn flow;\n+\n+free_flow:\n+\trte_flow_error_set(error, -ret,\n+\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t   \"Failed to create flow.\");\n+\trte_free(flow);\n+\treturn NULL;\n+}\n+\n+static int\n+fm10k_flow_destroy(struct rte_eth_dev *dev,\n+\t\t  struct rte_flow *flow,\n+\t\t  struct rte_flow_error *error)\n+{\n+\tstruct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);\n+\tint ret = 0;\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tif (flow->rule)\t{\n+\t\tfm10k_config_flow_list_delete\n+\t\t\t((struct fm10k_cfg_flow *)flow->rule);\n+\t\tfm10k_ffu_flow_disable(sw,\n+\t\t\t(struct fm10k_cfg_flow *)flow->rule);\n+\t}\n+\n+\tif (!ret) {\n+\t\tTAILQ_REMOVE((struct fm10k_flow_list *)\n+\t\t\t\tfm10k_switch_dpdk_port_flow_list_get(hw),\n+\t\t\t\tflow, node);\n+\t\trte_free(flow->rule);\n+\t\trte_free(flow);\n+\t} else {\n+\t\trte_flow_error_set(error, -ret,\n+\t\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t   \"Failed to destroy flow.\");\n+\t}\n+\treturn ret;\n+}\n+\n+\n+static int\n+fm10k_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)\n+{\n+\tstruct fm10k_hw *hw = FM10K_DEV_PRIVATE_TO_HW(dev->data->dev_private);\n+\tstruct rte_flow *flow;\n+\tvoid *temp;\n+\tint ret = 0;\n+\tstruct fm10k_cfg_flow *cf;\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\t/* Delete flows in flow list. */\n+\tTAILQ_FOREACH_SAFE(flow,\n+\t\t\t(struct fm10k_flow_list *)\n+\t\t\tfm10k_switch_dpdk_port_flow_list_get(hw),\n+\t\t\tnode, temp) {\n+\t\tcf = flow->rule;\n+\t\tif (cf) {\n+\t\t\tfm10k_config_flow_list_delete(cf);\n+\t\t\tfm10k_ffu_flow_disable(sw, cf);\n+\t\t} else {\n+\t\t\trte_flow_error_set(error, -ret,\n+\t\t\t\t\t   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,\n+\t\t\t\t\t   \"No such rule in flow.\");\n+\t\t}\n+\t\tTAILQ_REMOVE((struct fm10k_flow_list *)\n+\t\t\t\tfm10k_switch_dpdk_port_flow_list_get(hw),\n+\t\t\t\tflow, node);\n+\t\trte_free(flow);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+void\n+fm10k_flow_list_init(void *flow_list)\n+{\n+\tTAILQ_INIT((struct fm10k_flow_list *)flow_list);\n+}\n+\n+/* Flow operations */\n+const struct rte_flow_ops *\n+fm10k_flow_ops_get(void)\n+{\n+\treturn &fm10k_flow_ops;\n+}\n+\n+\ndiff --git a/drivers/net/fm10k/switch/fm10k_flow.h b/drivers/net/fm10k/switch/fm10k_flow.h\nnew file mode 100644\nindex 0000000..c538544\n--- /dev/null\n+++ b/drivers/net/fm10k/switch/fm10k_flow.h\n@@ -0,0 +1,26 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2019   Silicom Ltd. Connectivity Solutions\n+ */\n+\n+#ifndef _FM10K_SW_FLOW_H_\n+#define _FM10K_SW_FLOW_H_\n+\n+#include <rte_time.h>\n+#include <rte_kvargs.h>\n+#include <rte_hash.h>\n+#include <rte_flow.h>\n+#include <rte_flow_driver.h>\n+#include <rte_tm_driver.h>\n+\n+/*\n+ * Struct to store flow created.\n+ */\n+struct rte_flow {\n+\tTAILQ_ENTRY(rte_flow) node;\n+\tenum rte_filter_type filter_type;\n+\tvoid *rule;\n+};\n+\n+TAILQ_HEAD(fm10k_flow_list, rte_flow);\n+\n+#endif /* _FM10K_SW_FLOW_H_ */\ndiff --git a/drivers/net/fm10k/switch/fm10k_stats.c b/drivers/net/fm10k/switch/fm10k_stats.c\nindex 563f9ac..b90f190 100644\n--- a/drivers/net/fm10k/switch/fm10k_stats.c\n+++ b/drivers/net/fm10k/switch/fm10k_stats.c\n@@ -1012,6 +1012,133 @@ struct fm10k_stats_data {\n \t}\n }\n \n+void\n+fm10k_stats_dpdk_port_print(struct fm10k_switch *sw)\n+{\n+\tint i, j, lport, pf_no;\n+\tstruct fm10k_port_counters counters;\n+\tstruct fm10k_ext_port ext_port;\n+\tstatic struct fm10k_stats_data last_data[FM10K_SW_PEPS_MAX];\n+\tstatic struct fm10k_stats_data last_queue_data[FM10K_SW_PEPS_MAX][4];\n+\tstruct fm10k_stats_data data, mydata;\n+\tchar pf_ports[10];\n+\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tif (sw->dpdk_cfg->ports[i].hw == NULL)\n+\t\t\tcontinue;\n+\t\tif (sw->dpdk_cfg->ports[i].type != FM10K_CONFIG_DPDK_PF)\n+\t\t\tcontinue;\n+\t\tif (sw->dpdk_cfg->dpdk_port_map[i].type ==\n+\t\t\t\tFM10K_CONFIG_PORT_MAP_NULL)\n+\t\t\tcontinue;\n+\n+\t\tmemset(&mydata, 0, sizeof(mydata));\n+\t\tif (sw->dpdk_cfg->dpdk_port_map[i].type ==\n+\t\t\t\tFM10K_CONFIG_PORT_MAP_PFS) {\n+\t\t\tfor (j = 0; j < 2; j++) {\n+\t\t\t\tpf_no =\n+\t\t\t\tsw->dpdk_cfg->dpdk_port_map[i].map_no[j];\n+\t\t\t\tlport = sw->pep_map[pf_no].logical_port;\n+\t\t\t\tmemset(&ext_port, 0, sizeof(ext_port));\n+\t\t\t\text_port.portno = lport;\n+\t\t\t\tfm10k_get_port_counters\n+\t\t\t\t(sw, &ext_port, &counters);\n+\t\t\t\tdata.rx_pkts = counters.cnt_rx_bcst_pkts +\n+\t\t\t\t\t\tcounters.cnt_rx_ucst_pkts;\n+\t\t\t\tdata.tx_pkts = counters.cnt_tx_bcst_pkts +\n+\t\t\t\t\t\tcounters.cnt_tx_ucst_pkts;\n+\t\t\t\tdata.rx_drop = counters.cnt_cmpriv_drop_pkts;\n+\t\t\t\tmydata.rx_pkts += data.rx_pkts -\n+\t\t\t\t\t\tlast_data[pf_no].rx_pkts;\n+\t\t\t\tmydata.tx_pkts += data.tx_pkts -\n+\t\t\t\t\t\tlast_data[pf_no].tx_pkts;\n+\t\t\t\tmydata.rx_drop += data.rx_drop -\n+\t\t\t\t\t\tlast_data[pf_no].rx_drop;\n+\t\t\t\tlast_data[pf_no] = data;\n+\t\t\t}\n+\t\t} else if (sw->dpdk_cfg->dpdk_port_map[i].type ==\n+\t\t\t\tFM10K_CONFIG_PORT_MAP_PF) {\n+\t\t\tpf_no = sw->dpdk_cfg->dpdk_port_map[i].map_no[0];\n+\t\t\tlport = sw->pep_map[pf_no].logical_port;\n+\t\t\tmemset(&ext_port, 0, sizeof(ext_port));\n+\t\t\text_port.portno = lport;\n+\t\t\tfm10k_get_port_counters(sw, &ext_port, &counters);\n+\t\t\tdata.rx_pkts = counters.cnt_rx_bcst_pkts +\n+\t\t\t\t\tcounters.cnt_rx_ucst_pkts;\n+\t\t\tdata.tx_pkts = counters.cnt_tx_bcst_pkts +\n+\t\t\t\t\tcounters.cnt_tx_ucst_pkts;\n+\t\t\tdata.rx_drop = counters.cnt_cmpriv_drop_pkts;\n+\t\t\tmydata.rx_pkts += data.rx_pkts -\n+\t\t\t\t\tlast_data[pf_no].rx_pkts;\n+\t\t\tmydata.tx_pkts += data.tx_pkts -\n+\t\t\t\t\tlast_data[pf_no].tx_pkts;\n+\t\t\tmydata.rx_drop += data.rx_drop -\n+\t\t\t\t\tlast_data[pf_no].rx_drop;\n+\t\t\tlast_data[pf_no] = data;\n+\t\t} else {\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (sw->dpdk_cfg->dpdk_port_map[i].type ==\n+\t\t\t\tFM10K_CONFIG_PORT_MAP_PF)\n+\t\t\tsprintf(pf_ports, \"%d\",\n+\t\t\t\tsw->dpdk_cfg->dpdk_port_map[i].map_no[0]);\n+\t\telse\n+\t\t\tsprintf(pf_ports, \"%d/%d\",\n+\t\t\t\tsw->dpdk_cfg->dpdk_port_map[i].map_no[0],\n+\t\t\t\tsw->dpdk_cfg->dpdk_port_map[i].map_no[1]);\n+\n+\t\tFM10K_SW_INFO(\"DPDK port %-2d  pf %-5s   tx_pkt %-12llu \"\n+\t\t\t\t\"rx_pkt %-12llu drop_pkt %-12llu\\n\",\n+\t\t\t\ti, pf_ports,\n+\t\t\t\t(unsigned long long)mydata.tx_pkts,\n+\t\t\t\t(unsigned long long)mydata.rx_pkts,\n+\t\t\t\t(unsigned long long)mydata.rx_drop);\n+\n+\t\tif (!fm10k_config_check_debug(sw->dpdk_cfg,\n+\t\t\t\tFM10K_CONFIG_DEBUG_STATS_QUEUE))\n+\t\t\tcontinue;\n+\t\tmemset(&mydata, 0, sizeof(mydata));\n+\t\tfor (j = 0;\n+\t\t\t j < sw->dpdk_cfg->ports[i].tx_queue_num;\n+\t\t\t j++) {\n+\t\t\tstruct fm10k_hw *hw = sw->dpdk_cfg->ports[i].hw;\n+\t\t\tuint16_t queue_id = j, pf_no;\n+\n+\t\t\tfm10k_switch_dpdk_hw_queue_map(hw, queue_id,\n+\t\t\t\t\tsw->dpdk_cfg->ports[i].tx_queue_num,\n+\t\t\t\t\t&hw, &queue_id);\n+\t\t\tpf_no = fm10k_switch_dpdk_pf_no_get(hw);\n+\t\t\tdata.tx_pkts =\n+\t\t\t\tFM10K_READ_REG(hw, FM10K_QPTC(queue_id));\n+\t\t\tdata.rx_pkts =\n+\t\t\t\tFM10K_READ_REG(hw, FM10K_QPRC(queue_id));\n+\t\t\tdata.rx_drop =\n+\t\t\t\tFM10K_READ_REG(hw, FM10K_QPRDC(queue_id));\n+\t\t\tmydata.tx_pkts += data.tx_pkts -\n+\t\t\t\tlast_queue_data[pf_no][queue_id].tx_pkts;\n+\t\t\tmydata.rx_pkts += data.rx_pkts -\n+\t\t\t\tlast_queue_data[pf_no][queue_id].rx_pkts;\n+\t\t\tmydata.rx_drop += data.rx_drop -\n+\t\t\t\tlast_queue_data[pf_no][queue_id].rx_drop;\n+\t\t\tFM10K_SW_INFO(\"            queue %d(%d:%d) tx_pkt %-12llu \"\n+\t\t\t\t\"rx_pkt %-12llu drop_pkt %-12llu\\n\", j,\n+\t\t\t\tpf_no, queue_id,\n+\t\t\t\t(unsigned long long)(data.tx_pkts -\n+\t\t\t\tlast_queue_data[pf_no][queue_id].tx_pkts),\n+\t\t\t\t(unsigned long long)(data.rx_pkts -\n+\t\t\t\tlast_queue_data[pf_no][queue_id].rx_pkts),\n+\t\t\t\t(unsigned long long)(data.rx_drop -\n+\t\t\t\tlast_queue_data[pf_no][queue_id].rx_drop));\n+\t\t\tlast_queue_data[pf_no][queue_id] = data;\n+\t\t}\n+\t\tFM10K_SW_INFO(\"                   total tx_pkt %-12llu \"\n+\t\t\t\t\"rx_pkt %-12llu drop_pkt %-12llu\\n\",\n+\t\t\t\t(unsigned long long)mydata.tx_pkts,\n+\t\t\t\t(unsigned long long)mydata.rx_pkts,\n+\t\t\t\t(unsigned long long)mydata.rx_drop);\n+\t}\n+}\n \n static void\n fm10k_stats_port_counter_print(struct fm10k_switch *sw, int lport)\n@@ -1096,6 +1223,7 @@ struct fm10k_stats_data {\n \t\t\t\tFM10K_CONFIG_DEBUG_STATS_PORT)) {\n \t\t\tFM10K_SW_INFO(\"--- port statistic ---\\n\");\n \t\t\tfm10k_stats_epl_port_print(sw);\n+\t\t\tfm10k_stats_dpdk_port_print(sw);\n \t\t}\n \t\tif (fm10k_config_check_debug(sw->dpdk_cfg,\n \t\t\t\tFM10K_CONFIG_DEBUG_STATS_FFU)) {\ndiff --git a/drivers/net/fm10k/switch/fm10k_switch.c b/drivers/net/fm10k/switch/fm10k_switch.c\nnew file mode 100644\nindex 0000000..009d62a\n--- /dev/null\n+++ b/drivers/net/fm10k/switch/fm10k_switch.c\n@@ -0,0 +1,2376 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright 2019   Silicom Ltd. Connectivity Solutions\n+ */\n+\n+#include <rte_ethdev.h>\n+#include <rte_ethdev_pci.h>\n+\n+#include <rte_malloc.h>\n+\n+#include \"../base/fm10k_type.h\"\n+#include \"../base/fm10k_osdep.h\"\n+\n+#include \"../fm10k.h\"\n+#include \"../fm10k_logs.h\"\n+#include \"fm10k_debug.h\"\n+#include \"fm10k_regs.h\"\n+#include \"fm10k_switch.h\"\n+#include \"fm10k_ext_port.h\"\n+#include \"fm10k_serdes.h\"\n+#include \"fm10k_i2c.h\"\n+#include \"fm10k_ffu.h\"\n+#include \"fm10k_stats.h\"\n+#include \"fm10k_config.h\"\n+\n+\n+static struct fm10k_switch fm10k_sw;\n+\n+#define FM10K_AM_TIMEOUT\t\t\t16384\n+#define FM10K_COMP_PPM_SCALE\t\t\t1000000\n+\n+#define FM10K_LED_POLL_INTERVAL_MS\t\t500\n+#define FM10K_LED_BLINKS_PER_SECOND\t\t2\n+\n+\n+/*\n+ * use epl as external port map, only support QUAD_ON\n+ */\n+struct fm10k_sched_prog {\n+\tuint8_t idle;\n+\tuint8_t phys;\t/* physical port */\n+\tuint8_t log;\t/* logical port */\n+\tuint8_t quad;\t/* now, only support QUAD_ON */\n+/* convert entry to idle if EPL in quad port mode */\n+#define FM10K_SW_QUAD_OFF\t\t0\n+/* always use quad port mode */\n+#define FM10K_SW_QUAD_ON\t\t1\n+/* use quad port mode if link speed is 40/100G */\n+#define FM10K_SW_QUAD_40_100\t\t2\n+};\n+\n+static struct fm10k_sched_prog\n+\tfm10k_sched_prog[FM10K_SW_PEPS_SUPPORTED + FM10K_SW_EPLS_SUPPORTED + 1];\n+\n+\n+/*\n+ * Note that for physical port numbers, the initial values used for\n+ * the EPL entries assume EPL[A] is EPL[0] and EPL[B] is EPL[1].\n+ * fm10k_switch_determine_epls() will update these physical port\n+ * numbers based on the actual A and B indices.\n+ */\n+static void\n+fm10k_switch_set_sched_prog(void)\n+{\n+\tint i;\n+\tint start = 0;\n+\n+\tfor (i = 0; i < FM10K_SW_EPLS_SUPPORTED; i++) {\n+\t\tfm10k_sched_prog[i].idle = 0;\n+\t\tfm10k_sched_prog[i].phys = fm10k_epl_port_map[i].physical_port;\n+\t\tfm10k_sched_prog[i].log = fm10k_epl_port_map[i].logical_port;\n+\t\tfm10k_sched_prog[i].quad = FM10K_SW_QUAD_ON;\n+\t}\n+\tstart += FM10K_SW_EPLS_SUPPORTED;\n+\tfor (i = 0; i < FM10K_SW_PEPS_SUPPORTED; i++) {\n+\t\tfm10k_sched_prog[start + i].idle = 0;\n+\t\tfm10k_sched_prog[start + i].phys =\n+\t\t\t\tfm10k_pep_port_map[i].physical_port;\n+\t\tfm10k_sched_prog[start + i].log =\n+\t\t\t\tfm10k_pep_port_map[i].logical_port;\n+\t\tfm10k_sched_prog[start + i].quad = FM10K_SW_QUAD_40_100;\n+\t}\n+\tstart += FM10K_SW_PEPS_SUPPORTED;\n+\tfm10k_sched_prog[start].idle = 1;\n+}\n+\n+\n+static void\n+fm10k_switch_determine_epls(struct fm10k_switch *sw)\n+{\n+\tstruct fm10k_device_info *cfg = sw->info;\n+\tunsigned int i;\n+\tuint8_t phys;\n+\n+\tsw->epla_no = 0;\n+\tsw->eplb_no = 6;\n+\n+\tswitch (FM10K_SW_CARD_ID(cfg->subvendor, cfg->subdevice)) {\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIR_QXSL4):\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIR_QXSL4_REV_2):\n+\t\tsw->epla_no = 1;\n+\t\tsw->eplb_no = 6;\n+\t\tbreak;\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIRL_QXSL4):\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIRM_QXSL4):\n+\tcase FM10K_SW_CARD(SILICOM, PE325G2DSIR):\n+\t\tsw->epla_no = 1;\n+\t\tsw->eplb_no = 7;\n+\t\tbreak;\n+\t}\n+\n+\tfor (i = 0;\n+\t\t\ti < sizeof(fm10k_sched_prog) /\n+\t\t\t\tsizeof(fm10k_sched_prog[0]);\n+\t\t\ti++) {\n+\t\tif (fm10k_sched_prog[i].idle)\n+\t\t\tcontinue;\n+\n+\t\tphys = fm10k_sched_prog[i].phys;\n+\t\tif (phys <= 3) {\n+\t\t\t/* Substitute actual epla phys port number */\n+\t\t\tfm10k_sched_prog[i].phys = sw->epla_no * 4 + phys;\n+\t\t} else if (phys >= 4 && phys <= 7) {\n+\t\t\t/* Substitute actual eplb phys port number */\n+\t\t\tfm10k_sched_prog[i].phys = sw->eplb_no * 4 + (phys - 4);\n+\t\t}\n+\t}\n+}\n+\n+static void\n+fm10k_hw_eicr_disable_source(struct fm10k_switch *sw, unsigned int source)\n+{\n+\tunsigned int shift;\n+\n+\tswitch (source) {\n+\tcase FM10K_SW_EICR_PCA_FAULT:\n+\t\tshift = FM10K_SW_EICR_PCA_FAULT_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_THI_FAULT:\n+\t\tshift = FM10K_SW_EICR_THI_FAULT_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_FUM_FAULT:\n+\t\tshift = FM10K_SW_EICR_FUM_FAULT_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_MAILBOX:\n+\t\tshift = FM10K_SW_EICR_MAILBOX_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_SWITCH_READY:\n+\t\tshift = FM10K_SW_EICR_SWITCH_READY_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_SWITCH_NREADY:\n+\t\tshift = FM10K_SW_EICR_SWITCH_NREADY_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_SWITCH_INT:\n+\t\tshift = FM10K_SW_EICR_SWITCH_INT_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_SRAM_ERROR:\n+\t\tshift = FM10K_SW_EICR_SRAM_ERROR_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_VFLR:\n+\t\tshift = FM10K_SW_EICR_VFLR_SHIFT;\n+\t\tbreak;\n+\tcase FM10K_SW_EICR_MAX_HOLD_TIME:\n+\t\tshift = FM10K_SW_EICR_MAX_HOLD_TIME_SHIFT;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn;\n+\t}\n+\n+\tfm10k_write_switch_reg(sw,\n+\t\t\tFM10K_SW_EIMR, FM10K_SW_EIMR_DISABLE << (shift * 2));\n+\tfm10k_write_flush(sw);\n+}\n+\n+\n+unsigned int\n+fm10k_switch_eplidx_to_eplno(struct fm10k_switch *sw, unsigned int eplidx)\n+{\n+\treturn eplidx ? sw->eplb_no : sw->epla_no;\n+}\n+\n+\n+static uint16_t\n+fm10k_switch_ppm_to_tx_clk_compensation_timeout(uint32_t pcs, uint32_t num_ppm)\n+{\n+\tunsigned int scale;\n+\tunsigned int ppm;\n+\tunsigned int timeout;\n+\tunsigned int am_ppm;\n+\n+\tif (num_ppm == 0 || pcs == FM10K_SW_EPL_PCS_SEL_DISABLE) {\n+\t\tif (pcs == FM10K_SW_EPL_PCS_SEL_40GBASER ||\n+\t\t    pcs == FM10K_SW_EPL_PCS_SEL_100GBASER)\n+\t\t\treturn (FM10K_AM_TIMEOUT / 2);\n+\t\telse\n+\t\t\treturn (0);\n+\t}\n+\n+\tif (pcs == FM10K_SW_EPL_PCS_SEL_40GBASER ||\n+\t    pcs == FM10K_SW_EPL_PCS_SEL_100GBASER) {\n+\t\tam_ppm = 1000000 / FM10K_AM_TIMEOUT;\n+\t\tscale = FM10K_COMP_PPM_SCALE / 2;\n+\t} else {\n+\t\tam_ppm = 0;\n+\t\tscale = FM10K_COMP_PPM_SCALE;\n+\t}\n+\n+\tppm = num_ppm + am_ppm;\n+\ttimeout = scale / ppm;\n+\n+\tif (timeout >= 0xffff)\n+\t\treturn 0xffff;\n+\telse\n+\t\treturn timeout;\n+}\n+\n+\n+static int\n+fm10k_switch_configure_epls(struct fm10k_hw *hw, struct fm10k_switch *sw)\n+{\n+\tstruct fm10k_ext_ports *ext_ports = sw->ext_ports;\n+\tstruct fm10k_ext_port *port;\n+\tstruct fm10k_device_info *cfg = sw->info;\n+\tu32 mac_cfg[FM10K_SW_MAC_CFG_ARRAY_SIZE];\n+\tu32 data, pcs, qpl;\n+\tu32 pcstmp;\n+\tunsigned int i, j;\n+\tunsigned int dic_enable;\n+\tunsigned int anti_bubble_wm;\n+\tunsigned int rate_fifo_wm;\n+\tunsigned int rate_fifo_slow_inc, rate_fifo_fast_inc;\n+\tint error;\n+\tu16 timeout;\n+\n+\tcfg = fm10k_get_device_info(hw);\n+\tif (cfg == NULL)\n+\t\treturn -1;\n+\n+\t/*\n+\t * Assumptions:\n+\t *   - All external interfaces are the same speed\n+\t *   - 1G/10G ports are packed into the minimum number of EPLs\n+\t *   - quad-mode EPLs use lane 0 as master\n+\t *   - The lowest numbered PEPs are used\n+\t *   - PEPs are always used in x8 mode.\n+\t */\n+\tswitch (cfg->ext_port_speed) {\n+\tcase 10:\n+\t\tpcs = FM10K_SW_EPL_PCS_SEL_10GBASER;\n+\t\tqpl = FM10K_SW_EPL_QPL_MODE_L1_L1_L1_L1;\n+\t\tdic_enable = 1;\n+\t\tanti_bubble_wm = 5;\n+\t\trate_fifo_wm = 3;\n+\t\trate_fifo_slow_inc = 12;\n+\t\trate_fifo_fast_inc = 13;\n+\t\tbreak;\n+\tcase 25:\n+\t\tpcs = FM10K_SW_EPL_PCS_SEL_100GBASER;\n+\t\tqpl = FM10K_SW_EPL_QPL_MODE_L1_L1_L1_L1;\n+\t\tdic_enable = 0;\n+\t\tanti_bubble_wm = 6;\n+\t\trate_fifo_wm = 3;\n+\t\trate_fifo_slow_inc = 32;\n+\t\trate_fifo_fast_inc = 33;\n+\t\tbreak;\n+\tcase 40:\n+\t\tpcs = FM10K_SW_EPL_PCS_SEL_40GBASER;\n+\t\tqpl = FM10K_SW_EPL_QPL_MODE_L4_XX_XX_XX;\n+\t\tdic_enable = 1;\n+\t\tanti_bubble_wm = 4;\n+\t\trate_fifo_wm = 5;\n+\t\trate_fifo_slow_inc = 51;\n+\t\trate_fifo_fast_inc = 52;\n+\t\tbreak;\n+\tcase 100:\n+\t\tpcs = FM10K_SW_EPL_PCS_SEL_100GBASER;\n+\t\tqpl = FM10K_SW_EPL_QPL_MODE_L4_XX_XX_XX;\n+\t\tdic_enable = 1;\n+\t\tanti_bubble_wm = 4;\n+\t\trate_fifo_wm = 3;\n+\t\trate_fifo_slow_inc = 129;\n+\t\trate_fifo_fast_inc = 130;\n+\t\tbreak;\n+\tdefault:\n+\t\terror = -1;\n+\t\tgoto done;\n+\t}\n+\n+\t/*\n+\t * EPL_CFG_A\n+\t *\n+\t * Mark all used lanes as active and all unused lanes as\n+\t * inactive. Adjust timeout and skew tolerance values for EPLs that\n+\t * are used.\n+\t */\n+\tfor (i = 0; i < FM10K_SW_EPLS_MAX; i++) {\n+\t\tdata = fm10k_read_switch_reg(sw, FM10K_SW_EPL_CFG_A(i));\n+\t\tdata &= ~FM10K_SW_EPL_CFG_A_ACTIVE_QUAD;\n+\t\tif (FM10K_SW_EXT_PORTS_EPL_USED(ext_ports, i)) {\n+\t\t\tfor (j = 0; j < ext_ports->num_ports; j++) {\n+\t\t\t\tport = &ext_ports->ports[j];\n+\t\t\t\tif (port->eplno == i)\n+\t\t\t\t\tdata |= port->is_quad ?\n+\t\t\t\t\t    FM10K_SW_EPL_CFG_A_ACTIVE_QUAD :\n+\t\t\t\t\t    FM10K_SW_EPL_CFG_A_ACTIVE\n+\t\t\t\t\t\t(port->first_lane);\n+\t\t\t}\n+\t\t\tFM10K_SW_REPLACE_REG_FIELD(data,\n+\t\t\t\t\tEPL_CFG_A_TIMEOUT, 19, data);\n+\t\t\tFM10K_SW_REPLACE_REG_FIELD(data,\n+\t\t\t\t\tEPL_CFG_A_SKEW_TOLERANCE, 38, data);\n+\t\t}\n+\t\tfm10k_write_switch_reg(sw, FM10K_SW_EPL_CFG_A(i), data);\n+\t}\n+\n+\t/*\n+\t * EPL_CFG_B\n+\t *\n+\t * Disable all unused lanes and configure all used ones\n+\t * appropriately.  For EPLs used in quad port mode, the master lane\n+\t * is the only one that gets configured.\n+\t */\n+\tdata = 0;\n+\tfor (i = 0; i < FM10K_SW_EPLS_MAX; i++) {\n+\t\tif (FM10K_SW_EXT_PORTS_EPL_USED(ext_ports, i)) {\n+\t\t\tfor (j = 0; j < FM10K_SW_EPL_LANES; j++) {\n+\t\t\t\tif (j < ext_ports->ports_per_epl)\n+\t\t\t\t\tpcstmp = pcs;\n+\t\t\t\telse\n+\t\t\t\t\tpcstmp = FM10K_SW_EPL_PCS_SEL_DISABLE;\n+\t\t\t\tdata |=\n+\t\t\t\t    FM10K_SW_MAKE_REG_FIELD_IDX\n+\t\t\t\t\t(EPL_CFG_B_PCS_SEL, j, pcstmp, j, j);\n+\t\t\t}\n+\t\t\tdata |=\n+\t\t\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t\t\t(EPL_CFG_B_QPL_MODE, qpl);\n+\t\t} else {\n+\t\t\tfor (j = 0; j < FM10K_SW_EPL_LANES; j++)\n+\t\t\t\tdata |=\n+\t\t\t\t    FM10K_SW_MAKE_REG_FIELD_IDX\n+\t\t\t\t\t(EPL_CFG_B_PCS_SEL,\tj,\n+\t\t\t\t\tFM10K_SW_EPL_PCS_SEL_DISABLE, j, j);\n+\t\t\tdata |=\n+\t\t\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t\t\t(EPL_CFG_B_QPL_MODE,\n+\t\t\t\tFM10K_SW_EPL_QPL_MODE_XX_XX_XX_XX);\n+\t\t}\n+\t\tfm10k_write_switch_reg(sw, FM10K_SW_EPL_CFG_B(i), data);\n+\t}\n+\n+\t/*\n+\t * MAC_CFG, LINK_RULES and PCS_ML_BASER_CFG\n+\t *\n+\t * Only EPLs/lanes that are being used are initialized. All others\n+\t * are left at their defaults.\n+\t */\n+\tfor (i = 0; i < FM10K_SW_EPLS_MAX; i++) {\n+\t\tif (!FM10K_SW_EXT_PORTS_EPL_USED(ext_ports, i))\n+\t\t\tcontinue;\n+\t\tfor (j = 0; j < ext_ports->ports_per_epl; j++) {\n+\t\t\tfm10k_read_switch_array(sw, FM10K_SW_MAC_CFG(i, j),\n+\t\t\t    mac_cfg, FM10K_SW_MAC_CFG_ARRAY_SIZE);\n+\n+\t\t\t/* dic enable */\n+\t\t\tFM10K_SW_SET_ARRAY_BIT(mac_cfg,\n+\t\t\t    MAC_CFG_TX_IDLE_ENABLE_DIC,\n+\t\t\t    dic_enable, mac_cfg);\n+\n+\t\t\t/* ifg */\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_IDLE_MIN_IFG_BYTES,\n+\t\t\t    12, mac_cfg);\n+\n+\t\t\t/* tx pad size: (64 bytes + 8 preamble) / 4 */\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_MIN_COLUMNS,\n+\t\t\t    18, mac_cfg);\n+\n+\t\t\t/* tx clock compensation */\n+\t\t\ttimeout =\n+\t\t\t    fm10k_switch_ppm_to_tx_clk_compensation_timeout(pcs,\n+\t\t\t\t100);\n+\t\t\tFM10K_SW_SET_ARRAY_BIT(mac_cfg,\n+\t\t\t    MAC_CFG_TX_CLOCK_COMPENSATION_ENABLE,\n+\t\t\t    (timeout > 0), mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_CLOCK_COMPENSATION_TIMEOUT,\n+\t\t\t    timeout, mac_cfg);\n+\n+\t\t\tFM10K_SW_SET_ARRAY_BIT(mac_cfg,\n+\t\t\t    MAC_CFG_PREAMBLE_MODE,\n+\t\t\t    0, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_RX_MIN_FRAME_LENGTH,\n+\t\t\t    64, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_RX_MAX_FRAME_LENGTH,\n+\t\t\t    FM10K_SW_PACKET_SIZE_MAX, mac_cfg);\n+\t\t\tFM10K_SW_SET_ARRAY_BIT(mac_cfg,\n+\t\t\t    MAC_CFG_RX_IGNORE_IFG_ERRORS,\n+\t\t\t    0, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_FCS_MODE,\n+\t\t\t    FM10K_SW_TX_MAX_FCS_MODE_REPLACE_NORMAL, mac_cfg);\n+\n+\t\t\tFM10K_SW_SET_ARRAY_BIT(mac_cfg,\n+\t\t\t    MAC_CFG_IEEE_1588_ENABLE,\n+\t\t\t    0, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_DRAIN_MODE,\n+\t\t\t    FM10K_SW_TX_MAC_DRAIN_MODE_DRAIN_NORMAL, mac_cfg);\n+\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_PC_ACT_TIMEOUT,\n+\t\t\t    100, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_PC_ACT_TIME_SCALE,\n+\t\t\t    3, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_LPI_TIMEOUT,\n+\t\t\t    180, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_LPI_TIME_SCALE,\n+\t\t\t    1, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_LPI_HOLD_TIMEOUT,\n+\t\t\t    20, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_LPI_HOLD_TIME_SCALE,\n+\t\t\t    1, mac_cfg);\n+\n+\t\t\tFM10K_SW_SET_ARRAY_BIT(mac_cfg,\n+\t\t\t    MAC_CFG_TX_LPI_AUTOMATIC,\n+\t\t\t    1, mac_cfg);\n+\t\t\tFM10K_SW_SET_ARRAY_BIT(mac_cfg,\n+\t\t\t    MAC_CFG_TX_LP_IDLE_REQUEST,\n+\t\t\t    0, mac_cfg);\n+\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_FAULT_MODE,\n+\t\t\t    FM10K_SW_TX_MAC_FAULT_MODE_NORMAL, mac_cfg);\n+\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_ANTI_BUBBLE_WATERMARK,\n+\t\t\t    anti_bubble_wm, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_RATE_FIFO_WATERMARK,\n+\t\t\t    rate_fifo_wm, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_RATE_FIFO_FAST_INC,\n+\t\t\t    rate_fifo_fast_inc, mac_cfg);\n+\t\t\tFM10K_SW_REPLACE_ARRAY_FIELD(mac_cfg,\n+\t\t\t    MAC_CFG_TX_RATE_FIFO_SLOW_INC,\n+\t\t\t    rate_fifo_slow_inc, mac_cfg);\n+\n+\t\t\tfm10k_write_switch_array(sw, FM10K_SW_MAC_CFG(i, j),\n+\t\t\t    mac_cfg, FM10K_SW_MAC_CFG_ARRAY_SIZE);\n+\n+\t\t\tdata =\n+\t\t\t\tfm10k_read_switch_reg(sw,\n+\t\t\t\t\tFM10K_SW_LINK_RULES(i, j));\n+\n+\t\t\t/* link-up debounce params */\n+\t\t\tFM10K_SW_REPLACE_REG_FIELD(data,\n+\t\t\t    LINK_RULES_FAULT_TIME_SCALE_UP,\n+\t\t\t    4, data);\n+\t\t\tFM10K_SW_REPLACE_REG_FIELD(data,\n+\t\t\t    LINK_RULES_FAULT_TICKS_UP,\n+\t\t\t    30, data);\n+\n+\t\t\t/* link-down debounce params */\n+\t\t\tFM10K_SW_REPLACE_REG_FIELD(data,\n+\t\t\t    LINK_RULES_FAULT_TIME_SCALE_DOWN,\n+\t\t\t    4, data);\n+\t\t\tFM10K_SW_REPLACE_REG_FIELD(data,\n+\t\t\t    LINK_RULES_FAULT_TICKS_DOWN,\n+\t\t\t    5, data);\n+\n+\t\t\tFM10K_SW_REPLACE_REG_FIELD(data,\n+\t\t\t    LINK_RULES_HEARTBEAT_TIME_SCALE,\n+\t\t\t    cfg->ext_port_speed == 10 ? 4 : 0, data);\n+\t\t\tfm10k_write_switch_reg(sw,\n+\t\t\t\tFM10K_SW_LINK_RULES(i, j), data);\n+\t\t}\n+\n+\t\tif (cfg->ext_port_speed != 10)\n+\t\t\tfm10k_write_switch_reg(sw,\n+\t\t\t\tFM10K_SW_PCS_ML_BASER_CFG(i), 0x00003fff);\n+\t}\n+\n+\n+\t/*\n+\t * LANE_CFG, LANE_SERDES_CFG, LANE_ENERGY_DETECT_CFG,\n+\t * LANE_SIGNAL_DETECT_CFG, and EPL_FIFO_ERROR_STATUS\n+\t *\n+\t * Only EPLs/lanes that are being used are initialized. All others\n+\t * are left at their defaults.\n+\t */\n+\tfor (i = 0; i < FM10K_SW_EPLS_MAX; i++) {\n+\t\tif (!FM10K_SW_EXT_PORTS_EPL_USED(ext_ports, i))\n+\t\t\tcontinue;\n+\t\tfor (j = 0; j < ext_ports->ports_per_epl; j++) {\n+\t\t\tfm10k_write_switch_reg(sw,\n+\t\t\t\tFM10K_SW_LANE_CFG(i, j), 0);\n+\t\t\tfm10k_write_switch_reg(sw,\n+\t\t\t\tFM10K_SW_LANE_SERDES_CFG(i, j), 0x1106);\n+\n+\t\t\tdata = fm10k_read_switch_reg(sw,\n+\t\t\t    FM10K_SW_LANE_ENERGY_DETECT_CFG(i, j));\n+\n+\t\t\tdata |=\n+\t\t\tFM10K_SW_LANE_ENERGY_DETECT_CFG_ED_MASK_RX_SIGNAL_OK |\n+\t\t\tFM10K_SW_LANE_ENERGY_DETECT_CFG_ED_MASK_RX_RDY |\n+\t\t\tFM10K_SW_LANE_ENERGY_DETECT_CFG_ED_MASK_RX_ACTIVITY;\n+\n+\t\t\tdata &=\n+\t\t\t~FM10K_SW_LANE_ENERGY_DETECT_CFG_ED_MASK_ENERGY_DETECT;\n+\t\t\tfm10k_write_switch_reg(sw,\n+\t\t\t    FM10K_SW_LANE_ENERGY_DETECT_CFG(i, j), data);\n+\n+\t\t\tdata = fm10k_read_switch_reg(sw,\n+\t\t\t    FM10K_SW_LANE_SIGNAL_DETECT_CFG(i, j));\n+\n+\t\t\tdata &=\n+\t\t\t~(FM10K_SW_LANE_SIGNAL_DETECT_CFG_SD_MASK_RX_SIGNAL_OK |\n+\t\t\tFM10K_SW_LANE_SIGNAL_DETECT_CFG_SD_MASK_RX_RDY);\n+\n+\t\t\tdata |=\n+\t\t\tFM10K_SW_LANE_SIGNAL_DETECT_CFG_SD_MASK_RX_ACTIVITY |\n+\t\t\tFM10K_SW_LANE_SIGNAL_DETECT_CFG_SD_MASK_ENERGY_DETECT;\n+\n+\t\t\tfm10k_write_switch_reg(sw,\n+\t\t\t    FM10K_SW_LANE_SIGNAL_DETECT_CFG(i, j), data);\n+\n+\t\t\tdata = 0;\n+\t\t\tdata |= ((1 << j) << 4) | (1 << j);\n+\t\t\tfm10k_write_switch_reg(sw,\n+\t\t\t    FM10K_SW_EPL_FIFO_ERROR_STATUS(i), data);\n+\t\t}\n+\t}\n+\n+\terror = fm10k_epl_serdes_reset_and_load_all(sw);\n+\tif (error)\n+\t\tgoto done;\n+\n+\t/*\n+\t * EPL_FIFO_ERROR_STATUS LINK_IP\n+\t */\n+\tfor (i = 0; i < FM10K_SW_EPLS_MAX; i++) {\n+\t\tif (!FM10K_SW_EXT_PORTS_EPL_USED(ext_ports, i))\n+\t\t\tcontinue;\n+\t\tfor (j = 0; j < ext_ports->ports_per_epl; j++) {\n+\t\t\tfm10k_write_switch_reg(sw,\n+\t\t\t    FM10K_SW_LINK_IP(i, j), FM10K_SW_MASK32(31, 0));\n+\t\t}\n+\n+\t\tdata = 0;\n+\t\tdata |= ((1 << j) << 4) | (1 << j);\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_EPL_FIFO_ERROR_STATUS(i), data);\n+\t}\n+done:\n+\treturn (error);\n+}\n+\n+int fm10k_switch_dpdk_port_no_get(struct fm10k_hw *hw);\n+\n+int\n+fm10k_switch_mirror_set(struct fm10k_hw *hw, u16 dest_port, u16 vlan)\n+{\n+\tstruct fm10k_switch *sw = &fm10k_sw;\n+\tint src_port = fm10k_switch_dpdk_port_no_get(hw);\n+\n+\t/* source port is external port number */\n+\tif (src_port < 0 || src_port == dest_port)\n+\t\treturn -1;\n+\n+\treturn fm10k_ffu_mirror_set(sw, src_port, dest_port, vlan);\n+}\n+\n+int fm10k_switch_mirror_reset(struct fm10k_hw *hw)\n+{\n+\tstruct fm10k_switch *sw = &fm10k_sw;\n+\tint src_port = fm10k_switch_dpdk_port_no_get(hw);\n+\n+\tif (src_port < 0)\n+\t\treturn -1;\n+\n+\treturn fm10k_ffu_mirror_reset(sw, src_port);\n+}\n+\n+\n+typedef struct {\n+\tu8 lport;\n+\tu8 has_ftag;\n+} fm10k_sw_lport;\n+\n+static int\n+fm10k_switch_init(struct fm10k_hw *hw, struct fm10k_switch *sw)\n+{\n+\tu32 data;\n+\tunsigned int num_lports = sw->info->num_peps + FM10K_SW_EPLS_SUPPORTED;\n+\tfm10k_sw_lport all_lports[num_lports];\n+\tstruct fm10k_device_info *cfg = sw->info;\n+\tunsigned int i;\n+\tunsigned int is_quad;\n+\tunsigned int table_idx;\n+\tint error;\n+\tu32 watermark;\n+\tu64 data64, data64_2;\n+\n+\t/*\n+\t * Build list of all logical ports that might appear in the\n+\t * scheduler program.  Note that for any particular card\n+\t * configuration, not all of these logical ports may be used.\n+\t */\n+\ttable_idx = 0;\n+\tfor (i = 0; i < sw->info->num_peps; i++, table_idx++) {\n+\t\tall_lports[table_idx].lport = sw->pep_map[i].logical_port;\n+\t\tall_lports[table_idx].has_ftag = 1;\n+\t}\n+\tfor (i = 0; i < FM10K_SW_EPLS_SUPPORTED; i++, table_idx++) {\n+\t\tall_lports[table_idx].lport = sw->epl_map[i].logical_port;\n+\t\tall_lports[table_idx].has_ftag = 0;\n+\t}\n+\n+\tif (table_idx != num_lports) {\n+\t\tFM10K_SW_ERR(\"fm10k switch lport table construction error\");\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * Reset the switch to get to the default state\n+\t */\n+\tdata = fm10k_read_switch_reg(sw, FM10K_SW_SOFT_RESET);\n+\tdata &= ~FM10K_SW_SOFT_RESET_SWITCH_READY;\n+\tfm10k_write_switch_reg(sw, FM10K_SW_SOFT_RESET, data);\n+\tfm10k_write_flush(sw);\n+\n+\tusec_delay(100);\n+\tdata = fm10k_read_switch_reg(sw, FM10K_SW_SOFT_RESET);\n+\tdata |= FM10K_SW_SOFT_RESET_SWITCH_RESET |\n+\t\t\tFM10K_SW_SOFT_RESET_EPL_RESET;\n+\tfm10k_write_switch_reg(sw, FM10K_SW_SOFT_RESET, data);\n+\tfm10k_write_flush(sw);\n+\tusec_delay(1000);\n+\n+\t/* Clear memories */\n+\tfm10k_write_switch_reg64(sw, FM10K_SW_BIST_CTRL,\n+\t    FM10K_SW_BIST_CTRL_BIST_MODE_FABRIC |\n+\t    FM10K_SW_BIST_CTRL_BIST_MODE_TUNNEL |\n+\t    FM10K_SW_BIST_CTRL_BIST_MODE_EPL);\n+\tfm10k_write_flush(sw);\n+\n+\tfm10k_write_switch_reg64(sw, FM10K_SW_BIST_CTRL,\n+\t    FM10K_SW_BIST_CTRL_BIST_MODE_FABRIC |\n+\t    FM10K_SW_BIST_CTRL_BIST_MODE_TUNNEL |\n+\t    FM10K_SW_BIST_CTRL_BIST_MODE_EPL |\n+\t    FM10K_SW_BIST_CTRL_BIST_RUN_FABRIC |\n+\t    FM10K_SW_BIST_CTRL_BIST_RUN_TUNNEL |\n+\t    FM10K_SW_BIST_CTRL_BIST_RUN_EPL);\n+\tfm10k_write_flush(sw);\n+\tusec_delay(800);\n+\n+\tfm10k_write_switch_reg64(sw, FM10K_SW_BIST_CTRL, 0);\n+\tfm10k_write_flush(sw);\n+\n+\tdata = fm10k_read_switch_reg(sw, FM10K_SW_SOFT_RESET);\n+\tdata &= ~(FM10K_SW_SOFT_RESET_SWITCH_RESET |\n+\t\t\tFM10K_SW_SOFT_RESET_EPL_RESET);\n+\tfm10k_write_switch_reg(sw, FM10K_SW_SOFT_RESET, data);\n+\tfm10k_write_flush(sw);\n+\t/* ensure switch reset is deasserted for at least 100ns */\n+\tusec_delay(1);\n+\n+\tsw->epl_sbus = fm10k_sbus_attach(sw, \"EPL\", FM10K_SW_SBUS_EPL_CFG);\n+\tif (sw->epl_sbus == NULL) {\n+\t\terror = -1;\n+\t\tgoto done;\n+\t}\n+\n+\t/* Clear non-BIST accessible pause state memories */\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t    FM10K_SW_CM_EGRESS_PAUSE_COUNT(i, 0), 0);\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t    FM10K_SW_CM_EGRESS_PAUSE_COUNT(i, 1), 0);\n+\t}\n+\n+\t/* Initialize RXQ_MCAST list */\n+\tfor (i = 0; i < FM10K_SW_SCHED_RXQ_STORAGE_POINTERS_ENTRIES; i++) {\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t    FM10K_SW_SCHED_RXQ_STORAGE_POINTERS(i),\n+\t\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t\t(SCHED_RXQ_STORAGE_POINTERS_HEAD_PAGE, i) |\n+\t\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t\t(SCHED_RXQ_STORAGE_POINTERS_TAIL_PAGE, i));\n+\t}\n+\tfor (i = 0;\n+\t     i < FM10K_SW_SCHED_RXQ_FREELIST_INIT_ENTRIES -\n+\t\t FM10K_SW_SCHED_RXQ_STORAGE_POINTERS_ENTRIES; i++) {\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_SCHED_RXQ_FREELIST_INIT,\n+\t\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t\t(SCHED_RXQ_FREELIST_INIT_ADDRESS,\n+\t\t\ti + FM10K_SW_SCHED_RXQ_STORAGE_POINTERS_ENTRIES));\n+\t}\n+\t/* Initialize TXQ list */\n+\tfor (i = 0; i < FM10K_SW_SCHED_TXQ_HEAD_PERQ_ENTRIES; i++) {\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_SCHED_TXQ_HEAD_PERQ(i),\n+\t\t    FM10K_SW_MAKE_REG_FIELD(SCHED_TXQ_HEAD_PERQ_HEAD, i));\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_SCHED_TXQ_TAIL0_PERQ(i),\n+\t\t    FM10K_SW_MAKE_REG_FIELD(SCHED_TXQ_TAIL0_PERQ_TAIL, i));\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_SCHED_TXQ_TAIL1_PERQ(i),\n+\t\t    FM10K_SW_MAKE_REG_FIELD(SCHED_TXQ_TAIL1_PERQ_TAIL, i));\n+\t}\n+\tfor (i = 0;\n+\t     i < FM10K_SW_SCHED_TXQ_FREELIST_INIT_ENTRIES -\n+\t\t FM10K_SW_SCHED_TXQ_HEAD_PERQ_ENTRIES; i++) {\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_SCHED_TXQ_FREELIST_INIT,\n+\t\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t\t(SCHED_TXQ_FREELIST_INIT_ADDRESS,\n+\t\t\ti + FM10K_SW_SCHED_TXQ_HEAD_PERQ_ENTRIES));\n+\t}\n+\t/* Initialize free segment list */\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_SCHED_SSCHED_RX_PERPORT(i),\n+\t\t    FM10K_SW_MAKE_REG_FIELD(SCHED_SSCHED_RX_PERPORT_NEXT, i));\n+\t}\n+\tfor (i = 0;\n+\t     i < FM10K_SW_SCHED_FREELIST_INIT_ENTRIES -\n+\t\t FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_SCHED_FREELIST_INIT,\n+\t\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t\t(SCHED_FREELIST_INIT_ADDRESS,\n+\t\t\ti + FM10K_SW_LOGICAL_PORTS_MAX));\n+\t}\n+\t/* Disable switch scan chain */\n+\tfm10k_write_switch_reg(sw,\n+\t\tFM10K_SW_SCAN_DATA_IN,\n+\t    FM10K_SW_SCAN_DATA_IN_UPDATE_NODES |\n+\t\tFM10K_SW_SCAN_DATA_IN_PASSTHRU);\n+\n+\terror = fm10k_switch_configure_epls(hw, sw);\n+\tif (error)\n+\t\tgoto done;\n+\n+\t/*\n+\t * for now configure store-and-forward between PEPs and external\n+\t * ports regardless of relative speeds\n+\t */\n+\tfor (i = 0; i < num_lports; i++) {\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t    FM10K_SW_SAF_MATRIX(all_lports[i].lport),\n+\t\t    FM10K_SW_SAF_MATRIX_ENABLE_SNF_ALL_PORTS);\n+\t}\n+\n+\t/* Disable MTU violation trap */\n+\tdata = fm10k_read_switch_reg(sw, FM10K_SW_SYS_CFG_1);\n+\tdata &= ~FM10K_SW_SYS_CFG_1_TRAP_MTU_VIOLATIONS;\n+\tfm10k_write_switch_reg(sw, FM10K_SW_SYS_CFG_1, data);\n+\n+\t/* Disable ingress VLAN filtering and learning */\n+\tfor (i = 0; i < num_lports; i++) {\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_PORT_CFG_3(all_lports[i].lport), 0);\n+\t}\n+\t/*\n+\t * Make all ports members of every VLAN, and configure every VLAN to\n+\t * use MST instance 0.\n+\t */\n+\tdata64 = 0;\n+\tfor (i = 0; i < num_lports; i++)\n+\t\tdata64 |=\n+\t\t\tFM10K_SW_INGRESS_VID_TABLE_MEMBERSHIP\n+\t\t\t(all_lports[i].lport);\n+\tfor (i = 0; i < FM10K_SW_INGRESS_VID_TABLE_ENTRIES; i++) {\n+\t\tfm10k_write_switch_reg128(sw, FM10K_SW_INGRESS_VID_TABLE(i),\n+\t\t    FM10K_SW_INGRESS_VID_TABLE_REFLECT, data64);\n+\t}\n+\tdata64 = 0;\n+\tfor (i = 0; i < num_lports; i++)\n+\t\tdata64 |=\n+\t\t\tFM10K_SW_EGRESS_VID_TABLE_MEMBERSHIP\n+\t\t\t(all_lports[i].lport);\n+\tfor (i = 0; i < FM10K_SW_EGRESS_VID_TABLE_ENTRIES; i++)\n+\t\tfm10k_write_switch_reg128(sw,\n+\t\t\tFM10K_SW_EGRESS_VID_TABLE(i), 0, data64);\n+\n+\t/* Init MOD_VLAN_TAG_VID1_MAP */\n+\tfor (i = 0; i < FM10K_SW_INGRESS_VID_TABLE_ENTRIES; i++) {\n+\t\tdata64 = i;\n+\t\tdata64 = data64 << 48;\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t\t0xE80000 + 0x2 * i + 0x20000, data64);\n+\t}\n+\n+\t/* Configure MST instance 0 to forward for all ports */\n+\tdata64 = 0;\n+\tfor (i = 0; i < num_lports; i++)\n+\t\tdata64 |=\n+\t\t\tFM10K_SW_EGRESS_MST_TABLE_FORWARDING\n+\t\t\t(all_lports[i].lport);\n+\tfm10k_write_switch_reg64(sw,\n+\t\t\tFM10K_SW_EGRESS_MST_TABLE(0), data64);\n+\n+\tdata64 = 0;\n+\tdata64_2 = 0;\n+\tfor (i = 0; i < num_lports; i++) {\n+\t\tif (all_lports[i].lport <\n+\t\t    FM10K_SW_INGRESS_MST_TABLE_PORTS_PER_TABLE) {\n+\t\t\tdata64 |=\n+\t\t\t    FM10K_SW_MAKE_REG_FIELD_IDX64\n+\t\t\t\t(INGRESS_MST_TABLE_STP_STATE,\n+\t\t\t\tall_lports[i].lport,\n+\t\t\t\tFM10K_SW_INGRESS_MST_TABLE_STP_STATE_FORWARD,\n+\t\t\t\tall_lports[i].lport, all_lports[i].lport);\n+\t\t} else {\n+\t\t\tdata64_2 |=\n+\t\t\t    FM10K_SW_MAKE_REG_FIELD_IDX64\n+\t\t\t\t(INGRESS_MST_TABLE_STP_STATE,\n+\t\t\t\tall_lports[i].lport,\n+\t\t\t\tFM10K_SW_INGRESS_MST_TABLE_STP_STATE_FORWARD,\n+\t\t\t\tall_lports[i].lport, all_lports[i].lport);\n+\t\t}\n+\t}\n+\tfm10k_write_switch_reg64(sw,\n+\t\t\tFM10K_SW_INGRESS_MST_TABLE(0, 0), data64);\n+\tfm10k_write_switch_reg64(sw,\n+\t\t\tFM10K_SW_INGRESS_MST_TABLE(1, 0), data64_2);\n+\n+\tfor (i = 0; i < num_lports; i++) {\n+\t\tdata64 = fm10k_read_switch_reg64(sw,\n+\t\t    FM10K_SW_PARSER_PORT_CFG_1(all_lports[i].lport));\n+\t\tdata64 |= FM10K_SW_PARSER_PORT_CFG_1_VLAN1_TAG(0) |\n+\t\t\t\t  FM10K_SW_PARSER_PORT_CFG_1_VLAN2_TAG(0);\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t    FM10K_SW_PARSER_PORT_CFG_1(all_lports[i].lport), data64);\n+\n+\t\t/*\n+\t\t * Configure tags for f-tagged lports\n+\t\t */\n+\t\tif (all_lports[i].has_ftag) {\n+\t\t\tdata64 = fm10k_read_switch_reg64(sw,\n+\t\t\t    FM10K_SW_PARSER_PORT_CFG_1(all_lports[i].lport));\n+\t\t\tdata64 |= FM10K_SW_PARSER_PORT_CFG_1_FTAG;\n+\t\t\tfm10k_write_switch_reg64(sw,\n+\t\t\t    FM10K_SW_PARSER_PORT_CFG_1(all_lports[i].lport),\n+\t\t\t    data64);\n+\n+\t\t\tdata64 = fm10k_read_switch_reg64(sw,\n+\t\t\t    FM10K_SW_MOD_PER_PORT_CFG_2(all_lports[i].lport));\n+\t\t\tdata64 |= FM10K_SW_MOD_PER_PORT_CFG_2_FTAG;\n+\t\t\tfm10k_write_switch_reg64(sw,\n+\t\t\t    FM10K_SW_MOD_PER_PORT_CFG_2(all_lports[i].lport),\n+\t\t\t    data64);\n+\t\t}\n+\t\tdata64 = fm10k_read_switch_reg64(sw,\n+\t\t    FM10K_SW_PARSER_PORT_CFG_2(all_lports[i].lport));\n+\t\tdata64 |= FM10K_SW_PARSER_PORT_CFG_2_PARSE_L3;\n+\t\tdata64 |= FM10K_SW_PARSER_PORT_CFG_2_PARSE_L4;\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t    FM10K_SW_PARSER_PORT_CFG_2(all_lports[i].lport), data64);\n+\t}\n+\n+\t/*\n+\t * Assign default SGLORTs for the EPL ports in the PARSER config.\n+\t * This isn't necessary for the PEPs as for those, as all frames\n+\t * ingressing from PEPs are tagged with an SGLORT that is derived\n+\t * from a per-tx-queue setting.\n+\t *\n+\t * The PORT_CFG_ISL register offset is determined by logical port\n+\t * number and the register contents determined by the corresponding\n+\t * SGLORT.\n+\t */\n+\tfor (i = 0; i < FM10K_SW_EPLS_SUPPORTED; i++) {\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t\t    FM10K_SW_PORT_CFG_ISL\n+\t\t\t\t(fm10k_sw.epl_map[i].logical_port),\n+\t\t\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t\t\t(PORT_CFG_ISL_SGLORT,\n+\t\t\t\tfm10k_sw.epl_map[i].glort));\n+\t}\n+\n+\t/*\n+\t * FFU counter, 11.10.3.5 POLICER_CFG[0..3]\n+\t */\n+\tfm10k_write_switch_reg64(sw,\n+\t\t\t0xE40000 + 0x2 * FM10K_SW_FFU_CNT_BANK + 0x11000,\n+\t\t\tFM10K_SW_POLICER_LAST);\n+\n+\t/*\n+\t * 11.10.3.1 POLICER_CFG_4K[0..1][0..4095]\n+\t * 11.10.3.2 POLICER_CFG_512[0..1][0..511]\n+\t */\n+\tfor (i = 0; i < FM10K_SW_FFU_CNT_MAX; i++) {\n+\t\tif (FM10K_SW_FFU_CNT_BANK < 2) {\n+\t\t\tfm10k_read_switch_reg64(sw,\n+\t\t\t\t0xE40000 + 0x2000 * FM10K_SW_FFU_CNT_BANK +\n+\t\t\t\t0x2 * (i + FM10K_SW_FFU_CNT_START) + 0x0);\n+\t\t} else {\n+\t\t\tfm10k_read_switch_reg64(sw,\n+\t\t\t\t0xE40000 + 0x400 * (FM10K_SW_FFU_CNT_BANK - 2) +\n+\t\t\t\t0x2 * (i + FM10K_SW_FFU_CNT_START) + 0x4000);\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * FFU\n+\t *\n+\t * The FFU is programmed to match on SGLORT and to set the DGLORT to\n+\t * a unique value corresponding to the given SGLORT.  One TCAM entry\n+\t * is required per host port per PEP and one per external interface.\n+\t * Only slice 0 is used.\n+\t */\n+\tif (fm10k_ffu_init(sw, sw->dpdk_cfg) < 0)\n+\t\treturn -1;\n+\n+\t/*\n+\t * Program the segment scheduler (see tables at top)\n+\t *\n+\t * The TX and RX schedules are the same.  Page 0 is used.\n+\t */\n+\tif (cfg->ext_port_speed == 40 || cfg->ext_port_speed == 100)\n+\t\tis_quad = 1;\n+\telse\n+\t\tis_quad = 0;\n+\tfor (i = 0;\n+\t\t\ti < sizeof(fm10k_sched_prog) /\n+\t\t\t\tsizeof(fm10k_sched_prog[0]);\n+\t\t\ti++) {\n+\t\t/*\n+\t\t * In addition to explicit idle cycles, non-quad port\n+\t\t * entries are converted to idle cycles if the interfaces\n+\t\t * are configured in quad-port mode.\n+\t\t */\n+\t\tif (fm10k_sched_prog[i].idle ||\n+\t\t    (!fm10k_sched_prog[i].quad && is_quad))\n+\t\t\tdata = FM10K_SW_SCHED_SCHEDULE_IDLE;\n+\t\telse\n+\t\t\tdata = FM10K_SW_SCHED_SCHEDULE_ENTRY\n+\t\t\t\t(fm10k_sched_prog[i].phys,\n+\t\t\t    fm10k_sched_prog[i].log,\n+\t\t\t    (fm10k_sched_prog[i].quad == FM10K_SW_QUAD_40_100) ?\n+\t\t\t    is_quad : fm10k_sched_prog[i].quad);\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t\tFM10K_SW_SCHED_RX_SCHEDULE(0, i), data);\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t\tFM10K_SW_SCHED_TX_SCHEDULE(0, i), data);\n+\t}\n+\n+\tfm10k_write_switch_reg(sw, FM10K_SW_SCHED_SCHEDULE_CTRL,\n+\t    FM10K_SW_SCHED_SCHEDULE_CTRL_RX_ENABLE |\n+\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t(SCHED_SCHEDULE_CTRL_RX_MAX_INDEX,\n+\t\t(sizeof(fm10k_sched_prog) /\n+\t\tsizeof(fm10k_sched_prog[0])) - 1) |\n+\t    FM10K_SW_SCHED_SCHEDULE_CTRL_TX_ENABLE |\n+\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t(SCHED_SCHEDULE_CTRL_TX_MAX_INDEX,\n+\t\t(sizeof(fm10k_sched_prog) /\n+\t\tsizeof(fm10k_sched_prog[0])) - 1));\n+\n+\t/* Per 5.7.10.4 */\n+\twatermark = FM10K_SW_MEM_POOL_SEGS_MAX -\n+\t    ((sw->info->num_peps +\n+\t    FM10K_SW_EPLS_SUPPORTED * FM10K_SW_EPL_LANES) *\n+\t    FM10K_SW_HOWMANY(FM10K_SW_PACKET_SIZE_MAX,\n+\t    FM10K_SW_MEM_POOL_SEG_SIZE, FM10K_SW_MEM_POOL_SEG_SIZE)) -\n+\t    FM10K_SW_MEM_POOL_SEGS_RSVD;\n+\tfm10k_write_switch_reg(sw, FM10K_SW_CM_GLOBAL_WM,\n+\t    FM10K_SW_MAKE_REG_FIELD(CM_GLOBAL_WM_WATERMARK, watermark));\n+\tfm10k_write_switch_reg(sw, FM10K_SW_CM_GLOBAL_CFG,\n+\t    FM10K_SW_CM_GLOBAL_CFG_WM_SWEEP_EN |\n+\t    FM10K_SW_CM_GLOBAL_CFG_PAUSE_GEN_SWEEP_EN |\n+\t    FM10K_SW_CM_GLOBAL_CFG_PAUSE_REC_SWEEP_EN |\n+\t    FM10K_SW_MAKE_REG_FIELD\n+\t\t(CM_GLOBAL_CFG_NUM_SWEEPER_PORTS,\n+\t\tFM10K_SW_LOGICAL_PORTS_MAX));\n+\n+\t/* Configure stats counters */\n+\tdata = FM10K_SW_RX_STATS_CFG_ENABLE_ALL_BANKS;\n+\tdata64 =\n+\t    FM10K_SW_MOD_STATS_CFG_ENABLE_GROUP_7 |\n+\t    FM10K_SW_MOD_STATS_CFG_ENABLE_GROUP_8;\n+\tfor (i = 0; i < num_lports; i++) {\n+\t\tfm10k_write_switch_reg(sw,\n+\t\t    FM10K_SW_RX_STATS_CFG(all_lports[i].lport),\n+\t\t    data |\n+\t\t    ((all_lports[i].has_ftag) ?\n+\t\t\tFM10K_SW_MAKE_REG_FIELD\n+\t\t\t\t(RX_STATS_CFG_PER_FRAME_ADJUSTMENT,\n+\t\t\t    FM10K_SW_FTAG_SIZE) :\n+\t\t\t0));\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t    FM10K_SW_MOD_STATS_CFG(all_lports[i].lport),\n+\t\t    data64);\n+\t}\n+\n+\t/* Transition switch to ready */\n+\tdata = fm10k_read_switch_reg(sw, FM10K_SW_SOFT_RESET);\n+\tdata |= FM10K_SW_SOFT_RESET_SWITCH_READY;\n+\tfm10k_write_switch_reg(sw, FM10K_SW_SOFT_RESET, data);\n+\n+ done:\n+\treturn (error);\n+}\n+\n+\n+static void\n+fm10k_switch_leds_init(struct fm10k_switch *sw)\n+{\n+\tstruct fm10k_device_info *cfg = sw->info;\n+\tunsigned int i;\n+\tuint8_t addr;\n+\tuint32_t data;\n+\tint max;\n+\n+\tswitch (FM10K_SW_CARD_ID(cfg->subvendor, cfg->subdevice)) {\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QS41):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QS41):\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QS43):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QS43):\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QL4):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QL4):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\t/*\n+\t\t * Set up the first PCA9545 mux so we can get at the PCA9635\n+\t\t * that the LED control lines are connected to.\n+\t\t */\n+\t\tfm10k_i2c_write8(sw->i2c, 0x70, 0x04);\n+\n+\t\t/*\n+\t\t * PCA9635 initialization\n+\t\t * only differences from defaults are noted\n+\t\t */\n+\n+\t\t/* MODE1 - put into sleep mode to ensure it is brought out\n+\t\t * of sleep without violating the oscillator startup wait\n+\t\t */\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x00, 0x10);\n+\t\tfm10k_udelay(10);\n+\n+\t\t/* MODE1 - normal mode, disable all call */\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x00, 0x00);\n+\n+\t\t/* Wait for oscillator to stabilize after coming out of sleep */\n+\t\tfm10k_udelay(500);\n+\n+\t\t/* MODE2 - group control is blinking, open drain outputs,\n+\t\t * OE high -> LEDn = 0\n+\t\t */\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x01, 0x20);\n+\n+\t\t/* PWM0 - 100% duty cycle */\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x02, 0xff);\n+\n+\t\t/* PWM1 - 100% duty cycle */\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x03, 0xff);\n+\n+\t\t/* GRPPWM - 50% blink duty cycle */\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x12, 0x80);\n+\n+\t\t/* GRPFREQ - FM10K_LED_BLINKS_PER_SECOND */\n+\t\tif (24 / FM10K_LED_BLINKS_PER_SECOND > 1)\n+\t\t\tmax = 24 / FM10K_LED_BLINKS_PER_SECOND;\n+\t\telse\n+\t\t\tmax = 1;\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x13, max - 1);\n+\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIR_QXSL4):\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIR_QXSL4_REV_2):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\t/*\n+\t\t * Set up the first PCA9545 mux so we can get at the PCA9635s\n+\t\t * that the LED control lines are connected to.\n+\t\t */\n+\t\tfm10k_i2c_write8(sw->i2c, 0x70, 0x01);\n+\n+\t\t/*\n+\t\t * PCA9635 initialization\n+\t\t * only differences from defaults are noted\n+\t\t */\n+\n+\t\taddr = 0x6a;\n+\t\tfor (i = 0; i < 2; i++) {\n+\t\t\t/* MODE1 - put into sleep mode to ensure it is\n+\t\t\t * brought out of sleep without violating the\n+\t\t\t * oscillator startup wait\n+\t\t\t */\n+\t\t\tfm10k_i2c_write16(sw->i2c, addr, 0x00, 0x10);\n+\t\t\tfm10k_udelay(10);\n+\n+\t\t\t/* MODE1 - normal mode, disable all call */\n+\t\t\tfm10k_i2c_write16(sw->i2c, addr, 0x00, 0x00);\n+\n+\t\t\t/* MODE2 - group control is blinking, open drain\n+\t\t\t * outputs, OE high -> LEDn = 0\n+\t\t\t */\n+\t\t\tfm10k_i2c_write16(sw->i2c, addr, 0x01, 0x20);\n+\n+\t\t\t/* Wait for oscillator to stabilize\n+\t\t\t * after coming out of sleep\n+\t\t\t */\n+\t\t\tfm10k_udelay(500);\n+\n+\t\t\t/* PWM0 - 100% duty cycle */\n+\t\t\tfm10k_i2c_write16(sw->i2c, addr, 0x02, 0xff);\n+\n+\t\t\t/* PWM3 - 100% duty cycle */\n+\t\t\tfm10k_i2c_write16(sw->i2c, addr, 0x05, 0xff);\n+\n+\t\t\t/* GRPPWM - 50% blink duty cycle */\n+\t\t\tfm10k_i2c_write16(sw->i2c, addr, 0x12, 0x80);\n+\n+\t\t\t/* GRPFREQ - FM10K_LED_BLINKS_PER_SECOND */\n+\t\t\tif (24 / FM10K_LED_BLINKS_PER_SECOND > 1)\n+\t\t\t\tmax = 24 / FM10K_LED_BLINKS_PER_SECOND;\n+\t\t\telse\n+\t\t\t\tmax = 1;\n+\t\t\tfm10k_i2c_write16(sw->i2c, addr, 0x13, max - 1);\n+\n+\t\t\taddr = 0x69;\n+\t\t}\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIRL_QXSL4):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\taddr = 0x62;\n+\t\tfm10k_i2c_write16(sw->i2c, addr, 0x03, 0x88);\n+\t\tfm10k_i2c_write16(sw->i2c, addr, 0x01, 0x0);\n+\n+\t\tdata = fm10k_read_switch_reg(sw, 0xc2b);\n+\t\tdata |= 1 << 24;\n+\t\tfm10k_write_switch_reg(sw, 0xc2b, data);\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIRM_QXSL4):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\t/*\n+\t\t * PCA9538 initialization\n+\t\t * only differences from defaults are noted\n+\t\t */\n+\t\t/*\n+\t\t *\t00000000: No link\n+\t\t *\t00000001: 10G Port 0\n+\t\t *  00000010: 40G Port 0\n+\t\t *  00000100: 25G Port 0\n+\t\t *  00001000: 100G Port 0\n+\t\t */\n+\t\taddr = 0x62;\n+\t\tfm10k_i2c_write16(sw->i2c, addr, 0x03, 0x0);\n+\t\tfm10k_i2c_write16(sw->i2c, addr, 0x01, 0x0);\n+\n+\t\taddr = 0x65;\n+\t\tfm10k_i2c_write16(sw->i2c, addr, 0x03, 0xf0);\n+\t\tfm10k_i2c_write16(sw->i2c, addr, 0x01, 0x0);\n+\n+\t\taddr = 0x66;\n+\t\tfm10k_i2c_write16(sw->i2c, addr, 0x03, 0x0);\n+\t\tfm10k_i2c_write16(sw->i2c, addr, 0x01, 0x0);\n+\n+\t\t/* set LEC_CFG */\n+\t\tdata = fm10k_read_switch_reg(sw, 0xc2b);\n+\t\tdata |= 1 << 24;\n+\t\tfm10k_write_switch_reg(sw, 0xc2b, data);\n+\n+\t\t/* port from rdifd, LED */\n+\t\tfm10k_gpio_output_set(sw, 4, 0);\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tFM10K_SW_ERR(\"don't know how to operate LEDs for this card \"\n+\t\t    \"(subvendor=0x%04x subdevice=0x%04x)\",\n+\t\t    cfg->subvendor, cfg->subdevice);\n+\t\tbreak;\n+\t}\n+}\n+\n+\n+static unsigned int\n+fm10k_switch_pca9635_led_bits(uint8_t led_flags)\n+{\n+\tunsigned int bits;\n+\n+\tif (led_flags & FM10K_SW_EXT_PORT_LED_FLAG_UP) {\n+\t\tif (led_flags & FM10K_SW_EXT_PORT_LED_FLAG_ACTIVE)\n+\t\t\tbits = 0x3; /* group blink */\n+\t\telse\n+\t\t\tbits = 0x1; /* full on */\n+\t} else {\n+\t\tbits = 0; /* off */\n+\t}\n+\treturn (bits);\n+}\n+\n+static void\n+fm10k_switch_process_leds(void *ctx)\n+{\n+\tstruct fm10k_switch *sw = ctx;\n+\tstruct fm10k_device_info *cfg = sw->info;\n+\tstruct fm10k_ext_ports *ports = sw->ext_ports;\n+\tstruct fm10k_ext_port *port;\n+\tunsigned int i;\n+\tunsigned int num_ports = ports->num_ports;\n+\tuint32_t data;\n+\tuint8_t update_port[num_ports];\n+\tuint8_t led_flags = 0, read;\n+\tuint8_t addr;\n+\n+\tFM10K_SW_SWITCH_LOCK(sw);\n+\n+\tif (sw->master_hw->sw_addr == NULL) {\n+\t\tFM10K_SW_SWITCH_UNLOCK(sw);\n+\t\treturn;\n+\t}\n+\n+\tfor (i = 0; i < num_ports; i++) {\n+\t\tport = &ports->ports[i];\n+\t\tdata = fm10k_read_switch_reg(sw,\n+\t\t    FM10K_SW_EPL_LED_STATUS(port->eplno));\n+\t\tled_flags =\n+\t\t    ((data & FM10K_SW_EPL_LED_STATUS_PORT_LINK_UP\n+\t\t    (port->first_lane)) ?\n+\t\t\tFM10K_SW_EXT_PORT_LED_FLAG_UP : 0) |\n+\t\t    ((data &\n+\t\t\t(FM10K_SW_EPL_LED_STATUS_PORT_TRANSMITTING\n+\t\t\t(port->first_lane) |\n+\t\t\tFM10K_SW_EPL_LED_STATUS_PORT_RECEIVING\n+\t\t\t(port->first_lane))) ?\n+\t\t\tFM10K_SW_EXT_PORT_LED_FLAG_ACTIVE : 0);\n+\t\tupdate_port[i] = (led_flags != port->last_led_flags);\n+\t\tport->last_led_flags = led_flags;\n+\t}\n+\tFM10K_SW_SWITCH_UNLOCK(sw);\n+\n+\tswitch (FM10K_SW_CARD_ID(cfg->subvendor, cfg->subdevice)) {\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QS41):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QS41):\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QS43):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QS43):\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QL4):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QL4):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\t/*\n+\t\t * Set up the first PCA9545 mux so we can get at the PCA9635\n+\t\t * that the LED control lines are connected to.\n+\t\t */\n+\t\tfm10k_i2c_write8(sw->i2c, 0x70, 0x04);\n+\n+\t\tif (!(update_port[0] || update_port[1])) {\n+\t\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tled_flags =\n+\t\t    fm10k_switch_pca9635_led_bits\n+\t\t\t(ports->ports[0].last_led_flags) |\n+\t\t    (fm10k_switch_pca9635_led_bits\n+\t\t    (ports->ports[1].last_led_flags) << 2);\n+\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x14, led_flags);\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIR_QXSL4):\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIR_QXSL4_REV_2):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\t/*\n+\t\t * Set up the first PCA9545 mux so we can get at the PCA9635s\n+\t\t * that the LED control lines are connected to.\n+\t\t */\n+\t\tfm10k_i2c_write8(sw->i2c, 0x70, 0x01);\n+\n+\t\t/* will need to update for QSFPs operating\n+\t\t * as four independent lanes/ports\n+\t\t */\n+\t\tfor (i = 0; i < 2; i++) {\n+\t\t\tif (update_port[i] == 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\taddr = (i == 0) ? 0x6a : 0x69;\n+\n+\t\t\tport = &ports->ports[i];\n+\t\t\tled_flags =\n+\t\t\t\tfm10k_switch_pca9635_led_bits\n+\t\t\t\t(port->last_led_flags);\n+\n+\t\t\tswitch (port->lane_speed * port->num_lanes) {\n+\t\t\tcase 100:\n+\t\t\t\tfm10k_i2c_write16(sw->i2c,\n+\t\t\t\t\taddr, 0x14, led_flags);\n+\t\t\t\tbreak;\n+\t\t\tcase 40:\n+\t\t\t\tfm10k_i2c_write16(sw->i2c,\n+\t\t\t\t\taddr, 0x14, led_flags << 6);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIRL_QXSL4):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\tled_flags = 0;\n+\t\taddr = 0x62;\n+\t\tfor (i = 0; i < 2; i++) {\n+\t\t\tif (!update_port[i])\n+\t\t\t\tcontinue;\n+\t\t\tport = &ports->ports[i];\n+\t\t\tif (port->last_led_flags &\n+\t\t\t\tFM10K_SW_EXT_PORT_LED_FLAG_UP) {\n+\t\t\t\tswitch (port->lane_speed * port->num_lanes) {\n+\t\t\t\tcase 100:\n+\t\t\t\tcase 25:\n+\t\t\t\t\tled_flags |= 0x6 << (4 * i); /* 100G */\n+\t\t\t\t\tbreak;\n+\t\t\t\tcase 40:\n+\t\t\t\tcase 10:\n+\t\t\t\t\tled_flags |= 0x4 << (4 * i); /* 40G */\n+\t\t\t\t\tbreak;\n+\t\t\t\tdefault:\n+\t\t\t\t\tled_flags = 0;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tled_flags = 0; /* off */\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (update_port[0] || update_port[1]) {\n+\t\t\tfm10k_i2c_read8_ext(sw->i2c, addr, 0x1, &read);\n+\t\t\tif (update_port[0])\n+\t\t\t\tled_flags |= read & 0xf0;\n+\t\t\telse\n+\t\t\t\tled_flags |= read & 0xf;\n+\t\t\tfm10k_i2c_write16(sw->i2c, addr, 0x1, led_flags);\n+\t\t\tfm10k_i2c_read8_ext(sw->i2c, addr, 0x1, &read);\n+\t\t}\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIRM_QXSL4):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\t/* will need to update for QSFPs\n+\t\t * operating as four independent lanes/ports\n+\t\t */\n+\t\tfor (i = 0; i < 2; i++) {\n+\t\t\tif (!update_port[i])\n+\t\t\t\tcontinue;\n+\t\t\t/*\n+\t\t\t *  00000000: No link\n+\t\t\t *  00000001: 10G Port 0\n+\t\t\t *  00000010: 40G Port 0\n+\t\t\t *  00000100: 25G Port 0\n+\t\t\t *  00001000: 100G Port 0\n+\t\t\t */\n+\t\t\taddr = (i == 0) ? 0x62 : 0x66;\n+\t\t\tport = &ports->ports[i];\n+\t\t\tif (port->last_led_flags &\n+\t\t\t\tFM10K_SW_EXT_PORT_LED_FLAG_UP) {\n+\t\t\t\tswitch (port->lane_speed * port->num_lanes) {\n+\t\t\t\tcase 100:\n+\t\t\t\t\tled_flags = 0x08; /* 100G */\n+\t\t\t\t\tbreak;\n+\t\t\t\tcase 40:\n+\t\t\t\t\tled_flags = 0x02; /* 40G */\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tled_flags = 0; /* off */\n+\t\t\t}\n+\t\t\tfm10k_i2c_write16(sw->i2c,\n+\t\t\t\taddr, 0x1, led_flags);\n+\t\t}\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\t}\n+}\n+\n+static void *\n+fm10k_switch_leds_update(void *ctx)\n+{\n+\tstruct fm10k_switch *sw = ctx;\n+\n+\twhile (sw->detaching == 0) {\n+\t\tfm10k_switch_process_leds(ctx);\n+\t\tusec_delay(FM10K_LED_POLL_INTERVAL_MS * 1000);\n+\t}\n+\treturn NULL;\n+}\n+\n+static void\n+fm10k_switch_leds_off(struct fm10k_switch *sw, struct fm10k_ext_ports *ports)\n+{\n+\tstruct fm10k_device_info *cfg = sw->info;\n+\tstruct fm10k_ext_port *port;\n+\tunsigned int i;\n+\tuint8_t led_flags;\n+\tuint8_t addr;\n+\n+\tswitch (FM10K_SW_CARD_ID(cfg->subvendor, cfg->subdevice)) {\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QS41):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QS41):\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QS43):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QS43):\n+\tcase FM10K_SW_CARD(SILICOM, PE340G2DBIR_QL4):\n+\tcase FM10K_SW_CARD(SILICOM_RB, PE340G2DBIR_QL4):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\t/*\n+\t\t * Set up the first PCA9545 mux so we can get at the PCA9635\n+\t\t * that the LED control lines are connected to.\n+\t\t */\n+\t\tfm10k_i2c_write8(sw->i2c, 0x70, 0x04);\n+\n+\t\tled_flags =\n+\t\t    fm10k_switch_pca9635_led_bits(0) |\n+\t\t    (fm10k_switch_pca9635_led_bits(0) << 2);\n+\n+\t\tfm10k_i2c_write16(sw->i2c, 0x6a, 0x14, led_flags);\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIR_QXSL4):\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIR_QXSL4_REV_2):\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIRL_QXSL4):\n+\tcase FM10K_SW_CARD(SILICOM, PE3100G2DQIRM_QXSL4):\n+\t\tFM10K_SW_I2C_REQ_LOCK(sw->i2c);\n+\t\t/*\n+\t\t * Set up the first PCA9545 mux so we can get at the PCA9635s\n+\t\t * that the LED control lines are connected to.\n+\t\t */\n+\t\tfm10k_i2c_write8(sw->i2c, 0x70, 0x01);\n+\n+\t\t/* will need to update for QSFPs\n+\t\t * operating as four independent lanes/ports\n+\t\t */\n+\t\taddr = 0x6a;\n+\t\tled_flags = fm10k_switch_pca9635_led_bits(0);\n+\t\tfor (i = 0; i < 2; i++) {\n+\t\t\tport = &ports->ports[i];\n+\t\t\tswitch (port->lane_speed * port->num_lanes) {\n+\t\t\tcase 100:\n+\t\t\t\tfm10k_i2c_write16(sw->i2c,\n+\t\t\t\t\taddr, 0x14, led_flags);\n+\t\t\t\tbreak;\n+\t\t\tcase 40:\n+\t\t\t\tfm10k_i2c_write16(sw->i2c,\n+\t\t\t\t\taddr, 0x14, led_flags << 6);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\taddr = 0x69;\n+\t\t}\n+\t\tFM10K_SW_I2C_REQ_UNLOCK(sw->i2c);\n+\t\tbreak;\n+\t}\n+}\n+\n+\n+static void *\n+fm10k_switch_process_intr(void *ctx)\n+{\n+\tstruct fm10k_switch *sw = ctx;\n+\tstruct fm10k_ext_ports *ports;\n+\tuint64_t gid;\n+\tuint64_t reenable_mask;\n+\tuint16_t epl_mask;\n+\n+\twhile (sw->detaching == 0) {\n+\t\tsem_wait(&sw->intr_tq);\n+\t\t/*\n+\t\t * Mask off all global interrupt detect interrupts\n+\t\t * toward PCIe to ensure that the PEP sees the\n+\t\t * interrupt condition clear so that all subsequent\n+\t\t * events will be recognized.  The same result could\n+\t\t * be achieved by masking off all block-internal\n+\t\t * interrupt sources in all blocks prior to handling\n+\t\t * any global interrupt detect interrupts, but the\n+\t\t * approach taken here makes the interrupt processing\n+\t\t * easier to decompose and increases the likelihood that\n+\t\t * more work will be coalesced into fewer interrupts.\n+\t\t */\n+\t\tFM10K_SW_TRACE(\"masking off PCIe gid interrupts\");\n+\t\tFM10K_SW_SWITCH_LOCK(sw);\n+\t\t/*\n+\t\t * sw->ext_ports will be set to NULL during detach\n+\t\t * to indicate that we are to no longer process EPL\n+\t\t * interrupts.\n+\t\t */\n+\t\tports = sw->ext_ports;\n+\t\t/*\n+\t\t * sw->sm_mailbox_enabled will be set to 0 during\n+\t\t * detach to indicate that we are to no longer process\n+\t\t * PEP interrupts.\n+\t\t */\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t\tFM10K_SW_INTERRUPT_MASK_PCIE(sw->pepno),\n+\t\t\tFM10K_SW_INTERRUPT_MASK_PCIE_ALL);\n+\t\tgid = fm10k_read_switch_reg64(sw,\n+\t\t\t\tFM10K_SW_GLOBAL_INTERRUPT_DETECT);\n+\t\tFM10K_SW_SWITCH_UNLOCK(sw);\n+\n+\t\treenable_mask = 0;\n+\t\tif (ports) {\n+\t\t\tepl_mask = fm10k_ext_ports_epl_intrs(ports, gid);\n+\t\t\treenable_mask |=\n+\t\t\t\tFM10K_SW_MAKE_REG_FIELD64\n+\t\t\t\t(INTERRUPT_MASK_PCIE_EPL, epl_mask);\n+\t\t}\n+\n+\t\tif (gid & FM10K_SW_GLOBAL_INTERRUPT_DETECT_I2C)\n+\t\t\tfm10k_i2c_intr(sw->i2c);\n+\n+\t\treenable_mask |= FM10K_SW_INTERRUPT_MASK_PCIE_I2C;\n+\n+\t\tFM10K_SW_TRACE(\"re-enabling PCIe gid interrupts\");\n+\t\tFM10K_SW_SWITCH_LOCK(sw);\n+\t\tfm10k_write_switch_reg64(sw,\n+\t\t\tFM10K_SW_INTERRUPT_MASK_PCIE(sw->pepno),\n+\t\t\t~reenable_mask);\n+\t\tFM10K_SW_SWITCH_UNLOCK(sw);\n+\t}\n+\treturn NULL;\n+}\n+\n+void\n+fm10k_switch_intr(struct fm10k_hw *hw)\n+{\n+\tif (hw)\n+\t\tsem_post(&fm10k_sw.intr_tq);\n+}\n+\n+\n+static void\n+fm10k_switch_enable_interrupts(struct fm10k_switch *sw)\n+{\n+\tuint64_t data64;\n+\tunsigned int i;\n+\n+\tdata64 = fm10k_read_switch_reg64(sw,\n+\t\t\tFM10K_SW_INTERRUPT_MASK_PCIE(sw->pepno));\n+\n+\t/* enable interrupts from all EPLs in use */\n+\tFM10K_SW_REPLACE_REG_FIELD64(data64, INTERRUPT_MASK_PCIE_EPL,\n+\t    ~sw->ext_ports->epl_mask, data64);\n+\n+\t/* enable interrupts from all non-master PEPs in use */\n+\tFM10K_SW_REPLACE_REG_FIELD64(data64, INTERRUPT_MASK_PCIE_PCIE,\n+\t    ~sw->pep_mask, data64);\n+\n+\t/* enable I2C interrupt */\n+\tdata64 &= ~FM10K_SW_INTERRUPT_MASK_PCIE_I2C;\n+\tfm10k_write_switch_reg64(sw,\n+\t\tFM10K_SW_INTERRUPT_MASK_PCIE(sw->pepno), data64);\n+\n+\t/* enable outbound mailbox interrupts from all non-master PEPs */\n+\tfor (i = 0; i < FM10K_SW_PEPS_MAX; i++) {\n+\t\tif (sw->pep_mask & (1 << i))\n+\t\t\tfm10k_write_switch_reg(sw, FM10K_SW_PCIE_GLOBAL(i, IM),\n+\t\t\t    ~FM10K_SW_IM_MAILBOX);\n+\t}\n+\tFM10K_WRITE_REG(sw->master_hw,\n+\t\tFM10K_SW_EIMR, FM10K_SW_EIMR_FIELD(SWITCH_INT, ENABLE));\n+}\n+\n+\n+static void\n+fm10k_switch_detach(struct fm10k_hw *hw)\n+{\n+\tstruct fm10k_ext_ports *ports;\n+\tstruct fm10k_switch *sw = &fm10k_sw;\n+\n+\tif (hw == NULL || sw == NULL)\n+\t\treturn;\n+\n+\tFM10K_SW_SWITCH_LOCK(sw);\n+\tsw->detaching = 1;\n+\tFM10K_SW_SWITCH_UNLOCK(sw);\n+\n+\tif (sw->ext_ports) {\n+\t\tports = sw->ext_ports;\n+\t\t/*\n+\t\t * Ensure that any further switch interrupts will not\n+\t\t * process sw->ext_ports before detaching them.\n+\t\t */\n+\t\tFM10K_SW_SWITCH_LOCK(sw);\n+\t\tsw->ext_ports = NULL;\n+\t\tFM10K_SW_SWITCH_UNLOCK(sw);\n+\t\tfm10k_switch_leds_off(sw, ports);\n+\t\tfm10k_ext_ports_detach(ports);\n+\t}\n+\n+\tif (sw->epl_sbus)\n+\t\tfm10k_sbus_detach(sw->epl_sbus);\n+\n+\t/*\n+\t * Detach i2c after ext_ports so ext_ports can use i2c to disable\n+\t * phys.\n+\t */\n+\tif (sw->i2c)\n+\t\tfm10k_i2c_detach(sw->i2c);\n+\n+\tfm10k_hw_eicr_disable_source(sw, FM10K_SW_EICR_SWITCH_INT);\n+\n+\tpthread_join(sw->intr_task, NULL);\n+\tpthread_join(sw->led_task, NULL);\n+\tpthread_join(sw->stats_task, NULL);\n+}\n+\n+\n+static unsigned int\n+fm10k_switch_get_fabric_clock(struct fm10k_switch *sw)\n+{\n+\tuint32_t pll_fabric;\n+\tunsigned int freq;\n+\n+\tpll_fabric = fm10k_read_switch_reg(sw, FM10K_SW_PLL_FABRIC_LOCK);\n+\n+\tswitch (FM10K_SW_REG_FIELD(pll_fabric, PLL_FABRIC_FREQSEL)) {\n+\tcase FM10K_SW_PLL_FABRIC_FREQSEL_CTRL: {\n+\t\tuint32_t ctrl;\n+\t\tunsigned int refdiv, fbdiv4, fbdiv255;\n+\n+\t\tctrl = fm10k_read_switch_reg(sw, FM10K_SW_PLL_FABRIC_CTRL);\n+\t\trefdiv = FM10K_SW_REG_FIELD(ctrl, PLL_FABRIC_REFDIV);\n+\t\tfbdiv4 = FM10K_SW_REG_FIELD(ctrl, PLL_FABRIC_FBDIV4);\n+\t\tfbdiv255 = FM10K_SW_REG_FIELD(ctrl, PLL_FABRIC_FBDIV255);\n+\n+\t\tfreq = (15625 * 4 * fbdiv255 * (1 + fbdiv4)) / (refdiv * 100);\n+\t\tbreak;\n+\t}\n+\tcase FM10K_SW_PLL_FABRIC_FREQSEL_F600:\n+\t\tfreq = 600;\n+\t\tbreak;\n+\tcase FM10K_SW_PLL_FABRIC_FREQSEL_F500:\n+\t\tfreq = 500;\n+\t\tbreak;\n+\tcase FM10K_SW_PLL_FABRIC_FREQSEL_F400:\n+\t\tfreq = 400;\n+\t\tbreak;\n+\tcase FM10K_SW_PLL_FABRIC_FREQSEL_F300:\n+\t\tfreq = 300;\n+\t\tbreak;\n+\tdefault:\n+\t\tfreq = 0;\n+\t\tbreak;\n+\t}\n+\n+\treturn freq;\n+}\n+\n+static unsigned int\n+fm10k_switch_get_sku(struct fm10k_switch *sw)\n+{\n+\tuint32_t fuse_data;\n+\n+\tfuse_data = fm10k_read_switch_reg(sw, FM10K_SW_FUSE_DATA_0);\n+\treturn FM10K_SW_REG_FIELD(fuse_data, FUSE_SKU);\n+}\n+\n+static const char *\n+fm10k_switch_get_sku_name(unsigned int sku)\n+{\n+\tconst char *name;\n+\n+\tswitch (sku) {\n+\tcase FM10K_SW_FUSE_SKU_FM10840:\n+\t\tname = \"FM10840\";\n+\t\tbreak;\n+\tcase FM10K_SW_FUSE_SKU_FM10420:\n+\t\tname = \"FM10420\";\n+\t\tbreak;\n+\tcase FM10K_SW_FUSE_SKU_FM10064:\n+\t\tname = \"FM10064\";\n+\t\tbreak;\n+\tdefault:\n+\t\tname = \"FM10xxx-unknown\";\n+\t\tbreak;\n+\t}\n+\n+\treturn name;\n+}\n+\n+\n+static void\n+fm10k_switch_describe(struct fm10k_switch *sw)\n+{\n+\tunsigned int i, pair;\n+\tunsigned int reset_state, active_state;\n+\tuint32_t device_cfg, resets;\n+\n+\tif (!fm10k_config_check_debug(sw->dpdk_cfg, FM10K_CONFIG_DEBUG_CONFIG))\n+\t\treturn;\n+\n+\tFM10K_SW_INFO(\"switch: device is %s, fabric clock %u MHz\",\n+\t    fm10k_switch_get_sku_name(fm10k_switch_get_sku(sw)),\n+\t    fm10k_switch_get_fabric_clock(sw));\n+\n+\tdevice_cfg = fm10k_read_switch_reg(sw, FM10K_SW_DEVICE_CFG);\n+\tFM10K_SW_INFO(\"switch: 100G Ethernet is %s\",\n+\t    (device_cfg & FM10K_SW_DEVICE_CFG_PCIE_100G_DIS) ?\n+\t    \"disabled\" : \"enabled\");\n+\tswitch (FM10K_SW_REG_FIELD(device_cfg, DEVICE_CFG_FEATURE)) {\n+\tcase FM10K_SW_DEVICE_CFG_PCIE_FULL:\n+\t\tFM10K_SW_INFO(\"switch: PEPs 0-7 support 2x4 and 1x8 \"\n+\t\t    \"modes, PEP 8 is x1\");\n+\t\tbreak;\n+\tcase FM10K_SW_DEVICE_CFG_PCIE_HALF:\n+\t\tFM10K_SW_INFO(\"switch: PEPs 0-3 support 2x4 and 1x8 \"\n+\t\t    \"modes, PEPs 4 and 6 are 1x4, PEP 8 is x1\");\n+\t\tbreak;\n+\tcase FM10K_SW_DEVICE_CFG_PCIE_BASIC:\n+\t\tFM10K_SW_INFO(\"switch: PEP 0 supports, PEP 8 is x1, \"\n+\t\t    \"only one can be used\");\n+\t\tbreak;\n+\t}\n+\n+\tresets = fm10k_read_switch_reg(sw, FM10K_SW_SOFT_RESET);\n+\tfor (i = 0; i < FM10K_SW_PEPS_MAX; i++) {\n+\t\tif (!(device_cfg & FM10K_SW_DEVICE_CFG_PCIE_EN(i)))\n+\t\t\tcontinue;\n+\n+\t\tpair = i / 2;\n+\t\treset_state = !!(resets & FM10K_SW_SOFT_RESET_PCIE_RESET(i));\n+\t\tactive_state = !!(resets & FM10K_SW_SOFT_RESET_PCIE_ACTIVE(i));\n+\t\tif (pair < FM10K_SW_DEVICE_CFG_PCIE_MODE_PAIRS &&\n+\t\t    !(device_cfg & FM10K_SW_DEVICE_CFG_PCIE_MODE_2X4(pair))) {\n+\t\t\tif (i % 2 == 0)\n+\t\t\t\tFM10K_SW_INFO(\"switch: PEP[%u,%u] is enabled in 1x8 \"\n+\t\t\t\t    \"mode (Reset=%u, Active=%u)\", i, i + 1,\n+\t\t\t\t    reset_state, active_state);\n+\t\t\telse\n+\t\t\t\tFM10K_SW_INFO(\"switch: PEP[%u] unexpectedly enabled when \"\n+\t\t\t\t    \"PEP[%u,%u] is in 1x8 mode (Reset=%u, \"\n+\t\t\t\t    \"Active=%u)\", i, i - 1, i, reset_state,\n+\t\t\t\t    active_state);\n+\t\t} else {\n+\t\t\tFM10K_SW_INFO(\"switch: PEP[%u] is enabled in 1x4 \"\n+\t\t\t    \"mode (Reset=%u, Active=%u)\", i, reset_state,\n+\t\t\t    active_state);\n+\t\t}\n+\t}\n+}\n+\n+\n+static struct fm10k_switch *\n+fm10k_switch_attach(struct fm10k_hw *hw, struct fm10k_switch *sw)\n+{\n+\tint i;\n+\tint error = 0;\n+\n+\t/*\n+\t * apparently no way to determine one's own PEP number.\n+\t */\n+\tswitch (sw->info->num_peps) {\n+\tcase 1:\n+\t\tsw->pepno = 0;\n+\t\tbreak;\n+\n+\tcase 2:\n+\t\t/*\n+\t\t * assumption is using even numbered PEPs\n+\t\t * starting with 0, and the highest numbered PEP\n+\t\t * is the master\n+\t\t */\n+\t\tsw->pepno = 2;\n+\t\tfor (i = 0; i < sw->info->num_peps - 1; i++)\n+\t\t\tsw->pep_mask |= (1 << (i * 2));\n+\t\tbreak;\n+\n+\tcase 4:\n+\t\tsw->pepno = 6;\n+\t\tsw->pep_mask = 0x7f;\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tsw->pepno = 0;\n+\t}\n+\n+\t/* When not zero, initialize serdes in 'near loopback' mode */\n+\tsw->serdes_loopback = 0;\n+\n+\tpthread_mutex_init(&sw->lock, NULL);\n+\n+\tfm10k_switch_determine_epls(sw);\n+\n+\tsw->ext_ports = fm10k_ext_ports_attach(sw);\n+\tif (sw->ext_ports == NULL)\n+\t\tgoto fail;\n+\n+\t/* label all external ports with their logical port numbers */\n+\tfor (i = 0; i < sw->ext_ports->num_ports; i++)\n+\t\tsw->ext_ports->ports[i].lport = sw->epl_map[i].logical_port;\n+\n+\t/* interrupt */\n+\tsem_init(&sw->intr_tq, 0, 0);\n+\tpthread_create(&sw->intr_task, NULL, fm10k_switch_process_intr, sw);\n+\n+\tfm10k_switch_enable_interrupts(sw);\n+\tfm10k_switch_describe(sw);\n+\n+\tsw->i2c = fm10k_i2c_attach(sw);\n+\tif (sw->i2c == NULL)\n+\t\tgoto fail;\n+\n+\terror = fm10k_switch_init(hw, sw);\n+\tif (error)\n+\t\tgoto fail;\n+\n+\tfor (i = 0; i < sw->ext_ports->num_ports; i++)\n+\t\tfm10k_ext_port_up(&sw->ext_ports->ports[i]);\n+\n+\tusec_delay(10000);\n+\tfm10k_switch_leds_init(sw);\n+\n+\tpthread_create(&sw->led_task, NULL, &fm10k_switch_leds_update, sw);\n+\tpthread_create(&sw->stats_task, NULL, &fm10k_switch_process_stats, sw);\n+\tsw->inited = 1;\n+\treturn sw;\n+fail:\n+\tif (sw != NULL)\n+\t\tfm10k_switch_detach(hw);\n+\treturn NULL;\n+}\n+\n+struct fm10k_switch*\n+fm10k_switch_get(void)\n+{\n+\treturn &fm10k_sw;\n+}\n+\n+static int\n+fm10k_switch_dpdk_port_get(struct fm10k_switch *sw, int pf_no)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tif (sw->dpdk_cfg->ports[i].pf_no == pf_no)\n+\t\t\treturn i;\n+\t}\n+\treturn -1;\n+}\n+\n+static int\n+fm10k_switch_mapped_ext_port_get(struct fm10k_switch *sw, int pf_no)\n+{\n+\tint i;\n+\tstruct fm10k_cfg_port_pf_map *map;\n+\n+\tfor (i = 0; i < FM10K_SW_EXT_PORTS_MAX; i++) {\n+\t\tmap = &sw->dpdk_cfg->ext_port_map[i];\n+\t\tif (map->type == FM10K_CONFIG_PORT_MAP_PF) {\n+\t\t\tif (map->map_no[0] == pf_no)\n+\t\t\t\treturn i;\n+\t\t} else if (map->type == FM10K_CONFIG_PORT_MAP_PFS) {\n+\t\t\tif (map->map_no[0] == pf_no || map->map_no[1] == pf_no)\n+\t\t\t\treturn i;\n+\t\t}\n+\t}\n+\treturn -1;\n+}\n+\n+static int\n+fm10k_switch_start(struct fm10k_switch *sw,\n+\t\tstruct fm10k_hw *master_hw, eth_fm10k_dev_init_half_func *func)\n+{\n+\tint i, j;\n+\tstruct fm10k_dpdk_port *port;\n+\tstruct fm10k_cfg_port_pf_map *map;\n+\tstruct fm10k_cfg_port_pf_map *dpdk_map;\n+\tint dpdk_port_no, ext_port_no = 0;\n+\tint pf_no;\n+\n+\tsw->info = fm10k_get_device_info(master_hw);\n+\tsw->master_hw = master_hw;\n+\tsw->pep_map = fm10k_pep_port_map;\n+\tsw->epl_map = fm10k_epl_port_map;\n+\n+\tsw->info->ext_port_speed = sw->dpdk_cfg->ext_port_speed;\n+\tfm10k_switch_set_sched_prog();\n+\tfm10k_switch_attach(master_hw, &fm10k_sw);\n+\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tport = &sw->dpdk_cfg->ports[i];\n+\t\tmap = &sw->dpdk_cfg->dpdk_port_map[i];\n+\t\tif (port->type != FM10K_CONFIG_DPDK_PF ||\n+\t\t\tmap->type != FM10K_CONFIG_PORT_MAP_PFS)\n+\t\t\tcontinue;\n+\n+\t\tfor (j = 0; j < 2; j++) {\n+\t\t\tpf_no =\tmap->map_no[j];\n+\t\t\tdpdk_port_no =\n+\t\t\t\tfm10k_switch_dpdk_port_get(sw, pf_no);\n+\t\t\tdpdk_map =\n+\t\t\t\t&sw->dpdk_cfg->dpdk_port_map[dpdk_port_no];\n+\t\t\tif (map->type == FM10K_CONFIG_PORT_MAP_PF) {\n+\t\t\t\tdpdk_map->type = FM10K_CONFIG_PORT_MAP_PFSS;\n+\t\t\t\tdpdk_map->map_no[0] =\n+\t\t\t\tsw->dpdk_cfg->dpdk_port_map[i].map_no[0];\n+\t\t\t\tdpdk_map->map_no[1] =\n+\t\t\t\tsw->dpdk_cfg->dpdk_port_map[i].map_no[1];\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* do initialize all ports, after switch is ready */\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tuint32_t sglort;\n+\t\tstruct fm10k_dpdk_port *port = &sw->dpdk_cfg->ports[i];\n+\t\tstruct fm10k_hw *hw = port->hw;\n+\n+\t\tif (hw == NULL)\n+\t\t\tbreak;\n+\n+\t\tmap = &sw->dpdk_cfg->ext_port_map[ext_port_no];\n+\t\tif (port->type == FM10K_CONFIG_DPDK_PF)\t{\n+\t\t\tpf_no = fm10k_switch_dpdk_pf_no_get(hw);\n+\t\t\tif (map->type == FM10K_CONFIG_PORT_MAP_PF) {\n+\t\t\t\tsglort = fm10k_switch_pf_glort_get(pf_no);\n+\t\t\t} else if (map->type == FM10K_CONFIG_PORT_MAP_PFS) {\n+\t\t\t\text_port_no =\n+\t\t\t\t\tfm10k_switch_mapped_ext_port_get\n+\t\t\t\t\t(sw, pf_no);\n+\t\t\t\tsglort =\n+\t\t\t\t\tfm10k_switch_pfs_glort_get\n+\t\t\t\t\t(map->map_no[0], map->map_no[1]);\n+\t\t\t} else {\n+\t\t\t\tFM10K_SW_ERR(\"Unknown mapped port type %d!\",\n+\t\t\t\t\t\tport->type);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\thw->mac.dglort_map = sglort | 0xffff0000;\n+\t\t}\n+\t\tfunc(hw);\n+\t}\n+\treturn 0;\n+}\n+\n+\n+static int\n+fm10k_switch_dpdk_port_reg(struct fm10k_switch *sw,\n+\t\tstruct fm10k_hw *hw, void *rte_dev, uint8_t is_pf, bool master)\n+{\n+\tint i;\n+\tstruct fm10k_dpdk_port *port;\n+\tstruct fm10k_cfg_port_pf_map *map;\n+\n+\tif (sw->dpdk_cfg == NULL && is_pf) {\n+\t\tif (fm10k_config_init(sw, hw) < 0)\n+\t\t\treturn -1;\n+\t}\n+\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tport = &sw->dpdk_cfg->ports[i];\n+\t\tif (master && port->hw &&\n+\t\t\t\tport->type == FM10K_CONFIG_DPDK_PF) {\n+\t\t\tport->pf_no =\n+\t\t\t\tsw->dpdk_cfg->pf_max - 1 -\n+\t\t\t\t(hw->mac.addr[5] - port->hw->mac.addr[5]);\n+\t\t\tsw->dpdk_cfg->pf_hw[port->pf_no] = port->hw;\n+\t\t}\n+\n+\t\tif (port->hw == NULL) {\n+\t\t\tport->hw = hw;\n+\t\t\tport->rte_dev = rte_dev;\n+\t\t\tfm10k_flow_list_init(&port->flow_list);\n+\t\t\tmap = &sw->dpdk_cfg->dpdk_port_map[i];\n+\t\t\tif (is_pf) {\n+\t\t\t\tsw->dpdk_cfg->pf_bind++;\n+\t\t\t\tport->type = FM10K_CONFIG_DPDK_PF;\n+\t\t\t\tif (map->type == FM10K_CONFIG_PORT_MAP_NULL) {\n+\t\t\t\t\tmap->type = FM10K_CONFIG_PORT_MAP_PF;\n+\t\t\t\t\tmap->map_no[0] = i;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tport->type = FM10K_CONFIG_DPDK_VF;\n+\t\t\t}\n+\t\t\tif (master)\n+\t\t\t\tsw->dpdk_cfg->master_hw = hw;\n+\t\t\tif (sw->dpdk_cfg->master_hw) {\n+\t\t\t\tport->pf_no =\n+\t\t\t\t\tsw->dpdk_cfg->pf_max - 1 -\n+\t\t\t\t\t(sw->dpdk_cfg->master_hw->mac.addr[5] -\n+\t\t\t\t\thw->mac.addr[5]);\n+\t\t\t\tsw->dpdk_cfg->pf_hw[port->pf_no] = port->hw;\n+\t\t\t}\n+\n+\t\t\treturn 0;\n+\t\t}\n+\t}\n+\treturn -1;\n+}\n+\n+int\n+fm10k_switch_dpdk_port_no_get(struct fm10k_hw *hw)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tif (fm10k_sw.dpdk_cfg->ports[i].hw == NULL)\n+\t\t\tbreak;\n+\n+\t\tif (fm10k_sw.dpdk_cfg->ports[i].hw == hw)\n+\t\t\treturn i;\n+\t}\n+\treturn -1;\n+}\n+\n+void *\n+fm10k_switch_dpdk_port_rte_dev_get(struct fm10k_hw *hw)\n+{\n+\tint port_no = fm10k_switch_dpdk_port_no_get(hw);\n+\n+\tif (port_no < 0)\n+\t\treturn NULL;\n+\n+\treturn fm10k_switch_get()->dpdk_cfg->ports[port_no].rte_dev;\n+}\n+\n+struct fm10k_flow_list *\n+fm10k_switch_dpdk_port_flow_list_get(struct fm10k_hw *hw)\n+{\n+\tint port_no = fm10k_switch_dpdk_port_no_get(hw);\n+\n+\tif (port_no < 0)\n+\t\treturn NULL;\n+\n+\treturn fm10k_switch_get()->dpdk_cfg->ports[port_no].flow_list;\n+}\n+\n+static int\n+fm10k_switch_dpdk_cfg_check(struct fm10k_switch *sw)\n+{\n+\tint i;\n+\tbool need_default = true;\n+\tstruct fm10k_dpdk_port *port;\n+\tstruct fm10k_cfg_port_pf_map *map;\n+\n+\tif (sw->dpdk_cfg->master_hw == NULL) {\n+\t\tFM10K_SW_ERR(\"Master PF is not bound!!!\");\n+\t\treturn -1;\n+\t}\n+\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tport = &sw->dpdk_cfg->ports[i];\n+\t\tmap = &sw->dpdk_cfg->dpdk_port_map[i];\n+\t\tif (port->type == FM10K_CONFIG_DPDK_PF &&\n+\t\t\t\tmap->type != FM10K_CONFIG_PORT_MAP_NULL) {\n+\t\t\tneed_default = false;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (need_default) {\n+\t\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\t\tmap = &sw->dpdk_cfg->dpdk_port_map[i];\n+\t\t\tif (port->type == FM10K_CONFIG_DPDK_PF) {\n+\t\t\t\tmap->type = FM10K_CONFIG_PORT_MAP_PF;\n+\t\t\t\tmap->map_no[0] = i;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+static void\n+fm10k_switch_dpdk_cfg_describe(struct fm10k_switch *sw)\n+{\n+\tint i;\n+\tstruct fm10k_cfg_port_pf_map *map;\n+\n+\tif (!fm10k_config_check_debug(sw->dpdk_cfg, FM10K_CONFIG_DEBUG_CONFIG))\n+\t\treturn;\n+\n+\tFM10K_SW_INFO(\"--- FM10K DYNAMIC CONFIG ---\\n\");\n+\tFM10K_SW_INFO(\"  PF Bind  : %d\\n\", sw->dpdk_cfg->pf_bind);\n+\n+\tFM10K_SW_INFO(\"--- PF ---\\n\");\n+\tfor (i = 0; i < FM10K_SW_PEP_PORTS_MAX; i++)\t{\n+\t\tuint8_t *mac;\n+\t\tstruct rte_eth_dev *dev;\n+\t\tstruct rte_pci_device *pdev;\n+\n+\t\tif (sw->dpdk_cfg->pf_hw[i] == NULL)\n+\t\t\tcontinue;\n+\t\tdev = (struct rte_eth_dev *)\n+\t\t\tfm10k_switch_dpdk_port_rte_dev_get\n+\t\t\t(sw->dpdk_cfg->pf_hw[i]);\n+\t\tpdev = RTE_ETH_DEV_TO_PCI(dev);\n+\t\tmac = sw->dpdk_cfg->pf_hw[i]->mac.addr;\n+\t\tFM10K_SW_INFO(\"  PF%d : Logical %d Glort %#x \"\n+\t\t\t\t\"PCI Addr %02x:%02x.%x \"\n+\t\t\t\t\"MAC Addr %02x:%02x:%02x:%02x:%02x:%02x\\n\",\n+\t\t\t\ti, fm10k_pep_port_map[i].logical_port,\n+\t\t\t\tfm10k_switch_pf_glort_get(i), pdev->addr.bus,\n+\t\t\t\tpdev->addr.devid,\n+\t\t\t\tpdev->addr.function,\n+\t\t\t\tmac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);\n+\t}\n+\n+\tFM10K_SW_INFO(\"--- DPDK PORT ---\\n\");\n+\tfor (i = 0; i < FM10K_SW_LOGICAL_PORTS_MAX; i++) {\n+\t\tif (sw->dpdk_cfg->ports[i].type == FM10K_CONFIG_DPDK_NULL)\n+\t\t\tbreak;\n+\t\tmap = &sw->dpdk_cfg->dpdk_port_map[i];\n+\t\tif (map->type == FM10K_CONFIG_PORT_MAP_NULL)\n+\t\t\tbreak;\n+\t\tif (map->type == FM10K_CONFIG_PORT_MAP_PF) {\n+\t\t\tFM10K_SW_INFO(\"  DPDK PORT%d : Map to PF%d\\n\",\n+\t\t\t\t\ti, map->map_no[0]);\n+\t\t} else {\n+\t\t\tFM10K_SW_INFO(\"  DPDK PORT%d : Map to PF%d&PF%d Glort %#x\\n\",\n+\t\t\t\t\ti,\n+\t\t\t\t\tmap->map_no[0],\tmap->map_no[1],\n+\t\t\t\t\tfm10k_switch_pfs_glort_get\n+\t\t\t\t\t(map->map_no[0], map->map_no[1]));\n+\t\t}\n+\t}\n+\n+\tFM10K_SW_INFO(\"--- EXT PORT ---\\n\");\n+\tfor (i = 0; i < sw->dpdk_cfg->ext_port_num; i++) {\n+\t\tmap = &sw->dpdk_cfg->ext_port_map[i];\n+\t\tFM10K_SW_INFO(\"  EXT  PORT%d : Logical %d Glort %#x\", i,\n+\t\t\t\tfm10k_epl_port_map[i].logical_port,\n+\t\t\t\tfm10k_switch_epl_glort_get(i));\n+\n+\t\tif (map->type == FM10K_CONFIG_PORT_MAP_NULL)\n+\t\t\tFM10K_SW_INFO(\"\\n\");\n+\t\telse if (map->type == FM10K_CONFIG_PORT_MAP_PF)\n+\t\t\tFM10K_SW_INFO(\" Map to PF%d\\n\", map->map_no[0]);\n+\t\telse\n+\t\t\tFM10K_SW_INFO(\" Map to PF%d&PF%d Glort %#x\\n\",\n+\t\t\t\t\tmap->map_no[0], map->map_no[1],\n+\t\t\t\t\tfm10k_switch_pfs_glort_get\n+\t\t\t\t\t(map->map_no[0], map->map_no[1]));\n+\t}\n+}\n+\n+\n+int\n+fm10k_switch_dpdk_port_start(struct fm10k_hw *hw, void *rte_dev,\n+\t\tuint8_t is_pf, bool master, eth_fm10k_dev_init_half_func *func)\n+{\n+\tint ret;\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tif (fm10k_switch_dpdk_port_reg(sw, hw, rte_dev, is_pf, master) != 0) {\n+\t\tFM10K_SW_ERR(\"Register ports failed!!!\");\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * After all pfs are started\n+\t * start switch here\n+\t */\n+\tif (fm10k_sw.dpdk_cfg->pf_max != 0 &&\n+\t\tfm10k_sw.dpdk_cfg->pf_bind == fm10k_sw.dpdk_cfg->pf_num) {\n+\t\tif (fm10k_switch_dpdk_cfg_check(&fm10k_sw) != 0)\n+\t\t\treturn -1;\n+\n+\t\tret = fm10k_switch_start(&fm10k_sw,\n+\t\t\t\tfm10k_sw.dpdk_cfg->master_hw, func);\n+\t\tfm10k_switch_dpdk_cfg_describe(&fm10k_sw);\n+\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+void fm10k_switch_dpdk_port_stop(struct fm10k_hw *hw)\n+{\n+\tif (hw)\n+\t\treturn;\n+}\n+\n+\n+/*\n+ * for multi-host, only dpdk port 0 and 1 are real rx/tx packets\n+ * so we need init/setup/start dpdk port queue for them.\n+ * for dpdk port 2/3, we need init/setup except start.\n+ * we map the pf queue to 0/1 dpdk queue first, then map\n+ * the other pf queue to 2/3 dpdk queue.\n+ */\n+int\n+fm10k_switch_dpdk_hw_queue_map(struct fm10k_hw *hw,\n+\t\tuint16_t queue, uint16_t max_queue,\n+\t\tstruct fm10k_hw **map_hw, uint16_t *map_queue)\n+{\n+\tint idx, pf_no;\n+\tint dpdk_port_no = fm10k_switch_dpdk_port_no_get(hw);\n+\tstruct fm10k_dpdk_port *port;\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tif (dpdk_port_no < 0) {\n+\t\tFM10K_SW_ERR(\"Can not find the dpdk port!!!\");\n+\t\treturn -1;\n+\t}\n+\n+\tport = &sw->dpdk_cfg->ports[dpdk_port_no];\n+\n+\tif (port->type == FM10K_CONFIG_DPDK_VF) {\n+\t\tFM10K_SW_ERR(\"Not support yet!!!\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (port->type != FM10K_CONFIG_DPDK_PF) {\n+\t\tFM10K_SW_ERR(\"Can not be here!!!\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (sw->dpdk_cfg->dpdk_port_map[dpdk_port_no].type ==\n+\t\t\tFM10K_CONFIG_PORT_MAP_PF) {\n+\t\tpf_no = sw->dpdk_cfg->dpdk_port_map[dpdk_port_no].map_no[0];\n+\t\t*map_hw = sw->dpdk_cfg->pf_hw[pf_no];\n+\t\t*map_queue = queue;\n+\t\treturn 1;\n+\t} else if (sw->dpdk_cfg->dpdk_port_map[dpdk_port_no].type ==\n+\t\t\tFM10K_CONFIG_PORT_MAP_PFS) {\n+\t\tidx = queue % 2;\n+\t\tpf_no = sw->dpdk_cfg->dpdk_port_map[dpdk_port_no].map_no[idx];\n+\t\t*map_hw = sw->dpdk_cfg->pf_hw[pf_no];\n+\t\t*map_queue = queue / 2;\n+\t\treturn 1;\n+\t} else if (sw->dpdk_cfg->dpdk_port_map[dpdk_port_no].type ==\n+\t\t\tFM10K_CONFIG_PORT_MAP_PFSS) {\n+\t\tidx = queue % 2;\n+\t\tpf_no = sw->dpdk_cfg->dpdk_port_map[dpdk_port_no].map_no[idx];\n+\t\t*map_hw = sw->dpdk_cfg->pf_hw[pf_no];\n+\t\t*map_queue = (max_queue + 1) / 2 + queue / 2;\n+\t\treturn 0;\n+\t} else if (sw->dpdk_cfg->dpdk_port_map[dpdk_port_no].type ==\n+\t\t\tFM10K_CONFIG_PORT_MAP_NULL) {\n+\t\tFM10K_SW_ERR(\"Unmapped dpdk port %d!!!\", dpdk_port_no);\n+\t\treturn -1;\n+\t}\n+\tFM10K_SW_ERR(\"Unknown mapped type!!!\");\n+\treturn -1;\n+}\n+\n+int\n+fm10k_switch_dpdk_mapped_hw_get(struct fm10k_hw *hw, struct fm10k_hw *hw_list[])\n+{\n+\tint pf_no, pf_no_ext;\n+\tint dpdk_port_no = fm10k_switch_dpdk_port_no_get(hw);\n+\tstruct fm10k_dpdk_port *port;\n+\tstruct fm10k_cfg_port_pf_map *map;\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tif (dpdk_port_no < 0) {\n+\t\tFM10K_SW_ERR(\"Can not find the dpdk port!!!\");\n+\t\treturn -1;\n+\t}\n+\n+\tport = &sw->dpdk_cfg->ports[dpdk_port_no];\n+\tmap = &sw->dpdk_cfg->dpdk_port_map[dpdk_port_no];\n+\n+\tif (port->type == FM10K_CONFIG_DPDK_VF) {\n+\t\thw_list[0] = hw;\n+\t\thw_list[1] = NULL;\n+\t\treturn 1;\n+\t}\n+\n+\tif (port->type != FM10K_CONFIG_DPDK_PF) {\n+\t\tFM10K_SW_ERR(\"Can not be here!!!\");\n+\t\treturn -1;\n+\t} else if (map->type ==\tFM10K_CONFIG_PORT_MAP_PF) {\n+\t\tpf_no = map->map_no[0];\n+\t\thw_list[0] = sw->dpdk_cfg->pf_hw[pf_no];\n+\t\thw_list[1] = NULL;\n+\t\treturn 1;\n+\t} else if (map->type ==\tFM10K_CONFIG_PORT_MAP_PFS) {\n+\t\tpf_no = map->map_no[0];\n+\t\thw_list[0] = sw->dpdk_cfg->pf_hw[pf_no];\n+\t\tpf_no_ext = map->map_no[1];\n+\t\thw_list[1] = sw->dpdk_cfg->pf_hw[pf_no_ext];\n+\t\treturn 2;\n+\t} else if (map->type == FM10K_CONFIG_PORT_MAP_PFSS) {\n+\t\tpf_no = map->map_no[0];\n+\t\thw_list[0] = sw->dpdk_cfg->pf_hw[pf_no];\n+\t\tpf_no_ext = map->map_no[1];\n+\t\thw_list[1] = sw->dpdk_cfg->pf_hw[pf_no_ext];\n+\t\treturn 0;\n+\t}\n+\n+\thw_list[0] = NULL;\n+\thw_list[1] = NULL;\n+\treturn 0;\n+}\n+\n+void\n+fm10k_switch_dpdk_tx_queue_num_set(struct fm10k_hw *hw, uint8_t num)\n+{\n+\tint port_no = fm10k_switch_dpdk_port_no_get(hw);\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tif (port_no < 0) {\n+\t\tFM10K_SW_ERR(\"Can not find the dpdk port!!!\");\n+\t\treturn;\n+\t}\n+\n+\tsw->dpdk_cfg->ports[port_no].tx_queue_num = num;\n+}\n+\n+void\n+fm10k_switch_dpdk_rx_queue_num_set(struct fm10k_hw *hw, uint8_t num)\n+{\n+\tint port_no = fm10k_switch_dpdk_port_no_get(hw);\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tif (port_no < 0) {\n+\t\tFM10K_SW_ERR(\"Can not find the dpdk port!!!\");\n+\t\treturn;\n+\t}\n+\n+\tsw->dpdk_cfg->ports[port_no].rx_queue_num = num;\n+}\n+\n+int\n+fm10k_switch_dpdk_pf_no_get(struct fm10k_hw *hw)\n+{\n+\tint port_no = fm10k_switch_dpdk_port_no_get(hw);\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tif (port_no < 0) {\n+\t\tFM10K_SW_ERR(\"Can not find the dpdk port!!!\");\n+\t\treturn -1;\n+\t}\n+\n+\treturn sw->dpdk_cfg->ports[port_no].pf_no;\n+}\n+\n+\n+void\n+fm10k_switch_flowset_switchto(const char *name)\n+{\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tfm10k_ffu_flowset_switch(sw, name);\n+}\n+\n+void\n+fm10k_switch_show_port(void)\n+{\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tfm10k_stats_epl_port_print(sw);\n+\tfm10k_stats_dpdk_port_print(sw);\n+}\n+\n+void\n+fm10k_switch_show_ffu(void)\n+{\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tfm10k_stats_ffu_count_print(sw);\n+}\n+\n+void\n+fm10k_switch_show_bank(void)\n+{\n+\tstruct fm10k_switch *sw = fm10k_switch_get();\n+\n+\tfm10k_stats_port_bank_print(sw);\n+}\n",
    "prefixes": [
        "v1",
        "4/5"
    ]
}