get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 63744,
    "url": "http://patches.dpdk.org/api/patches/63744/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1576057875-7677-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": "<1576057875-7677-5-git-send-email-xiaojun.liu@silicom.co.il>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1576057875-7677-5-git-send-email-xiaojun.liu@silicom.co.il",
    "date": "2019-12-11T09:52:10",
    "name": "[v2,4/7] net/fm10k: add flow and switch management",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": true,
    "hash": "48cb5ec572a497666a75ed34051f1e2fbb4dc5ef",
    "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/1576057875-7677-5-git-send-email-xiaojun.liu@silicom.co.il/mbox/",
    "series": [
        {
            "id": 7788,
            "url": "http://patches.dpdk.org/api/series/7788/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=7788",
            "date": "2019-12-11T09:51:58",
            "name": "support switch management",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/7788/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/63744/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/63744/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 1562AA04F1;\n\tWed, 11 Dec 2019 10:52:47 +0100 (CET)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id E58071BF7E;\n\tWed, 11 Dec 2019 10:52:13 +0100 (CET)",
            "from EUR01-VE1-obe.outbound.protection.outlook.com\n (mail-eopbgr140132.outbound.protection.outlook.com [40.107.14.132])\n by dpdk.org (Postfix) with ESMTP id 42C371BF73\n for <dev@dpdk.org>; Wed, 11 Dec 2019 10:52:12 +0100 (CET)",
            "from DB7PR04MB5196.eurprd04.prod.outlook.com (20.176.234.140) by\n DB7PR04MB4203.eurprd04.prod.outlook.com (52.135.131.12) with Microsoft SMTP\n Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.2538.14; Wed, 11 Dec 2019 09:52:10 +0000",
            "from DB7PR04MB5196.eurprd04.prod.outlook.com\n ([fe80::cdaa:fcae:322b:59ed]) by DB7PR04MB5196.eurprd04.prod.outlook.com\n ([fe80::cdaa:fcae:322b:59ed%7]) with mapi id 15.20.2516.018; Wed, 11 Dec 2019\n 09:52:10 +0000"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=igMZ8WxrRxF6b+3kHmhBo4XuIzfGvkNE1GM8Bm/G7/zhbeqGlNrAtE5ZdskVHsLwd/Quub8xKxvwQtJTbuBtQtbsYMZc9U0ZFL+W58DcR38kOYJTbVh357VLYARv9bFodSrNoqAByc72yiSvUMzCFayfCULw3kxhAvQyVH5sqM2643zJ17oJJ+kWIl0lB2ewa4fmbQQTJwiXYcUfHZXgmSEr30K5JOrBTwdffooTy03Yq8i2Ap4KMS4cVj1V9W+ePSXf9K9PeLShHpOXzjhhjoCSDgu7SD+L97nsXNuHr/MAbSzF9wRtExGSXl33O+9qe575kPUkdCO3+D5YEOFeVg==",
        "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=6QA/aBMlgA+lf74+ky5gcYh7KpWcdtfJi98kzJwlNns=;\n b=Ltw/+Uv8DqVeAvRpIqvIZ6TZlaECDRoBzuPSS2QO0eYM05CI/ESsPcorRm9t8HCnE0JfjrGGtUeAWIOaO173K+CnEkR+Mckul1O3Yw5APqlqfNF6iMz10Qt79ERAfTt8E5VDNVn+EKNci8fZqAG8+fYAF+xNDuAPlGo20tkqNYdd9i0wu/ohA9qgCV7cd/74VKq99j85Vsb2U16iUUE0ANl3DCPz6tPO++OeX8xY0v0fWV0GpHBX50pKqByvVNTukUw5DefxqzGuWcIUK8CM/dZMx8qukmtdCXUPBUbHjoX9aosOlNJM7iYuuZL0KU1DQ0+PhX20Bq8NxjciUKDAvQ==",
        "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=6QA/aBMlgA+lf74+ky5gcYh7KpWcdtfJi98kzJwlNns=;\n b=f7LoRsncJZwdNPzevEGU1nFt+Q+x9fNAe1Zqesg7wTLCdNKjV+qr4WCpbnIYIx622XkKiLR0MaKK3H0S9heSgxnLgVWqsO7aClWhA3QEXEiP2S9WUSO5D6Csbyz6f/spO0FtUJTkWAnC78uoEUYjZiAqDJsg0EbZGzcqsNlQJHQ=",
        "From": "Xiaojun Liu <xiaojun.liu@silicom.co.il>",
        "To": "\"xiao.w.wang@intel.com\" <xiao.w.wang@intel.com>, \"qi.z.zhang@intel.com\"\n <qi.z.zhang@intel.com>, \"ngai-mint.kwan@intel.com\"\n <ngai-mint.kwan@intel.com>, \"jakub.fornal@intel.co\" <jakub.fornal@intel.co>,\n \"jacob.e.keller@intel.com\" <jacob.e.keller@intel.com>",
        "CC": "\"dev@dpdk.org\" <dev@dpdk.org>, Xiaojun Liu <xiaojun.liu@silicom.co.il>",
        "Thread-Topic": "[PATCH v2 4/7] net/fm10k: add flow and switch management",
        "Thread-Index": "AQHVsAio5Q7GPKA61UezUT6MLAT9Zg==",
        "Date": "Wed, 11 Dec 2019 09:52:10 +0000",
        "Message-ID": "<1576057875-7677-5-git-send-email-xiaojun.liu@silicom.co.il>",
        "References": "<xiaojun.liu@silicom.co.il>\n <1576057875-7677-1-git-send-email-xiaojun.liu@silicom.co.il>",
        "In-Reply-To": "<1576057875-7677-1-git-send-email-xiaojun.liu@silicom.co.il>",
        "Accept-Language": "en-US",
        "Content-Language": "en-US",
        "X-MS-Has-Attach": "",
        "X-MS-TNEF-Correlator": "",
        "x-clientproxiedby": "HK2PR02CA0180.apcprd02.prod.outlook.com\n (2603:1096:201:21::16) To DB7PR04MB5196.eurprd04.prod.outlook.com\n (2603:10a6:10:1a::12)",
        "authentication-results": "spf=none (sender IP is )\n smtp.mailfrom=xiaojun.liu@silicom.co.il;",
        "x-ms-exchange-messagesentrepresentingtype": "1",
        "x-mailer": "git-send-email 1.8.3.1",
        "x-originating-ip": "[113.110.226.253]",
        "x-ms-publictraffictype": "Email",
        "x-ms-office365-filtering-correlation-id": "aa8b3655-c9ac-4428-01aa-08d77e1fca62",
        "x-ms-traffictypediagnostic": "DB7PR04MB4203:",
        "x-ms-exchange-transport-forked": "True",
        "x-microsoft-antispam-prvs": "\n <DB7PR04MB4203A5AE12DF9C0FC4F1AF04BD5A0@DB7PR04MB4203.eurprd04.prod.outlook.com>",
        "x-ms-oob-tlc-oobclassifiers": "OLM:205;",
        "x-forefront-prvs": "024847EE92",
        "x-forefront-antispam-report": "SFV:NSPM;\n SFS:(10019020)(346002)(366004)(136003)(39850400004)(376002)(396003)(199004)(189003)(2906002)(71200400001)(81156014)(64756008)(316002)(66556008)(6506007)(44832011)(8676002)(52116002)(81166006)(26005)(66476007)(54906003)(110136005)(66946007)(186003)(36756003)(30864003)(6512007)(4326008)(86362001)(2616005)(107886003)(6486002)(66446008)(8936002)(5660300002)(478600001)(21314003)(579004)(569006);\n DIR:OUT; SFP:1102; SCL:1; SRVR:DB7PR04MB4203;\n H:DB7PR04MB5196.eurprd04.prod.outlook.com; FPR:; SPF:None; LANG:en;\n PTR:InfoNoRecords; A:1; MX: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 3NFg5P5n8AwFp7IolM93c04yXGRtKkaHpsqJr7r2ga5srkJee5u/AmPLGMztv3Yis3EFziWUoEB/MWbQEc2GaU4nhbz+AN8uHlV+tVxu3Gye5RdOGy++tcSyw1prdPC608wj1gxYOJfl93Y/qD/l8eaeDT+lpRxsJTH+Qq/duCIoSIxUwcyTDco5+oj1hL3R/tJEl9cr9rzaEvTpioScAqGdxZMtGVKa2EWbmwrU45r/ynF/Y4sbZaJqvuK0SY6ED9H1OskCyA3j704YBcfs4Bgiuj5kDLrrZ6DKV6SEwCXpK98kDxld2eOyl+7oHgoFI9+lMKfRsiKzu8UhbXSnlgQYa+RboK+F0LxyMCfj93yRBL/+tc8sVD5oNiih40MfW5q5Pmw1RPmLXJqzqN7NxdeDuEmfPKAk7RXBC9ShvQP5aP/MH2AxtWQu8C9NDi2rIV2JK/MumSco3eOdZbmnc/u8uqXtrI4Zg8gN7UvtPepqk4fMAcub/4azmY4YgNSa",
        "Content-Type": "text/plain; charset=\"iso-8859-1\"",
        "Content-Transfer-Encoding": "quoted-printable",
        "MIME-Version": "1.0",
        "X-OriginatorOrg": "silicom.co.il",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n aa8b3655-c9ac-4428-01aa-08d77e1fca62",
        "X-MS-Exchange-CrossTenant-originalarrivaltime": "11 Dec 2019 09:52:10.2669 (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 5GImiDm4GmbzeTIf+dFePKBxYbDMiCcaM3/hgd/UcgJrgpEJ301cc6x5nRbkgB+B1lUcvKZnhf40xhxh6rGnKrZYnSy8sbhLEr0Uoa+bdxU=",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DB7PR04MB4203",
        "Subject": "[dpdk-dev] [PATCH v2 4/7] net/fm10k: add flow and switch management",
        "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": "To support switch management, add the following new files:\nAdd fm10k/switch/fm10k_flow.h.\nAdd fm10k/switch/fm10k_flow.c(support dpdk flow operations)\nAdd fm10k/switch/fm10k_switch.c(support switch management)\nModify fm10k/Makefile(add fm10k_flow.c\nand fm10k_switch.c).\n\nTo avoid configuration for both kernel driver\nand userspace SDK outside DPDK, we add switch\nmanagement in FM10K DPDK PMD driver.\nTo enable 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_switch.c | 2562 +++++++++++++++++++++++++++++++\n 4 files changed, 3462 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 ed73251..ab263c5 100644\n--- a/drivers/net/fm10k/Makefile\n+++ b/drivers/net/fm10k/Makefile\n@@ -93,6 +93,8 @@ SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_spico_code.c\n SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_stats.c\n SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_ffu.c\n SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_config.c\n+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_switch.c\n+SRCS-$(CONFIG_RTE_LIBRTE_FM10K_PMD) += fm10k_flow.c\n endif\n \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_switch.c b/drivers/net/fm10k/switch/fm10k_switch.c\nnew file mode 100644\nindex 0000000..c3887d0\n--- /dev/null\n+++ b/drivers/net/fm10k/switch/fm10k_switch.c\n@@ -0,0 +1,2562 @@\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+static struct fm10k_device_info fm10k_device_table[] = {\n+\t{   FM10K_SW_VENDOR_ID_SILICOM,\tFM10K_SW_DEV_ID_PE3100G2DQIR_QXSL4,\n+\t\t\"Silicom PE3100G2DQiR-QX4/QS4/QL4\",\t\t2, 100, 2, 2 },\n+\t{   FM10K_SW_VENDOR_ID_SILICOM,\tFM10K_SW_DEV_ID_PE3100G2DQIRL_QXSL4,\n+\t\t\"Silicom PE3100G2DQiRL-QX4/QS4/QL4\",\t2, 100, 2, 2 },\n+\t{   FM10K_SW_VENDOR_ID_SILICOM,\tFM10K_SW_DEV_ID_PE3100G2DQIRM_QXSL4,\n+\t\t\"Silicom PE3100G2DQiRM-QX4/QS4/QL4\",\t2, 100, 2, 4 },\n+};\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\t1000000\n+\n+#define FM10K_LED_POLL_INTERVAL_MS\t500\n+#define FM10K_LED_BLINKS_PER_SECOND\t2\n+\n+/*\n+ * GLORT MAP\n+ */\n+#define FM10K_SW_EPLA_GLORT\t\t\t0x10\n+#define FM10K_SW_EPLB_GLORT\t\t\t0x20\n+#define FM10K_SW_PEP01_GLORT\t\t0x30\n+#define FM10K_SW_PEP23_GLORT\t\t0x40\n+#define FM10K_SW_PEP45_GLORT\t\t0x50\n+#define FM10K_SW_PEP67_GLORT\t\t0x60\n+\n+/*\n+ * logical port number\n+ */\n+#define FM10K_SW_EPLA_LOGICAL_PORT\t\t1\n+#define FM10K_SW_EPLB_LOGICAL_PORT\t\t2\n+\n+#define FM10K_SW_PEP01_LOGICAL_PORT\t\t3\n+#define FM10K_SW_PEP23_LOGICAL_PORT\t\t4\n+#define FM10K_SW_PEP45_LOGICAL_PORT\t\t5\n+#define FM10K_SW_PEP67_LOGICAL_PORT\t\t6\n+\n+/*\n+ * physical port number\n+ */\n+#define FM10K_SW_EPLA_PHYSICAL_PORT\t\t0\n+#define FM10K_SW_EPLB_PHYSICAL_PORT\t\t4\n+\n+#define FM10K_SW_PEP01_PHYSICAL_PORT\t36\n+#define FM10K_SW_PEP23_PHYSICAL_PORT\t40\n+#define FM10K_SW_PEP45_PHYSICAL_PORT\t44\n+#define FM10K_SW_PEP67_PHYSICAL_PORT\t48\n+\n+static struct fm10k_sw_port_map fm10k_pep_port_map[FM10K_SW_PEPS_SUPPORTED] = {\n+\t{\n+\t\tFM10K_SW_PEP01_GLORT,\n+\t\tFM10K_SW_PEP01_LOGICAL_PORT,\n+\t\tFM10K_SW_PEP01_PHYSICAL_PORT\n+\t},\n+\t{\n+\t\tFM10K_SW_PEP23_GLORT,\n+\t\tFM10K_SW_PEP23_LOGICAL_PORT,\n+\t\tFM10K_SW_PEP23_PHYSICAL_PORT\n+\t},\n+\t{\n+\t\tFM10K_SW_PEP45_GLORT,\n+\t\tFM10K_SW_PEP45_LOGICAL_PORT,\n+\t\tFM10K_SW_PEP45_PHYSICAL_PORT\n+\t},\n+\t{\n+\t\tFM10K_SW_PEP67_GLORT,\n+\t\tFM10K_SW_PEP67_LOGICAL_PORT,\n+\t\tFM10K_SW_PEP67_PHYSICAL_PORT\n+\t},\n+};\n+\n+static struct fm10k_sw_port_map fm10k_epl_port_map[FM10K_SW_EPLS_SUPPORTED] = {\n+\t{\n+\t\tFM10K_SW_EPLA_GLORT,\n+\t\tFM10K_SW_EPLA_LOGICAL_PORT,\n+\t\tFM10K_SW_EPLA_PHYSICAL_PORT\n+\t},\n+\t{\n+\t\tFM10K_SW_EPLB_GLORT,\n+\t\tFM10K_SW_EPLB_LOGICAL_PORT,\n+\t\tFM10K_SW_EPLB_PHYSICAL_PORT\n+\t},\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\t2\n+};\n+\n+static struct fm10k_sched_prog\n+\tfm10k_sched_prog[FM10K_SW_PEPS_SUPPORTED + FM10K_SW_EPLS_SUPPORTED + 1];\n+\n+uint32_t\n+fm10k_switch_pf_logical_get(uint8_t pf_no)\n+{\n+\treturn fm10k_pep_port_map[pf_no].logical_port;\n+}\n+\n+uint32_t\n+fm10k_switch_epl_logical_get(uint8_t epl_no)\n+{\n+\treturn fm10k_epl_port_map[epl_no].logical_port;\n+}\n+\n+uint32_t\n+fm10k_switch_vf_glort_get(uint8_t vf_no)\n+{\n+\treturn FM10K_SW_VF_GLORT_START + vf_no;\n+}\n+\n+uint32_t\n+fm10k_switch_pf_glort_get(uint8_t pf_no)\n+{\n+\treturn fm10k_pep_port_map[pf_no].glort;\n+}\n+\n+uint32_t\n+fm10k_switch_epl_glort_get(uint8_t epl_no)\n+{\n+\treturn fm10k_epl_port_map[epl_no].glort;\n+}\n+\n+uint32_t\n+fm10k_switch_pfs_glort_get(uint8_t pf1, uint8_t pf2)\n+{\n+\tuint8_t idx;\n+\tif (pf1 > pf2)\n+\t\tidx = (pf2 & 0xf) | (pf1 << 4 & 0xf0);\n+\telse\n+\t\tidx = (pf1 & 0xf) | (pf2 << 4 & 0xf0);\n+\treturn FM10K_SW_PFS_GLORT_START + idx;\n+}\n+\n+struct fm10k_multi_glort {\n+\tuint8_t lport1;\n+\tuint8_t lport2;\n+\tuint16_t vlan1;\n+\tuint16_t vlan2;\n+} fm10k_multi_glorts[FM10K_SW_FFU_RULE_MAX];\n+\n+uint32_t\n+fm10k_switch_multi_glort_get(uint8_t lport1, uint8_t lport2,\n+\t\tuint16_t vlan1, uint16_t vlan2, bool *p_new)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < FM10K_SW_FFU_RULE_MAX; i++) {\n+\t\tif (lport1 == fm10k_multi_glorts[i].lport1 &&\n+\t\t   lport2 == fm10k_multi_glorts[i].lport2 &&\n+\t\t   vlan1 == fm10k_multi_glorts[i].vlan1 &&\n+\t\t   vlan2 == fm10k_multi_glorts[i].vlan2) {\n+\t\t\tif (p_new != NULL)\n+\t\t\t\t*p_new = false;\n+\t\t\treturn FM10K_SW_MULTI_GLORT_START + i;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < FM10K_SW_FFU_RULE_MAX; i++) {\n+\t\tif (fm10k_multi_glorts[i].lport1 == 0 &&\n+\t\t   fm10k_multi_glorts[i].lport2 == 0 &&\n+\t\t   fm10k_multi_glorts[i].vlan1 == 0 &&\n+\t\t   fm10k_multi_glorts[i].vlan2 == 0) {\n+\t\t\tfm10k_multi_glorts[i].lport1 = lport1;\n+\t\t\tfm10k_multi_glorts[i].lport2 = lport2;\n+\t\t\tfm10k_multi_glorts[i].vlan1 = vlan1;\n+\t\t\tfm10k_multi_glorts[i].vlan2 = vlan2;\n+\t\t\tif (p_new != NULL)\n+\t\t\t\t*p_new = true;\n+\t\t\treturn FM10K_SW_MULTI_GLORT_START + i;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\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+struct fm10k_device_info*\n+fm10k_get_device_info(struct fm10k_hw *hw)\n+{\n+\tunsigned int i;\n+\tstruct fm10k_device_info *info;\n+\tuint16_t pci_vendor = hw->vendor_id;\n+\tuint16_t pci_device = hw->device_id;\n+\tuint16_t pci_subvendor = hw->subsystem_vendor_id;\n+\tuint16_t pci_subdevice = hw->subsystem_device_id;\n+\n+\tif (pci_vendor != FM10K_SW_VENDOR_ID_INTEL ||\n+\t    pci_device != FM10K_SW_DEV_ID_FM10K)\n+\t\treturn (NULL);\n+\n+\tfor (i = 0;\n+\t\t\ti < sizeof(fm10k_device_table) /\n+\t\t\t\tsizeof(fm10k_device_table[0]);\n+\t\t\ti++) {\n+\t\tinfo = &fm10k_device_table[i];\n+\t\tif (pci_subvendor == info->subvendor &&\n+\t\t    pci_subdevice == info->subdevice) {\n+\t\t\treturn info;\n+\t\t}\n+\t}\n+\n+\treturn NULL;\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+\t\t/* XXX\twhat is the physical config for 25G? */\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+\n+\t\t\t/* XXX add 10GBASER config */\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 * XXX 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/* XXX 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/* XXX 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 *\t00000000: No link\n+\t\t\t *\t00000001: 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/* XXX 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 (1) {\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+\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 * XXX 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 * XXX 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+\tprintf(\"--- FM10K DYNAMIC CONFIG ---\\n\");\n+\tprintf(\"  PF Bind  : %d\\n\", sw->dpdk_cfg->pf_bind);\n+\n+\tprintf(\"--- 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\tprintf(\"  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+\tprintf(\"--- 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\tprintf(\"  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\tprintf(\"  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+\tprintf(\"--- 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\tprintf(\"  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\tprintf(\"\\n\");\n+\t\telse if (map->type == FM10K_CONFIG_PORT_MAP_PF)\n+\t\t\tprintf(\" Map to PF%d\\n\", map->map_no[0]);\n+\t\telse\n+\t\t\tprintf(\" 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": [
        "v2",
        "4/7"
    ]
}