From patchwork Tue Aug 29 10:17:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mykola Kostenok X-Patchwork-Id: 130834 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9A44841F54; Tue, 29 Aug 2023 12:18:19 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4E34C409FA; Tue, 29 Aug 2023 12:17:25 +0200 (CEST) Received: from egress-ip27b.ess.de.barracuda.com (egress-ip27b.ess.de.barracuda.com [18.185.115.231]) by mails.dpdk.org (Postfix) with ESMTP id B1086402C4 for ; Tue, 29 Aug 2023 12:17:18 +0200 (CEST) Received: from EUR05-DB8-obe.outbound.protection.outlook.com (mail-db8eur05lp2106.outbound.protection.outlook.com [104.47.17.106]) by mx-outbound19-169.eu-central-1b.ess.aws.cudaops.com (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Tue, 29 Aug 2023 10:17:16 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=lj3zIogBKVUfmJZvQwvvnzRhoBltJtl4MIZlzT0fVqiJuxya09Akpx76AYnCUb0bzsnlKBpp7UGRN8wwW8jslXAr8hGtPUQgBEUAfy6clDbYGOX88BXll9dSn+Ewu0rqSHMLtGGe/fXheFfxbf2F9RoVqvuIwHD8+0nbrOS29W5m4lRUfqOhrOM+1uvulGNNO4sO2/sil2kYK8RjzklCyu9ZdnbhHZfwMeBONz4dbxT3hcHIXWDsrgqscQgOx1cvexXII0ST68M7ac6EGfFOi7bX2fBPdBrDTliJKrrxnT8n/uyo3LgtALr1wKdpSzb8G5dcr0fBJ5mHrEP50n4EzQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=coaSWDzaaKevc53tnjLZCjyrixItwk0PKdKMoAXdpgc=; b=SPSwfAcm3o9sou+NBjwqDRi8HbyHsRPkzCFzPaPQOqe3NocuCosI1TBFl21jRs88dtsS+WDwfBYRR5OF0lZNDWW7WzasObOjwknSxZy7NH2Pq+jtT/2ifxpbYHtbu2JFqdnkuu/ZpDZjfxTUAqJ+r2Y3usGIteUHT5+ZH5qkOiOwEjvj3kmvt3XCz15PYStDOhOFlgmgc9VielUlrFafdpYoO4gYuUKQ4XYSwAupMZrMJ1vktkNSoy5uPCTo4hx1x3MUWHPeL7zmcJ33u7eDYxMnIHVBHLeOVs/P8PUOe6pPzG98TnR/ucl1fB+Y0G1GG9BCQtCDYRh0MUDycNzjRQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=fail (sender ip is 178.72.21.4) smtp.rcpttodomain=dpdk.org smtp.mailfrom=napatech.com; dmarc=fail (p=none sp=none pct=100) action=none header.from=napatech.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=napatech.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=coaSWDzaaKevc53tnjLZCjyrixItwk0PKdKMoAXdpgc=; b=EjWpuo/Mtg6ZqUcmeJRcIldyWlxt2L6lV+waOTPaIAvDDGY4WCEXJBmNp0YMdL7BkOt7ygr8Ap+P/KlFt4c5qjY9IfDLUKuy0Yc+EzdeExD4HsT68o3V3e7vGK2WecwGM5YCKorDP29puDYes8bNN5OXqldKBlh3G+MjqCrH428= Received: from AS4P189CA0044.EURP189.PROD.OUTLOOK.COM (2603:10a6:20b:5dd::13) by AM8P190MB0834.EURP190.PROD.OUTLOOK.COM (2603:10a6:20b:1d8::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6699.35; Tue, 29 Aug 2023 10:16:55 +0000 Received: from AMS1EPF00000045.eurprd04.prod.outlook.com (2603:10a6:20b:5dd:cafe::cf) by AS4P189CA0044.outlook.office365.com (2603:10a6:20b:5dd::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6699.35 via Frontend Transport; Tue, 29 Aug 2023 10:16:55 +0000 X-MS-Exchange-Authentication-Results: spf=fail (sender IP is 178.72.21.4) smtp.mailfrom=napatech.com; dkim=none (message not signed) header.d=none;dmarc=fail action=none header.from=napatech.com; Received-SPF: Fail (protection.outlook.com: domain of napatech.com does not designate 178.72.21.4 as permitted sender) receiver=protection.outlook.com; client-ip=178.72.21.4; helo=k8s-node.default.svc.cluster.local; Received: from k8s-node.default.svc.cluster.local (178.72.21.4) by AMS1EPF00000045.mail.protection.outlook.com (10.167.16.42) with Microsoft SMTP Server id 15.20.6745.16 via Frontend Transport; Tue, 29 Aug 2023 10:16:55 +0000 From: Mykola Kostenok To: dev@dpdk.org, mko-plv@napatech.com, thomas@monjalon.net Cc: ckm@napatech.com Subject: [PATCH v9 2/8] net/ntnic: adds core registers and fpga functionality Date: Tue, 29 Aug 2023 12:17:17 +0200 Message-Id: <20230829101723.1295814-2-mko-plv@napatech.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20230829101723.1295814-1-mko-plv@napatech.com> References: <20230816132552.2483752-1-mko-plv@napatech.com> <20230829101723.1295814-1-mko-plv@napatech.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AMS1EPF00000045:EE_|AM8P190MB0834:EE_ X-MS-Office365-Filtering-Correlation-Id: 46be6e6d-a1da-4a57-740a-08dba8791267 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: rBkXLNKV++ybx312V2m1t8vPYeZdx7S5CIx/aNIdt8q7h4GJGX72Tvy3YvU4XuWtIogkDt8jdwL8C0y6ezW0g/XdYswBVHUoZiaC+GdlC7DuoD3MfQr1M7KczK+eaTdjmWd90hQRAW1bekeL6BNfNNvay86K+vONpPMIc/2RqlJNon02bOe+1mvF/6OZLOcd5WzCccZVyvbBDw00i6gxr7Ya5jv8NpzGPk5KmlUqPCFvR5417sLcX6Mbn64iHZ0mrB/yXq5J49DReV22FLzhU6J09tewjAf7dyyK9HS4qgoib9iD3HltoYRhYOtKUhFPZvW/49BynZOviJ6cCbmyksyJJXYWnB14ySyNBNsw0BIMWlj3QkOGHqTNH643T6WiseFvnv5Swz/lX5jFzqAdYEr7UmspYD2luMUkxrEZ5GKHpMAykRmm8LKZN8ugsbFblv/PIz75EhqkjBF4A77dOIZqhJFWgEmkIaPIoc/8uCXqjBl3nD9wAVN8dIV0zT/mxCQ/ZCZm2DEXyYV5ILg887Amd3M5KrdPkRckSQV2KS8SmAwCYFuP1a299t4dRoCCgKzY9lpexvAVCdQB8vVkZFQwFejivAyYMrgpSNXzASgZom8uVzFbAsBz3OJXFCnuEKVSxJUD29cbYfZI4iBMpLOxlgTPlLOWnNfiHlpO0eZyGasfE5pGSq9+UNbTu9VkKIm8JhjkUATWX9XuxEvCdgrOrcHsi8jmnNh594mxxzMQRK3CwmbOU26fE28JSVQL X-Forefront-Antispam-Report: CIP:178.72.21.4; CTRY:DK; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:k8s-node.default.svc.cluster.local; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230031)(376002)(39840400004)(346002)(396003)(136003)(82310400011)(186009)(451199024)(1800799009)(36840700001)(46966006)(6512007)(6506007)(6666004)(6486002)(19627235002)(478600001)(83380400001)(107886003)(956004)(336012)(1076003)(26005)(2906002)(30864003)(2616005)(36736006)(316002)(41300700001)(70206006)(70586007)(9316004)(8936002)(5660300002)(8676002)(4326008)(36756003)(40480700001)(47076005)(36860700001)(86362001)(15974865002)(81166007)(356005)(21314003)(36900700001)(579004)(559001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0: iHD31pM/wtCC/z2OM3fSX8QWQW+0uOxlWgNN+6dl2IQNHT6NDfJbuMilE3RpZQ/bwOBNAaam9Syg8hNd+ZpX6Bpjd2ICjcyw5X3xaeWbCeZQfx2SfOX+uSWcup4kyGYLeGGTfOTPmCboApNqiLKF/NqA3VxVtNB17/Sq17hd1+Jai4Bk4A+ojlovb28tfYqPSrYndziw9HdOIdvks/os/+8lJYl7iAMIhvK/G14wcYGmIpQVoN/KDx2Eqc1joTXfQF1Qruenq2apz461jOdDWtWMTHBAWRkQ7Wr+8YClekh3Ql1bwBnZCTa5M0GfYmJaJ0cWGToyeyypzzxv+ZLgkiIVjylvk0HEtXfAdCyRQMB9JK/vEYOeYwWdJFrzRa0v3x/vhGE9Kamwsj/Blj6Z/IfhJdpLXS2rulDlLaruJqXbahQYSyBq9/rLmcopdmF0ZoeDfzj/zVscISrYgyRXzsw3o05QwEiw+ihLadbLWcuLOuxjAnpL+OvsVwifExM3yXS4X2FJ35hIecyl1PgDBQFfVMS1nr3BwIE+JAqvg680FRU4iTfTVXSxSqZTbynfRxdxGtnXPZs/rPXd2AQWOiidiwh39zG98eoSKsxo9G0SmPPBXtUdGiDlpb/0H6MxZCfSmNWkxCquU8pkd2LowW8conPACdFReD5pnGEmRQ/jUO8z8BkRY6TZHr6ZE8vS9pSrniVF0wIbllnLXVGckcGGfglvAWEj0tKEXsS2mYCbibwrKuE4d+k8usBKbpTEde9jGiD84JA07OwOk3gzn3qAfap3io/u2nmpHRp0wOQ= X-OriginatorOrg: napatech.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Aug 2023 10:16:55.5242 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 46be6e6d-a1da-4a57-740a-08dba8791267 X-MS-Exchange-CrossTenant-Id: c4540d0b-728a-4233-9da5-9ea30c7ec3ed X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=c4540d0b-728a-4233-9da5-9ea30c7ec3ed; Ip=[178.72.21.4]; Helo=[k8s-node.default.svc.cluster.local] X-MS-Exchange-CrossTenant-AuthSource: AMS1EPF00000045.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM8P190MB0834 X-BESS-ID: 1693304231-305033-12339-16306-2 X-BESS-VER: 2019.1_20230822.1529 X-BESS-Apparent-Source-IP: 104.47.17.106 X-BESS-Parts: H4sIAAAAAAACA4uuVkqtKFGyUioBkjpK+cVKVqaGhmYmZkB2BlDYKCUxycwkNd HIzDgx2TTRKCXZ1NgyJcUsLdnMItHIwlKpNhYAcGvTrkMAAAA= X-BESS-Outbound-Spam-Score: 0.00 X-BESS-Outbound-Spam-Report: Code version 3.2, rules version 3.2.2.250465 [from cloudscan22-3.eu-central-1b.ess.aws.cudaops.com] Rule breakdown below pts rule name description ---- ---------------------- -------------------------------- 0.00 LARGE_BODY_SHORTCUT META: X-BESS-Outbound-Spam-Status: SCORE=0.00 using account:ESS113687 scores of KILL_LEVEL=7.0 tests=LARGE_BODY_SHORTCUT X-BESS-BRTS-Status: 1 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Christian Koue Muf Includes functionality to reset, initialize, program, and collect stats for the NTNIC FPGA. Signed-off-by: Christian Koue Muf Reviewed-by: Mykola Kostenok --- v2: * Fixed WARNING:TYPO_SPELLING * Fix compilation for Fedora38 v3: * Fixed WARNING:TYPO_SPELLING * Fix compilation for Fedora38 v9: * Add missing header --- drivers/net/ntnic/include/nthw_bus.h | 10 + drivers/net/ntnic/meson.build | 32 + .../net/ntnic/nthw/core/nthw_clock_profiles.c | 9 + .../net/ntnic/nthw/core/nthw_clock_profiles.h | 39 + drivers/net/ntnic/nthw/core/nthw_core.h | 31 + drivers/net/ntnic/nthw/core/nthw_fpga.c | 914 +++++++++ drivers/net/ntnic/nthw/core/nthw_fpga.h | 47 + .../net/ntnic/nthw/core/nthw_fpga_nt200a0x.c | 46 + .../net/ntnic/nthw/core/nthw_fpga_nt200a0x.h | 14 + drivers/net/ntnic/nthw/core/nthw_fpga_rst.c | 10 + drivers/net/ntnic/nthw/core/nthw_fpga_rst.h | 17 + .../net/ntnic/nthw/core/nthw_fpga_rst9563.c | 241 +++ .../ntnic/nthw/core/nthw_fpga_rst_nt200a0x.c | 674 +++++++ .../ntnic/nthw/core/nthw_fpga_rst_nt200a0x.h | 89 + drivers/net/ntnic/nthw/core/nthw_gpio_phy.c | 271 +++ drivers/net/ntnic/nthw/core/nthw_gpio_phy.h | 57 + drivers/net/ntnic/nthw/core/nthw_hif.c | 342 ++++ drivers/net/ntnic/nthw/core/nthw_hif.h | 156 ++ drivers/net/ntnic/nthw/core/nthw_iic.c | 570 ++++++ drivers/net/ntnic/nthw/core/nthw_iic.h | 101 + drivers/net/ntnic/nthw/core/nthw_mac_pcs.c | 1034 ++++++++++ drivers/net/ntnic/nthw/core/nthw_mac_pcs.h | 261 +++ .../net/ntnic/nthw/core/nthw_mac_pcs_xxv.c | 1631 ++++++++++++++++ .../net/ntnic/nthw/core/nthw_mac_pcs_xxv.h | 291 +++ drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.c | 121 ++ drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.h | 51 + drivers/net/ntnic/nthw/core/nthw_pci_ta.c | 99 + drivers/net/ntnic/nthw/core/nthw_pci_ta.h | 40 + drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.c | 127 ++ drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.h | 55 + drivers/net/ntnic/nthw/core/nthw_pcie3.c | 274 +++ drivers/net/ntnic/nthw/core/nthw_pcie3.h | 100 + drivers/net/ntnic/nthw/core/nthw_sdc.c | 177 ++ drivers/net/ntnic/nthw/core/nthw_sdc.h | 43 + drivers/net/ntnic/nthw/core/nthw_si5340.c | 206 ++ drivers/net/ntnic/nthw/core/nthw_si5340.h | 34 + drivers/net/ntnic/nthw/core/nthw_spi_v3.c | 380 ++++ drivers/net/ntnic/nthw/core/nthw_spi_v3.h | 106 ++ drivers/net/ntnic/nthw/core/nthw_spim.c | 117 ++ drivers/net/ntnic/nthw/core/nthw_spim.h | 52 + drivers/net/ntnic/nthw/core/nthw_spis.c | 147 ++ drivers/net/ntnic/nthw/core/nthw_spis.h | 63 + drivers/net/ntnic/nthw/core/nthw_tsm.c | 179 ++ drivers/net/ntnic/nthw/core/nthw_tsm.h | 53 + drivers/net/ntnic/nthw/nthw_dbs.c | 1301 +++++++++++++ drivers/net/ntnic/nthw/nthw_dbs.h | 313 +++ drivers/net/ntnic/nthw/nthw_drv.h | 82 + drivers/net/ntnic/nthw/nthw_epp.c | 335 ++++ drivers/net/ntnic/nthw/nthw_epp.h | 99 + drivers/net/ntnic/nthw/nthw_fpga_model.c | 1677 +++++++++++++++++ drivers/net/ntnic/nthw/nthw_fpga_model.h | 308 +++ drivers/net/ntnic/nthw/nthw_helper.h | 21 + drivers/net/ntnic/nthw/nthw_platform.c | 35 + drivers/net/ntnic/nthw/nthw_platform_drv.h | 42 + drivers/net/ntnic/nthw/nthw_profile.h | 15 + drivers/net/ntnic/nthw/nthw_rac.c | 976 ++++++++++ drivers/net/ntnic/nthw/nthw_rac.h | 161 ++ drivers/net/ntnic/nthw/nthw_register.h | 2 + drivers/net/ntnic/nthw/nthw_stat.c | 266 +++ drivers/net/ntnic/nthw/nthw_stat.h | 72 + drivers/net/ntnic/ntlog/include/ntlog.h | 162 ++ drivers/net/ntnic/ntlog/ntlog.c | 115 ++ drivers/net/ntnic/ntutil/include/nt_util.h | 72 + drivers/net/ntnic/ntutil/nt_util.c | 77 + 64 files changed, 15442 insertions(+) create mode 100644 drivers/net/ntnic/include/nthw_bus.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_clock_profiles.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_clock_profiles.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_core.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga_nt200a0x.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga_nt200a0x.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga_rst.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga_rst.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga_rst9563.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga_rst_nt200a0x.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga_rst_nt200a0x.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_gpio_phy.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_gpio_phy.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_hif.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_hif.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_iic.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_iic.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_mac_pcs.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_mac_pcs.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_pci_ta.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_pci_ta.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_pcie3.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_pcie3.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_sdc.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_sdc.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_si5340.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_si5340.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_spi_v3.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_spi_v3.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_spim.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_spim.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_spis.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_spis.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_tsm.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_tsm.h create mode 100644 drivers/net/ntnic/nthw/nthw_dbs.c create mode 100644 drivers/net/ntnic/nthw/nthw_dbs.h create mode 100644 drivers/net/ntnic/nthw/nthw_drv.h create mode 100644 drivers/net/ntnic/nthw/nthw_epp.c create mode 100644 drivers/net/ntnic/nthw/nthw_epp.h create mode 100644 drivers/net/ntnic/nthw/nthw_fpga_model.c create mode 100644 drivers/net/ntnic/nthw/nthw_fpga_model.h create mode 100644 drivers/net/ntnic/nthw/nthw_helper.h create mode 100644 drivers/net/ntnic/nthw/nthw_platform.c create mode 100644 drivers/net/ntnic/nthw/nthw_platform_drv.h create mode 100644 drivers/net/ntnic/nthw/nthw_profile.h create mode 100644 drivers/net/ntnic/nthw/nthw_rac.c create mode 100644 drivers/net/ntnic/nthw/nthw_rac.h create mode 100644 drivers/net/ntnic/nthw/nthw_stat.c create mode 100644 drivers/net/ntnic/nthw/nthw_stat.h create mode 100644 drivers/net/ntnic/ntlog/include/ntlog.h create mode 100644 drivers/net/ntnic/ntlog/ntlog.c create mode 100644 drivers/net/ntnic/ntutil/include/nt_util.h create mode 100644 drivers/net/ntnic/ntutil/nt_util.c diff --git a/drivers/net/ntnic/include/nthw_bus.h b/drivers/net/ntnic/include/nthw_bus.h new file mode 100644 index 0000000000..975cc95e78 --- /dev/null +++ b/drivers/net/ntnic/include/nthw_bus.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_BUS_H__ +#define __NTHW_BUS_H__ + +typedef uint8_t rab_bus_id_t; + +#endif /* __NTHW_BUS_H__ */ diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build index 1194ce6aea..428fc7af98 100644 --- a/drivers/net/ntnic/meson.build +++ b/drivers/net/ntnic/meson.build @@ -11,13 +11,45 @@ endif includes = [ include_directories('.'), include_directories('include'), + include_directories('ntlog/include'), + include_directories('ntutil/include'), include_directories('nthw'), + include_directories('nthw/core'), include_directories('nthw/supported'), ] # all sources sources = files( + 'nthw/core/nthw_clock_profiles.c', + 'nthw/core/nthw_fpga.c', + 'nthw/core/nthw_fpga_nt200a0x.c', + 'nthw/core/nthw_fpga_rst.c', + 'nthw/core/nthw_fpga_rst9563.c', + 'nthw/core/nthw_fpga_rst_nt200a0x.c', + 'nthw/core/nthw_gpio_phy.c', + 'nthw/core/nthw_hif.c', + 'nthw/core/nthw_iic.c', + 'nthw/core/nthw_mac_pcs.c', + 'nthw/core/nthw_mac_pcs_xxv.c', + 'nthw/core/nthw_pci_rd_tg.c', + 'nthw/core/nthw_pci_ta.c', + 'nthw/core/nthw_pci_wr_tg.c', + 'nthw/core/nthw_pcie3.c', + 'nthw/core/nthw_sdc.c', + 'nthw/core/nthw_si5340.c', + 'nthw/core/nthw_spi_v3.c', + 'nthw/core/nthw_spim.c', + 'nthw/core/nthw_spis.c', + 'nthw/core/nthw_tsm.c', + 'nthw/nthw_fpga_model.c', + 'nthw/nthw_dbs.c', + 'nthw/nthw_epp.c', + 'nthw/nthw_platform.c', + 'nthw/nthw_rac.c', + 'nthw/nthw_stat.c', 'nthw/supported/nthw_fpga_9563_055_024_0000.c', + 'ntlog/ntlog.c', + 'ntutil/nt_util.c', ) if is_variable('default_cflags') diff --git a/drivers/net/ntnic/nthw/core/nthw_clock_profiles.c b/drivers/net/ntnic/nthw/core/nthw_clock_profiles.c new file mode 100644 index 0000000000..efdcc222a8 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_clock_profiles.c @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "nthw_clock_profiles.h" + +/* Clock profile for NT200A02 2x40G, 2x100G */ +const int n_data_si5340_nt200a02_u23_v5; +const clk_profile_data_fmt2_t *p_data_si5340_nt200a02_u23_v5; diff --git a/drivers/net/ntnic/nthw/core/nthw_clock_profiles.h b/drivers/net/ntnic/nthw/core/nthw_clock_profiles.h new file mode 100644 index 0000000000..4252f69e92 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_clock_profiles.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_CLOCK_PROFILES_H__ +#define __NTHW_CLOCK_PROFILES_H__ + +#include + +#include "nthw_helper.h" + +#define clk_profile_size_error_msg "size test failed" + +typedef struct { + unsigned char reg_addr; + unsigned char reg_val; + unsigned char reg_mask; +} clk_profile_data_fmt0_t; + +typedef struct { + uint16_t reg_addr; + uint8_t reg_val; +} clk_profile_data_fmt1_t; + +typedef struct { + unsigned int reg_addr; + unsigned char reg_val; +} clk_profile_data_fmt2_t; + +typedef enum { + CLK_PROFILE_DATA_FMT_0, + CLK_PROFILE_DATA_FMT_1, + CLK_PROFILE_DATA_FMT_2 +} clk_profile_data_fmt_t; + +extern const int n_data_si5340_nt200a02_u23_v5; +extern const clk_profile_data_fmt2_t *p_data_si5340_nt200a02_u23_v5; + +#endif /* __NTHW_CLOCK_PROFILES_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_core.h b/drivers/net/ntnic/nthw/core/nthw_core.h new file mode 100644 index 0000000000..798a95d5cf --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_core.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_CORE_H__ +#define __NTHW_CORE_H__ + +#include "nthw_helper.h" + +#include "nthw_platform_drv.h" +#include "nthw_fpga_model.h" +#include "nthw_hif.h" +#include "nthw_pcie3.h" +#include "nthw_pci_rd_tg.h" +#include "nthw_pci_wr_tg.h" +#include "nthw_pci_ta.h" +#include "nthw_iic.h" + +#include "nthw_gpio_phy.h" +#include "nthw_mac_pcs.h" +#include "nthw_mac_pcs_xxv.h" +#include "nthw_sdc.h" + +#include "nthw_spim.h" +#include "nthw_spis.h" + +#include "nthw_tsm.h" + +#include "nthw_si5340.h" + +#endif /* __NTHW_CORE_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga.c b/drivers/net/ntnic/nthw/core/nthw_fpga.c new file mode 100644 index 0000000000..646d45b7eb --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga.c @@ -0,0 +1,914 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_fpga.h" +#include "nthw_fpga_instances.h" + +#include "nthw_spi_v3.h" + +#include + +int nthw_fpga_get_param_info(struct fpga_info_s *p_fpga_info, nt_fpga_t *p_fpga) +{ + const int n_nims = fpga_get_product_param(p_fpga, NT_NIMS, -1); + const int n_phy_ports = fpga_get_product_param(p_fpga, NT_PHY_PORTS, -1); + const int n_phy_quads = fpga_get_product_param(p_fpga, NT_PHY_QUADS, -1); + const int n_rx_ports = fpga_get_product_param(p_fpga, NT_RX_PORTS, -1); + const int n_tx_ports = fpga_get_product_param(p_fpga, NT_TX_PORTS, -1); + + p_fpga_info->n_nims = n_nims; + p_fpga_info->n_phy_ports = n_phy_ports; + p_fpga_info->n_phy_quads = n_phy_quads; + p_fpga_info->n_rx_ports = n_rx_ports; + p_fpga_info->n_tx_ports = n_tx_ports; + p_fpga_info->profile = FPGA_INFO_PROFILE_UNKNOWN; + + /* Check for VSWITCH FPGA */ + if (fpga_get_product_param(p_fpga, NT_NFV_OVS_PRODUCT, 0) != 0) + p_fpga_info->profile = FPGA_INFO_PROFILE_VSWITCH; + /* Check for VSWITCH FPGA - legacy */ + else if (fpga_get_product_param(p_fpga, NT_IOA_PRESENT, 0) != 0) + p_fpga_info->profile = FPGA_INFO_PROFILE_VSWITCH; + + else if (fpga_get_product_param(p_fpga, NT_QM_PRESENT, 0) != 0) + p_fpga_info->profile = FPGA_INFO_PROFILE_CAPTURE; + + else + p_fpga_info->profile = FPGA_INFO_PROFILE_INLINE; + + return 0; +} + +int nthw_fpga_iic_read_byte(nt_fpga_t *p_fpga, const int n_instance_no, + const uint8_t n_dev_addr, const uint8_t n_reg_addr) +{ + nthw_iic_t nthw_iic; + uint8_t val = 0; + + if (nthw_iic_init(&nthw_iic, p_fpga, n_instance_no, 8) != 0) + return -1; + + if (nthw_iic_readbyte(&nthw_iic, n_dev_addr, n_reg_addr, 1, &val) == 0) + return val; + + else + return -1; +} + +int nthw_fpga_iic_write_byte(nt_fpga_t *p_fpga, const int n_instance_no, + const uint8_t n_dev_addr, const uint8_t n_reg_addr, + uint8_t val) +{ + nthw_iic_t nthw_iic; + + if (nthw_iic_init(&nthw_iic, p_fpga, n_instance_no, 8) != 0) + return -1; + + if (nthw_iic_writebyte(&nthw_iic, n_dev_addr, n_reg_addr, 1, &val) != 0) + return -1; + + return 0; +} + +int nthw_fpga_iic_scan(nt_fpga_t *p_fpga, const int n_instance_no_begin, + const int n_instance_no_end) +{ + int i; + + assert(n_instance_no_begin <= n_instance_no_end); + + for (i = n_instance_no_begin; i <= n_instance_no_end; i++) { + nthw_iic_t *p_nthw_iic = nthw_iic_new(); + + if (p_nthw_iic) { + const int rc = nthw_iic_init(p_nthw_iic, p_fpga, i, 8); + + if (rc == 0) { + nthw_iic_set_retry_params(p_nthw_iic, -1, 100, 100, + 3, 3); + nthw_iic_scan(p_nthw_iic); + } + nthw_iic_delete(p_nthw_iic); + p_nthw_iic = NULL; + } + } + return 0; +} + +int nthw_fpga_silabs_detect(nt_fpga_t *p_fpga, const int n_instance_no, + const int n_dev_addr, const int n_page_reg_addr) +{ + const char *const p_adapter_id_str _unused = + p_fpga->p_fpga_info->mp_adapter_id_str; + uint64_t ident = -1; + int res = -1; + + nthw_iic_t *p_nthw_iic = nthw_iic_new(); + + if (p_nthw_iic) { + uint8_t data; + uint8_t a_silabs_ident[8]; + + nthw_iic_init(p_nthw_iic, p_fpga, n_instance_no, 8); + + data = 0; + /* switch to page 0 */ + nthw_iic_write_data(p_nthw_iic, (uint8_t)n_dev_addr, + (uint8_t)n_page_reg_addr, 1, &data); + res = nthw_iic_read_data(p_nthw_iic, (uint8_t)n_dev_addr, 0x00, + sizeof(a_silabs_ident), a_silabs_ident); + if (res == 0) { + int i; + + for (i = 0; i < (int)sizeof(a_silabs_ident); i++) { + ident <<= 8; + ident |= a_silabs_ident[i]; + } + } + nthw_iic_delete(p_nthw_iic); + p_nthw_iic = NULL; + + /* Conclude SiLabs part */ + if (res == 0) { + if (a_silabs_ident[3] == 0x53) { + if (a_silabs_ident[2] == 0x40) + res = 5340; + else if (a_silabs_ident[2] == 0x41) + res = 5341; + } else if (a_silabs_ident[2] == 38) { + res = 5338; + } else { + res = -1; + } + } + } + + NT_LOG(DBG, NTHW, "%s: %016" PRIX64 ": %d\n", p_adapter_id_str, ident, + res); + return res; +} + +/* + * Calculate CRC-16-CCITT of passed data + * CRC-16-CCITT ^16 + ^12 + ^5 + 1 (0x1021) (X.25, HDLC, XMODEM, Bluetooth, + * SD, many others; known as CRC-CCITT) + */ +static uint16_t crc16(uint8_t *buffer, size_t length) +{ + uint16_t seed = 0; + + while (length--) { + seed = (uint16_t)(seed >> 8 | seed << 8); + seed = (uint16_t)(seed ^ *buffer++); + seed = (uint16_t)(seed ^ (seed & 0xff) >> 4); + seed = (uint16_t)(seed ^ seed << 8 << 4); + seed = (uint16_t)(seed ^ (seed & 0xff) << 4 << 1); + } + return seed; +} + +int nthw_fpga_avr_probe(nt_fpga_t *p_fpga, const int n_instance_no) +{ + struct fpga_info_s *p_fpga_info = p_fpga->p_fpga_info; + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + nthw_spi_v3_t *p_avr_spi; + int res = -1; + + p_avr_spi = nthw_spi_v3_new(); + if (p_avr_spi) { + struct avr_vpd_info_s { + /* avr info */ + uint32_t n_avr_spi_version; + uint8_t n_avr_fw_ver_major; + uint8_t n_avr_fw_ver_minor; + uint8_t n_avr_fw_ver_micro; + uint8_t a_avr_fw_ver_str[50]; + uint8_t a_avr_fw_plat_id_str[20]; + + /* vpdEeprom_t */ + uint8_t psu_hw_version; + uint8_t vpd_pn[GEN2_PN_SIZE]; + uint8_t vpd_pba[GEN2_PBA_SIZE]; + uint8_t vpd_sn[GEN2_SN_SIZE]; + uint8_t vpd_board_name[GEN2_BNAME_SIZE]; + uint8_t vpd_platform_section[GEN2_PLATFORM_SIZE]; + + /* BoardInfo_t aka vpd_platform_section: */ + uint32_t product_family; /* uint8_t 1: capture, 2: Inline, 3: analysis */ + uint32_t feature_mask; /* Bit 0: OC192 capable */ + uint32_t invfeature_mask; + uint8_t no_of_macs; + uint8_t mac_address[6]; + uint16_t custom_id; + uint8_t user_id[8]; + /* + * Reserved NT operations to monitor the reprogram count of userId with + * vpduser + */ + uint16_t user_id_erase_write_count; + + /* + * AVR_OP_SYSINFO: struct version_sysinfo_request_container + * Which version of the sysinfo container to retrieve. Set to zero to fetch + * latest. offset zero of latest always contain an uint8_t version info + */ + uint8_t sysinfo_container_version; + + /* AVR_OP_SYSINFO: struct AvrLibcVersion */ + uint32_t sysinfo_avr_libc_version; /* The constant __AVR_LIBC_VERSION__ */ + + /* AVR_OP_SYSINFO: struct AvrLibcSignature */ + uint8_t sysinfo_signature_0; /* The constant SIGNATURE_0 */ + uint8_t sysinfo_signature_1; /* The constant SIGNATURE_1 */ + uint8_t sysinfo_signature_2; /* The constant SIGNATURE_2 */ + + /* AVR_OP_SYSINFO: struct AvrOs */ + uint8_t sysinfo_spi_version; /* SPI command layer version */ + /* + * Hardware revision. Locked to eeprom address zero. Is also available via + * VPD read opcode (prior to v1.4b, this is required) + */ + uint8_t sysinfo_hw_revision; + /* + * Number of ticks/second (Note: Be aware this may become zero if timer + * module is rewritten to a tickles system!) + */ + uint8_t sysinfo_ticks_per_second; + uint32_t sysinfo_uptime; /* Uptime in seconds since last AVR reset */ + uint8_t sysinfo_osccal; /* OSCCAL value */ + + /* + * Meta data concluded/calculated from req/reply + */ + bool b_feature_mask_valid; + bool b_crc16_valid; + uint16_t n_crc16_stored; + uint16_t n_crc16_calced; + uint64_t n_mac_val; + }; + + struct avr_vpd_info_s avr_vpd_info; + struct tx_rx_buf tx_buf; + struct tx_rx_buf rx_buf; + char rx_data[MAX_AVR_CONTAINER_SIZE]; + uint32_t u32; + + memset(&avr_vpd_info, 0, sizeof(avr_vpd_info)); + + nthw_spi_v3_init(p_avr_spi, p_fpga, n_instance_no); + + /* AVR_OP_SPI_VERSION */ + tx_buf.size = 0; + tx_buf.p_buf = NULL; + rx_buf.size = sizeof(u32); + rx_buf.p_buf = &u32; + u32 = 0; + res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_SPI_VERSION, &tx_buf, + &rx_buf); + avr_vpd_info.n_avr_spi_version = u32; + NT_LOG(DBG, NTHW, "%s: AVR%d: SPI_VER: %d\n", p_adapter_id_str, + n_instance_no, avr_vpd_info.n_avr_spi_version); + + /* AVR_OP_VERSION */ + tx_buf.size = 0; + tx_buf.p_buf = NULL; + rx_buf.size = sizeof(rx_data); + rx_buf.p_buf = &rx_data; + res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_VERSION, &tx_buf, + &rx_buf); + + avr_vpd_info.n_avr_fw_ver_major = rx_data[0]; + avr_vpd_info.n_avr_fw_ver_minor = rx_data[1]; + avr_vpd_info.n_avr_fw_ver_micro = rx_data[2]; + NT_LOG(DBG, NTHW, "%s: AVR%d: FW_VER: %c.%c.%c\n", + p_adapter_id_str, n_instance_no, avr_vpd_info.n_avr_fw_ver_major, + avr_vpd_info.n_avr_fw_ver_minor, + avr_vpd_info.n_avr_fw_ver_micro); + + memcpy(avr_vpd_info.a_avr_fw_ver_str, &rx_data[0 + 3], + sizeof(avr_vpd_info.a_avr_fw_ver_str)); + NT_LOG(DBG, NTHW, "%s: AVR%d: FW_VER_STR: '%.*s'\n", + p_adapter_id_str, n_instance_no, + (int)sizeof(avr_vpd_info.a_avr_fw_ver_str), + avr_vpd_info.a_avr_fw_ver_str); + + memcpy(avr_vpd_info.a_avr_fw_plat_id_str, &rx_data[0 + 3 + 50], + sizeof(avr_vpd_info.a_avr_fw_plat_id_str)); + NT_LOG(DBG, NTHW, "%s: AVR%d: FW_HW_ID_STR: '%.*s'\n", + p_adapter_id_str, n_instance_no, + (int)sizeof(avr_vpd_info.a_avr_fw_plat_id_str), + avr_vpd_info.a_avr_fw_plat_id_str); + + rte_strscpy(p_fpga_info->nthw_hw_info.hw_plat_id_str, + (char *)avr_vpd_info.a_avr_fw_plat_id_str, + sizeof(p_fpga_info->nthw_hw_info.hw_plat_id_str)); + p_fpga_info->nthw_hw_info.hw_plat_id_str + [sizeof(p_fpga_info->nthw_hw_info.hw_plat_id_str) - 1] = + 0; + + /* AVR_OP_SYSINFO_2 */ + tx_buf.size = 0; + tx_buf.p_buf = NULL; + rx_buf.size = sizeof(rx_data); + rx_buf.p_buf = &rx_data; + res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_SYSINFO_2, &tx_buf, + &rx_buf); + if (res == 0 && avr_vpd_info.n_avr_spi_version >= 3 && + rx_buf.size >= 16) { + if (rx_buf.size != 16) { + NT_LOG(WRN, NTHW, + "%s: AVR%d: SYSINFO2: reply is larger than expected: %04X %04X\n", + p_adapter_id_str, n_instance_no, rx_buf.size, + 16); + } else { + NT_LOG(DBG, NTHW, + "%s: AVR%d: SYSINFO2: OK: res=%d sz=%d\n", + p_adapter_id_str, n_instance_no, res, + rx_buf.size); + } + + avr_vpd_info.sysinfo_container_version = rx_data[0]; + NT_LOG(DBG, NTHW, "%s: AVR%d: SYSINFO_REQ_VER: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_container_version); + + memcpy(&avr_vpd_info.sysinfo_avr_libc_version, + &rx_data[0 + 1], + sizeof(avr_vpd_info.sysinfo_avr_libc_version)); + NT_LOG(DBG, NTHW, "%s: AVR%d: LIBC_VER: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_avr_libc_version); + + avr_vpd_info.sysinfo_signature_0 = rx_data[5]; + avr_vpd_info.sysinfo_signature_1 = rx_data[6]; + avr_vpd_info.sysinfo_signature_2 = rx_data[7]; + NT_LOG(DBG, NTHW, + "%s: AVR%d: SIGNATURE: %02x%02x%02x\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_signature_0, + avr_vpd_info.sysinfo_signature_1, + avr_vpd_info.sysinfo_signature_2); + + avr_vpd_info.sysinfo_spi_version = rx_data[8]; + NT_LOG(DBG, NTHW, "%s: AVR%d: SPI_VER: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_spi_version); + + avr_vpd_info.sysinfo_hw_revision = rx_data[9]; + NT_LOG(DBG, NTHW, "%s: AVR%d: HW_REV: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_hw_revision); + + avr_vpd_info.sysinfo_ticks_per_second = rx_data[10]; + NT_LOG(DBG, NTHW, "%s: AVR%d: TICKS_PER_SEC: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_ticks_per_second); + + memcpy(&avr_vpd_info.sysinfo_uptime, &rx_data[11], + sizeof(avr_vpd_info.sysinfo_uptime)); + NT_LOG(DBG, NTHW, "%s: AVR%d: UPTIME: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_uptime); + + avr_vpd_info.sysinfo_osccal = rx_data[15]; + NT_LOG(DBG, NTHW, "%s: AVR%d: OSCCAL: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_osccal); + + { + bool b_spi_ver_match _unused = + (avr_vpd_info.n_avr_spi_version == + avr_vpd_info.sysinfo_spi_version); + NT_LOG(DBG, NTHW, + "%s: AVR%d: SPI_VER_TST: %s (%d %d)\n", + p_adapter_id_str, n_instance_no, + (b_spi_ver_match ? "OK" : "MISMATCH"), + avr_vpd_info.n_avr_spi_version, + avr_vpd_info.sysinfo_spi_version); + } + /* SYSINFO2: if response: only populate hw_id not hw_id_emulated */ + p_fpga_info->nthw_hw_info.hw_id = + avr_vpd_info.sysinfo_hw_revision; + } else { + /* AVR_OP_SYSINFO */ + tx_buf.size = 0; + tx_buf.p_buf = NULL; + rx_buf.size = sizeof(rx_data); + rx_buf.p_buf = &rx_data; + res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_SYSINFO, + &tx_buf, &rx_buf); + if (res == 0 && avr_vpd_info.n_avr_spi_version >= 3 && + rx_buf.size >= 16) { + if (rx_buf.size != 16) { + NT_LOG(WRN, NTHW, + "%s: AVR%d: SYSINFO: reply is larger than expected: %04X %04X\n", + p_adapter_id_str, n_instance_no, + rx_buf.size, 16); + } else { + NT_LOG(DBG, NTHW, + "%s: AVR%d: SYSINFO: OK: res=%d sz=%d\n", + p_adapter_id_str, n_instance_no, res, + rx_buf.size); + } + + avr_vpd_info.sysinfo_container_version = + rx_data[0]; + NT_LOG(DBG, NTHW, + "%s: AVR%d: SYSINFO_REQ_VER: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_container_version); + + memcpy(&avr_vpd_info.sysinfo_avr_libc_version, + &rx_data[0 + 1], + sizeof(avr_vpd_info + .sysinfo_avr_libc_version)); + NT_LOG(DBG, NTHW, "%s: AVR%d: LIBC_VER: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_avr_libc_version); + + avr_vpd_info.sysinfo_signature_0 = rx_data[5]; + avr_vpd_info.sysinfo_signature_1 = rx_data[6]; + avr_vpd_info.sysinfo_signature_2 = rx_data[7]; + NT_LOG(DBG, NTHW, + "%s: AVR%d: SIGNATURE: %02x%02x%02x\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_signature_0, + avr_vpd_info.sysinfo_signature_1, + avr_vpd_info.sysinfo_signature_2); + + avr_vpd_info.sysinfo_spi_version = rx_data[8]; + NT_LOG(DBG, NTHW, "%s: AVR%d: SPI_VER: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_spi_version); + + avr_vpd_info.sysinfo_hw_revision = rx_data[9]; + NT_LOG(DBG, NTHW, "%s: AVR%d: HW_REV: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_hw_revision); + NT_LOG(INF, NTHW, "%s: AVR%d: HW_REV: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_hw_revision); + + avr_vpd_info.sysinfo_ticks_per_second = + rx_data[10]; + NT_LOG(DBG, NTHW, + "%s: AVR%d: TICKS_PER_SEC: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_ticks_per_second); + + memcpy(&avr_vpd_info.sysinfo_uptime, + &rx_data[11], + sizeof(avr_vpd_info.sysinfo_uptime)); + NT_LOG(DBG, NTHW, "%s: AVR%d: UPTIME: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_uptime); + + avr_vpd_info.sysinfo_osccal = rx_data[15]; + NT_LOG(DBG, NTHW, "%s: AVR%d: OSCCAL: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.sysinfo_osccal); + + { + bool b_spi_ver_match _unused = + (avr_vpd_info.n_avr_spi_version == + avr_vpd_info + .sysinfo_spi_version); + NT_LOG(DBG, NTHW, + "%s: AVR%d: SPI_VER_TST: %s (%d %d)\n", + p_adapter_id_str, n_instance_no, + (b_spi_ver_match ? "OK" : + "MISMATCH"), + avr_vpd_info.n_avr_spi_version, + avr_vpd_info.sysinfo_spi_version); + } + + p_fpga_info->nthw_hw_info.hw_id = + avr_vpd_info.sysinfo_hw_revision; + p_fpga_info->nthw_hw_info.hw_id_emulated = + avr_vpd_info.sysinfo_hw_revision; + } else { + NT_LOG(ERR, NTHW, + "%s: AVR%d: SYSINFO: NA: res=%d sz=%d\n", + p_adapter_id_str, n_instance_no, res, + rx_buf.size); + } + } + + /* AVR_OP_VPD_READ */ + tx_buf.size = 0; + tx_buf.p_buf = NULL; + rx_buf.size = sizeof(rx_data); + rx_buf.p_buf = &rx_data; + res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_VPD_READ, &tx_buf, + &rx_buf); + if (res == 0 && avr_vpd_info.n_avr_spi_version >= 3 && + rx_buf.size >= GEN2_VPD_SIZE_TOTAL) { + avr_vpd_info.n_crc16_calced = + crc16(rx_buf.p_buf, rx_buf.size - 2); + memcpy(&avr_vpd_info.n_crc16_stored, + &rx_data[rx_buf.size - 2], + sizeof(avr_vpd_info.n_crc16_stored)); + NT_LOG(DBG, NTHW, "%s: AVR%d: VPD_CRC: %04X %04X\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.n_crc16_stored, + avr_vpd_info.n_crc16_calced); + + avr_vpd_info.b_crc16_valid = (avr_vpd_info.n_crc16_stored == + avr_vpd_info.n_crc16_calced); + NT_LOG(DBG, NTHW, "%s: AVR%d: CRC_TST: %s\n", + p_adapter_id_str, n_instance_no, + (avr_vpd_info.b_crc16_valid ? "OK" : "ERROR")); + + if (avr_vpd_info.b_crc16_valid) { + memcpy(&avr_vpd_info.psu_hw_version, &rx_data[0], + sizeof(avr_vpd_info.psu_hw_version)); + NT_LOG(DBG, NTHW, "%s: AVR%d: PSU_HW_VER: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.psu_hw_version); + + memcpy(&avr_vpd_info.vpd_pn, &rx_data[0 + 1], + sizeof(avr_vpd_info.vpd_pn)); + NT_LOG(DBG, NTHW, "%s: AVR%d: PN: '%.*s'\n", + p_adapter_id_str, n_instance_no, GEN2_PN_SIZE, + avr_vpd_info.vpd_pn); + + memcpy(&avr_vpd_info.vpd_pba, + &rx_data[0 + 1 + GEN2_PN_SIZE], + sizeof(avr_vpd_info.vpd_pba)); + NT_LOG(DBG, NTHW, "%s: AVR%d: PBA: '%.*s'\n", + p_adapter_id_str, n_instance_no, + GEN2_PBA_SIZE, avr_vpd_info.vpd_pba); + + memcpy(&avr_vpd_info.vpd_sn, + &rx_data[0 + 1 + GEN2_PN_SIZE + + GEN2_PBA_SIZE], + sizeof(avr_vpd_info.vpd_sn)); + NT_LOG(DBG, NTHW, "%s: AVR%d: SN: '%.*s'\n", + p_adapter_id_str, n_instance_no, GEN2_SN_SIZE, + avr_vpd_info.vpd_sn); + + memcpy(&avr_vpd_info.vpd_board_name, + &rx_data[0 + 1 + GEN2_PN_SIZE + + GEN2_PBA_SIZE + GEN2_SN_SIZE], + sizeof(avr_vpd_info.vpd_board_name)); + NT_LOG(DBG, NTHW, "%s: AVR%d: BN: '%.*s'\n", + p_adapter_id_str, n_instance_no, + GEN2_BNAME_SIZE, + avr_vpd_info.vpd_board_name); + + { + uint32_t u1; + union mac_u { + uint8_t a_u8[8]; + uint16_t a_u16[4]; + uint32_t a_u32[2]; + uint64_t a_u64[1]; + } mac; + + /* vpd_platform_section */ + uint8_t *p_vpd_board_info = + (uint8_t *)(&rx_data[1 + + GEN2_PN_SIZE + + GEN2_PBA_SIZE + + GEN2_SN_SIZE + + GEN2_BNAME_SIZE]); + memcpy(&avr_vpd_info.product_family, + &p_vpd_board_info[0], + sizeof(avr_vpd_info + .product_family)); + NT_LOG(DBG, NTHW, + "%s: AVR%d: PROD_FAM: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.product_family); + + memcpy(&avr_vpd_info.feature_mask, + &p_vpd_board_info[0 + 4], + sizeof(avr_vpd_info.feature_mask)); + NT_LOG(DBG, NTHW, + "%s: AVR%d: FMSK_VAL: 0x%08X\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.feature_mask); + + memcpy(&avr_vpd_info.invfeature_mask, + &p_vpd_board_info[0 + 4 + 4], + sizeof(avr_vpd_info + .invfeature_mask)); + NT_LOG(DBG, NTHW, + "%s: AVR%d: FMSK_INV: 0x%08X\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.invfeature_mask); + + avr_vpd_info.b_feature_mask_valid = + (avr_vpd_info.feature_mask == + ~avr_vpd_info.invfeature_mask); + NT_LOG(DBG, NTHW, + "%s: AVR%d: FMSK_TST: %s\n", + p_adapter_id_str, n_instance_no, + (avr_vpd_info.b_feature_mask_valid ? + "OK" : + "ERROR")); + + memcpy(&avr_vpd_info.no_of_macs, + &p_vpd_board_info[0 + 4 + 4 + 4], + sizeof(avr_vpd_info.no_of_macs)); + NT_LOG(DBG, NTHW, + "%s: AVR%d: NUM_MACS: %d\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.no_of_macs); + + memcpy(&avr_vpd_info.mac_address, + &p_vpd_board_info[0 + 4 + 4 + 4 + 1], + sizeof(avr_vpd_info.mac_address)); + NT_LOG(DBG, NTHW, + "%s: AVR%d: MAC_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.mac_address[0], + avr_vpd_info.mac_address[1], + avr_vpd_info.mac_address[2], + avr_vpd_info.mac_address[3], + avr_vpd_info.mac_address[4], + avr_vpd_info.mac_address[5]); + + mac.a_u64[0] = 0; + memcpy(&mac.a_u8[2], + &avr_vpd_info.mac_address, + sizeof(avr_vpd_info.mac_address)); + u1 = ntohl(mac.a_u32[0]); + if (u1 != mac.a_u32[0]) { + const uint32_t u0 = ntohl(mac.a_u32[1]); + mac.a_u32[0] = u0; + mac.a_u32[1] = u1; + } + avr_vpd_info.n_mac_val = mac.a_u64[0]; + NT_LOG(DBG, NTHW, + "%s: AVR%d: MAC_U64: %012" PRIX64 + "\n", + p_adapter_id_str, n_instance_no, + avr_vpd_info.n_mac_val); + } + } + p_fpga_info->nthw_hw_info.vpd_info.mn_mac_addr_count = + avr_vpd_info.no_of_macs; + p_fpga_info->nthw_hw_info.vpd_info.mn_mac_addr_value = + avr_vpd_info.n_mac_val; + memcpy(p_fpga_info->nthw_hw_info.vpd_info.ma_mac_addr_octets, + avr_vpd_info.mac_address, + ARRAY_SIZE(p_fpga_info->nthw_hw_info.vpd_info + .ma_mac_addr_octets)); + } else { + NT_LOG(ERR, NTHW, "%s:%u: res=%d\n", __func__, __LINE__, + res); + NT_LOG(ERR, NTHW, + "%s: AVR%d: SYSINFO2: NA: res=%d sz=%d\n", + p_adapter_id_str, n_instance_no, res, rx_buf.size); + } + } + + return res; +} + +/* + * NT50B01, NT200A02, NT200A01-HWbuild2 + */ +int nthw_fpga_si5340_clock_synth_init_fmt2(nt_fpga_t *p_fpga, + const uint8_t n_iic_addr, + const clk_profile_data_fmt2_t *p_clk_profile, + const int n_clk_profile_rec_cnt) +{ + int res; + nthw_iic_t *p_nthw_iic = nthw_iic_new(); + nthw_si5340_t *p_nthw_si5340 = nthw_si5340_new(); + + assert(p_nthw_iic); + assert(p_nthw_si5340); + nthw_iic_init(p_nthw_iic, p_fpga, 0, 8); /* I2C cycle time 125Mhz ~ 8ns */ + + nthw_si5340_init(p_nthw_si5340, p_nthw_iic, + n_iic_addr); /* Si5340_U23_I2c_Addr_7bit */ + res = nthw_si5340_config_fmt2(p_nthw_si5340, p_clk_profile, + n_clk_profile_rec_cnt); + nthw_si5340_delete(p_nthw_si5340); + p_nthw_si5340 = NULL; + + return res; +} + +int nthw_fpga_init(struct fpga_info_s *p_fpga_info) +{ + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + + nthw_hif_t *p_nthw_hif = NULL; + nthw_pcie3_t *p_nthw_pcie3 = NULL; + nthw_rac_t *p_nthw_rac = NULL; + nthw_tsm_t *p_nthw_tsm = NULL; + + uint64_t n_fpga_ident = 0; + nt_fpga_mgr_t *p_fpga_mgr = NULL; + nt_fpga_t *p_fpga = NULL; + + char s_fpga_prod_ver_rev_str[32] = { 0 }; + + int res = 0; + + assert(p_fpga_info); + + { + int n_fpga_type_id, n_fpga_prod_id, n_fpga_ver_id, n_fpga_rev_id; + uint64_t n_fpga_ident; + uint32_t n_fpga_ident_low, n_fpga_ident_high, n_fpga_build_time; + + nthw_rac_reg_read32(p_fpga_info, 0x0, &n_fpga_ident_low); + nthw_rac_reg_read32(p_fpga_info, 0x8, &n_fpga_ident_high); + nthw_rac_reg_read32(p_fpga_info, 0x10, &n_fpga_build_time); + + n_fpga_ident = (((uint64_t)n_fpga_ident_high << 32) | n_fpga_ident_low); + n_fpga_type_id = FPGAID_TO_PRODUCTTYPE(n_fpga_ident); + n_fpga_prod_id = FPGAID_TO_PRODUCTCODE(n_fpga_ident); + n_fpga_ver_id = FPGAID_TO_VERSIONCODE(n_fpga_ident); + n_fpga_rev_id = FPGAID_TO_REVISIONCODE(n_fpga_ident); + + p_fpga_info->n_fpga_ident = n_fpga_ident; + p_fpga_info->n_fpga_type_id = n_fpga_type_id; + p_fpga_info->n_fpga_prod_id = n_fpga_prod_id; + p_fpga_info->n_fpga_ver_id = n_fpga_ver_id; + p_fpga_info->n_fpga_rev_id = n_fpga_rev_id; + p_fpga_info->n_fpga_build_time = n_fpga_build_time; + + snprintf(s_fpga_prod_ver_rev_str, sizeof(s_fpga_prod_ver_rev_str), + "%04d-%04d-%02d-%02d", n_fpga_type_id, n_fpga_prod_id, + n_fpga_ver_id, n_fpga_rev_id); + + NT_LOG(INF, NTHW, "%s: FPGA %s (%" PRIX64 ") [%08X]\n", + p_adapter_id_str, s_fpga_prod_ver_rev_str, n_fpga_ident, + n_fpga_build_time); + } + + n_fpga_ident = p_fpga_info->n_fpga_ident; + + p_fpga_mgr = fpga_mgr_new(); + fpga_mgr_init(p_fpga_mgr); + fpga_mgr_log_dump(p_fpga_mgr); + p_fpga = fpga_mgr_query_fpga(p_fpga_mgr, n_fpga_ident, p_fpga_info); + p_fpga_info->mp_fpga = p_fpga; + if (p_fpga == NULL) { + NT_LOG(ERR, NTHW, "%s: Unsupported FPGA: %s (%08X)\n", + p_adapter_id_str, s_fpga_prod_ver_rev_str, + p_fpga_info->n_fpga_build_time); + return -1; + } + + if (p_fpga_mgr) { + fpga_mgr_delete(p_fpga_mgr); + p_fpga_mgr = NULL; + } + + /* Read Fpga param info */ + nthw_fpga_get_param_info(p_fpga_info, p_fpga); + + /* debug: report params */ + NT_LOG(DBG, NTHW, "%s: NT_NIMS=%d\n", p_adapter_id_str, p_fpga_info->n_nims); + NT_LOG(DBG, NTHW, "%s: NT_PHY_PORTS=%d\n", p_adapter_id_str, + p_fpga_info->n_phy_ports); + NT_LOG(DBG, NTHW, "%s: NT_PHY_QUADS=%d\n", p_adapter_id_str, + p_fpga_info->n_phy_quads); + NT_LOG(DBG, NTHW, "%s: NT_RX_PORTS=%d\n", p_adapter_id_str, + p_fpga_info->n_rx_ports); + NT_LOG(DBG, NTHW, "%s: NT_TX_PORTS=%d\n", p_adapter_id_str, + p_fpga_info->n_tx_ports); + NT_LOG(DBG, NTHW, "%s: nProfile=%d\n", p_adapter_id_str, + (int)p_fpga_info->profile); + + p_nthw_rac = nthw_rac_new(); + if (p_nthw_rac == NULL) { + NT_LOG(ERR, NTHW, + "%s: Unsupported FPGA: RAC is not found: %s (%08X)\n", + p_adapter_id_str, s_fpga_prod_ver_rev_str, + p_fpga_info->n_fpga_build_time); + return -1; + } + + nthw_rac_init(p_nthw_rac, p_fpga, p_fpga_info); + nthw_rac_rab_flush(p_nthw_rac); + p_fpga_info->mp_nthw_rac = p_nthw_rac; + + /* special case: values below 0x100 will disable debug on RAC communication */ + { + const int n_fpga_initial_debug_mode = p_fpga_info->n_fpga_debug_mode; + + fpga_set_debug_mode(p_fpga, n_fpga_initial_debug_mode); + } + + switch (p_fpga_info->n_nthw_adapter_id) { + case NT_HW_ADAPTER_ID_NT200A01: /* fallthrough */ + case NT_HW_ADAPTER_ID_NT200A02: + res = nthw_fpga_nt200a0x_init(p_fpga_info); + break; + default: + NT_LOG(ERR, NTHW, "%s: Unsupported HW product id: %d\n", + p_adapter_id_str, p_fpga_info->n_nthw_adapter_id); + res = -1; + break; + } + + if (res) { + NT_LOG(ERR, NTHW, "%s: status: 0x%08X\n", p_adapter_id_str, res); + return res; + } + + res = nthw_pcie3_init(NULL, p_fpga, 0); /* Probe for module */ + if (res == 0) { + p_nthw_pcie3 = nthw_pcie3_new(); + if (p_nthw_pcie3) { + res = nthw_pcie3_init(p_nthw_pcie3, p_fpga, 0); + if (res == 0) { + NT_LOG(DBG, NTHW, "%s: Pcie3 module found\n", + p_adapter_id_str); + nthw_pcie3_trigger_sample_time(p_nthw_pcie3); + } else { + nthw_pcie3_delete(p_nthw_pcie3); + p_nthw_pcie3 = NULL; + } + } + p_fpga_info->mp_nthw_pcie3 = p_nthw_pcie3; + } + + if (p_nthw_pcie3 == NULL) { + p_nthw_hif = nthw_hif_new(); + if (p_nthw_hif) { + res = nthw_hif_init(p_nthw_hif, p_fpga, 0); + if (res == 0) { + NT_LOG(DBG, NTHW, "%s: Hif module found\n", + p_adapter_id_str); + nthw_hif_trigger_sample_time(p_nthw_hif); + } else { + nthw_hif_delete(p_nthw_hif); + p_nthw_hif = NULL; + } + } + } + p_fpga_info->mp_nthw_hif = p_nthw_hif; + + p_nthw_tsm = nthw_tsm_new(); + if (p_nthw_tsm) { + nthw_tsm_init(p_nthw_tsm, p_fpga, 0); + + nthw_tsm_set_config_ts_format(p_nthw_tsm, + 1); /* 1 = TSM: TS format native */ + + /* Timer T0 - stat toggle timer */ + nthw_tsm_set_timer_t0_enable(p_nthw_tsm, false); + nthw_tsm_set_timer_t0_max_count(p_nthw_tsm, 50 * 1000 * 1000); /* ns */ + nthw_tsm_set_timer_t0_enable(p_nthw_tsm, true); + + /* Timer T1 - keep alive timer */ + nthw_tsm_set_timer_t1_enable(p_nthw_tsm, false); + nthw_tsm_set_timer_t1_max_count(p_nthw_tsm, + 100 * 1000 * 1000); /* ns */ + nthw_tsm_set_timer_t1_enable(p_nthw_tsm, true); + } + p_fpga_info->mp_nthw_tsm = p_nthw_tsm; + + /* TSM sample triggering: test validation... */ +#if defined(DEBUG) && (1) + { + uint64_t n_time, n_ts; + int i; + + for (i = 0; i < 4; i++) { + if (p_nthw_hif) + nthw_hif_trigger_sample_time(p_nthw_hif); + + else if (p_nthw_pcie3) + nthw_pcie3_trigger_sample_time(p_nthw_pcie3); + nthw_tsm_get_time(p_nthw_tsm, &n_time); + nthw_tsm_get_ts(p_nthw_tsm, &n_ts); + + NT_LOG(DBG, NTHW, + "%s: TSM time: %016" PRIX64 " %016" PRIX64 "\n", + p_adapter_id_str, n_time, n_ts); + + NT_OS_WAIT_USEC(1000); + } + } +#endif + + return res; +} + +int nthw_fpga_shutdown(struct fpga_info_s *p_fpga_info) +{ + int res = -1; + + if (p_fpga_info) { + if (p_fpga_info && p_fpga_info->mp_nthw_rac) + res = nthw_rac_rab_reset(p_fpga_info->mp_nthw_rac); + } + + return res; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga.h b/drivers/net/ntnic/nthw/core/nthw_fpga.h new file mode 100644 index 0000000000..336d81f337 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_FPGA_H__ +#define __NTHW_FPGA_H__ + +#include "nthw_drv.h" + +#include "nthw_fpga_model.h" + +#include "nthw_rac.h" +#include "nthw_iic.h" + +#include "nthw_stat.h" + +#include "nthw_fpga_rst.h" + +#include "nthw_fpga_nt200a0x.h" + +#include "nthw_dbs.h" + +int nthw_fpga_init(struct fpga_info_s *p_fpga_info); +int nthw_fpga_shutdown(struct fpga_info_s *p_fpga_info); + +int nthw_fpga_get_param_info(struct fpga_info_s *p_fpga_info, nt_fpga_t *p_fpga); + +int nthw_fpga_avr_probe(nt_fpga_t *p_fpga, const int n_instance_no); + +int nthw_fpga_iic_scan(nt_fpga_t *p_fpga, const int n_instance_no_begin, + const int n_instance_no_end); + +int nthw_fpga_iic_read_byte(nt_fpga_t *p_fpga, const int n_instance_no, + const uint8_t n_dev_addr, const uint8_t n_reg_addr); +int nthw_fpga_iic_write_byte(nt_fpga_t *p_fpga, const int n_instance_no, + const uint8_t n_dev_addr, const uint8_t n_reg_addr, + uint8_t val); + +int nthw_fpga_silabs_detect(nt_fpga_t *p_fpga, const int n_instance_no, + const int n_dev_addr, const int n_page_reg_addr); + +int nthw_fpga_si5340_clock_synth_init_fmt2(nt_fpga_t *p_fpga, + const uint8_t n_iic_addr, + const clk_profile_data_fmt2_t *p_clk_profile, + const int n_clk_profile_rec_cnt); + +#endif /* __NTHW_FPGA_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga_nt200a0x.c b/drivers/net/ntnic/nthw/core/nthw_fpga_nt200a0x.c new file mode 100644 index 0000000000..70338fdfd7 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga_nt200a0x.c @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_fpga.h" +#include "nthw_fpga_nt200a0x.h" + +int nthw_fpga_nt200a0x_init(struct fpga_info_s *p_fpga_info) +{ + assert(p_fpga_info); + + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + struct nthw_fpga_rst_nt200a0x rst; + int res = -1; + + /* reset common */ + res = nthw_fpga_rst_nt200a0x_init(p_fpga_info, &rst); + if (res) { + NT_LOG(ERR, NTHW, "%s: %s: loc=%u: FPGA=%04d res=%d\n", + p_adapter_id_str, __func__, __LINE__, + p_fpga_info->n_fpga_prod_id, res); + return res; + } + + /* reset specific */ + switch (p_fpga_info->n_fpga_prod_id) { + case 9563: + res = nthw_fpga_rst9563_init(p_fpga_info, &rst); + break; + default: + NT_LOG(ERR, NTHW, "%s: Unsupported FPGA product: %04d\n", + p_adapter_id_str, p_fpga_info->n_fpga_prod_id); + res = -1; + break; + } + if (res) { + NT_LOG(ERR, NTHW, "%s: %s: loc=%u: FPGA=%04d res=%d\n", + p_adapter_id_str, __func__, __LINE__, + p_fpga_info->n_fpga_prod_id, res); + return res; + } + + return res; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga_nt200a0x.h b/drivers/net/ntnic/nthw/core/nthw_fpga_nt200a0x.h new file mode 100644 index 0000000000..ff324bee39 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga_nt200a0x.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_FPGA_NT200A0X_H__ +#define __NTHW_FPGA_NT200A0X_H__ + +int nthw_fpga_nt200a0x_init(struct fpga_info_s *p_fpga_info); + +/* NT200A02: 9563 */ +int nthw_fpga_rst9563_init(struct fpga_info_s *p_fpga_info, + struct nthw_fpga_rst_nt200a0x *const p); + +#endif /* __NTHW_FPGA_NT200A0X_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga_rst.c b/drivers/net/ntnic/nthw/core/nthw_fpga_rst.c new file mode 100644 index 0000000000..66c148bab2 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga_rst.c @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_fpga.h" +#include "nthw_fpga_nt200a0x.h" + +#include "nthw_fpga_rst.h" diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga_rst.h b/drivers/net/ntnic/nthw/core/nthw_fpga_rst.h new file mode 100644 index 0000000000..2099c4b677 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga_rst.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_FPGA_RST_H__ +#define __NTHW_FPGA_RST_H__ + +#include "nthw_drv.h" + +#include "nthw_fpga_model.h" + +#include "nthw_rac.h" +#include "nthw_iic.h" + +#include "nthw_fpga_rst_nt200a0x.h" + +#endif /* __NTHW_FPGA_RST_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga_rst9563.c b/drivers/net/ntnic/nthw/core/nthw_fpga_rst9563.c new file mode 100644 index 0000000000..077b043c60 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga_rst9563.c @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" +#include "nthw_fpga.h" + +#include "nthw_clock_profiles.h" + +static int nthw_fpga_rst9563_setup(nt_fpga_t *p_fpga, + struct nthw_fpga_rst_nt200a0x *const p) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + const int n_fpga_product_id = p_fpga->m_product_id; + const int n_fpga_version = p_fpga->m_fpga_version; + const int n_fpga_revision = p_fpga->m_fpga_revision; + + nt_module_t *p_mod_rst; + nt_register_t *p_curr_reg; + + assert(p); + p->mn_fpga_product_id = n_fpga_product_id; + p->mn_fpga_version = n_fpga_version; + p->mn_fpga_revision = n_fpga_revision; + + NT_LOG(DBG, NTHW, "%s: %s: FPGA reset setup: FPGA %04d-%02d-%02d\n", + p_adapter_id_str, __func__, n_fpga_product_id, n_fpga_version, + n_fpga_revision); + + p_mod_rst = fpga_query_module(p_fpga, MOD_RST9563, 0); + if (p_mod_rst == NULL) { + NT_LOG(ERR, NTHW, "%s: RST %d: no such instance\n", + p_adapter_id_str, 0); + return -1; + } + + p_mod_rst = fpga_query_module(p_fpga, MOD_RST9563, 0); + if (p_mod_rst == NULL) { + NT_LOG(ERR, NTHW, "%s: RST %d: no such instance\n", + p_adapter_id_str, 0); + return -1; + } + + /* RST register field pointers */ + p_curr_reg = module_get_register(p_mod_rst, RST9563_RST); + p->mp_fld_rst_sys = register_get_field(p_curr_reg, RST9563_RST_SYS); + p->mp_fld_rst_sys_mmcm = register_get_field(p_curr_reg, RST9563_RST_SYS_MMCM); + p->mp_fld_rst_core_mmcm = + register_get_field(p_curr_reg, RST9563_RST_CORE_MMCM); + p->mp_fld_rst_rpp = register_get_field(p_curr_reg, RST9563_RST_RPP); + p->mp_fld_rst_ddr4 = register_get_field(p_curr_reg, RST9563_RST_DDR4); + p->mp_fld_rst_sdc = register_get_field(p_curr_reg, RST9563_RST_SDC); + p->mp_fld_rst_phy = register_get_field(p_curr_reg, RST9563_RST_PHY); + p->mp_fld_rst_serdes_rx = NULL; /* Field not present on 9563 */ + p->mp_fld_rst_serdes_tx = NULL; /* Field not present on 9563 */ + p->mp_fld_rst_serdes_rx_datapath = NULL; /* Field not present on 9563 */ + p->mp_fld_rst_pcs_rx = NULL; /* Field not present on 9563 */ + p->mp_fld_rst_mac_rx = register_get_field(p_curr_reg, RST9563_RST_MAC_RX); + p->mp_fld_rst_mac_tx = NULL; + p->mp_fld_rst_ptp = register_get_field(p_curr_reg, RST9563_RST_PTP); + p->mp_fld_rst_ptp = register_get_field(p_curr_reg, RST9563_RST_PTP); + p->mp_fld_rst_ts = register_get_field(p_curr_reg, RST9563_RST_TS); + p->mp_fld_rst_ptp_mmcm = register_get_field(p_curr_reg, RST9563_RST_PTP_MMCM); + p->mp_fld_rst_ts_mmcm = register_get_field(p_curr_reg, RST9563_RST_TS_MMCM); + /* referenced in separate function */ + p->mp_fld_rst_periph = register_get_field(p_curr_reg, RST9563_RST_PERIPH); + p->mp_fld_rst_tsm_ref_mmcm = + register_query_field(p_curr_reg, RST9563_RST_TSM_REF_MMCM); + p->mp_fld_rst_tmc = register_query_field(p_curr_reg, RST9563_RST_TMC); + + if (!p->mp_fld_rst_tsm_ref_mmcm) { + NT_LOG(DBG, NTHW, "%s: No RST9563_RST_TSM_REF_MMCM found\n", + p_adapter_id_str); + } + if (!p->mp_fld_rst_tmc) { + NT_LOG(DBG, NTHW, "%s: No RST9563_RST_TMC found\n", + p_adapter_id_str); + } + register_update(p_curr_reg); + + /* CTRL register field pointers */ + p_curr_reg = module_get_register(p_mod_rst, RST9563_CTRL); + p->mp_fld_ctrl_ts_clk_sel_override = + register_get_field(p_curr_reg, RST9563_CTRL_TS_CLKSEL_OVERRIDE); + /* Field not present on 9563 */ + p->mp_fld_ctrl_ts_clk_sel = + register_get_field(p_curr_reg, RST9563_CTRL_TS_CLKSEL); + p->mp_fld_ctrl_ts_clk_sel_ref = NULL; /* Field not present on 9563 */ + p->mp_fld_ctrl_ptp_mmcm_clk_sel = + register_get_field(p_curr_reg, RST9563_CTRL_PTP_MMCM_CLKSEL); + register_update(p_curr_reg); + + /* STAT register field pointers */ + p_curr_reg = module_get_register(p_mod_rst, RST9563_STAT); + p->mp_fld_stat_ddr4_mmcm_locked = + register_get_field(p_curr_reg, RST9563_STAT_DDR4_MMCM_LOCKED); + p->mp_fld_stat_sys_mmcm_locked = + register_get_field(p_curr_reg, RST9563_STAT_SYS_MMCM_LOCKED); + p->mp_fld_stat_core_mmcm_locked = + register_get_field(p_curr_reg, RST9563_STAT_CORE_MMCM_LOCKED); + p->mp_fld_stat_ddr4_pll_locked = + register_get_field(p_curr_reg, RST9563_STAT_DDR4_PLL_LOCKED); + p->mp_fld_stat_ptp_mmcm_locked = + register_get_field(p_curr_reg, RST9563_STAT_PTP_MMCM_LOCKED); + p->mp_fld_stat_ts_mmcm_locked = + register_get_field(p_curr_reg, RST9563_STAT_TS_MMCM_LOCKED); + p->mp_fld_stat_tsm_ref_mmcm_locked = NULL; /* Field not present on 9563 */ + + if (!p->mp_fld_stat_tsm_ref_mmcm_locked) { + NT_LOG(DBG, NTHW, + "%s: No RST9563_STAT_TSM_REF_MMCM_LOCKED found\n", + p_adapter_id_str); + } + register_update(p_curr_reg); + + /* STICKY register field pointers */ + p_curr_reg = module_get_register(p_mod_rst, RST9563_STICKY); + p->mp_fld_sticky_ptp_mmcm_unlocked = + register_get_field(p_curr_reg, RST9563_STICKY_PTP_MMCM_UNLOCKED); + p->mp_fld_sticky_ts_mmcm_unlocked = + register_get_field(p_curr_reg, RST9563_STICKY_TS_MMCM_UNLOCKED); + p->mp_fld_sticky_ddr4_mmcm_unlocked = + register_get_field(p_curr_reg, RST9563_STICKY_DDR4_MMCM_UNLOCKED); + p->mp_fld_sticky_ddr4_pll_unlocked = + register_get_field(p_curr_reg, RST9563_STICKY_DDR4_PLL_UNLOCKED); + p->mp_fld_sticky_core_mmcm_unlocked = + register_get_field(p_curr_reg, RST9563_STICKY_CORE_MMCM_UNLOCKED); + p->mp_fld_sticky_pci_sys_mmcm_unlocked = NULL; /* Field not present on 9563 */ + p->mp_fld_sticky_tsm_ref_mmcm_unlocked = NULL; /* Field not present on 9563 */ + + if (!p->mp_fld_sticky_tsm_ref_mmcm_unlocked) { + NT_LOG(DBG, NTHW, + "%s: No RST9563_STICKY_TSM_REF_MMCM_UNLOCKED found\n", + p_adapter_id_str); + } + register_update(p_curr_reg); + + /* POWER register field pointers */ + p_curr_reg = module_get_register(p_mod_rst, RST9563_POWER); + p->mp_fld_power_pu_phy = register_get_field(p_curr_reg, RST9563_POWER_PU_PHY); + p->mp_fld_power_pu_nseb = + register_get_field(p_curr_reg, RST9563_POWER_PU_NSEB); + register_update(p_curr_reg); + + return 0; +} + +static int nthw_fpga_rst9563_periph_reset(nt_fpga_t *p_fpga) +{ + const char *const _unused p_adapter_id_str = + p_fpga->p_fpga_info->mp_adapter_id_str; + nt_module_t *p_mod_rst = fpga_query_module(p_fpga, MOD_RST9563, 0); + + if (p_mod_rst) { + nt_register_t *p_reg_rst; + nt_field_t *p_fld_rst_periph; + + NT_LOG(DBG, NTHW, "%s: PERIPH RST\n", p_adapter_id_str); + p_reg_rst = module_get_register(p_mod_rst, RST9563_RST); + p_fld_rst_periph = register_get_field(p_reg_rst, RST9563_RST_PERIPH); + field_set_flush(p_fld_rst_periph); + field_clr_flush(p_fld_rst_periph); + } else { + return -1; + } + return 0; +} + +static int +nthw_fpga_rst9563_clock_synth_init(nt_fpga_t *p_fpga, + const int n_si_labs_clock_synth_model, + const uint8_t n_si_labs_clock_synth_i2c_addr) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + const int n_fpga_product_id = p_fpga->m_product_id; + int res; + + if (n_si_labs_clock_synth_model == 5340) { + res = nthw_fpga_si5340_clock_synth_init_fmt2(p_fpga, + n_si_labs_clock_synth_i2c_addr, + p_data_si5340_nt200a02_u23_v5, + n_data_si5340_nt200a02_u23_v5); + } else { + NT_LOG(ERR, NTHW, + "%s: Fpga %d: Unsupported clock synth model (%d)\n", + p_adapter_id_str, n_fpga_product_id, n_si_labs_clock_synth_model); + res = -1; + } + return res; +} + +int nthw_fpga_rst9563_init(struct fpga_info_s *p_fpga_info, + struct nthw_fpga_rst_nt200a0x *p_rst) +{ + assert(p_fpga_info); + assert(p_rst); + + const char *const _unused p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + int res = -1; + int n_si_labs_clock_synth_model; + uint8_t n_si_labs_clock_synth_i2c_addr; + nt_fpga_t *p_fpga = NULL; + + p_fpga = p_fpga_info->mp_fpga; + n_si_labs_clock_synth_model = p_rst->mn_si_labs_clock_synth_model; + n_si_labs_clock_synth_i2c_addr = p_rst->mn_si_labs_clock_synth_i2c_addr; + + res = nthw_fpga_rst9563_periph_reset(p_fpga); + if (res) { + NT_LOG(DBG, NTHW, "%s: ERROR: res=%d [%s:%u]\n", p_adapter_id_str, + res, __func__, __LINE__); + return res; + } + + res = nthw_fpga_rst9563_clock_synth_init(p_fpga, n_si_labs_clock_synth_model, + n_si_labs_clock_synth_i2c_addr); + if (res) { + NT_LOG(DBG, NTHW, "%s: ERROR: res=%d [%s:%u]\n", p_adapter_id_str, + res, __func__, __LINE__); + return res; + } + + res = nthw_fpga_rst9563_setup(p_fpga, p_rst); + if (res) { + NT_LOG(DBG, NTHW, "%s: ERROR: res=%d [%s:%u]\n", p_adapter_id_str, + res, __func__, __LINE__); + return res; + } + + res = nthw_fpga_rst_nt200a0x_reset(p_fpga, p_rst); + if (res) { + NT_LOG(DBG, NTHW, "%s: ERROR: res=%d [%s:%u]\n", p_adapter_id_str, + res, __func__, __LINE__); + return res; + } + + return res; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga_rst_nt200a0x.c b/drivers/net/ntnic/nthw/core/nthw_fpga_rst_nt200a0x.c new file mode 100644 index 0000000000..ae63fefb09 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga_rst_nt200a0x.c @@ -0,0 +1,674 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" +#include "nthw_fpga.h" + +static const uint8_t si5338_u23_i2c_addr_7bit = 0x70; +static const uint8_t si5340_u23_i2c_addr_7bit = 0x74; + +/* + * Wait until DDR4 PLL LOCKED + */ +static int nthw_fpga_rst_nt200a0x_wait_ddr4_pll_locked(nt_fpga_t *p_fpga, + const struct nthw_fpga_rst_nt200a0x *p) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + uint32_t locked; + uint32_t retrycount = 5; + uint32_t timeout = 50000; /* initial timeout must be set to 5 sec. */ + /* 14: wait until DDR4 PLL LOCKED */ + NT_LOG(DBG, NTHW, "%s: Waiting for DDR4 PLL to lock\n", p_adapter_id_str); + /* + * The following retry count gives a total timeout of 1 * 5 + 5 * 8 = 45sec + * It has been observed that at least 21sec can be necessary + */ + while (true) { + int locked = field_wait_set_any32(p->mp_fld_stat_ddr4_pll_locked, + timeout, 100); + if (locked == 0) + break; + NT_LOG(DBG, NTHW, + "%s: Waiting for DDR4 PLL to lock - timeout\n", + p_adapter_id_str); + if (retrycount <= 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for DDR4 PLL to lock failed (%d)\n", + p_adapter_id_str, locked); + break; + } + field_set_flush(p->mp_fld_rst_ddr4); /* Reset DDR PLL */ + field_clr_flush(p->mp_fld_rst_ddr4); /* Reset DDR PLL */ + retrycount--; + timeout = + 80000; /* Increase timeout for second attempt to 8 sec. */ + } + + NT_LOG(DBG, NTHW, "%s: Waiting for DDR4 MMCM to lock\n", p_adapter_id_str); + locked = field_wait_set_any32(p->mp_fld_stat_ddr4_mmcm_locked, -1, -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for DDR4 MMCM to lock failed (%d)\n", + p_adapter_id_str, locked); + return -1; + } + + if ((true) && p->mp_fld_stat_tsm_ref_mmcm_locked) { + NT_LOG(DBG, NTHW, "%s: Waiting for TSM REF MMCM to lock\n", + p_adapter_id_str); + locked = field_wait_set_any32(p->mp_fld_stat_tsm_ref_mmcm_locked, -1, + -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for TSM REF MMCM to lock failed (%d)\n", + p_adapter_id_str, locked); + return -1; + } + } + + /* 10: Clear all MMCM/PLL lock sticky bits before testing them */ + NT_LOG(DBG, NTHW, "%s: Clear sticky MMCM unlock bits\n", p_adapter_id_str); + field_update_register(p->mp_fld_sticky_ptp_mmcm_unlocked); + /* Clear all sticky bits */ + field_set_flush(p->mp_fld_sticky_ptp_mmcm_unlocked); + field_set_flush(p->mp_fld_sticky_ts_mmcm_unlocked); + field_set_flush(p->mp_fld_sticky_ddr4_mmcm_unlocked); + field_set_flush(p->mp_fld_sticky_ddr4_pll_unlocked); + field_set_flush(p->mp_fld_sticky_core_mmcm_unlocked); + if (p->mp_fld_sticky_tsm_ref_mmcm_unlocked) + field_set_flush(p->mp_fld_sticky_tsm_ref_mmcm_unlocked); + if (p->mp_fld_sticky_pci_sys_mmcm_unlocked) + field_set_flush(p->mp_fld_sticky_pci_sys_mmcm_unlocked); + + /* 11: Ensure sticky bits are not unlocked except PTP MMCM and TS MMCM */ + if (field_get_updated(p->mp_fld_sticky_ddr4_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_ddr4_mmcm_unlocked() returned true\n", + p_adapter_id_str); + } + + if (field_get_updated(p->mp_fld_sticky_ddr4_pll_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_ddr4_pll_unlocked() returned true\n", + p_adapter_id_str); + } + + return 0; +} + +/* + * Wait for SDRAM controller has been calibrated - On some adapters we have seen + * calibration time of 2.3 seconds + */ +static int +nthw_fpga_rst_nt200a0x_wait_sdc_calibrated(nt_fpga_t *p_fpga, + const struct nthw_fpga_rst_nt200a0x *p) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + nthw_sdc_t *p_nthw_sdc = NULL; + const int n_retry_cnt_max = 5; + int n_retry_cnt; + int res; + + res = nthw_sdc_init(NULL, p_fpga, 0); /* probe for module */ + if (res == 0) { + p_nthw_sdc = nthw_sdc_new(); + if (p_nthw_sdc) { + res = nthw_sdc_init(p_nthw_sdc, p_fpga, 0); + if (res) { + NT_LOG(ERR, NTHW, + "%s: SDC init failed: res=%d [%s:%d]\n", + p_adapter_id_str, res, __func__, __LINE__); + nthw_sdc_delete(p_nthw_sdc); + p_nthw_sdc = NULL; + return -1; + } + } else { + nthw_sdc_delete(p_nthw_sdc); + p_nthw_sdc = NULL; + } + } else { + NT_LOG(DBG, NTHW, "%s: No SDC found\n", p_adapter_id_str); + } + n_retry_cnt = 0; + res = -1; + while ((res != 0) && (n_retry_cnt <= n_retry_cnt_max)) { + /* wait until DDR4 PLL LOCKED */ + res = nthw_fpga_rst_nt200a0x_wait_ddr4_pll_locked(p_fpga, p); + if (res == 0) { + if (p_nthw_sdc) { + /* + * Wait for SDRAM controller has been calibrated + * On some adapters we have seen calibration time of 2.3 seconds + */ + NT_LOG(DBG, NTHW, + "%s: Waiting for SDRAM to calibrate\n", + p_adapter_id_str); + res = nthw_sdc_wait_states(p_nthw_sdc, 10000, 1000); + { + uint64_t n_result_mask; + + int n_state_code _unused = + nthw_sdc_get_states(p_nthw_sdc, + &n_result_mask); + NT_LOG(DBG, NTHW, + "%s: SDRAM state=0x%08lX state_code=%d retry=%d code=%d\n", + p_adapter_id_str, n_result_mask, + n_state_code, n_retry_cnt, res); + } + if (res == 0) + break; + } + + if (n_retry_cnt >= n_retry_cnt_max) { + uint64_t n_result_mask; + int n_state_code _unused = nthw_sdc_get_states(p_nthw_sdc, + &n_result_mask); + + NT_LOG(DBG, NTHW, + "%s: SDRAM state=0x%08lX state_code=%d retry=%d code=%d\n", + p_adapter_id_str, n_result_mask, n_state_code, + n_retry_cnt, res); + if (res != 0) { + NT_LOG(ERR, NTHW, + "%s: Timeout waiting for SDRAM controller calibration\n", + p_adapter_id_str); + } + } + } + + /* + * SDRAM controller is not calibrated with DDR4 ram blocks: + * reset DDR and perform calibration retry + */ + field_set_flush(p->mp_fld_rst_ddr4); /* Reset DDR PLL */ + NT_OS_WAIT_USEC(100); + field_clr_flush(p->mp_fld_rst_ddr4); + + n_retry_cnt++; + } + nthw_sdc_delete(p_nthw_sdc); + + return res; +} + +int nthw_fpga_rst_nt200a0x_reset(nt_fpga_t *p_fpga, + const struct nthw_fpga_rst_nt200a0x *p) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + const fpga_info_t *const p_fpga_info = p_fpga->p_fpga_info; + + const int n_fpga_product_id = p->mn_fpga_product_id; + const int n_fpga_version = p->mn_fpga_version; + const int n_fpga_revision = p->mn_fpga_revision; + const int n_nthw_adapter_id = p_fpga_info->n_nthw_adapter_id; + const bool b_is_nt200a01 = (n_nthw_adapter_id == NT_HW_ADAPTER_ID_NT200A01); + const int n_hw_id = p_fpga_info->nthw_hw_info.hw_id; + const uint8_t index = 0; + int locked; + int res = -1; + + NT_LOG(DBG, NTHW, + "%s: %s: FPGA reset sequence: FPGA %04d-%02d-%02d @ HWId%d\n", + p_adapter_id_str, __func__, n_fpga_product_id, n_fpga_version, + n_fpga_revision, n_hw_id); + assert(n_fpga_product_id == p_fpga->m_product_id); + + /* + * Reset all domains / modules except peripherals + * Set default reset values to ensure that all modules are reset correctly + * no matter if nic has been powercycled or ntservice has been reloaded + */ + + /* + * Reset to defaults + * 1: Reset all domains + */ + NT_LOG(DBG, NTHW, "%s: RST defaults\n", p_adapter_id_str); + + field_update_register(p->mp_fld_rst_sys); + field_set_flush(p->mp_fld_rst_sys); + if (p->mp_fld_rst_tmc) + field_set_flush(p->mp_fld_rst_tmc); + field_set_flush(p->mp_fld_rst_rpp); + field_set_flush(p->mp_fld_rst_ddr4); /* 0x07 3 banks */ + field_set_flush(p->mp_fld_rst_sdc); + + /* Reset port 0 and 1 in the following registers: */ + field_set_flush(p->mp_fld_rst_phy); /* 0x03 2 ports */ + if (p->mp_fld_rst_mac_rx) + field_set_flush(p->mp_fld_rst_mac_rx); /* 0x03 2 ports */ + + if (p->mp_fld_rst_mac_tx) + field_set_flush(p->mp_fld_rst_mac_tx); /* 0x03 2 ports */ + + if (p->mp_fld_rst_pcs_rx) + field_set_flush(p->mp_fld_rst_pcs_rx); /* 0x03 2 ports */ + + if (p->mp_fld_rst_serdes_rx) + field_set_flush(p->mp_fld_rst_serdes_rx); /* 0x03 2 ports */ + + if (p->mp_fld_rst_serdes_rx_datapath) { + field_set_flush(p->mp_fld_rst_serdes_rx_datapath); + field_clr_flush(p->mp_fld_rst_serdes_rx); + } + if (p->mp_fld_rst_serdes_tx) + field_set_flush(p->mp_fld_rst_serdes_tx); + + field_set_flush(p->mp_fld_rst_ptp); + field_set_flush(p->mp_fld_rst_ts); + field_set_flush(p->mp_fld_rst_sys_mmcm); + field_set_flush(p->mp_fld_rst_core_mmcm); + field_set_flush(p->mp_fld_rst_ptp_mmcm); + field_set_flush(p->mp_fld_rst_ts_mmcm); + + if ((true) && p->mp_fld_rst_tsm_ref_mmcm) + field_set_flush(p->mp_fld_rst_tsm_ref_mmcm); + + /* Write all changes to register */ + field_flush_register(p->mp_fld_rst_sys); + + if (b_is_nt200a01 && n_hw_id == 2) { /* Not relevant to NT200A02 */ + if (p->mp_fld_rst_tsm_ref_mmcm) { + field_update_register(p->mp_fld_rst_tsm_ref_mmcm); + field_set_flush(p->mp_fld_rst_tsm_ref_mmcm); + } + } + + /* + * 2: Force use of 50 MHz reference clock for timesync; + * NOTE: From 9508-05-18 this is a 20 MHz clock + */ + NT_LOG(DBG, NTHW, "%s: Setting TS CLK SEL OVERRIDE\n", p_adapter_id_str); + field_update_register(p->mp_fld_ctrl_ts_clk_sel_override); + field_set_flush(p->mp_fld_ctrl_ts_clk_sel_override); + + NT_LOG(DBG, NTHW, "%s: Setting TS CLK SEL\n", p_adapter_id_str); + field_update_register(p->mp_fld_ctrl_ts_clk_sel); + field_set_flush(p->mp_fld_ctrl_ts_clk_sel); + + if (b_is_nt200a01 && n_hw_id == 2) { /* Not relevant to NT200A02 */ + NT_LOG(DBG, NTHW, "%s: _selecting 20MHz TS CLK SEL REF\n", + p_adapter_id_str); + if (p->mp_fld_ctrl_ts_clk_sel_ref) { + field_update_register(p->mp_fld_ctrl_ts_clk_sel_ref); + field_clr_flush(p->mp_fld_ctrl_ts_clk_sel_ref); + } + } + + /* 4: De-assert sys reset, CORE and SYS MMCM resets */ + NT_LOG(DBG, NTHW, "%s: De-asserting SYS, CORE and SYS MMCM resets\n", + p_adapter_id_str); + field_update_register(p->mp_fld_rst_sys); + field_clr_flush(p->mp_fld_rst_sys); + field_clr_flush(p->mp_fld_rst_sys_mmcm); + field_clr_flush(p->mp_fld_rst_core_mmcm); + + /* 5: wait until CORE MMCM and SYS MMCM are LOCKED */ + NT_LOG(DBG, NTHW, "%s: Waiting for SYS MMCM to lock\n", p_adapter_id_str); + locked = field_wait_set_any32(p->mp_fld_stat_sys_mmcm_locked, -1, -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for SYS MMCM to lock failed (%d)\n", + p_adapter_id_str, locked); + } + + NT_LOG(DBG, NTHW, "%s: Waiting for CORE MMCM to lock\n", p_adapter_id_str); + locked = field_wait_set_any32(p->mp_fld_stat_core_mmcm_locked, -1, -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for CORE MMCM to lock failed (%d)\n", + p_adapter_id_str, locked); + } + + /* RAC RAB bus "flip/flip" reset second stage - new impl (ref RMT#37020) */ + /* RAC/RAB init - SYS/CORE MMCM is locked - pull the remaining RAB buses out of reset */ + { + nthw_rac_t *p_nthw_rac = p_fpga_info->mp_nthw_rac; + + NT_LOG(DBG, NTHW, "%s: De-asserting remaining RAB buses\n", + p_adapter_id_str); + nthw_rac_rab_init(p_nthw_rac, 0); + } + + if ((true) && p->mp_fld_rst_tsm_ref_mmcm) { + NT_LOG(DBG, NTHW, "%s: De-asserting TSM REF MMCM\n", + p_adapter_id_str); + field_clr_flush(p->mp_fld_rst_tsm_ref_mmcm); + if (p->mp_fld_stat_tsm_ref_mmcm_locked) { + NT_LOG(DBG, NTHW, + "%s: Waiting for TSM REF MMCM to lock\n", + p_adapter_id_str); + locked = field_wait_set_any32(p->mp_fld_stat_tsm_ref_mmcm_locked, + -1, -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for TSM REF MMCM to lock failed (%d)\n", + p_adapter_id_str, locked); + } + } + } + + /* + * 5.2: Having ensured CORE MMCM and SYS MMCM are LOCKED, + * we need to select the alternative 20 MHz reference clock, + * the external TSM reference clock + * on NT200A01 - build 2 HW only (see SSF00024 p.32) + */ + if (b_is_nt200a01 && n_hw_id == 2) { /* Not relevant to NT200A02 */ + NT_LOG(DBG, NTHW, "%s: Setting TS CLK SEL REF\n", + p_adapter_id_str); + if (p->mp_fld_ctrl_ts_clk_sel_ref) + field_set_flush(p->mp_fld_ctrl_ts_clk_sel_ref); + if (p->mp_fld_rst_tsm_ref_mmcm) { + NT_LOG(DBG, NTHW, "%s: De-asserting TSM REF MMCM\n", + p_adapter_id_str); + field_clr_flush(p->mp_fld_rst_tsm_ref_mmcm); + } + NT_LOG(DBG, NTHW, "%s: Waiting for TSM REF MMCM to lock\n", + p_adapter_id_str); + if (p->mp_fld_stat_tsm_ref_mmcm_locked) { + locked = field_wait_set_any32(p->mp_fld_stat_tsm_ref_mmcm_locked, + -1, -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for TSM REF MMCM to lock failed (%d)\n", + p_adapter_id_str, locked); + } + } + } + + NT_LOG(DBG, NTHW, "%s: De-asserting all PHY resets\n", p_adapter_id_str); + field_update_register(p->mp_fld_rst_phy); + field_clr_flush(p->mp_fld_rst_phy); + + /* MAC_PCS_XXV 10G/25G: 9530 / 9544 */ + if (n_fpga_product_id == 9530 || n_fpga_product_id == 9544) { + { + /* Based on nt200e3_2_ptp.cpp My25GbPhy::resetRx */ + nthw_mac_pcs_xxv_t *p_nthw_mac_pcs_xxv0 = nthw_mac_pcs_xxv_new(); + + assert(p_nthw_mac_pcs_xxv0); + nthw_mac_pcs_xxv_init(p_nthw_mac_pcs_xxv0, p_fpga, 0, 1); + + nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv0, true, + index); + NT_OS_WAIT_USEC(1000); + + nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv0, false, + index); + NT_OS_WAIT_USEC(1000); + + nthw_mac_pcs_xxv_delete(p_nthw_mac_pcs_xxv0); + } + + { + /* Based on nt200e3_2_ptp.cpp My25GbPhy::resetRx */ + nthw_mac_pcs_xxv_t *p_nthw_mac_pcs_xxv1 = nthw_mac_pcs_xxv_new(); + + assert(p_nthw_mac_pcs_xxv1); + nthw_mac_pcs_xxv_init(p_nthw_mac_pcs_xxv1, p_fpga, 1, 1); + + nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv1, true, + index); + NT_OS_WAIT_USEC(1000); + + nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv1, false, + index); + NT_OS_WAIT_USEC(1000); + + nthw_mac_pcs_xxv_delete(p_nthw_mac_pcs_xxv1); + } + NT_OS_WAIT_USEC(3000); + } + + /* + * 8: De-assert reset for remaining domains/modules resets except + * TS, PTP, PTP_MMCM and TS_MMCM + */ + NT_LOG(DBG, NTHW, "%s: De-asserting TMC RST\n", p_adapter_id_str); + if (p->mp_fld_rst_tmc) { + field_update_register(p->mp_fld_rst_tmc); + field_clr_flush(p->mp_fld_rst_tmc); + } + + NT_LOG(DBG, NTHW, "%s: De-asserting RPP RST\n", p_adapter_id_str); + field_update_register(p->mp_fld_rst_rpp); + field_clr_flush(p->mp_fld_rst_rpp); + + NT_LOG(DBG, NTHW, "%s: De-asserting DDR4 RST\n", p_adapter_id_str); + field_update_register(p->mp_fld_rst_ddr4); + field_clr_flush(p->mp_fld_rst_ddr4); + + NT_LOG(DBG, NTHW, "%s: De-asserting SDC RST\n", p_adapter_id_str); + field_update_register(p->mp_fld_rst_sdc); + field_clr_flush(p->mp_fld_rst_sdc); + + /* NOTE: 9522 implements PHY10G_QPLL reset and lock at this stage in mac_rx_rst() */ + NT_LOG(DBG, NTHW, "%s: De-asserting MAC RX RST\n", p_adapter_id_str); + if (p->mp_fld_rst_mac_rx) { + field_update_register(p->mp_fld_rst_mac_rx); + field_clr_flush(p->mp_fld_rst_mac_rx); + } + + /* await until DDR4 PLL LOCKED and SDRAM controller has been calibrated */ + res = nthw_fpga_rst_nt200a0x_wait_sdc_calibrated(p_fpga, p); + if (res) { + NT_LOG(ERR, NTHW, + "%s: nthw_fpga_rst_nt200a0x_wait_sdc_calibrated() returned true\n", + p_adapter_id_str); + return -1; + } + + if (field_get_updated(p->mp_fld_sticky_core_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_core_mmcm_unlocked() returned true\n", + p_adapter_id_str); + return -1; + } + + if (p->mp_fld_sticky_pci_sys_mmcm_unlocked && + field_get_updated(p->mp_fld_sticky_pci_sys_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_pci_sys_mmcm_unlocked() returned true\n", + p_adapter_id_str); + return -1; + } + + if (b_is_nt200a01 && n_hw_id == 2) { /* Not relevant to NT200A02 */ + if (p->mp_fld_sticky_tsm_ref_mmcm_unlocked && + field_get_updated(p->mp_fld_sticky_tsm_ref_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_tsm_ref_mmcm_unlocked returned true\n", + p_adapter_id_str); + return -1; + } + } + + /* + * Timesync/PTP reset sequence + * De-assert TS_MMCM reset + */ + NT_LOG(DBG, NTHW, "%s: De-asserting TS MMCM RST\n", p_adapter_id_str); + field_clr_flush(p->mp_fld_rst_ts_mmcm); + + /* Wait until TS_MMCM LOCKED (NT_RAB0_REG_P9508_RST9508_STAT_TS_MMCM_LOCKED=1); */ + NT_LOG(DBG, NTHW, "%s: Waiting for TS MMCM to lock\n", p_adapter_id_str); + locked = field_wait_set_any32(p->mp_fld_stat_ts_mmcm_locked, -1, -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for TS MMCM to lock failed (%d)\n", + p_adapter_id_str, locked); + } + + NT_LOG(DBG, NTHW, "%s: Calling clear_sticky_mmcm_unlock_bits()\n", + p_adapter_id_str); + field_update_register(p->mp_fld_sticky_ptp_mmcm_unlocked); + /* Clear all sticky bits */ + field_set_flush(p->mp_fld_sticky_ptp_mmcm_unlocked); + field_set_flush(p->mp_fld_sticky_ts_mmcm_unlocked); + field_set_flush(p->mp_fld_sticky_ddr4_mmcm_unlocked); + field_set_flush(p->mp_fld_sticky_ddr4_pll_unlocked); + field_set_flush(p->mp_fld_sticky_core_mmcm_unlocked); + if (p->mp_fld_sticky_tsm_ref_mmcm_unlocked) + field_set_flush(p->mp_fld_sticky_tsm_ref_mmcm_unlocked); + if (p->mp_fld_sticky_pci_sys_mmcm_unlocked) + field_set_flush(p->mp_fld_sticky_pci_sys_mmcm_unlocked); + + /* De-assert TS reset bit */ + NT_LOG(DBG, NTHW, "%s: De-asserting TS RST\n", p_adapter_id_str); + field_clr_flush(p->mp_fld_rst_ts); + + if (field_get_updated(p->mp_fld_sticky_ts_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_ts_mmcm_unlocked() returned true\n", + p_adapter_id_str); + return -1; + } + + if (field_get_updated(p->mp_fld_sticky_ddr4_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_ddr4_mmcm_unlocked() returned true\n", + p_adapter_id_str); + return -1; + } + + if (field_get_updated(p->mp_fld_sticky_ddr4_pll_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_ddr4_pll_unlocked() returned true\n", + p_adapter_id_str); + return -1; + } + + if (field_get_updated(p->mp_fld_sticky_core_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_core_mmcm_unlocked() returned true\n", + p_adapter_id_str); + return -1; + } + + if (p->mp_fld_sticky_pci_sys_mmcm_unlocked && + field_get_updated(p->mp_fld_sticky_pci_sys_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_pci_sys_mmcm_unlocked() returned true\n", + p_adapter_id_str); + return -1; + } + + if (b_is_nt200a01 && n_hw_id == 2) { /* Not relevant to NT200A02 */ + if (p->mp_fld_sticky_tsm_ref_mmcm_unlocked && + field_get_updated(p->mp_fld_sticky_tsm_ref_mmcm_unlocked)) { + NT_LOG(ERR, NTHW, + "%s: get_sticky_tsm_ref_mmcm_unlocked() returned true\n", + p_adapter_id_str); + return -1; + } + } + + if (false) { + /* Deassert PTP_MMCM */ + NT_LOG(DBG, NTHW, "%s: De-asserting PTP MMCM RST\n", + p_adapter_id_str); + field_clr_flush(p->mp_fld_rst_ptp_mmcm); + + if ((b_is_nt200a01 && n_fpga_version >= 9) || !b_is_nt200a01) { + /* Wait until PTP_MMCM LOCKED */ + NT_LOG(DBG, NTHW, "%s: Waiting for PTP MMCM to lock\n", + p_adapter_id_str); + locked = field_wait_set_any32(p->mp_fld_stat_ptp_mmcm_locked, + -1, -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for PTP MMCM to lock failed (%d)\n", + p_adapter_id_str, locked); + } + } + + /* Switch PTP MMCM sel to use ptp clk */ + NT_LOG(DBG, NTHW, "%s: Setting PTP MMCM CLK SEL\n", + p_adapter_id_str); + field_set_flush(p->mp_fld_ctrl_ptp_mmcm_clk_sel); + + /* Wait until TS_MMCM LOCKED (NT_RAB0_REG_P9508_RST9508_STAT_TS_MMCM_LOCKED=1); */ + NT_LOG(DBG, NTHW, "%s: Waiting for TS MMCM to re-lock\n", + p_adapter_id_str); + locked = field_wait_set_any32(p->mp_fld_stat_ts_mmcm_locked, -1, -1); + if (locked != 0) { + NT_LOG(ERR, NTHW, + "%s: Waiting for TS MMCM to re-lock failed (%d)\n", + p_adapter_id_str, locked); + } + } + + NT_LOG(DBG, NTHW, "%s: De-asserting PTP RST\n", p_adapter_id_str); + field_clr_flush(p->mp_fld_rst_ptp); + + /* POWER staging introduced in 9508-05-09 and always for 9512 */ + if (n_fpga_product_id == 9508 && n_fpga_version <= 5 && + n_fpga_revision <= 8) { + NT_LOG(DBG, NTHW, "%s: No power staging\n", p_adapter_id_str); + } else { + NT_LOG(DBG, NTHW, "%s: Staging power\n", p_adapter_id_str); + field_set_flush(p->mp_fld_power_pu_phy); /* PHY power up */ + field_clr_flush(p->mp_fld_power_pu_nseb); /* NSEB power down */ + } + + NT_LOG(DBG, NTHW, "%s: %s: END\n", p_adapter_id_str, __func__); + + return 0; +} + +int nthw_fpga_rst_nt200a0x_init(struct fpga_info_s *p_fpga_info, + struct nthw_fpga_rst_nt200a0x *p_rst) +{ + assert(p_fpga_info); + + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + int res = -1; + int n_si_labs_clock_synth_model = -1; + uint8_t n_si_labs_clock_synth_i2c_addr = 0; + nt_fpga_t *p_fpga = NULL; + + p_fpga = p_fpga_info->mp_fpga; + + NT_LOG(DBG, NTHW, "%s: %s: RAB init/reset\n", p_adapter_id_str, __func__); + nthw_rac_rab_reset(p_fpga_info->mp_nthw_rac); + nthw_rac_rab_setup(p_fpga_info->mp_nthw_rac); + + res = nthw_fpga_avr_probe(p_fpga, 0); + + res = nthw_fpga_iic_scan(p_fpga, 0, 0); + res = nthw_fpga_iic_scan(p_fpga, 2, 3); + + /* + * Detect clock synth model + * check for NT200A02/NT200A01 HW-build2 - most commonly seen + */ + n_si_labs_clock_synth_i2c_addr = si5340_u23_i2c_addr_7bit; + n_si_labs_clock_synth_model = + nthw_fpga_silabs_detect(p_fpga, 0, n_si_labs_clock_synth_i2c_addr, 1); + if (n_si_labs_clock_synth_model == -1) { + /* check for old NT200A01 HW-build1 */ + n_si_labs_clock_synth_i2c_addr = si5338_u23_i2c_addr_7bit; + n_si_labs_clock_synth_model = + nthw_fpga_silabs_detect(p_fpga, 0, + n_si_labs_clock_synth_i2c_addr, 255); + if (n_si_labs_clock_synth_model == -1) { + NT_LOG(ERR, NTHW, + "%s: Failed to detect clock synth model (%d)\n", + p_adapter_id_str, n_si_labs_clock_synth_model); + return -1; + } + } + p_rst->mn_si_labs_clock_synth_model = n_si_labs_clock_synth_model; + p_rst->mn_si_labs_clock_synth_i2c_addr = n_si_labs_clock_synth_i2c_addr; + p_rst->mn_hw_id = p_fpga_info->nthw_hw_info.hw_id; + NT_LOG(DBG, NTHW, "%s: %s: Si%04d @ 0x%02x\n", p_adapter_id_str, __func__, + p_rst->mn_si_labs_clock_synth_model, p_rst->mn_si_labs_clock_synth_i2c_addr); + + return res; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga_rst_nt200a0x.h b/drivers/net/ntnic/nthw/core/nthw_fpga_rst_nt200a0x.h new file mode 100644 index 0000000000..1f192f5ecc --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_fpga_rst_nt200a0x.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_FPGA_RST_NT200A0X_H__ +#define __NTHW_FPGA_RST_NT200A0X_H__ + +#include "nthw_drv.h" +#include "nthw_fpga_model.h" + +struct nthw_fpga_rst_nt200a0x { + int mn_fpga_product_id; + int mn_fpga_version; + int mn_fpga_revision; + + int mn_hw_id; + + int mn_si_labs_clock_synth_model; + uint8_t mn_si_labs_clock_synth_i2c_addr; + + nt_field_t *mp_fld_rst_sys; + nt_field_t *mp_fld_rst_sys_mmcm; + nt_field_t *mp_fld_rst_core_mmcm; + nt_field_t *mp_fld_rst_rpp; + nt_field_t *mp_fld_rst_ddr4; + nt_field_t *mp_fld_rst_sdc; + nt_field_t *mp_fld_rst_phy; + nt_field_t *mp_fld_rst_serdes_rx; + nt_field_t *mp_fld_rst_serdes_tx; + nt_field_t *mp_fld_rst_serdes_rx_datapath; + nt_field_t *mp_fld_rst_pcs_rx; + nt_field_t *mp_fld_rst_mac_rx; + nt_field_t *mp_fld_rst_mac_tx; + nt_field_t *mp_fld_rst_ptp; + nt_field_t *mp_fld_rst_ts; + nt_field_t *mp_fld_rst_ptp_mmcm; + nt_field_t *mp_fld_rst_ts_mmcm; + nt_field_t *mp_fld_rst_periph; + nt_field_t *mp_fld_rst_tsm_ref_mmcm; + nt_field_t *mp_fld_rst_tmc; + + /* CTRL register field pointers */ + nt_field_t *mp_fld_ctrl_ts_clk_sel_override; + nt_field_t *mp_fld_ctrl_ts_clk_sel; + nt_field_t *mp_fld_ctrl_ts_clk_sel_ref; + nt_field_t *mp_fld_ctrl_ptp_mmcm_clk_sel; + + /* STAT register field pointers */ + nt_field_t *mp_fld_stat_ddr4_mmcm_locked; + nt_field_t *mp_fld_stat_sys_mmcm_locked; + nt_field_t *mp_fld_stat_core_mmcm_locked; + nt_field_t *mp_fld_stat_ddr4_pll_locked; + nt_field_t *mp_fld_stat_ptp_mmcm_locked; + nt_field_t *mp_fld_stat_ts_mmcm_locked; + nt_field_t *mp_fld_stat_tsm_ref_mmcm_locked; + + /* STICKY register field pointers */ + nt_field_t *mp_fld_sticky_ptp_mmcm_unlocked; + nt_field_t *mp_fld_sticky_ts_mmcm_unlocked; + nt_field_t *mp_fld_sticky_ddr4_mmcm_unlocked; + nt_field_t *mp_fld_sticky_ddr4_pll_unlocked; + nt_field_t *mp_fld_sticky_core_mmcm_unlocked; + nt_field_t *mp_fld_sticky_pci_sys_mmcm_unlocked; + nt_field_t *mp_fld_sticky_tsm_ref_mmcm_unlocked; + + /* POWER register field pointers */ + nt_field_t *mp_fld_power_pu_phy; + nt_field_t *mp_fld_power_pu_nseb; + /* */ + + void (*reset_serdes_rx)(struct nthw_fpga_rst_nt200a0x *p, uint32_t intf_no, + uint32_t rst); + void (*pcs_rx_rst)(struct nthw_fpga_rst_nt200a0x *p, uint32_t intf_no, + uint32_t rst); + void (*get_serdes_rx_rst)(struct nthw_fpga_rst_nt200a0x *p, + uint32_t intf_no, uint32_t *p_set); + void (*get_pcs_rx_rst)(struct nthw_fpga_rst_nt200a0x *p, uint32_t intf_no, + uint32_t *p_set); + bool (*is_rst_serdes_rx_datapath_implemented)(struct nthw_fpga_rst_nt200a0x *p); +}; + +typedef struct nthw_fpga_rst_nt200a0x nthw_fpga_rst_nt200a0x_t; + +int nthw_fpga_rst_nt200a0x_init(struct fpga_info_s *p_fpga_info, + struct nthw_fpga_rst_nt200a0x *p_rst); +int nthw_fpga_rst_nt200a0x_reset(nt_fpga_t *p_fpga, + const struct nthw_fpga_rst_nt200a0x *p); + +#endif /* __NTHW_FPGA_RST_NT200A0X_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_gpio_phy.c b/drivers/net/ntnic/nthw/core/nthw_gpio_phy.c new file mode 100644 index 0000000000..9b536726d0 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_gpio_phy.c @@ -0,0 +1,271 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_gpio_phy.h" + +nthw_gpio_phy_t *nthw_gpio_phy_new(void) +{ + nthw_gpio_phy_t *p = malloc(sizeof(nthw_gpio_phy_t)); + + if (p) + memset(p, 0, sizeof(nthw_gpio_phy_t)); + return p; +} + +void nthw_gpio_phy_delete(nthw_gpio_phy_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_gpio_phy_t)); + free(p); + } +} + +int nthw_gpio_phy_init(nthw_gpio_phy_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + nt_module_t *p_mod = fpga_query_module(p_fpga, MOD_GPIO_PHY, n_instance); + + if (p == NULL) + return (p_mod == NULL ? -1 : 0); + + if (p_mod == NULL) { + NT_LOG(ERR, NTHW, "%s: GPIO_PHY %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_gpio_phy = p_mod; + + /* Registers */ + p->mp_reg_config = module_get_register(p->mp_mod_gpio_phy, GPIO_PHY_CFG); + p->mp_reg_gpio = module_get_register(p->mp_mod_gpio_phy, GPIO_PHY_GPIO); + + /* PORT-0, config fields */ + p->mpa_fields[0].cfg_fld_lp_mode = + register_get_field(p->mp_reg_config, GPIO_PHY_CFG_PORT0_LPMODE); + p->mpa_fields[0].cfg_int = + register_get_field(p->mp_reg_config, GPIO_PHY_CFG_PORT0_INT_B); + p->mpa_fields[0].cfg_reset = + register_get_field(p->mp_reg_config, GPIO_PHY_CFG_PORT0_RESET_B); + p->mpa_fields[0].cfg_mod_prs = + register_get_field(p->mp_reg_config, GPIO_PHY_CFG_PORT0_MODPRS_B); + + /* PORT-0, Non-mandatory fields (queryField) */ + p->mpa_fields[0].cfg_pll_int = + register_query_field(p->mp_reg_config, GPIO_PHY_CFG_PORT0_PLL_INTR); + p->mpa_fields[0].cfg_port_rxlos = + register_query_field(p->mp_reg_config, GPIO_PHY_CFG_E_PORT0_RXLOS); + + /* PORT-1, config fields */ + p->mpa_fields[1].cfg_fld_lp_mode = + register_get_field(p->mp_reg_config, GPIO_PHY_CFG_PORT1_LPMODE); + p->mpa_fields[1].cfg_int = + register_get_field(p->mp_reg_config, GPIO_PHY_CFG_PORT1_INT_B); + p->mpa_fields[1].cfg_reset = + register_get_field(p->mp_reg_config, GPIO_PHY_CFG_PORT1_RESET_B); + p->mpa_fields[1].cfg_mod_prs = + register_get_field(p->mp_reg_config, GPIO_PHY_CFG_PORT1_MODPRS_B); + + /* PORT-1, Non-mandatory fields (queryField) */ + p->mpa_fields[1].cfg_pll_int = + register_query_field(p->mp_reg_config, GPIO_PHY_CFG_PORT1_PLL_INTR); + p->mpa_fields[1].cfg_port_rxlos = + register_query_field(p->mp_reg_config, GPIO_PHY_CFG_E_PORT1_RXLOS); + + /* PORT-0, gpio fields */ + p->mpa_fields[0].gpio_fld_lp_mode = + register_get_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT0_LPMODE); + p->mpa_fields[0].gpio_int = + register_get_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT0_INT_B); + p->mpa_fields[0].gpio_reset = + register_get_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT0_RESET_B); + p->mpa_fields[0].gpio_mod_prs = + register_get_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT0_MODPRS_B); + + /* PORT-0, Non-mandatory fields (queryField) */ + p->mpa_fields[0].gpio_pll_int = + register_query_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT0_PLL_INTR); + p->mpa_fields[0].gpio_port_rxlos = + register_query_field(p->mp_reg_gpio, GPIO_PHY_GPIO_E_PORT0_RXLOS); + + /* PORT-1, gpio fields */ + p->mpa_fields[1].gpio_fld_lp_mode = + register_get_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT1_LPMODE); + p->mpa_fields[1].gpio_int = + register_get_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT1_INT_B); + p->mpa_fields[1].gpio_reset = + register_get_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT1_RESET_B); + p->mpa_fields[1].gpio_mod_prs = + register_get_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT1_MODPRS_B); + + /* PORT-1, Non-mandatory fields (queryField) */ + p->mpa_fields[1].gpio_pll_int = + register_query_field(p->mp_reg_gpio, GPIO_PHY_GPIO_PORT1_PLL_INTR); + p->mpa_fields[1].gpio_port_rxlos = + register_query_field(p->mp_reg_gpio, GPIO_PHY_GPIO_E_PORT1_RXLOS); + + register_update(p->mp_reg_config); + + return 0; +} + +bool nthw_gpio_phy_is_low_power_enabled(nthw_gpio_phy_t *p, uint8_t if_no) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return false; + } + + if (field_get_updated(p->mpa_fields[if_no].gpio_fld_lp_mode)) + return true; + + else + return false; +} + +bool nthw_gpio_phy_is_interrupt_set(nthw_gpio_phy_t *p, uint8_t if_no) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return false; + } + + /* NOTE: This is a negated GPIO PIN "INT_B" */ + if (field_get_updated(p->mpa_fields[if_no].gpio_int)) + return false; + + else + return true; +} + +bool nthw_gpio_phy_is_reset(nthw_gpio_phy_t *p, uint8_t if_no) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return false; + } + + /* NOTE: This is a negated GPIO PIN "RESET_B" */ + if (field_get_updated(p->mpa_fields[if_no].gpio_reset)) + return false; + + else + return true; +} + +bool nthw_gpio_phy_is_module_present(nthw_gpio_phy_t *p, uint8_t if_no) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return false; + } + + /* NOTE: This is a negated GPIO PIN "MODPRS_B" */ + return field_get_updated(p->mpa_fields[if_no].gpio_mod_prs) == 0U ? true : + false; +} + +bool nthw_gpio_phy_is_pll_interrupt_set(nthw_gpio_phy_t *p, uint8_t if_no) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return false; + } + + /* NOTE: This is a normal GPIO PIN "PLL_INTR" */ + if (p->mpa_fields[if_no].gpio_pll_int) { + if (field_get_updated(p->mpa_fields[if_no].gpio_pll_int)) + return true; + + else + return false; + } else { + /* this HW doesn't support "PLL_INTR" (INTR from SyncE jitter attenuater) */ + return false; + } +} + +bool nthw_gpio_phy_is_port_rxlos(nthw_gpio_phy_t *p, uint8_t if_no) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return false; + } + + if (p->mpa_fields[if_no].gpio_port_rxlos) { + if (field_get_updated(p->mpa_fields[if_no].gpio_port_rxlos)) + return true; + else + return false; + } else { + return false; + } +} + +void nthw_gpio_phy_set_low_power(nthw_gpio_phy_t *p, uint8_t if_no, bool enable) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return; + } + + if (enable) + field_set_flush(p->mpa_fields[if_no].gpio_fld_lp_mode); + + else + field_clr_flush(p->mpa_fields[if_no].gpio_fld_lp_mode); + field_clr_flush(p->mpa_fields[if_no].cfg_fld_lp_mode); /* enable output */ +} + +void nthw_gpio_phy_set_reset(nthw_gpio_phy_t *p, uint8_t if_no, bool enable) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return; + } + + if (enable) + field_clr_flush(p->mpa_fields[if_no].gpio_reset); + + else + field_set_flush(p->mpa_fields[if_no].gpio_reset); + field_clr_flush(p->mpa_fields[if_no].cfg_reset); /* enable output */ +} + +void nthw_gpio_phy_set_port_rxlos(nthw_gpio_phy_t *p, uint8_t if_no, bool enable) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return; + } + + if (p->mpa_fields[if_no].gpio_port_rxlos) { + if (enable) + field_set_flush(p->mpa_fields[if_no].gpio_port_rxlos); + + else + field_clr_flush(p->mpa_fields[if_no].gpio_port_rxlos); + } +} + +void nthw_gpio_phy_set_cfg_default_values(nthw_gpio_phy_t *p, uint8_t if_no) +{ + if (if_no >= ARRAY_SIZE(p->mpa_fields)) { + assert(false); + return; + } + + field_set_flush(p->mpa_fields[if_no].cfg_fld_lp_mode); /* enable input */ + field_set_flush(p->mpa_fields[if_no].cfg_int); /* enable input */ + field_set_flush(p->mpa_fields[if_no].cfg_reset); /* enable input */ + field_set_flush(p->mpa_fields[if_no].cfg_mod_prs); /* enable input */ + if (p->mpa_fields[if_no].cfg_port_rxlos) + field_clr_flush(p->mpa_fields[if_no].cfg_port_rxlos); /* enable output */ +} diff --git a/drivers/net/ntnic/nthw/core/nthw_gpio_phy.h b/drivers/net/ntnic/nthw/core/nthw_gpio_phy.h new file mode 100644 index 0000000000..1c6185150c --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_gpio_phy.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef NTHW_GPIO_PHY_H_ +#define NTHW_GPIO_PHY_H_ + +#define GPIO_PHY_INTERFACES (2) + +typedef struct { + nt_field_t *cfg_fld_lp_mode; /* Cfg Low Power Mode */ + nt_field_t *cfg_int; /* Cfg Port Interrupt */ + nt_field_t *cfg_reset; /* Cfg Reset */ + nt_field_t *cfg_mod_prs; /* Cfg Module Present */ + nt_field_t *cfg_pll_int; /* Cfg PLL Interrupt */ + nt_field_t *cfg_port_rxlos; /* Emulate Cfg Port RXLOS */ + + nt_field_t *gpio_fld_lp_mode; /* Gpio Low Power Mode */ + nt_field_t *gpio_int; /* Gpio Port Interrupt */ + nt_field_t *gpio_reset; /* Gpio Reset */ + nt_field_t *gpio_mod_prs; /* Gpio Module Present */ + nt_field_t *gpio_pll_int; /* Gpio PLL Interrupt */ + nt_field_t *gpio_port_rxlos; /* Emulate Gpio Port RXLOS */ +} gpio_phy_fields_t; + +struct nthw_gpio_phy { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_gpio_phy; + int mn_instance; + + /* Registers */ + nt_register_t *mp_reg_config; + nt_register_t *mp_reg_gpio; + + /* Fields */ + gpio_phy_fields_t mpa_fields[GPIO_PHY_INTERFACES]; +}; + +typedef struct nthw_gpio_phy nthw_gpio_phy_t; +typedef struct nthw_gpio_phy nthw_gpio_phy; + +nthw_gpio_phy_t *nthw_gpio_phy_new(void); +void nthw_gpio_phy_delete(nthw_gpio_phy_t *p); +int nthw_gpio_phy_init(nthw_gpio_phy_t *p, nt_fpga_t *p_fpga, int n_instance); + +bool nthw_gpio_phy_is_low_power_enabled(nthw_gpio_phy_t *p, uint8_t if_no); +bool nthw_gpio_phy_is_interrupt_set(nthw_gpio_phy_t *p, uint8_t if_no); +bool nthw_gpio_phy_is_reset(nthw_gpio_phy_t *p, uint8_t if_no); +bool nthw_gpio_phy_is_module_present(nthw_gpio_phy_t *p, uint8_t if_no); +bool nthw_gpio_phy_is_pll_interrupt_set(nthw_gpio_phy_t *p, uint8_t if_no); +bool nthw_gpio_phy_is_port_rxlos(nthw_gpio_phy_t *p, uint8_t if_no); +void nthw_gpio_phy_set_low_power(nthw_gpio_phy_t *p, uint8_t if_no, bool enable); +void nthw_gpio_phy_set_reset(nthw_gpio_phy_t *p, uint8_t if_no, bool enable); +void nthw_gpio_phy_set_port_rxlos(nthw_gpio_phy_t *p, uint8_t if_no, bool enable); +void nthw_gpio_phy_set_cfg_default_values(nthw_gpio_phy_t *p, uint8_t if_no); + +#endif /* NTHW_GPIO_PHY_H_ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_hif.c b/drivers/net/ntnic/nthw/core/nthw_hif.c new file mode 100644 index 0000000000..7b7a919108 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_hif.c @@ -0,0 +1,342 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "nt_util.h" +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_hif.h" + +nthw_hif_t *nthw_hif_new(void) +{ + nthw_hif_t *p = malloc(sizeof(nthw_hif_t)); + + if (p) + memset(p, 0, sizeof(nthw_hif_t)); + return p; +} + +void nthw_hif_delete(nthw_hif_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_hif_t)); + free(p); + } +} + +int nthw_hif_init(nthw_hif_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + const char *const p_adapter_id_str _unused = + p_fpga->p_fpga_info->mp_adapter_id_str; + nt_module_t *mod = fpga_query_module(p_fpga, MOD_HIF, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: HIF %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_hif = mod; + + /* default for (Xilinx-based) products until august 2022: (1e6/4000 = 250 MHz) */ + p->mn_fpga_param_hif_per_ps = + fpga_get_product_param(p->mp_fpga, NT_HIF_PER_PS, 4000); + p->mn_fpga_hif_ref_clk_freq = + (uint32_t)(1000000000000ULL / + (unsigned int)p->mn_fpga_param_hif_per_ps); + + p->mp_reg_prod_id_lsb = module_get_register(p->mp_mod_hif, HIF_PROD_ID_LSB); + p->mp_fld_prod_id_lsb_rev_id = + register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_REV_ID); + p->mp_fld_prod_id_lsb_ver_id = + register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_VER_ID); + p->mp_fld_prod_id_lsb_group_id = + register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_GROUP_ID); + + p->mp_reg_prod_id_msb = module_get_register(p->mp_mod_hif, HIF_PROD_ID_MSB); + p->mp_fld_prod_id_msb_type_id = + register_get_field(p->mp_reg_prod_id_msb, HIF_PROD_ID_MSB_TYPE_ID); + p->mp_fld_prod_id_msb_build_no = + register_get_field(p->mp_reg_prod_id_msb, HIF_PROD_ID_MSB_BUILD_NO); + + p->mp_reg_build_time = module_get_register(p->mp_mod_hif, HIF_BUILD_TIME); + p->mp_fld_build_time = + register_get_field(p->mp_reg_build_time, HIF_BUILD_TIME_TIME); + + p->mn_fpga_id_prod = field_get_updated(p->mp_fld_prod_id_lsb_group_id); + p->mn_fpga_id_ver = field_get_updated(p->mp_fld_prod_id_lsb_ver_id); + p->mn_fpga_id_rev = field_get_updated(p->mp_fld_prod_id_lsb_rev_id); + p->mn_fpga_id_build_no = field_get_updated(p->mp_fld_prod_id_msb_build_no); + p->mn_fpga_id_item = field_get_updated(p->mp_fld_prod_id_msb_type_id); + + NT_LOG(DBG, NTHW, "%s: HIF %d: %s: %d-%d-%d-%d-%d\n", p_adapter_id_str, + p->mn_instance, __func__, p->mn_fpga_id_item, p->mn_fpga_id_prod, + p->mn_fpga_id_ver, p->mn_fpga_id_rev, p->mn_fpga_id_build_no); + NT_LOG(DBG, NTHW, + "%s: HIF %d: %s: HIF ref clock: %d Hz (%d ticks/ps)\n", + p_adapter_id_str, p->mn_instance, __func__, p->mn_fpga_hif_ref_clk_freq, + p->mn_fpga_param_hif_per_ps); + + p->mp_reg_build_seed = NULL; /* Reg/Fld not present on HIF */ + if (p->mp_reg_build_seed) + p->mp_fld_build_seed = NULL; /* Reg/Fld not present on HIF */ + else + p->mp_fld_build_seed = NULL; + + p->mp_reg_core_speed = NULL; /* Reg/Fld not present on HIF */ + if (p->mp_reg_core_speed) { + p->mp_fld_core_speed = NULL; /* Reg/Fld not present on HIF */ + p->mp_fld_ddr3_speed = NULL; /* Reg/Fld not present on HIF */ + } else { + p->mp_reg_core_speed = NULL; + p->mp_fld_core_speed = NULL; + p->mp_fld_ddr3_speed = NULL; + } + + /* Optional registers since: 2018-04-25 */ + p->mp_reg_int_mask = NULL; /* Reg/Fld not present on HIF */ + p->mp_reg_int_clr = NULL; /* Reg/Fld not present on HIF */ + p->mp_reg_int_force = NULL; /* Reg/Fld not present on HIF */ + + p->mp_fld_int_mask_timer = NULL; + p->mp_fld_int_clr_timer = NULL; + p->mp_fld_int_force_timer = NULL; + + p->mp_fld_int_mask_port = NULL; + p->mp_fld_int_clr_port = NULL; + p->mp_fld_int_force_port = NULL; + + p->mp_fld_int_mask_pps = NULL; + p->mp_fld_int_clr_pps = NULL; + p->mp_fld_int_force_pps = NULL; + + p->mp_reg_stat_ctrl = module_get_register(p->mp_mod_hif, HIF_STAT_CTRL); + p->mp_fld_stat_ctrl_ena = + register_get_field(p->mp_reg_stat_ctrl, HIF_STAT_CTRL_STAT_ENA); + p->mp_fld_stat_ctrl_req = + register_get_field(p->mp_reg_stat_ctrl, HIF_STAT_CTRL_STAT_REQ); + + p->mp_reg_stat_rx = module_get_register(p->mp_mod_hif, HIF_STAT_RX); + p->mp_fld_stat_rx_counter = + register_get_field(p->mp_reg_stat_rx, HIF_STAT_RX_COUNTER); + + p->mp_reg_stat_tx = module_get_register(p->mp_mod_hif, HIF_STAT_TX); + p->mp_fld_stat_tx_counter = + register_get_field(p->mp_reg_stat_tx, HIF_STAT_TX_COUNTER); + + p->mp_reg_stat_ref_clk = module_get_register(p->mp_mod_hif, HIF_STAT_REFCLK); + p->mp_fld_stat_ref_clk_ref_clk = register_get_field(p->mp_reg_stat_ref_clk, + HIF_STAT_REFCLK_REFCLK250); + + p->mp_reg_status = module_query_register(p->mp_mod_hif, HIF_STATUS); + if (p->mp_reg_status) { + p->mp_fld_status_tags_in_use = + register_query_field(p->mp_reg_status, HIF_STATUS_TAGS_IN_USE); + p->mp_fld_status_wr_err = + register_query_field(p->mp_reg_status, HIF_STATUS_WR_ERR); + p->mp_fld_status_rd_err = + register_query_field(p->mp_reg_status, HIF_STATUS_RD_ERR); + } else { + p->mp_reg_status = module_query_register(p->mp_mod_hif, HIF_STATUS); + p->mp_fld_status_tags_in_use = + register_query_field(p->mp_reg_status, HIF_STATUS_TAGS_IN_USE); + p->mp_fld_status_wr_err = NULL; + p->mp_fld_status_rd_err = NULL; + } + + p->mp_reg_pci_test0 = module_get_register(p->mp_mod_hif, HIF_TEST0); + p->mp_fld_pci_test0 = register_get_field(p->mp_reg_pci_test0, HIF_TEST0_DATA); + + p->mp_reg_pci_test1 = module_get_register(p->mp_mod_hif, HIF_TEST1); + p->mp_fld_pci_test1 = register_get_field(p->mp_reg_pci_test1, HIF_TEST1_DATA); + + /* Required to run TSM */ + p->mp_reg_sample_time = module_get_register(p->mp_mod_hif, HIF_SAMPLE_TIME); + if (p->mp_reg_sample_time) { + p->mp_fld_sample_time = + register_get_field(p->mp_reg_sample_time, HIF_SAMPLE_TIME_SAMPLE_TIME); + } else { + p->mp_fld_sample_time = NULL; + } + + /* We need to optimize PCIe3 TLP-size read-request and extended tag usage */ + { + p->mp_reg_config = module_query_register(p->mp_mod_hif, HIF_CONFIG); + if (p->mp_reg_config) { + p->mp_fld_max_tlp = + register_get_field(p->mp_reg_config, HIF_CONFIG_MAX_TLP); + p->mp_fld_max_read = + register_get_field(p->mp_reg_config, HIF_CONFIG_MAX_READ); + p->mp_fld_ext_tag = + register_get_field(p->mp_reg_config, HIF_CONFIG_EXT_TAG); + } else { + p->mp_fld_max_tlp = NULL; + p->mp_fld_max_read = NULL; + p->mp_fld_ext_tag = NULL; + } + } + + return 0; +} + +int nthw_hif_setup_config(nthw_hif_t *p) +{ + const char *const p_adapter_id_str _unused = + p->mp_fpga->p_fpga_info->mp_adapter_id_str; + + /* + * We need to optimize PCIe3 read-request and extended tag usage + * original check: HW_ADAPTER_ID_NT200A02 HW_ADAPTER_ID_NT100A01 HW_ADAPTER_ID_NT50B01 + */ + if (p->mp_fpga->p_fpga_info->n_nthw_adapter_id != NT_HW_ADAPTER_ID_NT40E3) { + if (p->mp_fld_max_read) { + /* + * NOTE: On Pandion DELL server, this param was negotiated to 4096 + * (index=5), but the server crashed. For now we need to limit this value to + * 512 (index=2) + */ + const uint32_t n_max_read_req_size = + field_get_updated(p->mp_fld_max_read); + if (n_max_read_req_size > 2) { + field_set_val_flush32(p->mp_fld_max_read, 2); + NT_LOG(INF, NTHW, + "%s: %s: PCIe: MaxReadReqsize %d - changed to 2 (512B)\n", + p_adapter_id_str, __func__, + n_max_read_req_size); + } + } + + if (p->mp_fld_ext_tag) + field_set_val_flush32(p->mp_fld_ext_tag, 1); + + if (p->mp_fld_max_tlp && p->mp_fld_max_read && p->mp_fld_ext_tag) { + NT_LOG(INF, NTHW, + "%s: %s: PCIe config: MaxTlp = %d, MaxReadReqsize = %d, ExtTagEna = %d\n", + p_adapter_id_str, __func__, + field_get_updated(p->mp_fld_max_tlp), + field_get_updated(p->mp_fld_max_read), + field_get_updated(p->mp_fld_ext_tag)); + } + } + return 0; +} + +int nthw_hif_trigger_sample_time(nthw_hif_t *p) +{ + field_set_val_flush32(p->mp_fld_sample_time, 0xfee1dead); + + return 0; +} + +int nthw_hif_get_stat(nthw_hif_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt, + uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, + uint32_t *p_tg_ref_freq, uint64_t *p_tags_in_use, + uint64_t *p_rd_err, uint64_t *p_wr_err) +{ + *p_rx_cnt = field_get_updated(p->mp_fld_stat_rx_counter); + *p_tx_cnt = field_get_updated(p->mp_fld_stat_tx_counter); + + *p_ref_clk_cnt = field_get_updated(p->mp_fld_stat_ref_clk_ref_clk); + + *p_tg_unit_size = NTHW_TG_CNT_SIZE; + *p_tg_ref_freq = p->mn_fpga_hif_ref_clk_freq; + + *p_tags_in_use = (p->mp_fld_status_tags_in_use ? + field_get_updated(p->mp_fld_status_tags_in_use) : + 0); + + *p_rd_err = (p->mp_fld_status_rd_err ? field_get_updated(p->mp_fld_status_rd_err) : + 0); + *p_wr_err = (p->mp_fld_status_wr_err ? field_get_updated(p->mp_fld_status_wr_err) : + 0); + + return 0; +} + +int nthw_hif_get_stat_rate(nthw_hif_t *p, uint64_t *p_pci_rx_rate, + uint64_t *p_pci_tx_rate, uint64_t *p_ref_clk_cnt, + uint64_t *p_tags_in_use, uint64_t *p_rd_err_cnt, + uint64_t *p_wr_err_cnt) +{ + uint32_t rx_cnt, tx_cnt, ref_clk_cnt, tg_unit_size, tg_ref_freq; + uint64_t n_tags_in_use, n_rd_err, n_wr_err; + + nthw_hif_get_stat(p, &rx_cnt, &tx_cnt, &ref_clk_cnt, &tg_unit_size, &tg_ref_freq, + &n_tags_in_use, &n_rd_err, &n_wr_err); + + *p_tags_in_use = n_tags_in_use; + if (n_rd_err) + (*p_rd_err_cnt)++; + if (n_wr_err) + (*p_wr_err_cnt)++; + + if (ref_clk_cnt) { + uint64_t rx_rate; + uint64_t tx_rate; + + *p_ref_clk_cnt = ref_clk_cnt; + + rx_rate = ((uint64_t)rx_cnt * tg_unit_size * tg_ref_freq) / + (uint64_t)ref_clk_cnt; + *p_pci_rx_rate = rx_rate; + + tx_rate = ((uint64_t)tx_cnt * tg_unit_size * tg_ref_freq) / + (uint64_t)ref_clk_cnt; + *p_pci_tx_rate = tx_rate; + } else { + *p_pci_rx_rate = 0; + *p_pci_tx_rate = 0; + *p_ref_clk_cnt = 0; + } + + return 0; +} + +int nthw_hif_stat_req_enable(nthw_hif_t *p) +{ + field_set_all(p->mp_fld_stat_ctrl_ena); + field_set_all(p->mp_fld_stat_ctrl_req); + field_flush_register(p->mp_fld_stat_ctrl_req); + return 0; +} + +int nthw_hif_stat_req_disable(nthw_hif_t *p) +{ + field_clr_all(p->mp_fld_stat_ctrl_ena); + field_set_all(p->mp_fld_stat_ctrl_req); + field_flush_register(p->mp_fld_stat_ctrl_req); + return 0; +} + +int nthw_hif_stat_sample(nthw_hif_t *p, uint64_t *p_rx_rate, uint64_t *p_tx_rate, + uint64_t *p_ref_clk_cnt, uint64_t *p_tags_in_use, + uint64_t *p_rd_err_cnt, uint64_t *p_wr_err_cnt) +{ + nthw_hif_stat_req_enable(p); + NT_OS_WAIT_USEC(100000); + nthw_hif_stat_req_disable(p); + nthw_hif_get_stat_rate(p, p_rx_rate, p_tx_rate, p_ref_clk_cnt, p_tags_in_use, + p_rd_err_cnt, p_wr_err_cnt); + + return 0; +} + +int nthw_hif_end_point_counters_sample(nthw_hif_t *p, + struct nthw_hif_end_point_counters *epc) +{ + assert(epc); + + /* Get stat rate and maintain rx/tx min/max */ + nthw_hif_get_stat_rate(p, &epc->cur_tx, &epc->cur_rx, &epc->n_ref_clk_cnt, + &epc->n_tags_in_use, &epc->n_rd_err, &epc->n_wr_err); + + return 0; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_hif.h b/drivers/net/ntnic/nthw/core/nthw_hif.h new file mode 100644 index 0000000000..2701e222b3 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_hif.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_HIF_H__ +#define __NTHW_HIF_H__ + +#define NTHW_TG_CNT_SIZE (4ULL) + +struct nthw_hif { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_hif; + int mn_instance; + + nt_register_t *mp_reg_prod_id_lsb; + nt_field_t *mp_fld_prod_id_lsb_rev_id; + nt_field_t *mp_fld_prod_id_lsb_ver_id; + nt_field_t *mp_fld_prod_id_lsb_group_id; + + nt_register_t *mp_reg_prod_id_msb; + nt_field_t *mp_fld_prod_id_msb_type_id; + nt_field_t *mp_fld_prod_id_msb_build_no; + + nt_register_t *mp_reg_build_time; + nt_field_t *mp_fld_build_time; + + nt_register_t *mp_reg_build_seed; + nt_field_t *mp_fld_build_seed; + + nt_register_t *mp_reg_core_speed; + nt_field_t *mp_fld_core_speed; + nt_field_t *mp_fld_ddr3_speed; + + nt_register_t *mp_reg_int_mask; + nt_field_t *mp_fld_int_mask_timer; + nt_field_t *mp_fld_int_mask_port; + nt_field_t *mp_fld_int_mask_pps; + + nt_register_t *mp_reg_int_clr; + nt_field_t *mp_fld_int_clr_timer; + nt_field_t *mp_fld_int_clr_port; + nt_field_t *mp_fld_int_clr_pps; + + nt_register_t *mp_reg_int_force; + nt_field_t *mp_fld_int_force_timer; + nt_field_t *mp_fld_int_force_port; + nt_field_t *mp_fld_int_force_pps; + + nt_register_t *mp_reg_sample_time; + nt_field_t *mp_fld_sample_time; + + nt_register_t *mp_reg_status; + nt_field_t *mp_fld_status_tags_in_use; + nt_field_t *mp_fld_status_wr_err; + nt_field_t *mp_fld_status_rd_err; + + nt_register_t *mp_reg_stat_ctrl; + nt_field_t *mp_fld_stat_ctrl_ena; + nt_field_t *mp_fld_stat_ctrl_req; + + nt_register_t *mp_reg_stat_rx; + nt_field_t *mp_fld_stat_rx_counter; + + nt_register_t *mp_reg_stat_tx; + nt_field_t *mp_fld_stat_tx_counter; + + nt_register_t *mp_reg_stat_ref_clk; + nt_field_t *mp_fld_stat_ref_clk_ref_clk; + + nt_register_t *mp_reg_pci_test0; + nt_field_t *mp_fld_pci_test0; + + nt_register_t *mp_reg_pci_test1; + nt_field_t *mp_fld_pci_test1; + + nt_register_t *mp_reg_pci_test2; + nt_field_t *mp_fld_pci_test2; + + nt_register_t *mp_reg_pci_test3; + nt_field_t *mp_fld_pci_test3; + + nt_register_t *mp_reg_config; + nt_field_t *mp_fld_max_tlp; + nt_field_t *mp_fld_max_read; + nt_field_t *mp_fld_ext_tag; + + int mn_fpga_id_item; + int mn_fpga_id_prod; + int mn_fpga_id_ver; + int mn_fpga_id_rev; + int mn_fpga_id_build_no; + + int mn_fpga_param_hif_per_ps; + uint32_t mn_fpga_hif_ref_clk_freq; +}; + +typedef struct nthw_hif nthw_hif_t; +typedef struct nthw_hif nthw_hif; + +struct nthw_hif_end_point_err_counters { + uint32_t n_err_correctable, n_err_non_fatal, n_err_fatal; +}; + +struct nthw_hif_end_point_counters { + int n_numa_node; + + int n_tg_direction; + int n_tg_pkt_size; + int n_tg_num_pkts; + int n_tg_delay; + + uint64_t cur_rx, cur_tx; + uint64_t cur_pci_nt_util, cur_pci_xil_util; + uint64_t n_ref_clk_cnt; + + uint64_t n_tags_in_use; + uint64_t n_rd_err; + uint64_t n_wr_err; + + struct nthw_hif_end_point_err_counters s_rc_ep_pre, s_rc_ep_post, s_rc_ep_delta; + struct nthw_hif_end_point_err_counters s_ep_rc_pre, s_ep_rc_post, s_ep_rc_delta; + + int bo_error; +}; + +struct nthw_hif_end_points { + struct nthw_hif_end_point_counters pri, sla; +}; + +nthw_hif_t *nthw_hif_new(void); +void nthw_hif_delete(nthw_hif_t *p); +int nthw_hif_init(nthw_hif_t *p, nt_fpga_t *p_fpga, int n_instance); + +int nthw_hif_setup_config(nthw_hif_t *p); + +int nthw_hif_trigger_sample_time(nthw_hif_t *p); + +int nthw_hif_stat_req_enable(nthw_hif_t *p); +int nthw_hif_stat_req_disable(nthw_hif_t *p); +int nthw_hif_stat_sample(nthw_hif_t *p, uint64_t *p_rx_rate, uint64_t *p_tx_rate, + uint64_t *p_ref_clk_cnt, uint64_t *p_tags_in_use, + uint64_t *p_rd_err_cnt, uint64_t *p_wr_err_cnt); + +int nthw_hif_get_stat(nthw_hif_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt, + uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, + uint32_t *p_tg_ref_freq, uint64_t *p_tags_in_use, + uint64_t *p_rd_err, uint64_t *p_wr_err); +int nthw_hif_get_stat_rate(nthw_hif_t *p, uint64_t *p_pci_rx_rate, + uint64_t *p_pci_tx_rate, uint64_t *p_ref_clk_cnt, + uint64_t *p_tags_in_use, uint64_t *p_rd_err_cnt, + uint64_t *p_wr_err_cnt); + +int nthw_hif_end_point_counters_sample(nthw_hif_t *p, + struct nthw_hif_end_point_counters *epc); + +#endif /* __NTHW_HIF_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_iic.c b/drivers/net/ntnic/nthw/core/nthw_iic.c new file mode 100644 index 0000000000..14aee221ce --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_iic.c @@ -0,0 +1,570 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "nt_util.h" +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_iic.h" + +#define I2C_TRANSMIT_WR (0x00) +#define I2C_TRANSMIT_RD (0x01) + +#define I2C_WAIT_US(x) NT_OS_WAIT_USEC(x) + +/* + * Minimum timing values for I2C for a Marvel 88E11111 Phy. + * This Phy is used in many Trispeed NIMs. + * In order to access this Phy, the I2C clock speed is needed to be set to 100KHz. + */ +static const uint32_t susta = 4700; /* ns */ +static const uint32_t susto = 4000; /* ns */ +static const uint32_t hdsta = 4000; /* ns */ +static const uint32_t sudat = 250; /* ns */ +static const uint32_t buf = 4700; /* ns */ +static const uint32_t high = 4000; /* ns */ +static const uint32_t low = 4700; /* ns */ +static const uint32_t hddat = 300; /* ns */ + +static int nthw_iic_reg_control_txfifo_reset(nthw_iic_t *p) +{ + field_update_register(p->mp_fld_cr_txfifo_reset); + + field_set_all(p->mp_fld_cr_txfifo_reset); + field_flush_register(p->mp_fld_cr_txfifo_reset); + + field_clr_all(p->mp_fld_cr_txfifo_reset); + field_flush_register(p->mp_fld_cr_txfifo_reset); + + return 0; +} + +static int nthw_iic_reg_tx_fifo_write(nthw_iic_t *p, uint32_t data, bool start, + bool stop) +{ + if (start) + field_set_all(p->mp_fld_tx_fifo_start); + + else + field_clr_all(p->mp_fld_tx_fifo_start); + + if (stop) + field_set_all(p->mp_fld_tx_fifo_stop); + + else + field_clr_all(p->mp_fld_tx_fifo_stop); + + field_set_val32(p->mp_fld_tx_fifo_txdata, data); + + register_flush(p->mp_reg_tx_fifo, 1); + + return 0; +} + +static int nthw_iic_reg_read_i2c_rx_fifo(nthw_iic_t *p, uint8_t *p_data) +{ + assert(p_data); + + *p_data = (uint8_t)field_get_updated(p->mp_fld_rx_fifo_rxdata); + + return 0; +} + +static int nthw_iic_reg_softr(nthw_iic_t *p) +{ + field_update_register(p->mp_fld_cr_en); + field_set_val_flush32(p->mp_fld_softr_rkey, 0x0A); + + return 0; +} + +static int nthw_iic_reg_enable(nthw_iic_t *p) +{ + field_update_register(p->mp_fld_cr_en); + field_set_flush(p->mp_fld_cr_en); + + return 0; +} + +static int nthw_iic_reg_busbusy(nthw_iic_t *p, bool *pb_flag) +{ + assert(pb_flag); + + *pb_flag = field_get_updated(p->mp_fld_sr_bb) ? true : false; + + return 0; +} + +static int nthw_iic_reg_rxfifo_empty(nthw_iic_t *p, bool *pb_flag) +{ + assert(pb_flag); + + *pb_flag = field_get_updated(p->mp_fld_sr_rxfifo_empty) ? true : false; + + return 0; +} + +/* + * nIicCycleTime is the I2C clock cycle time in ns ie 125MHz = 8ns + */ +static int nthw_iic_reg_set_timing(nthw_iic_t *p, uint32_t n_iic_cycle_time) +{ + uint32_t val; + + val = susta / n_iic_cycle_time; + field_set_val_flush(p->mp_fld_tsusta, &val, 1); + + val = susto / n_iic_cycle_time; + field_set_val_flush(p->mp_fld_tsusto, &val, 1); + + val = hdsta / n_iic_cycle_time; + field_set_val_flush(p->mp_fld_thdsta, &val, 1); + + val = sudat / n_iic_cycle_time; + field_set_val_flush(p->mp_fld_tsudat, &val, 1); + + val = buf / n_iic_cycle_time; + field_set_val_flush(p->mp_fld_tbuf, &val, 1); + + val = high / n_iic_cycle_time; + field_set_val_flush(p->mp_fld_thigh, &val, 1); + + val = low / n_iic_cycle_time; + field_set_val_flush(p->mp_fld_tlow, &val, 1); + + val = hddat / n_iic_cycle_time; + field_set_val_flush(p->mp_fld_thddat, &val, 1); + + return 0; +} + +nthw_iic_t *nthw_iic_new(void) +{ + nthw_iic_t *p = malloc(sizeof(nthw_iic_t)); + + if (p) + memset(p, 0, sizeof(nthw_iic_t)); + return p; +} + +int nthw_iic_init(nthw_iic_t *p, nt_fpga_t *p_fpga, int n_iic_instance, + uint32_t n_iic_cycle_time) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + nt_module_t *mod = fpga_query_module(p_fpga, MOD_IIC, n_iic_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: I2C %d: no such instance\n", + p_adapter_id_str, n_iic_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_iic_instance = n_iic_instance; + + p->mn_iic_cycle_time = n_iic_cycle_time; + + nthw_iic_set_retry_params(p, -1, -1, -1, -1, -1); + + p->mp_mod_iic = mod; + + /* I2C is a primary communication channel - turn off debug by default */ + module_set_debug_mode(p->mp_mod_iic, 0x00); + + p->mp_reg_tsusta = module_get_register(p->mp_mod_iic, IIC_TSUSTA); + p->mp_fld_tsusta = + register_get_field(p->mp_reg_tsusta, IIC_TSUSTA_TSUSTA_VAL); + + p->mp_reg_tsusto = module_get_register(p->mp_mod_iic, IIC_TSUSTO); + p->mp_fld_tsusto = + register_get_field(p->mp_reg_tsusto, IIC_TSUSTO_TSUSTO_VAL); + + p->mp_reg_thdsta = module_get_register(p->mp_mod_iic, IIC_THDSTA); + p->mp_fld_thdsta = + register_get_field(p->mp_reg_thdsta, IIC_THDSTA_THDSTA_VAL); + + p->mp_reg_tsudat = module_get_register(p->mp_mod_iic, IIC_TSUDAT); + p->mp_fld_tsudat = + register_get_field(p->mp_reg_tsudat, IIC_TSUDAT_TSUDAT_VAL); + + p->mp_reg_tbuf = module_get_register(p->mp_mod_iic, IIC_TBUF); + p->mp_fld_tbuf = register_get_field(p->mp_reg_tbuf, IIC_TBUF_TBUF_VAL); + + p->mp_reg_thigh = module_get_register(p->mp_mod_iic, IIC_THIGH); + p->mp_fld_thigh = register_get_field(p->mp_reg_thigh, IIC_THIGH_THIGH_VAL); + + p->mp_reg_tlow = module_get_register(p->mp_mod_iic, IIC_TLOW); + p->mp_fld_tlow = register_get_field(p->mp_reg_tlow, IIC_TLOW_TLOW_VAL); + + p->mp_reg_thddat = module_get_register(p->mp_mod_iic, IIC_THDDAT); + p->mp_fld_thddat = + register_get_field(p->mp_reg_thddat, IIC_THDDAT_THDDAT_VAL); + + p->mp_reg_cr = module_get_register(p->mp_mod_iic, IIC_CR); + p->mp_fld_cr_en = register_get_field(p->mp_reg_cr, IIC_CR_EN); + p->mp_fld_cr_msms = register_get_field(p->mp_reg_cr, IIC_CR_MSMS); + p->mp_fld_cr_txfifo_reset = + register_get_field(p->mp_reg_cr, IIC_CR_TXFIFO_RESET); + p->mp_fld_cr_txak = register_get_field(p->mp_reg_cr, IIC_CR_TXAK); + + p->mp_reg_sr = module_get_register(p->mp_mod_iic, IIC_SR); + p->mp_fld_sr_bb = register_get_field(p->mp_reg_sr, IIC_SR_BB); + p->mp_fld_sr_rxfifo_full = + register_get_field(p->mp_reg_sr, IIC_SR_RXFIFO_FULL); + p->mp_fld_sr_rxfifo_empty = + register_get_field(p->mp_reg_sr, IIC_SR_RXFIFO_EMPTY); + p->mp_fld_sr_txfifo_full = + register_get_field(p->mp_reg_sr, IIC_SR_TXFIFO_FULL); + p->mp_fld_sr_txfifo_empty = + register_get_field(p->mp_reg_sr, IIC_SR_TXFIFO_EMPTY); + + p->mp_reg_tx_fifo = module_get_register(p->mp_mod_iic, IIC_TX_FIFO); + p->mp_fld_tx_fifo_txdata = + register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_TXDATA); + p->mp_fld_tx_fifo_start = + register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_START); + p->mp_fld_tx_fifo_stop = + register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_STOP); + + p->mp_reg_rx_fifo_pirq = + module_get_register(p->mp_mod_iic, IIC_RX_FIFO_PIRQ); + p->mp_fld_rx_fifo_pirq_cmp_val = + register_get_field(p->mp_reg_rx_fifo_pirq, IIC_RX_FIFO_PIRQ_CMP_VAL); + + p->mp_reg_rx_fifo = module_get_register(p->mp_mod_iic, IIC_RX_FIFO); + p->mp_fld_rx_fifo_rxdata = + register_get_field(p->mp_reg_rx_fifo, IIC_RX_FIFO_RXDATA); + + p->mp_reg_softr = module_get_register(p->mp_mod_iic, IIC_SOFTR); + p->mp_fld_softr_rkey = register_get_field(p->mp_reg_softr, IIC_SOFTR_RKEY); + + /* + * Initialize I2C controller by applying soft reset and enable the controller + */ + nthw_iic_reg_softr(p); + /* Enable the controller */ + nthw_iic_reg_enable(p); + + /* Setup controller timing */ + if (p->mn_iic_cycle_time) { + NT_LOG(DBG, NTHW, "%s: I2C%d: cycletime=%d\n", p_adapter_id_str, + p->mn_iic_instance, p->mn_iic_cycle_time); + nthw_iic_reg_set_timing(p, p->mn_iic_cycle_time); + } + + /* Reset TX fifo - must be after enable */ + nthw_iic_reg_control_txfifo_reset(p); + nthw_iic_reg_tx_fifo_write(p, 0, 0, 0); + + return 0; +} + +void nthw_iic_delete(nthw_iic_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_iic_t)); + free(p); + } +} + +int nthw_iic_set_retry_params(nthw_iic_t *p, const int n_poll_delay, + const int n_bus_ready_retry, const int n_data_ready_retry, + const int n_read_data_retry, const int n_write_data_retry) +{ + p->mn_poll_delay = n_poll_delay >= 0 ? n_poll_delay : 10; + + p->mn_bus_ready_retry = n_bus_ready_retry >= 0 ? n_bus_ready_retry : 1000; + p->mn_data_ready_retry = n_data_ready_retry >= 0 ? n_data_ready_retry : 1000; + + p->mn_read_data_retry = n_read_data_retry >= 0 ? n_read_data_retry : 10; + p->mn_write_data_retry = n_write_data_retry >= 0 ? n_write_data_retry : 10; + + return 0; +} + +int nthw_iic_read_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t reg_addr, + uint8_t data_len, void *p_void) +{ + const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str; + const int n_debug_mode = module_get_debug_mode(p->mp_mod_iic); + + uint8_t *pb = (uint8_t *)p_void; + int retry = (p->mn_read_data_retry >= 0 ? p->mn_read_data_retry : 10); + + if (n_debug_mode == 0xff) { + NT_LOG(DBG, NTHW, "%s: adr=0x%2.2x, reg=%d, len=%d\n", + p_adapter_id_str, dev_addr, reg_addr, data_len); + } + + while (nthw_iic_readbyte(p, dev_addr, reg_addr, data_len, pb) != 0) { + retry--; + if (retry <= 0) { + NT_LOG(ERR, NTHW, + "%s: I2C%d: Read retry exhausted (dev_addr=%d reg_addr=%d)\n", + p_adapter_id_str, p->mn_iic_instance, dev_addr, + reg_addr); + return -1; + } +#if defined(DEBUG) + NT_LOG(DBG, NTHW, + "%s: I2C%d: Read retry=%d (dev_addr=%d reg_addr=%d)\n", + p_adapter_id_str, p->mn_iic_instance, retry, dev_addr, + reg_addr); +#endif + } + + if (n_debug_mode == 0xff) { + NT_LOG(DBG, NTHW, + "%s: adr=0x%2.2x, reg=%d, len=%d, retries remaining: %d\n", + p_adapter_id_str, dev_addr, reg_addr, data_len, retry); + } + + return 0; +} + +int nthw_iic_readbyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t reg_addr, + uint8_t data_len, uint8_t *p_byte) +{ + const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str; + + uint32_t value; + uint32_t i; + + if (nthw_iic_bus_ready(p)) { + /* Reset TX fifo */ + nthw_iic_reg_control_txfifo_reset(p); + + /* Write device address to TX_FIFO and set start bit!! */ + value = (dev_addr << 1) | I2C_TRANSMIT_WR; + nthw_iic_reg_tx_fifo_write(p, value, 1, 0); + + /* Write reg_addr to TX FIFO */ + nthw_iic_reg_tx_fifo_write(p, reg_addr, 0, 1); + + if (!nthw_iic_bus_ready(p)) { + NT_LOG(ERR, NTHW, "%s: error: (%s:%u)\n", p_adapter_id_str, + __func__, __LINE__); + return -1; + } + + /* Write device address + RD bit to TX_FIFO and set start bit!! */ + value = (dev_addr << 1) | I2C_TRANSMIT_RD; + nthw_iic_reg_tx_fifo_write(p, value, 1, 0); + + /* Write DataLen to TX_FIFO and set stop bit!! */ + nthw_iic_reg_tx_fifo_write(p, data_len, 0, 1); + + for (i = 0; i < data_len; i++) { + /* Wait for RX FIFO not empty */ + if (!nthw_iic_data_ready(p)) + return -1; + + /* Read DataLen bytes from RX_FIFO */ + nthw_iic_reg_read_i2c_rx_fifo(p, p_byte); + p_byte++; + } + + return 0; + + } else { + NT_LOG(ERR, NTHW, "%s: error: (%s:%u)\n", p_adapter_id_str, + __func__, __LINE__); + return -1; + } + return 0; +} + +int nthw_iic_write_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t reg_addr, + uint8_t data_len, void *p_void) +{ + const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str; + int retry = (p->mn_write_data_retry >= 0 ? p->mn_write_data_retry : 10); + uint8_t *pb = (uint8_t *)p_void; + + while (nthw_iic_writebyte(p, dev_addr, reg_addr, data_len, pb) != 0) { + retry--; + if (retry <= 0) { + NT_LOG(ERR, NTHW, + "%s: I2C%d: Write retry exhausted (dev_addr=%d reg_addr=%d)\n", + p_adapter_id_str, p->mn_iic_instance, dev_addr, + reg_addr); + return -1; + } +#if defined(DEBUG) + NT_LOG(DBG, NTHW, + "%s: I2C%d: Write retry=%d (dev_addr=%d reg_addr=%d)\n", + p_adapter_id_str, p->mn_iic_instance, retry, dev_addr, + reg_addr); +#endif + } + + return 0; +} + +int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t reg_addr, + uint8_t data_len, uint8_t *p_byte) +{ + const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str; + uint32_t value; + int count; + int i; + + if (data_len == 0) + return -1; + + count = data_len - 1; + if (nthw_iic_bus_ready(p)) { + /* Reset TX fifo */ + nthw_iic_reg_control_txfifo_reset(p); + + /* Write device address to TX_FIFO and set start bit!! */ + value = (dev_addr << 1) | I2C_TRANSMIT_WR; + nthw_iic_reg_tx_fifo_write(p, value, 1, 0); + + /* Write reg_addr to TX FIFO */ + nthw_iic_reg_tx_fifo_write(p, reg_addr, 0, 0); + + for (i = 0; i < count; i++) { + /* Write data byte to TX fifo and set stop bit */ + nthw_iic_reg_tx_fifo_write(p, *p_byte, 0, 0); + p_byte++; + } + + /* Write data byte to TX fifo and set stop bit */ + nthw_iic_reg_tx_fifo_write(p, *p_byte, 0, 1); + + if (!nthw_iic_bus_ready(p)) { + NT_LOG(WRN, NTHW, "%s: warn: !busReady (%s:%u)\n", + p_adapter_id_str, __func__, __LINE__); + while (true) { + if (nthw_iic_bus_ready(p)) { + NT_LOG(DBG, NTHW, + "%s: info: busReady (%s:%u)\n", + p_adapter_id_str, __func__, + __LINE__); + break; + } + } + } + + return 0; + + } else { + NT_LOG(WRN, NTHW, "%s: (%s:%u)\n", p_adapter_id_str, __func__, + __LINE__); + return -1; + } +} + +/* + * Support function for read/write functions below. Waits for bus ready. + */ +bool nthw_iic_bus_ready(nthw_iic_t *p) +{ + int count = (p->mn_bus_ready_retry >= 0 ? p->mn_bus_ready_retry : 1000); + bool b_bus_busy = true; + + while (true) { + nthw_iic_reg_busbusy(p, &b_bus_busy); + if (!b_bus_busy) + break; + + count--; + if (count <= 0) /* Test for timeout */ + break; + + if (p->mn_poll_delay != 0) + I2C_WAIT_US(p->mn_poll_delay); + } + + if (count == 0) + return false; + + return true; +} + +/* + * Support function for read function. Waits for data ready. + */ +bool nthw_iic_data_ready(nthw_iic_t *p) +{ + int count = (p->mn_data_ready_retry >= 0 ? p->mn_data_ready_retry : 1000); + bool b_rx_fifo_empty = true; + + while (true) { + nthw_iic_reg_rxfifo_empty(p, &b_rx_fifo_empty); + if (!b_rx_fifo_empty) + break; + + count--; + if (count <= 0) /* Test for timeout */ + break; + + if (p->mn_poll_delay != 0) + I2C_WAIT_US(p->mn_poll_delay); + } + + if (count == 0) + return false; + + return true; +} + +int nthw_iic_scan_dev_addr(nthw_iic_t *p, int n_dev_addr, int n_reg_addr) +{ + const char *const p_adapter_id_str _unused = + p->mp_fpga->p_fpga_info->mp_adapter_id_str; + int res; + uint8_t data_val = -1; + + res = nthw_iic_readbyte(p, (uint8_t)n_dev_addr, (uint8_t)n_reg_addr, 1, + &data_val); + if (res == 0) { + NT_LOG(DBG, NTHW, + "%s: I2C%d: devaddr=0x%02X (%03d) regaddr=%02X val=%02X (%03d) res=%d\n", + p_adapter_id_str, p->mn_iic_instance, n_dev_addr, n_dev_addr, + n_reg_addr, data_val, data_val, res); + } + return res; +} + +int nthw_iic_scan_find_dev(nthw_iic_t *p, int n_dev_addr_start, bool b_increate) +{ + const char *const p_adapter_id_str _unused = + p->mp_fpga->p_fpga_info->mp_adapter_id_str; + + int res = 0; + int i = 0; + + if (b_increate) { + for (i = n_dev_addr_start; i < 128; i++) { + res = nthw_iic_scan_dev_addr(p, i, 0x00); + if (res == 0) + break; + } + } else { + for (i = n_dev_addr_start; i >= 0; i--) { + res = nthw_iic_scan_dev_addr(p, i, 0x00); + if (res == 0) + break; + } + } + NT_LOG(DBG, NTHW, "%s: I2C%d: FOUND: %d\n", p_adapter_id_str, + p->mn_iic_instance, i); + return (res == 0 ? i : -1); +} + +int nthw_iic_scan(nthw_iic_t *p) +{ + int i; + + for (i = 0; i < 128; i++) + (void)nthw_iic_scan_dev_addr(p, i, 0x00); + return 0; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_iic.h b/drivers/net/ntnic/nthw/core/nthw_iic.h new file mode 100644 index 0000000000..e3bd313c88 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_iic.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_IIC_H__ +#define __NTHW_IIC_H__ + +#include "nthw_fpga_model.h" + +struct nthw_iic { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_iic; + int mn_iic_instance; + + uint32_t mn_iic_cycle_time; + int mn_poll_delay; + int mn_bus_ready_retry; + int mn_data_ready_retry; + int mn_read_data_retry; + int mn_write_data_retry; + + nt_register_t *mp_reg_tsusta; + nt_field_t *mp_fld_tsusta; + + nt_register_t *mp_reg_tsusto; + nt_field_t *mp_fld_tsusto; + + nt_register_t *mp_reg_thdsta; + nt_field_t *mp_fld_thdsta; + + nt_register_t *mp_reg_tsudat; + nt_field_t *mp_fld_tsudat; + + nt_register_t *mp_reg_tbuf; + nt_field_t *mp_fld_tbuf; + + nt_register_t *mp_reg_thigh; + nt_field_t *mp_fld_thigh; + + nt_register_t *mp_reg_tlow; + nt_field_t *mp_fld_tlow; + + nt_register_t *mp_reg_thddat; + nt_field_t *mp_fld_thddat; + + nt_register_t *mp_reg_cr; + nt_field_t *mp_fld_cr_en; + nt_field_t *mp_fld_cr_msms; + nt_field_t *mp_fld_cr_txfifo_reset; + nt_field_t *mp_fld_cr_txak; + + nt_register_t *mp_reg_sr; + nt_field_t *mp_fld_sr_bb; + nt_field_t *mp_fld_sr_rxfifo_full; + nt_field_t *mp_fld_sr_rxfifo_empty; + nt_field_t *mp_fld_sr_txfifo_full; + nt_field_t *mp_fld_sr_txfifo_empty; + + nt_register_t *mp_reg_tx_fifo; + nt_field_t *mp_fld_tx_fifo_txdata; + nt_field_t *mp_fld_tx_fifo_start; + nt_field_t *mp_fld_tx_fifo_stop; + + nt_register_t *mp_reg_rx_fifo_pirq; + nt_field_t *mp_fld_rx_fifo_pirq_cmp_val; + + nt_register_t *mp_reg_rx_fifo; + nt_field_t *mp_fld_rx_fifo_rxdata; + + nt_register_t *mp_reg_softr; + nt_field_t *mp_fld_softr_rkey; +}; + +typedef struct nthw_iic nthw_iic_t; +typedef struct nthw_iic nthw_iic; + +nthw_iic_t *nthw_iic_new(void); +int nthw_iic_init(nthw_iic_t *p, nt_fpga_t *p_fpga, int n_iic_instance, + uint32_t n_iic_cycle_time); +void nthw_iic_delete(nthw_iic_t *p); + +int nthw_iic_set_retry_params(nthw_iic_t *p, const int n_poll_delay, + const int n_bus_ready_retry, const int n_data_ready_retry, + const int n_read_data_retry, const int n_write_data_retry); + +int nthw_iic_read_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t reg_addr, + uint8_t data_len, void *p_void); +int nthw_iic_readbyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t reg_addr, + uint8_t data_len, uint8_t *p_byte); +int nthw_iic_write_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t reg_addr, + uint8_t data_len, void *p_void); +int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t reg_addr, + uint8_t data_len, uint8_t *p_byte); +bool nthw_iic_bus_ready(nthw_iic_t *p); +bool nthw_iic_data_ready(nthw_iic_t *p); + +int nthw_iic_scan(nthw_iic_t *p); +int nthw_iic_scan_dev_addr(nthw_iic_t *p, int n_dev_addr, int n_reg_addr); +int nthw_iic_scan_find_dev(nthw_iic_t *p, int n_dev_addr_start, bool b_increate); + +#endif /* __NTHW_IIC_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_mac_pcs.c b/drivers/net/ntnic/nthw/core/nthw_mac_pcs.c new file mode 100644 index 0000000000..448caf1fd5 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_mac_pcs.c @@ -0,0 +1,1034 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "nt_util.h" +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_mac_pcs.h" + +#define NTHW_MAC_PCS_LANES (20) + +static const uint8_t c_pcs_lanes = NTHW_MAC_PCS_LANES; +static const uint8_t c_mac_pcs_receiver_mode_dfe _unused; + +nthw_mac_pcs_t *nthw_mac_pcs_new(void) +{ + nthw_mac_pcs_t *p = malloc(sizeof(nthw_mac_pcs_t)); + + if (p) + memset(p, 0, sizeof(nthw_mac_pcs_t)); + return p; +} + +void nthw_mac_pcs_delete(nthw_mac_pcs_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_mac_pcs_t)); + free(p); + } +} + +/* + * Parameters: + * p != NULL: init struct pointed to by p + * p == NULL: check fpga module(s) presence (but no struct to init) + * + * Return value: + * <0: if p == NULL then fpga module(s) is/are not present. + * if p != NULL then fpga module(s) is/are not present, struct undefined + * ==0: if p == NULL then fpga module(s) is/are present (no struct to init) + * : if p != NULL then fpga module(s) is/are present and struct initialized + */ +int nthw_mac_pcs_init(nthw_mac_pcs_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + nt_module_t *mod = fpga_query_module(p_fpga, MOD_MAC_PCS, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: MAC_PCS %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_mac_pcs = mod; + + assert(n_instance >= 0 && n_instance <= 255); + nthw_mac_pcs_set_port_no(p, (uint8_t)n_instance); + + { + nt_register_t *p_reg_block_lock, *p_reg_stat_pcs_rx, + *p_reg_stat_pcs_rx_latch; + nt_register_t *p_reg_vl_demuxed, *p_reg_gty_stat, *p_reg_pcs_config, + *p_reg_phymac_misc; + const int product_id = fpga_get_product_id(p_fpga); + + p_reg_block_lock = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_BLOCK_LOCK); + p->mp_reg_block_lock = p_reg_block_lock; + p->mp_fld_block_lock_lock = + register_get_field(p_reg_block_lock, MAC_PCS_BLOCK_LOCK_LOCK); + + p_reg_stat_pcs_rx = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_STAT_PCS_RX); + p->mp_reg_stat_pcs_rx = p_reg_stat_pcs_rx; + p->mp_fld_stat_pcs_rx_status = + register_get_field(p_reg_stat_pcs_rx, MAC_PCS_STAT_PCS_RX_STATUS); + p->mp_fld_stat_pcs_rx_aligned = + register_get_field(p_reg_stat_pcs_rx, MAC_PCS_STAT_PCS_RX_ALIGNED); + p->mp_fld_stat_pcs_rx_aligned_err = + register_get_field(p_reg_stat_pcs_rx, MAC_PCS_STAT_PCS_RX_ALIGNED_ERR); + p->mp_fld_stat_pcs_rx_misaligned = + register_get_field(p_reg_stat_pcs_rx, MAC_PCS_STAT_PCS_RX_MISALIGNED); + p->mp_fld_stat_pcs_rx_internal_local_fault = + register_get_field(p_reg_stat_pcs_rx, + MAC_PCS_STAT_PCS_RX_INTERNAL_LOCAL_FAULT); + p->mp_fld_stat_pcs_rx_received_local_fault = + register_get_field(p_reg_stat_pcs_rx, + MAC_PCS_STAT_PCS_RX_RECEIVED_LOCAL_FAULT); + p->mp_fld_stat_pcs_rx_local_fault = + register_get_field(p_reg_stat_pcs_rx, + MAC_PCS_STAT_PCS_RX_LOCAL_FAULT); + p->mp_fld_stat_pcs_rx_remote_fault = + register_get_field(p_reg_stat_pcs_rx, + MAC_PCS_STAT_PCS_RX_REMOTE_FAULT); + p->mp_fld_stat_pcs_rx_hi_ber = + register_get_field(p_reg_stat_pcs_rx, + MAC_PCS_STAT_PCS_RX_HI_BER); + + p_reg_stat_pcs_rx_latch = + module_get_register(p->mp_mod_mac_pcs, + MAC_PCS_STAT_PCS_RX_LATCH); + p->mp_reg_stat_pcs_rx_latch = p_reg_stat_pcs_rx_latch; + p->mp_fld_stat_pcs_rx_latch_status = + register_get_field(p_reg_stat_pcs_rx_latch, + MAC_PCS_STAT_PCS_RX_LATCH_STATUS); + + p_reg_vl_demuxed = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_VL_DEMUXED); + p->mp_fld_vl_demuxed_lock = + register_get_field(p_reg_vl_demuxed, MAC_PCS_VL_DEMUXED_LOCK); + + p_reg_gty_stat = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_STAT); + p->mp_fld_gty_stat_tx_rst_done0 = + register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_TX_RST_DONE_0); + p->mp_fld_gty_stat_tx_rst_done1 = + register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_TX_RST_DONE_1); + p->mp_fld_gty_stat_tx_rst_done2 = + register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_TX_RST_DONE_2); + p->mp_fld_gty_stat_tx_rst_done3 = + register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_TX_RST_DONE_3); + p->mp_fld_gty_stat_rx_rst_done0 = + register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_RX_RST_DONE_0); + p->mp_fld_gty_stat_rx_rst_done1 = + register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_RX_RST_DONE_1); + p->mp_fld_gty_stat_rx_rst_done2 = + register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_RX_RST_DONE_2); + p->mp_fld_gty_stat_rx_rst_done3 = + register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_RX_RST_DONE_3); + + p->m_fld_block_lock_lock_mask = 0; + p->m_fld_vl_demuxed_lock_mask = 0; + p->m_fld_gty_stat_tx_rst_done_mask = 0; + p->m_fld_gty_stat_rx_rst_done_mask = 0; + + if (product_id == 9563) { + /* NT200A01_2X100 implements 20 virtual lanes */ + p->m_fld_block_lock_lock_mask = (1 << 20) - 1; + /* NT200A01_2X100 implements 20 virtual lanes */ + p->m_fld_vl_demuxed_lock_mask = (1 << 20) - 1; + p->m_fld_gty_stat_tx_rst_done_mask = + 1; /* NT200A01_2X100 implements 4 GTY */ + p->m_fld_gty_stat_rx_rst_done_mask = + 1; /* NT200A01_2X100 implements 4 GTY */ + } else { + /* Remember to add new productIds */ + assert(0); + } + + p_reg_pcs_config = module_get_register(p->mp_mod_mac_pcs, + MAC_PCS_MAC_PCS_CONFIG); + p->mp_fld_pcs_config_tx_path_rst = + register_get_field(p_reg_pcs_config, MAC_PCS_MAC_PCS_CONFIG_TX_PATH_RST); + p->mp_fld_pcs_config_rx_path_rst = + register_get_field(p_reg_pcs_config, MAC_PCS_MAC_PCS_CONFIG_RX_PATH_RST); + p->mp_fld_pcs_config_rx_enable = + register_get_field(p_reg_pcs_config, MAC_PCS_MAC_PCS_CONFIG_RX_ENABLE); + p->mp_fld_pcs_config_rx_force_resync = + register_get_field(p_reg_pcs_config, + MAC_PCS_MAC_PCS_CONFIG_RX_FORCE_RESYNC); + p->mp_fld_pcs_config_rx_test_pattern = + register_get_field(p_reg_pcs_config, + MAC_PCS_MAC_PCS_CONFIG_RX_TEST_PATTERN); + p->mp_fld_pcs_config_tx_enable = + register_get_field(p_reg_pcs_config, + MAC_PCS_MAC_PCS_CONFIG_TX_ENABLE); + p->mp_fld_pcs_config_tx_send_idle = + register_get_field(p_reg_pcs_config, + MAC_PCS_MAC_PCS_CONFIG_TX_SEND_IDLE); + p->mp_fld_pcs_config_tx_send_rfi = + register_get_field(p_reg_pcs_config, + MAC_PCS_MAC_PCS_CONFIG_TX_SEND_RFI); + p->mp_fld_pcs_config_tx_test_pattern = + register_get_field(p_reg_pcs_config, + MAC_PCS_MAC_PCS_CONFIG_TX_TEST_PATTERN); + + p->mp_reg_gty_loop = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_LOOP); + p->mp_fld_gty_loop_gt_loop0 = + register_get_field(p->mp_reg_gty_loop, MAC_PCS_GTY_LOOP_GT_LOOP_0); + p->mp_fld_gty_loop_gt_loop1 = + register_get_field(p->mp_reg_gty_loop, MAC_PCS_GTY_LOOP_GT_LOOP_1); + p->mp_fld_gty_loop_gt_loop2 = + register_get_field(p->mp_reg_gty_loop, MAC_PCS_GTY_LOOP_GT_LOOP_2); + p->mp_fld_gty_loop_gt_loop3 = + register_get_field(p->mp_reg_gty_loop, MAC_PCS_GTY_LOOP_GT_LOOP_3); + + p_reg_phymac_misc = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_PHYMAC_MISC); + p->mp_reg_phymac_misc = p_reg_phymac_misc; + p->mp_fld_phymac_misc_tx_sel_host = + register_get_field(p_reg_phymac_misc, MAC_PCS_PHYMAC_MISC_TX_SEL_HOST); + p->mp_fld_phymac_misc_tx_sel_tfg = + register_get_field(p_reg_phymac_misc, MAC_PCS_PHYMAC_MISC_TX_SEL_TFG); + p->mp_fld_phymac_misc_tx_sel_rx_loop = + register_get_field(p_reg_phymac_misc, MAC_PCS_PHYMAC_MISC_TX_SEL_RX_LOOP); + + /* SOP or EOP TIMESTAMP */ + p->mp_fld_phymac_misc_ts_eop = + register_query_field(p_reg_phymac_misc, MAC_PCS_PHYMAC_MISC_TS_EOP); + + p->mp_reg_link_summary = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_LINK_SUMMARY); + p->mp_fld_link_summary_abs = + register_get_field(p->mp_reg_link_summary, MAC_PCS_LINK_SUMMARY_ABS); + p->mp_fld_link_summary_nt_phy_link_state = + register_get_field(p->mp_reg_link_summary, + MAC_PCS_LINK_SUMMARY_NT_PHY_LINK_STATE); + p->mp_fld_link_summary_lh_abs = + register_get_field(p->mp_reg_link_summary, MAC_PCS_LINK_SUMMARY_LH_ABS); + p->mp_fld_link_summary_ll_nt_phy_link_state = + register_get_field(p->mp_reg_link_summary, + MAC_PCS_LINK_SUMMARY_LL_PHY_LINK_STATE); + p->mp_fld_link_summary_link_down_cnt = + register_get_field(p->mp_reg_link_summary, + MAC_PCS_LINK_SUMMARY_LINK_DOWN_CNT); + p->mp_fld_link_summary_nim_interr = + register_get_field(p->mp_reg_link_summary, + MAC_PCS_LINK_SUMMARY_NIM_INTERR); + p->mp_fld_link_summary_lh_local_fault = + register_get_field(p->mp_reg_link_summary, + MAC_PCS_LINK_SUMMARY_LH_LOCAL_FAULT); + p->mp_fld_link_summary_lh_remote_fault = + register_get_field(p->mp_reg_link_summary, + MAC_PCS_LINK_SUMMARY_LH_REMOTE_FAULT); + p->mp_fld_link_summary_local_fault = + register_get_field(p->mp_reg_link_summary, + MAC_PCS_LINK_SUMMARY_LOCAL_FAULT); + p->mp_fld_link_summary_remote_fault = + register_get_field(p->mp_reg_link_summary, + MAC_PCS_LINK_SUMMARY_REMOTE_FAULT); + + p->mp_reg_bip_err = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_BIP_ERR); + p->mp_fld_reg_bip_err_bip_err = + register_get_field(p->mp_reg_bip_err, MAC_PCS_BIP_ERR_BIP_ERR); + + p->mp_reg_fec_ctrl = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_FEC_CTRL); + p->mp_field_fec_ctrl_reg_rs_fec_ctrl_in = + register_get_field(p->mp_reg_fec_ctrl, MAC_PCS_FEC_CTRL_RS_FEC_CTRL_IN); + + p->mp_reg_fec_stat = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_FEC_STAT); + p->mp_field_fec_stat_bypass = + register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_BYPASS); + p->mp_field_fec_stat_valid = + register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_VALID); + p->mp_field_fec_stat_am_lock0 = + register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_AM_LOCK_0); + p->mp_field_fec_stat_am_lock1 = + register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_AM_LOCK_1); + p->mp_field_fec_stat_am_lock2 = + register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_AM_LOCK_2); + p->mp_field_fec_stat_am_lock3 = + register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_AM_LOCK_3); + p->mp_field_fec_stat_fec_lane_algn = + register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_FEC_LANE_ALGN); + + p->mp_reg_fec_cw_cnt = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_FEC_CW_CNT); + p->mp_field_fec_cw_cnt_cw_cnt = + register_get_field(p->mp_reg_fec_cw_cnt, MAC_PCS_FEC_CW_CNT_CW_CNT); + + p->mp_reg_fec_ucw_cnt = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_FEC_UCW_CNT); + p->mp_field_fec_ucw_cnt_ucw_cnt = + register_get_field(p->mp_reg_fec_ucw_cnt, MAC_PCS_FEC_UCW_CNT_UCW_CNT); + + /* GTY_RX_BUF_STAT */ +#ifdef RXBUFSTAT + p->mp_reg_gty_rx_buf_stat = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_RX_BUF_STAT); + p->mp_field_gty_rx_buf_stat_rx_buf_stat0 = + register_get_field(p->mp_reg_gty_rx_buf_stat, + MAC_PCS_GTY_RX_BUF_STAT_RX_BUF_STAT_0); + p->mp_field_gty_rx_buf_stat_rx_buf_stat1 = + register_get_field(p->mp_reg_gty_rx_buf_stat, + MAC_PCS_GTY_RX_BUF_STAT_RX_BUF_STAT_1); + p->mp_field_gty_rx_buf_stat_rx_buf_stat2 = + register_get_field(p->mp_reg_gty_rx_buf_stat, + MAC_PCS_GTY_RX_BUF_STAT_RX_BUF_STAT_2); + p->mp_field_gty_rx_buf_stat_rx_buf_stat3 = + register_get_field(p->mp_reg_gty_rx_buf_stat, + MAC_PCS_GTY_RX_BUF_STAT_RX_BUF_STAT_3); + p->mp_field_gty_rx_buf_stat_rx_buf_stat_changed0 = + register_get_field(p->mp_reg_gty_rx_buf_stat, + MAC_PCS_GTY_RX_BUF_STAT_RX_BUF_STAT_CHANGED_0); + p->mp_field_gty_rx_buf_stat_rx_buf_stat_changed1 = + register_get_field(p->mp_reg_gty_rx_buf_stat, + MAC_PCS_GTY_RX_BUF_STAT_RX_BUF_STAT_CHANGED_1); + p->mp_field_gty_rx_buf_stat_rx_buf_stat_changed2 = + register_get_field(p->mp_reg_gty_rx_buf_stat, + MAC_PCS_GTY_RX_BUF_STAT_RX_BUF_STAT_CHANGED_2); + p->mp_field_gty_rx_buf_stat_rx_buf_stat_changed3 = + register_get_field(p->mp_reg_gty_rx_buf_stat, + MAC_PCS_GTY_RX_BUF_STAT_RX_BUF_STAT_CHANGED_3); +#endif + + /* GTY_PRE_CURSOR */ + p->mp_reg_gty_pre_cursor = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_PRE_CURSOR); + p->mp_field_gty_pre_cursor_tx_pre_csr0 = + register_get_field(p->mp_reg_gty_pre_cursor, + MAC_PCS_GTY_PRE_CURSOR_TX_PRE_CSR_0); + p->mp_field_gty_pre_cursor_tx_pre_csr1 = + register_get_field(p->mp_reg_gty_pre_cursor, + MAC_PCS_GTY_PRE_CURSOR_TX_PRE_CSR_1); + p->mp_field_gty_pre_cursor_tx_pre_csr2 = + register_get_field(p->mp_reg_gty_pre_cursor, + MAC_PCS_GTY_PRE_CURSOR_TX_PRE_CSR_2); + p->mp_field_gty_pre_cursor_tx_pre_csr3 = + register_get_field(p->mp_reg_gty_pre_cursor, + MAC_PCS_GTY_PRE_CURSOR_TX_PRE_CSR_3); + + /* GTY_DIFF_CTL */ + p->mp_reg_gty_diff_ctl = + module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_DIFF_CTL); + p->mp_field_gty_gty_diff_ctl_tx_diff_ctl0 = + register_get_field(p->mp_reg_gty_diff_ctl, + MAC_PCS_GTY_DIFF_CTL_TX_DIFF_CTL_0); + p->mp_field_gty_gty_diff_ctl_tx_diff_ctl1 = + register_get_field(p->mp_reg_gty_diff_ctl, + MAC_PCS_GTY_DIFF_CTL_TX_DIFF_CTL_1); + p->mp_field_gty_gty_diff_ctl_tx_diff_ctl2 = + register_get_field(p->mp_reg_gty_diff_ctl, + MAC_PCS_GTY_DIFF_CTL_TX_DIFF_CTL_2); + p->mp_field_gty_gty_diff_ctl_tx_diff_ctl3 = + register_get_field(p->mp_reg_gty_diff_ctl, + MAC_PCS_GTY_DIFF_CTL_TX_DIFF_CTL_3); + + /* GTY_POST_CURSOR */ + p->mp_reg_gty_post_cursor = + module_get_register(p->mp_mod_mac_pcs, + MAC_PCS_GTY_POST_CURSOR); + p->mp_field_gty_post_cursor_tx_post_csr0 = + register_get_field(p->mp_reg_gty_post_cursor, + MAC_PCS_GTY_POST_CURSOR_TX_POST_CSR_0); + p->mp_field_gty_post_cursor_tx_post_csr1 = + register_get_field(p->mp_reg_gty_post_cursor, + MAC_PCS_GTY_POST_CURSOR_TX_POST_CSR_1); + p->mp_field_gty_post_cursor_tx_post_csr2 = + register_get_field(p->mp_reg_gty_post_cursor, + MAC_PCS_GTY_POST_CURSOR_TX_POST_CSR_2); + p->mp_field_gty_post_cursor_tx_post_csr3 = + register_get_field(p->mp_reg_gty_post_cursor, + MAC_PCS_GTY_POST_CURSOR_TX_POST_CSR_3); + + /* GTY_CTL */ + p->mp_reg_gty_ctl = + module_query_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_CTL); + if (p->mp_reg_gty_ctl) { + p->mp_field_gty_ctl_tx_pol0 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_TX_POLARITY_0); + p->mp_field_gty_ctl_tx_pol1 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_TX_POLARITY_1); + p->mp_field_gty_ctl_tx_pol2 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_TX_POLARITY_2); + p->mp_field_gty_ctl_tx_pol3 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_TX_POLARITY_3); + } else { + p->mp_reg_gty_ctl = + module_get_register(p->mp_mod_mac_pcs, + MAC_PCS_GTY_CTL_RX); + p->mp_reg_gty_ctl_tx = + module_get_register(p->mp_mod_mac_pcs, + MAC_PCS_GTY_CTL_TX); + p->mp_field_gty_ctl_tx_pol0 = + register_get_field(p->mp_reg_gty_ctl_tx, + MAC_PCS_GTY_CTL_TX_POLARITY_0); + p->mp_field_gty_ctl_tx_pol1 = + register_get_field(p->mp_reg_gty_ctl_tx, + MAC_PCS_GTY_CTL_TX_POLARITY_1); + p->mp_field_gty_ctl_tx_pol2 = + register_get_field(p->mp_reg_gty_ctl_tx, + MAC_PCS_GTY_CTL_TX_POLARITY_2); + p->mp_field_gty_ctl_tx_pol3 = + register_get_field(p->mp_reg_gty_ctl_tx, + MAC_PCS_GTY_CTL_TX_POLARITY_3); + } + p->mp_field_gty_ctl_rx_pol0 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_POLARITY_0); + p->mp_field_gty_ctl_rx_pol1 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_POLARITY_1); + p->mp_field_gty_ctl_rx_pol2 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_POLARITY_2); + p->mp_field_gty_ctl_rx_pol3 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_POLARITY_3); + p->mp_field_gty_ctl_rx_lpm_en0 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_LPM_EN_0); + p->mp_field_gty_ctl_rx_lpm_en1 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_LPM_EN_1); + p->mp_field_gty_ctl_rx_lpm_en2 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_LPM_EN_2); + p->mp_field_gty_ctl_rx_lpm_en3 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_LPM_EN_3); + p->mp_field_gty_ctl_rx_equa_rst0 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_EQUA_RST_0); + p->mp_field_gty_ctl_rx_equa_rst1 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_EQUA_RST_1); + p->mp_field_gty_ctl_rx_equa_rst2 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_EQUA_RST_2); + p->mp_field_gty_ctl_rx_equa_rst3 = + register_get_field(p->mp_reg_gty_ctl, + MAC_PCS_GTY_CTL_RX_EQUA_RST_3); + + /* DEBOUNCE_CTRL */ + p->mp_reg_debounce_ctrl = + module_get_register(p->mp_mod_mac_pcs, + MAC_PCS_DEBOUNCE_CTRL); + p->mp_field_debounce_ctrl_nt_port_ctrl = + register_get_field(p->mp_reg_debounce_ctrl, + MAC_PCS_DEBOUNCE_CTRL_NT_PORT_CTRL); + + p->mp_reg_time_stamp_comp = + module_query_register(p->mp_mod_mac_pcs, + MAC_PCS_TIMESTAMP_COMP); + if (p->mp_reg_time_stamp_comp) { + /* TIMESTAMP_COMP */ + p->mp_field_time_stamp_comp_rx_dly = + register_get_field(p->mp_reg_time_stamp_comp, + MAC_PCS_TIMESTAMP_COMP_RX_DLY); + p->mp_field_time_stamp_comp_tx_dly = + register_get_field(p->mp_reg_time_stamp_comp, + MAC_PCS_TIMESTAMP_COMP_TX_DLY); + } + } + return 0; +} + +/* wrapper - for ease of use */ +void nthw_mac_pcs_tx_host_enable(nthw_mac_pcs_t *p, bool enable) +{ + nthw_mac_pcs_set_tx_sel_host(p, enable); + nthw_mac_pcs_set_tx_sel_tfg(p, !enable); +} + +void nthw_mac_pcs_set_rx_enable(nthw_mac_pcs_t *p, bool enable) +{ + field_get_updated(p->mp_fld_pcs_config_rx_enable); + if (enable) + field_set_flush(p->mp_fld_pcs_config_rx_enable); + + else + field_clr_flush(p->mp_fld_pcs_config_rx_enable); +} + +void nthw_mac_pcs_set_tx_enable(nthw_mac_pcs_t *p, bool enable) +{ + field_get_updated(p->mp_fld_pcs_config_tx_enable); + if (enable) + field_set_flush(p->mp_fld_pcs_config_tx_enable); + + else + field_clr_flush(p->mp_fld_pcs_config_tx_enable); +} + +void nthw_mac_pcs_set_tx_sel_host(nthw_mac_pcs_t *p, bool enable) +{ + field_get_updated(p->mp_fld_phymac_misc_tx_sel_host); + if (enable) + field_set_flush(p->mp_fld_phymac_misc_tx_sel_host); + + else + field_clr_flush(p->mp_fld_phymac_misc_tx_sel_host); +} + +void nthw_mac_pcs_set_tx_sel_tfg(nthw_mac_pcs_t *p, bool enable) +{ + field_get_updated(p->mp_fld_phymac_misc_tx_sel_tfg); + if (enable) + field_set_flush(p->mp_fld_phymac_misc_tx_sel_tfg); + + else + field_clr_flush(p->mp_fld_phymac_misc_tx_sel_tfg); +} + +void nthw_mac_pcs_set_ts_eop(nthw_mac_pcs_t *p, bool enable) +{ + if (p->mp_fld_phymac_misc_ts_eop) { + field_get_updated(p->mp_fld_phymac_misc_ts_eop); + if (enable) + field_set_flush(p->mp_fld_phymac_misc_ts_eop); + + else + field_clr_flush(p->mp_fld_phymac_misc_ts_eop); + } +} + +bool nthw_mac_pcs_is_block_and_lane_lock_locked(nthw_mac_pcs_t *p) +{ + uint32_t block_lock; + uint32_t lane_lock; + + block_lock = field_get_updated(p->mp_fld_block_lock_lock) & + p->m_fld_block_lock_lock_mask; + lane_lock = field_get_updated(p->mp_fld_vl_demuxed_lock) & + p->m_fld_vl_demuxed_lock_mask; + if (block_lock == p->m_fld_block_lock_lock_mask && + lane_lock == p->m_fld_vl_demuxed_lock_mask) + return true; + + return false; +} + +void nthw_mac_pcs_tx_path_rst(nthw_mac_pcs_t *p, bool enable) +{ + field_get_updated(p->mp_fld_pcs_config_tx_path_rst); + if (enable) + field_set_flush(p->mp_fld_pcs_config_tx_path_rst); + + else + field_clr_flush(p->mp_fld_pcs_config_tx_path_rst); +} + +void nthw_mac_pcs_rx_path_rst(nthw_mac_pcs_t *p, bool enable) +{ + field_get_updated(p->mp_fld_pcs_config_rx_path_rst); + if (enable) + field_set_flush(p->mp_fld_pcs_config_rx_path_rst); + + else + field_clr_flush(p->mp_fld_pcs_config_rx_path_rst); +} + +bool nthw_mac_pcs_is_rx_path_rst(nthw_mac_pcs_t *p) +{ + return field_get_updated(p->mp_fld_pcs_config_rx_path_rst); +} + +void nthw_mac_pcs_tx_send_rfi(nthw_mac_pcs_t *p, bool enable) +{ + field_get_updated(p->mp_fld_pcs_config_tx_send_rfi); + if (enable) + field_set_flush(p->mp_fld_pcs_config_tx_send_rfi); + + else + field_clr_flush(p->mp_fld_pcs_config_tx_send_rfi); +} + +void nthw_mac_pcs_rx_force_resync(nthw_mac_pcs_t *p, bool enable) +{ + field_get_updated(p->mp_fld_pcs_config_rx_force_resync); + if (enable) + field_set_flush(p->mp_fld_pcs_config_rx_force_resync); + + else + field_clr_flush(p->mp_fld_pcs_config_rx_force_resync); +} + +bool nthw_mac_pcs_is_gt_fsm_rx_reset_done(nthw_mac_pcs_t *p) +{ + if ((field_get_updated(p->mp_fld_gty_stat_rx_rst_done0) & + p->m_fld_gty_stat_rx_rst_done_mask) == p->m_fld_gty_stat_rx_rst_done_mask && + (field_get_updated(p->mp_fld_gty_stat_rx_rst_done1) & + p->m_fld_gty_stat_rx_rst_done_mask) == p->m_fld_gty_stat_rx_rst_done_mask && + (field_get_updated(p->mp_fld_gty_stat_rx_rst_done2) & + p->m_fld_gty_stat_rx_rst_done_mask) == p->m_fld_gty_stat_rx_rst_done_mask && + (field_get_updated(p->mp_fld_gty_stat_rx_rst_done3) & + p->m_fld_gty_stat_rx_rst_done_mask) == p->m_fld_gty_stat_rx_rst_done_mask) + return true; + + else + return false; +} + +bool nthw_mac_pcs_is_gt_fsm_tx_reset_done(nthw_mac_pcs_t *p) +{ + if ((field_get_updated(p->mp_fld_gty_stat_tx_rst_done0) & + p->m_fld_gty_stat_tx_rst_done_mask) == p->m_fld_gty_stat_tx_rst_done_mask && + (field_get_updated(p->mp_fld_gty_stat_tx_rst_done1) & + p->m_fld_gty_stat_tx_rst_done_mask) == p->m_fld_gty_stat_tx_rst_done_mask && + (field_get_updated(p->mp_fld_gty_stat_tx_rst_done2) & + p->m_fld_gty_stat_tx_rst_done_mask) == p->m_fld_gty_stat_tx_rst_done_mask && + (field_get_updated(p->mp_fld_gty_stat_tx_rst_done3) & + p->m_fld_gty_stat_tx_rst_done_mask) == p->m_fld_gty_stat_tx_rst_done_mask) + return true; + + else + return false; +} + +void nthw_mac_pcs_set_host_loopback(nthw_mac_pcs_t *p, bool enable) +{ + register_update(p->mp_reg_gty_loop); + if (enable) { + field_set_val32(p->mp_fld_gty_loop_gt_loop0, 2); + field_set_val32(p->mp_fld_gty_loop_gt_loop1, 2); + field_set_val32(p->mp_fld_gty_loop_gt_loop2, 2); + field_set_val32(p->mp_fld_gty_loop_gt_loop3, 2); + } else { + field_set_val32(p->mp_fld_gty_loop_gt_loop0, 0); + field_set_val32(p->mp_fld_gty_loop_gt_loop1, 0); + field_set_val32(p->mp_fld_gty_loop_gt_loop2, 0); + field_set_val32(p->mp_fld_gty_loop_gt_loop3, 0); + } + register_flush(p->mp_reg_gty_loop, 1); +} + +void nthw_mac_pcs_set_line_loopback(nthw_mac_pcs_t *p, bool enable) +{ + register_update(p->mp_reg_gty_loop); + if (enable) { + field_set_val32(p->mp_fld_gty_loop_gt_loop0, 4); + field_set_val32(p->mp_fld_gty_loop_gt_loop1, 4); + field_set_val32(p->mp_fld_gty_loop_gt_loop2, 4); + field_set_val32(p->mp_fld_gty_loop_gt_loop3, 4); + } else { + field_set_val32(p->mp_fld_gty_loop_gt_loop0, 0); + field_set_val32(p->mp_fld_gty_loop_gt_loop1, 0); + field_set_val32(p->mp_fld_gty_loop_gt_loop2, 0); + field_set_val32(p->mp_fld_gty_loop_gt_loop3, 0); + } + register_flush(p->mp_reg_gty_loop, 1); +} + +void nthw_mac_pcs_reset_bip_counters(nthw_mac_pcs_t *p) +{ + uint32_t lane_bit_errors[NTHW_MAC_PCS_LANES]; + + register_update(p->mp_reg_bip_err); + field_get_val(p->mp_fld_reg_bip_err_bip_err, (uint32_t *)lane_bit_errors, + ARRAY_SIZE(lane_bit_errors)); + +#if defined(DEBUG) + { + uint8_t lane; + + for (lane = 0; lane < c_pcs_lanes; lane++) { + if (lane_bit_errors[lane]) { + NT_LOG(DBG, NTHW, + "Port %u: pcsLane %2u: BIP8 errors: %u\n", + p->m_port_no, lane, lane_bit_errors[lane]); + } + } + } +#else + (void)c_pcs_lanes; /* unused - kill warning */ +#endif +} + +void nthw_mac_pcs_get_status(nthw_mac_pcs_t *p, uint8_t *status) +{ + *status = field_get_updated(p->mp_fld_stat_pcs_rx_status) & 0x01; +} + +bool nthw_mac_pcs_get_hi_ber(nthw_mac_pcs_t *p) +{ + return field_get_updated(p->mp_fld_stat_pcs_rx_hi_ber); +} + +void nthw_mac_pcs_get_link_summary(nthw_mac_pcs_t *p, uint32_t *p_abs, + uint32_t *p_nt_phy_link_state, uint32_t *p_lh_abs, + uint32_t *p_ll_nt_phy_link_state, + uint32_t *p_link_down_cnt, uint32_t *p_nim_interr, + uint32_t *p_lh_local_fault, + uint32_t *p_lh_remote_fault, uint32_t *p_local_fault, + uint32_t *p_remote_fault) +{ + register_update(p->mp_reg_link_summary); + if (p_abs) + *p_abs = field_get_val32(p->mp_fld_link_summary_abs); + if (p_nt_phy_link_state) { + *p_nt_phy_link_state = + field_get_val32(p->mp_fld_link_summary_nt_phy_link_state); + } + if (p_lh_abs) + *p_lh_abs = field_get_val32(p->mp_fld_link_summary_lh_abs); + if (p_ll_nt_phy_link_state) { + *p_ll_nt_phy_link_state = + field_get_val32(p->mp_fld_link_summary_ll_nt_phy_link_state); + } + if (p_link_down_cnt) + *p_link_down_cnt = field_get_val32(p->mp_fld_link_summary_link_down_cnt); + if (p_nim_interr) + *p_nim_interr = field_get_val32(p->mp_fld_link_summary_nim_interr); + if (p_lh_local_fault) { + *p_lh_local_fault = + field_get_val32(p->mp_fld_link_summary_lh_local_fault); + } + if (p_lh_remote_fault) { + *p_lh_remote_fault = + field_get_val32(p->mp_fld_link_summary_lh_remote_fault); + } + if (p_local_fault) + *p_local_fault = field_get_val32(p->mp_fld_link_summary_local_fault); + if (p_remote_fault) + *p_remote_fault = field_get_val32(p->mp_fld_link_summary_remote_fault); +} + +/* + * Returns true if the lane/block lock bits indicate that a reset is required. + * This is the case if Block/Lane lock is not all zero but not all set either. + */ +bool nthw_mac_pcs_reset_required(nthw_mac_pcs_t *p) +{ + uint32_t block_lock = nthw_mac_pcs_get_fld_block_lock_lock(p); + uint32_t lane_lock = nthw_mac_pcs_get_fld_lane_lock_lock(p); + uint32_t block_lock_mask = nthw_mac_pcs_get_fld_block_lock_lock_mask(p); + uint32_t lane_lock_mask = nthw_mac_pcs_get_fld_lane_lock_lock_mask(p); + + return ((block_lock != 0) && (block_lock != block_lock_mask)) || + ((lane_lock != 0) && (lane_lock != lane_lock_mask)); +} + +void nthw_mac_pcs_set_fec(nthw_mac_pcs_t *p, bool enable) +{ + NT_LOG(DBG, NTHW, "Port %u: Set FEC: %u\n", p->m_port_no, enable); + + field_get_updated(p->mp_field_fec_ctrl_reg_rs_fec_ctrl_in); + if (enable) { + field_set_val_flush32(p->mp_field_fec_ctrl_reg_rs_fec_ctrl_in, 0); + } else { + field_set_val_flush32(p->mp_field_fec_ctrl_reg_rs_fec_ctrl_in, + (1 << 5) - 1); + } + + /* Both Rx and Tx must be reset for new FEC state to become active */ + nthw_mac_pcs_rx_path_rst(p, true); + nthw_mac_pcs_tx_path_rst(p, true); + NT_OS_WAIT_USEC(10000); /* 10ms */ + + nthw_mac_pcs_rx_path_rst(p, false); + nthw_mac_pcs_tx_path_rst(p, false); + NT_OS_WAIT_USEC(10000); /* 10ms */ + +#ifdef DEBUG + if (enable) { + NT_LOG(DBG, NTHW, "Port %u: FEC valid: %u\n", p->m_port_no, + field_get_updated(p->mp_field_fec_stat_valid)); + } else { + NT_LOG(DBG, NTHW, "Port %u: FEC bypass: %u\n", p->m_port_no, + field_get_updated(p->mp_field_fec_stat_bypass)); + } +#endif +} + +bool nthw_mac_pcs_get_fec_bypass(nthw_mac_pcs_t *p) +{ + return field_get_updated(p->mp_field_fec_stat_bypass); +} + +bool nthw_mac_pcs_get_fec_valid(nthw_mac_pcs_t *p) +{ + return field_get_updated(p->mp_field_fec_stat_valid); +} + +bool nthw_mac_pcs_get_fec_aligned(nthw_mac_pcs_t *p) +{ + return field_get_updated(p->mp_field_fec_stat_fec_lane_algn); +} + +bool nthw_mac_pcs_get_fec_stat_any_am_locked(nthw_mac_pcs_t *p) +{ + register_update(p->mp_reg_fec_stat); + if ((field_get_val32(p->mp_field_fec_stat_am_lock0)) || + (field_get_val32(p->mp_field_fec_stat_am_lock1)) || + (field_get_val32(p->mp_field_fec_stat_am_lock2)) || + (field_get_val32(p->mp_field_fec_stat_am_lock3))) + return true; + return false; +} + +bool nthw_mac_pcs_get_fec_stat_all_am_locked(nthw_mac_pcs_t *p) +{ + register_update(p->mp_reg_fec_stat); + if ((field_get_val32(p->mp_field_fec_stat_am_lock0)) && + (field_get_val32(p->mp_field_fec_stat_am_lock1)) && + (field_get_val32(p->mp_field_fec_stat_am_lock2)) && + (field_get_val32(p->mp_field_fec_stat_am_lock3))) + return true; + return false; +} + +void nthw_mac_pcs_dump_fec_stat_fields(nthw_mac_pcs_t *p) +{ + register_update(p->mp_reg_fec_stat); + NT_LOG(DBG, NTHW, + "Port %u: FEC_STAT VALID: %u, AM_LOCK_0: %u, AM_LOCK_1: %u, AM_LOCK_2: %u, AM_LOCK_0: %u, FEC_LANE_ALGN: %u\n", + p->m_port_no, field_get_val32(p->mp_field_fec_stat_valid), + field_get_val32(p->mp_field_fec_stat_am_lock0), + field_get_val32(p->mp_field_fec_stat_am_lock1), + field_get_val32(p->mp_field_fec_stat_am_lock2), + field_get_val32(p->mp_field_fec_stat_am_lock3), + field_get_val32(p->mp_field_fec_stat_fec_lane_algn)); +} + +void nthw_mac_pcs_reset_fec_counters(nthw_mac_pcs_t *p) +{ + register_update(p->mp_reg_fec_cw_cnt); + register_update(p->mp_reg_fec_ucw_cnt); + + if (field_get_val32(p->mp_field_fec_cw_cnt_cw_cnt)) { + NT_LOG(DBG, NTHW, "Port %u: FEC_CW_CNT: %u\n", p->m_port_no, + field_get_val32(p->mp_field_fec_cw_cnt_cw_cnt)); + } + if (field_get_val32(p->mp_field_fec_ucw_cnt_ucw_cnt)) { + NT_LOG(DBG, NTHW, "Port %u: FEC_UCW_CNT: %u\n", p->m_port_no, + field_get_val32(p->mp_field_fec_ucw_cnt_ucw_cnt)); + } +} + +bool nthw_mac_pcs_get_gty_rx_buf_stat_error(nthw_mac_pcs_t *p) +{ + register_update(p->mp_reg_gty_rx_buf_stat); + + if (field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat_changed0) || + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat_changed1) || + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat_changed2) || + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat_changed3)) { + if (field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat0) || + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat1) || + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat2) || + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat3)) { + NT_LOG(DBG, NTHW, + "Port %u: GTY RX_BUF_STAT_0: %u, RX_BUF_STAT_1: %u, RX_BUF_STAT_2: %u, RX_BUF_STAT_3: %u\n", + p->m_port_no, + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat0), + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat1), + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat2), + field_get_val32(p->mp_field_gty_rx_buf_stat_rx_buf_stat3)); + + return true; + } + } + return false; +} + +void nthw_mac_pcs_set_gty_tx_tuning(nthw_mac_pcs_t *p, uint8_t lane, uint8_t tx_pre_csr, + uint8_t tx_diff_ctl, uint8_t tx_post_csr) +{ + /* GTY_PRE_CURSOR */ + register_update(p->mp_reg_gty_pre_cursor); + switch (lane) { + case 0: + field_set_val_flush32(p->mp_field_gty_pre_cursor_tx_pre_csr0, + tx_pre_csr & 0x1F); + break; + case 1: + field_set_val_flush32(p->mp_field_gty_pre_cursor_tx_pre_csr1, + tx_pre_csr & 0x1F); + break; + case 2: + field_set_val_flush32(p->mp_field_gty_pre_cursor_tx_pre_csr2, + tx_pre_csr & 0x1F); + break; + case 3: + field_set_val_flush32(p->mp_field_gty_pre_cursor_tx_pre_csr3, + tx_pre_csr & 0x1F); + break; + } + + /* GTY_DIFF_CTL */ + register_update(p->mp_reg_gty_diff_ctl); + switch (lane) { + case 0: + field_set_val_flush32(p->mp_field_gty_gty_diff_ctl_tx_diff_ctl0, + tx_diff_ctl & 0x1F); + break; + case 1: + field_set_val_flush32(p->mp_field_gty_gty_diff_ctl_tx_diff_ctl1, + tx_diff_ctl & 0x1F); + break; + case 2: + field_set_val_flush32(p->mp_field_gty_gty_diff_ctl_tx_diff_ctl2, + tx_diff_ctl & 0x1F); + break; + case 3: + field_set_val_flush32(p->mp_field_gty_gty_diff_ctl_tx_diff_ctl3, + tx_diff_ctl & 0x1F); + break; + } + + /* GTY_POST_CURSOR */ + register_update(p->mp_reg_gty_post_cursor); + switch (lane) { + case 0: + field_set_val_flush32(p->mp_field_gty_post_cursor_tx_post_csr0, + tx_post_csr & 0x1F); + break; + case 1: + field_set_val_flush32(p->mp_field_gty_post_cursor_tx_post_csr1, + tx_post_csr & 0x1F); + break; + case 2: + field_set_val_flush32(p->mp_field_gty_post_cursor_tx_post_csr2, + tx_post_csr & 0x1F); + break; + case 3: + field_set_val_flush32(p->mp_field_gty_post_cursor_tx_post_csr3, + tx_post_csr & 0x1F); + break; + } + + NT_LOG(DBG, NTHW, + "Port %u, lane %u: GTY txPreCsr: %d, txDiffCtl: %d, txPostCsr: %d\n", + p->m_port_no, lane, tx_pre_csr, tx_diff_ctl, tx_post_csr); +} + +/* + * Set receiver equalization mode + * 0: enable DFE + * mode 1: enable LPM + * + * See UltraScale Architecture GTY Transceivers www.xilinx.com page 181, + * UG578 (v1.1) November 24, 2015 + */ +void nthw_mac_pcs_set_receiver_equalization_mode(nthw_mac_pcs_t *p, uint8_t mode) +{ + register_update(p->mp_reg_gty_ctl); + field_set_val32(p->mp_field_gty_ctl_rx_lpm_en0, mode & 0x1); + field_set_val32(p->mp_field_gty_ctl_rx_lpm_en1, mode & 0x1); + field_set_val32(p->mp_field_gty_ctl_rx_lpm_en2, mode & 0x1); + field_set_val_flush32(p->mp_field_gty_ctl_rx_lpm_en3, mode & 0x1); + + /* Toggle reset */ + field_set_val32(p->mp_field_gty_ctl_rx_equa_rst0, 1); + field_set_val32(p->mp_field_gty_ctl_rx_equa_rst1, 1); + field_set_val32(p->mp_field_gty_ctl_rx_equa_rst2, 1); + field_set_val_flush32(p->mp_field_gty_ctl_rx_equa_rst3, 1); + + NT_OS_WAIT_USEC(1000); /* 1ms */ + + field_set_val32(p->mp_field_gty_ctl_rx_equa_rst0, 0); + field_set_val32(p->mp_field_gty_ctl_rx_equa_rst1, 0); + field_set_val32(p->mp_field_gty_ctl_rx_equa_rst2, 0); + field_set_val_flush32(p->mp_field_gty_ctl_rx_equa_rst3, 0); + + NT_LOG(DBG, NTHW, "Port %u: GTY receiver mode: %s\n", p->m_port_no, + (mode == c_mac_pcs_receiver_mode_dfe ? "DFE" : "LPM")); +} + +void nthw_mac_pcs_swap_gty_tx_polarity(nthw_mac_pcs_t *p, uint8_t lane, bool swap) +{ + register_update(p->mp_reg_gty_ctl); + switch (lane) { + case 0: + field_set_val_flush32(p->mp_field_gty_ctl_tx_pol0, swap); + break; + case 1: + field_set_val_flush32(p->mp_field_gty_ctl_tx_pol1, swap); + break; + case 2: + field_set_val_flush32(p->mp_field_gty_ctl_tx_pol2, swap); + break; + case 3: + field_set_val_flush32(p->mp_field_gty_ctl_tx_pol3, swap); + break; + } + NT_LOG(DBG, NTHW, "Port %u: set GTY Tx lane (%d) polarity: %d\n", + p->m_port_no, lane, swap); +} + +void nthw_mac_pcs_swap_gty_rx_polarity(nthw_mac_pcs_t *p, uint8_t lane, bool swap) +{ + register_update(p->mp_reg_gty_ctl); + switch (lane) { + case 0: + field_set_val_flush32(p->mp_field_gty_ctl_rx_pol0, swap); + break; + case 1: + field_set_val_flush32(p->mp_field_gty_ctl_rx_pol1, swap); + break; + case 2: + field_set_val_flush32(p->mp_field_gty_ctl_rx_pol2, swap); + break; + case 3: + field_set_val_flush32(p->mp_field_gty_ctl_rx_pol3, swap); + break; + } + NT_LOG(DBG, NTHW, "Port %u: set GTY Rx lane (%d) polarity: %d\n", + p->m_port_no, lane, swap); +} + +void nthw_mac_pcs_set_led_mode(nthw_mac_pcs_t *p, uint8_t mode) +{ + field_get_updated(p->mp_field_debounce_ctrl_nt_port_ctrl); + field_set_val_flush32(p->mp_field_debounce_ctrl_nt_port_ctrl, mode); +} + +void nthw_mac_pcs_set_timestamp_comp_rx(nthw_mac_pcs_t *p, uint16_t rx_dly) +{ + if (p->mp_field_time_stamp_comp_rx_dly) { + field_get_updated(p->mp_field_time_stamp_comp_rx_dly); + field_set_val_flush32(p->mp_field_time_stamp_comp_rx_dly, rx_dly); + } +} + +void nthw_mac_pcs_set_port_no(nthw_mac_pcs_t *p, uint8_t port_no) +{ + p->m_port_no = port_no; +} + +uint32_t nthw_mac_pcs_get_fld_block_lock_lock(nthw_mac_pcs_t *p) +{ + return field_get_updated(p->mp_fld_block_lock_lock); +} + +uint32_t nthw_mac_pcs_get_fld_block_lock_lock_mask(nthw_mac_pcs_t *p) +{ + return p->m_fld_block_lock_lock_mask; +} + +uint32_t nthw_mac_pcs_get_fld_lane_lock_lock(nthw_mac_pcs_t *p) +{ + return field_get_updated(p->mp_fld_vl_demuxed_lock); +} + +uint32_t nthw_mac_pcs_get_fld_lane_lock_lock_mask(nthw_mac_pcs_t *p) +{ + return p->m_fld_vl_demuxed_lock_mask; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_mac_pcs.h b/drivers/net/ntnic/nthw/core/nthw_mac_pcs.h new file mode 100644 index 0000000000..08197f8b9e --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_mac_pcs.h @@ -0,0 +1,261 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef NTHW_MAC_PCS_H_ +#define NTHW_MAC_PCS_H_ + +enum nthw_mac_pcs_led_mode_e { + NTHW_MAC_PCS_LED_AUTO = 0x00, + NTHW_MAC_PCS_LED_ON = 0x01, + NTHW_MAC_PCS_LED_OFF = 0x02, + NTHW_MAC_PCS_LED_PORTID = 0x03, +}; + +#define nthw_mac_pcs_receiver_mode_dfe (0) +#define nthw_mac_pcs_receiver_mode_lpm (1) + +struct nthw_mac_pcs { + uint8_t m_port_no; + + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_mac_pcs; + int mn_instance; + + /* Block lock status */ + nt_field_t *mp_fld_block_lock_lock; + uint32_t m_fld_block_lock_lock_mask; + + /* Lane lock status */ + nt_field_t *mp_fld_vl_demuxed_lock; + uint32_t m_fld_vl_demuxed_lock_mask; + + /* GTY_STAT */ + nt_field_t *mp_fld_gty_stat_rx_rst_done0; + nt_field_t *mp_fld_gty_stat_rx_rst_done1; + nt_field_t *mp_fld_gty_stat_rx_rst_done2; + nt_field_t *mp_fld_gty_stat_rx_rst_done3; + nt_field_t *mp_fld_gty_stat_tx_rst_done0; + nt_field_t *mp_fld_gty_stat_tx_rst_done1; + nt_field_t *mp_fld_gty_stat_tx_rst_done2; + nt_field_t *mp_fld_gty_stat_tx_rst_done3; + uint32_t m_fld_gty_stat_rx_rst_done_mask; + uint32_t m_fld_gty_stat_tx_rst_done_mask; + + /* GTY_LOOP */ + nt_register_t *mp_reg_gty_loop; + nt_field_t *mp_fld_gty_loop_gt_loop0; + nt_field_t *mp_fld_gty_loop_gt_loop1; + nt_field_t *mp_fld_gty_loop_gt_loop2; + nt_field_t *mp_fld_gty_loop_gt_loop3; + + /* MAC_PCS_CONFIG */ + nt_field_t *mp_fld_pcs_config_tx_path_rst; + nt_field_t *mp_fld_pcs_config_rx_path_rst; + nt_field_t *mp_fld_pcs_config_rx_enable; + nt_field_t *mp_fld_pcs_config_rx_force_resync; + nt_field_t *mp_fld_pcs_config_rx_test_pattern; + nt_field_t *mp_fld_pcs_config_tx_enable; + nt_field_t *mp_fld_pcs_config_tx_send_idle; + nt_field_t *mp_fld_pcs_config_tx_send_rfi; + nt_field_t *mp_fld_pcs_config_tx_test_pattern; + + /* STAT PCS */ + nt_field_t *mp_fld_stat_pcs_rx_status; + nt_field_t *mp_fld_stat_pcs_rx_aligned; + nt_field_t *mp_fld_stat_pcs_rx_aligned_err; + nt_field_t *mp_fld_stat_pcs_rx_misaligned; + nt_field_t *mp_fld_stat_pcs_rx_internal_local_fault; + nt_field_t *mp_fld_stat_pcs_rx_received_local_fault; + nt_field_t *mp_fld_stat_pcs_rx_local_fault; + nt_field_t *mp_fld_stat_pcs_rx_remote_fault; + nt_field_t *mp_fld_stat_pcs_rx_hi_ber; + + /* STAT_PCS_RX_LATCH */ + nt_field_t *mp_fld_stat_pcs_rx_latch_status; + + /* PHYMAC_MISC */ + nt_field_t *mp_fld_phymac_misc_tx_sel_host; + nt_field_t *mp_fld_phymac_misc_tx_sel_tfg; + nt_field_t *mp_fld_phymac_misc_tx_sel_rx_loop; + nt_field_t *mp_fld_phymac_misc_ts_eop; + + /* LINK_SUMMARY */ + nt_register_t *mp_reg_link_summary; + nt_field_t *mp_fld_link_summary_abs; + nt_field_t *mp_fld_link_summary_nt_phy_link_state; + nt_field_t *mp_fld_link_summary_lh_abs; + nt_field_t *mp_fld_link_summary_ll_nt_phy_link_state; + nt_field_t *mp_fld_link_summary_link_down_cnt; + nt_field_t *mp_fld_link_summary_nim_interr; + nt_field_t *mp_fld_link_summary_lh_local_fault; + nt_field_t *mp_fld_link_summary_lh_remote_fault; + nt_field_t *mp_fld_link_summary_local_fault; + nt_field_t *mp_fld_link_summary_remote_fault; + + /* BIP_ERR */ + nt_register_t *mp_reg_bip_err; + nt_field_t *mp_fld_reg_bip_err_bip_err; + + /* FEC_CTRL */ + nt_register_t *mp_reg_fec_ctrl; + nt_field_t *mp_field_fec_ctrl_reg_rs_fec_ctrl_in; + + /* FEC_STAT */ + nt_register_t *mp_reg_fec_stat; + nt_field_t *mp_field_fec_stat_bypass; + nt_field_t *mp_field_fec_stat_valid; + nt_field_t *mp_field_fec_stat_am_lock0; + nt_field_t *mp_field_fec_stat_am_lock1; + nt_field_t *mp_field_fec_stat_am_lock2; + nt_field_t *mp_field_fec_stat_am_lock3; + nt_field_t *mp_field_fec_stat_fec_lane_algn; + + /* FEC Corrected code word count */ + nt_register_t *mp_reg_fec_cw_cnt; + nt_field_t *mp_field_fec_cw_cnt_cw_cnt; + + /* FEC Uncorrected code word count */ + nt_register_t *mp_reg_fec_ucw_cnt; + nt_field_t *mp_field_fec_ucw_cnt_ucw_cnt; + + /* GTY_RX_BUF_STAT */ + nt_register_t *mp_reg_gty_rx_buf_stat; + nt_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat0; + nt_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat1; + nt_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat2; + nt_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat3; + nt_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat_changed0; + nt_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat_changed1; + nt_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat_changed2; + nt_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat_changed3; + + /* GTY_PRE_CURSOR */ + nt_register_t *mp_reg_gty_pre_cursor; + nt_field_t *mp_field_gty_pre_cursor_tx_pre_csr0; + nt_field_t *mp_field_gty_pre_cursor_tx_pre_csr1; + nt_field_t *mp_field_gty_pre_cursor_tx_pre_csr2; + nt_field_t *mp_field_gty_pre_cursor_tx_pre_csr3; + + /* GTY_DIFF_CTL */ + nt_register_t *mp_reg_gty_diff_ctl; + nt_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl0; + nt_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl1; + nt_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl2; + nt_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl3; + + /* GTY_POST_CURSOR */ + nt_register_t *mp_reg_gty_post_cursor; + nt_field_t *mp_field_gty_post_cursor_tx_post_csr0; + nt_field_t *mp_field_gty_post_cursor_tx_post_csr1; + nt_field_t *mp_field_gty_post_cursor_tx_post_csr2; + nt_field_t *mp_field_gty_post_cursor_tx_post_csr3; + + /* GTY_CTL */ + nt_register_t *mp_reg_gty_ctl; + nt_register_t *mp_reg_gty_ctl_tx; + nt_field_t *mp_field_gty_ctl_tx_pol0; + nt_field_t *mp_field_gty_ctl_tx_pol1; + nt_field_t *mp_field_gty_ctl_tx_pol2; + nt_field_t *mp_field_gty_ctl_tx_pol3; + nt_field_t *mp_field_gty_ctl_rx_pol0; + nt_field_t *mp_field_gty_ctl_rx_pol1; + nt_field_t *mp_field_gty_ctl_rx_pol2; + nt_field_t *mp_field_gty_ctl_rx_pol3; + nt_field_t *mp_field_gty_ctl_rx_lpm_en0; + nt_field_t *mp_field_gty_ctl_rx_lpm_en1; + nt_field_t *mp_field_gty_ctl_rx_lpm_en2; + nt_field_t *mp_field_gty_ctl_rx_lpm_en3; + nt_field_t *mp_field_gty_ctl_rx_equa_rst0; + nt_field_t *mp_field_gty_ctl_rx_equa_rst1; + nt_field_t *mp_field_gty_ctl_rx_equa_rst2; + nt_field_t *mp_field_gty_ctl_rx_equa_rst3; + + /* DEBOUNCE_CTRL */ + nt_register_t *mp_reg_debounce_ctrl; + nt_field_t *mp_field_debounce_ctrl_nt_port_ctrl; + + /* TIMESTAMP_COMP */ + nt_register_t *mp_reg_time_stamp_comp; + nt_field_t *mp_field_time_stamp_comp_rx_dly; + nt_field_t *mp_field_time_stamp_comp_tx_dly; + + /* STAT_PCS_RX */ + nt_register_t *mp_reg_stat_pcs_rx; + + /* STAT_PCS_RX */ + nt_register_t *mp_reg_stat_pcs_rx_latch; + + /* PHYMAC_MISC */ + nt_register_t *mp_reg_phymac_misc; + + /* BLOCK_LOCK */ + nt_register_t *mp_reg_block_lock; +}; + +typedef struct nthw_mac_pcs nthw_mac_pcs_t; +typedef struct nthw_mac_pcs nthw_mac_pcs; + +nthw_mac_pcs_t *nthw_mac_pcs_new(void); +int nthw_mac_pcs_init(nthw_mac_pcs_t *p, nt_fpga_t *p_fpga, int n_instance); +void nthw_mac_pcs_delete(nthw_mac_pcs_t *p); + +bool nthw_mac_pcs_is_block_and_lane_lock_locked(nthw_mac_pcs_t *p); +bool nthw_mac_pcs_is_gt_fsm_rx_reset_done(nthw_mac_pcs_t *p); +bool nthw_mac_pcs_is_gt_fsm_tx_reset_done(nthw_mac_pcs_t *p); +void nthw_mac_pcs_tx_path_rst(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_rx_path_rst(nthw_mac_pcs_t *p, bool enable); +bool nthw_mac_pcs_is_rx_path_rst(nthw_mac_pcs_t *p); +void nthw_mac_pcs_rx_force_resync(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_tx_send_rfi(nthw_mac_pcs_t *p, bool enable); +bool nthw_mac_pcs_is_dd_r3_calib_done(nthw_mac_pcs_t *p); +void nthw_mac_pcs_tx_host_enable(nthw_mac_pcs_t *p, + bool enable); /* wrapper - for ease of use */ +void nthw_mac_pcs_set_rx_enable(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_set_tx_enable(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_set_tx_sel_host(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_set_tx_sel_tfg(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_set_ts_eop(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_set_host_loopback(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_set_line_loopback(nthw_mac_pcs_t *p, bool enable); +void nthw_mac_pcs_reset_bip_counters(nthw_mac_pcs_t *p); +void nthw_mac_pcs_get_status(nthw_mac_pcs_t *p, uint8_t *status); +bool nthw_mac_pcs_get_hi_ber(nthw_mac_pcs_t *p); + +void nthw_mac_pcs_get_link_summary1(nthw_mac_pcs_t *p, uint32_t *p_status, + uint32_t *p_status_latch, uint32_t *p_aligned, + uint32_t *p_local_fault, uint32_t *p_remote_fault); + +void nthw_mac_pcs_get_link_summary(nthw_mac_pcs_t *p, uint32_t *p_abs, + uint32_t *p_nt_phy_link_state, uint32_t *p_lh_abs, + uint32_t *p_ll_nt_phy_link_state, + uint32_t *p_link_down_cnt, uint32_t *p_nim_interr, + uint32_t *p_lh_local_fault, + uint32_t *p_lh_remote_fault, uint32_t *p_local_fault, + uint32_t *p_remote_fault); + +bool nthw_mac_pcs_reset_required(nthw_mac_pcs_t *p); +void nthw_mac_pcs_set_fec(nthw_mac_pcs_t *p, bool enable); +bool nthw_mac_pcs_get_fec_bypass(nthw_mac_pcs_t *p); +bool nthw_mac_pcs_get_fec_valid(nthw_mac_pcs_t *p); +bool nthw_mac_pcs_get_fec_aligned(nthw_mac_pcs_t *p); +bool nthw_mac_pcs_get_fec_stat_any_am_locked(nthw_mac_pcs_t *p); +bool nthw_mac_pcs_get_fec_stat_all_am_locked(nthw_mac_pcs_t *p); +void nthw_mac_pcs_dump_fec_stat_fields(nthw_mac_pcs_t *p); +void nthw_mac_pcs_reset_fec_counters(nthw_mac_pcs_t *p); +bool nthw_mac_pcs_get_gty_rx_buf_stat_error(nthw_mac_pcs_t *p); +void nthw_mac_pcs_set_gty_tx_tuning(nthw_mac_pcs_t *p, uint8_t lane, uint8_t tx_pre_csr, + uint8_t tx_diff_ctl, uint8_t tx_post_csr); +void nthw_mac_pcs_swap_gty_tx_polarity(nthw_mac_pcs_t *p, uint8_t lane, bool swap); +void nthw_mac_pcs_swap_gty_rx_polarity(nthw_mac_pcs_t *p, uint8_t lane, bool swap); +void nthw_mac_pcs_set_receiver_equalization_mode(nthw_mac_pcs_t *p, uint8_t mode); +void nthw_mac_pcs_set_led_mode(nthw_mac_pcs_t *p, uint8_t mode); +void nthw_mac_pcs_set_timestamp_comp_rx(nthw_mac_pcs_t *p, uint16_t rx_dly); +void nthw_mac_pcs_set_port_no(nthw_mac_pcs_t *p, uint8_t port_no); + +uint32_t nthw_mac_pcs_get_fld_block_lock_lock(nthw_mac_pcs_t *p); +uint32_t nthw_mac_pcs_get_fld_block_lock_lock_mask(nthw_mac_pcs_t *p); +uint32_t nthw_mac_pcs_get_fld_lane_lock_lock(nthw_mac_pcs_t *p); +uint32_t nthw_mac_pcs_get_fld_lane_lock_lock_mask(nthw_mac_pcs_t *p); + +#endif /* NTHW_MAC_PCS_H_ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.c b/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.c new file mode 100644 index 0000000000..d8e1f0de5d --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.c @@ -0,0 +1,1631 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_mac_pcs_xxv.h" + +static void nthw_mac_pcs_xxv_field_set_or_clr_flush(const nt_field_t *f, bool set) +{ + if (f) { + field_get_updated(f); + if (set) + field_set_flush(f); + else + field_clr_flush(f); + } +} + +nthw_mac_pcs_xxv_t *nthw_mac_pcs_xxv_new(void) +{ + nthw_mac_pcs_xxv_t *p = malloc(sizeof(nthw_mac_pcs_xxv_t)); + + if (p) + memset(p, 0, sizeof(nthw_mac_pcs_xxv_t)); + return p; +} + +void nthw_mac_pcs_xxv_delete(nthw_mac_pcs_xxv_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_mac_pcs_xxv_t)); + free(p); + } +} + +uint8_t nthw_mac_pcs_xxv_get_port_no(const nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + return index == 0 ? (uint8_t)p->mn_instance : index; +} + +void nthw_mac_pcs_xxv_set_port_no(nthw_mac_pcs_xxv_t *p, uint8_t port_no) +{ + p->m_port_no = port_no; +} + +void nthw_mac_pcs_xxv_get_link_summary(nthw_mac_pcs_xxv_t *p, + uint32_t *p_abs, uint32_t *p_nt_phy_link_state, + uint32_t *p_lh_abs, uint32_t *p_ll_nt_phy_link_state, uint32_t *p_link_down_cnt, + uint32_t *p_nim_interr, uint32_t *p_lh_local_fault, uint32_t *p_lh_remote_fault, + uint32_t *p_lh_internal_local_fault, uint32_t *p_lh_received_local_fault, + uint8_t index) +{ + struct nthw_mac_pcs_xxv__registers_fields *r = + &p->regs[index]; /* register and fields */ + + assert(p); + + register_update(r->mp_reg_link_summary); + if (p_abs) + *p_abs = field_get_val32(r->mp_fld_link_summary_abs); + if (p_nt_phy_link_state) { + *p_nt_phy_link_state = + field_get_val32(r->mp_fld_link_summary_nt_phy_link_state); + } + if (p_lh_abs) + *p_lh_abs = field_get_val32(r->mp_fld_link_summary_lh_abs); + if (p_ll_nt_phy_link_state) { + *p_ll_nt_phy_link_state = + field_get_val32(r->mp_fld_link_summary_ll_nt_phy_link_state); + } + if (p_link_down_cnt) + *p_link_down_cnt = field_get_val32(r->mp_fld_link_summary_link_down_cnt); + if (p_nim_interr) + *p_nim_interr = field_get_val32(r->mp_fld_link_summary_nim_interr); + if (p_lh_local_fault) { + *p_lh_local_fault = + field_get_val32(r->mp_fld_link_summary_lh_local_fault); + } + if (p_lh_remote_fault) { + *p_lh_remote_fault = + field_get_val32(r->mp_fld_link_summary_lh_remote_fault); + } + if (p_lh_internal_local_fault) { + *p_lh_internal_local_fault = + field_get_val32(r->mp_fld_link_summary_lh_internal_local_fault); + } + if (p_lh_received_local_fault) { + *p_lh_received_local_fault = + field_get_val32(r->mp_fld_link_summary_lh_received_local_fault); + } +} + +void nthw_mac_pcs_xxv_set_tx_enable(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_tx_enable; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_rx_enable(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_rx_enable; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_rx_force_resync(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_rx_force_resync; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_reset_rx_gt_data(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_sub_rst_rx_gt_data; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_reset_tx_gt_data(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_sub_rst_tx_gt_data; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_reset_an_lt(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_sub_rst_an_lt; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_reset_speed_ctrl(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_sub_rst_speed_ctrl; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_tx_send_rfi(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_tx_send_rfi; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_tx_send_lfi(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_tx_send_lfi; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_tx_send_lfi_tx_send_rfi(nthw_mac_pcs_xxv_t *p, bool enable_lfi, + bool enable_rfi, uint8_t index) +{ + register_update(p->regs[index].mp_reg_core_conf); + field_set_val32(p->regs[index].mp_fld_core_conf_tx_send_lfi, enable_lfi); + field_set_val32(p->regs[index].mp_fld_core_conf_tx_send_rfi, enable_rfi); + register_flush(p->regs[index].mp_reg_core_conf, 1); +} + +bool nthw_mac_pcs_xxv_is_dfe_enabled(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_gty_ctl_rx_lpm_en; + + /* NOTE: DFE is enabled when LPM is disabled */ + return !field_get_updated(f); +} + +void nthw_mac_pcs_xxv_set_dfe(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *f = p->regs[index].mp_fld_gty_ctl_rx_lpm_en; + const bool set_dfe = + !enable; /* NOTE: Enable DFE mode means setting LPM = 0 */ + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, set_dfe); + + /* Toggle GTY_CTL_RX->EQUA_RST to 1 and 0 to assert new LPM_EN setting */ + f = p->regs[index].mp_fld_gty_ctl_rx_equa_rst; + field_get_updated(f); + field_set_val_flush32(f, 1); /* Assert GTH SOFT RESET */ + field_get_updated(f); + field_set_val_flush32(f, 0); /* De-Assert GTH SOFT RESET */ + field_get_updated(f); +} + +void nthw_mac_pcs_xxv_set_rx_gty_polarity(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_gty_ctl_rx_polarity; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_tx_gty_polarity(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_gty_ctl_tx_polarity; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_tx_gty_inhibit(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_gty_ctl_tx_inhibit; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_host_loopback(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_gty_loop_gt_loop; + + field_get_updated(f); + field_set_val_flush32(f, enable ? 2U : 0U); +} + +void nthw_mac_pcs_xxv_set_line_loopback(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_line_loopback; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +bool nthw_mac_pcs_xxv_is_user_rx_rst(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + return field_get_updated(p->regs[index].mp_fld_sub_rst_status_user_rx_rst); +} + +bool nthw_mac_pcs_xxv_is_user_tx_rst(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + return field_get_updated(p->regs[index].mp_fld_sub_rst_status_user_tx_rst); +} + +/* + * QPLL lock signal. + * For cores capable of 10G only, there are only 1 QPLL. For cores capable of + * 10G/25G, there are 2 QPLLs. + */ +bool nthw_mac_pcs_xxv_is_qpll_lock(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + return (field_get_updated(p->regs[index].mp_fld_sub_rst_status_qpll_lock) == + 3); +} + +bool nthw_mac_pcs_xxv_is_sub_rst_ready(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + return (nthw_mac_pcs_xxv_is_qpll_lock(p, index) && + !nthw_mac_pcs_xxv_is_user_rx_rst(p, index) && + !nthw_mac_pcs_xxv_is_user_tx_rst(p, index)); +} + +bool nthw_mac_pcs_xxv_is_aneg_enabled(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + return field_get_updated(p->regs[index].mp_fld_aneg_config_enable); +} + +void nthw_mac_pcs_xxv_set_tx_send_idle(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_tx_send_idle; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_tx_ins_fcs(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_tx_ins_fcs; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +bool nthw_mac_pcs_xxv_get_link_speed10_g(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_link_speed10_g; + + return field_get_updated(f) != 0; /* 0 = 25g, 1 = 10g */ +} + +void nthw_mac_pcs_xxv_set_link_speed10_g(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_link_speed10_g; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_link_speed_toggle(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_link_speed_toggle; + + field_get_updated(f); + field_set_flush(f); +} + +void nthw_mac_pcs_xxv_set_rs_fec_conf_rs_fec_enable(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_rs_fec_conf_rs_fec_enable; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_led_mode(nthw_mac_pcs_xxv_t *p, uint8_t mode, uint8_t index) +{ + const nt_field_t *const f = + p->regs[index].mp_field_debounce_ctrl_nt_port_ctrl; + + field_get_updated(f); + field_set_val_flush32(f, mode); +} + +void nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_sub_rst_rx_mac_pcs; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_tx_mac_pcs_rst(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_sub_rst_tx_mac_pcs; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_reset_fec_counters(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + register_update(p->regs[index].mp_reg_rs_fec_ccw); + register_update(p->regs[index].mp_reg_rs_fec_ucw); + + if (field_get_val32(p->regs[index].mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt)) { + NT_LOG(DBG, NTHW, "Port %u: FEC_CW_CNT: %u", p->m_port_no, + field_get_val32(p->regs[index].mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt)); + } + if (field_get_val32(p->regs[index].mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt)) { + NT_LOG(DBG, NTHW, "Port %u: FEC_UCW_CNT: %u", p->m_port_no, + field_get_val32(p->regs[index].mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt)); + } +} + +void nthw_mac_pcs_xxv_set_timestamp_comp_rx(nthw_mac_pcs_xxv_t *p, uint16_t rx_dly, + uint8_t index) +{ + field_get_updated(p->regs[index].mp_field_timestamp_comp_rx_dly); + field_set_val_flush32(p->regs[index].mp_field_timestamp_comp_rx_dly, rx_dly); +} + +void nthw_mac_pcs_xxv_set_timestamp_comp_tx(nthw_mac_pcs_xxv_t *p, uint16_t tx_dly, + uint8_t index) +{ + field_get_updated(p->regs[index].mp_field_timestamp_comp_tx_dly); + field_set_val_flush32(p->regs[index].mp_field_timestamp_comp_tx_dly, tx_dly); +} + +void nthw_mac_pcs_xxv_set_ts_at_eop(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_core_conf_ts_at_eop; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_gty_diff(nthw_mac_pcs_xxv_t *p, uint8_t value, uint8_t index) +{ + field_get_updated(p->regs[index].mp_field_gty_gty_diff_ctl_tx_diff_ctl); + field_set_val_flush32(p->regs[index].mp_field_gty_gty_diff_ctl_tx_diff_ctl, + value); +} + +void nthw_mac_pcs_xxv_set_gty_pre(nthw_mac_pcs_xxv_t *p, uint8_t value, uint8_t index) +{ + field_get_updated(p->regs[index].mp_field_gty_pre_cursor_tx_pre_csr); + field_set_val_flush32(p->regs[index].mp_field_gty_pre_cursor_tx_pre_csr, value); +} + +void nthw_mac_pcs_xxv_set_gty_post(nthw_mac_pcs_xxv_t *p, uint8_t value, uint8_t index) +{ + field_get_updated(p->regs[index].mp_field_gty_post_cursor_tx_post_csr); + field_set_val_flush32(p->regs[index].mp_field_gty_post_cursor_tx_post_csr, + value); +} + +void nthw_mac_pcs_xxv_set_lt_conf_enable(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_lt_conf_enable; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_aneg_config_fec91_request(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_aneg_config_fec91_request; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_aneg_config_rs_fec_request(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_aneg_config_rs_fec_request; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_aneg_config_fec74_request(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_aneg_config_fec74_request; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_aneg_config_enable(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_aneg_config_enable; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_aneg_config_bypass(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index) +{ + const nt_field_t *const f = p->regs[index].mp_fld_aneg_config_bypass; + + nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable); +} + +void nthw_mac_pcs_xxv_set_dac_mode(nthw_mac_pcs_xxv_t *p, uint8_t dac_mode, + uint8_t index) +{ + if (dac_mode == NTHW_MAC_PCS_XXV_DAC_OFF) { + nthw_mac_pcs_xxv_reset_an_lt(p, false, index); + nthw_mac_pcs_xxv_set_aneg_config_enable(p, false, index); + nthw_mac_pcs_xxv_set_aneg_config_bypass(p, true, index); + nthw_mac_pcs_xxv_set_lt_conf_enable(p, false, index); + nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(p, true, index); + nthw_mac_pcs_xxv_set_tx_mac_pcs_rst(p, true, index); + nthw_mac_pcs_xxv_reset_rx_gt_data(p, true, index); + nthw_mac_pcs_xxv_reset_tx_gt_data(p, true, index); + nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(p, false, index); + nthw_mac_pcs_xxv_set_tx_mac_pcs_rst(p, false, index); + nthw_mac_pcs_xxv_reset_rx_gt_data(p, false, index); + nthw_mac_pcs_xxv_reset_tx_gt_data(p, false, index); + + return; + } + assert(0); /* If you end up here you need to implement other DAC modes */ +} + +bool nthw_mac_pcs_xxv_get_ll_rx_fec74_lock(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + return field_get_updated(p->regs[index].mp_fld_link_summary_ll_rx_fec74_lock); +} + +bool nthw_mac_pcs_xxv_get_ll_rx_rsfec_lane_alignment(nthw_mac_pcs_xxv_t *p, uint8_t index) +{ + return field_get_updated(p->regs[index].mp_fld_link_summary_ll_rx_rsfec_lane_alignment); +} + +int nthw_mac_pcs_xxv_init(nthw_mac_pcs_xxv_t *p, nt_fpga_t *p_fpga, int n_instance, + int n_channels) +{ + nt_module_t *p_mod = fpga_query_module(p_fpga, MOD_MAC_PCS_XXV, n_instance); + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + const bool m_mac8x10_g = false; + nt_module_t *module = p_mod; + uint64_t n_module_version_packed64 = -1; + nt_register_t *r; + nt_register_t *(*get_register)(nt_module_t *, uint32_t) = + module_get_register; + nt_field_t *(*get_field)(const nt_register_t *, uint32_t) = + register_get_field; + nt_field_t *(*query_field)(const nt_register_t *, uint32_t) = + register_query_field; + struct nthw_mac_pcs_xxv__registers_fields *rf; + + if (p == NULL) + return (p_mod == NULL ? -1 : 0); + + if (p_mod == NULL) { + NT_LOG(ERR, NTHW, + "%s: MAC_PCS_XXV instance=%d: no such instance\n", + p_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_mac_pcs_xxv = p_mod; + + memset(p->regs, 0, sizeof(p->regs)); + + n_module_version_packed64 = module_get_version_packed64(p->mp_mod_mac_pcs_xxv); + switch (n_module_version_packed64) { + case (0UL << 32) | 0UL: /* 0.0 */ + case (0UL << 32) | 1UL: /* 0.1 */ + case (0UL << 32) | 2UL: /* 0.2 */ + NT_LOG(DBG, NTHW, + "%s: MAC_PCS_XXV instance=%d: version=0x%08lX\n", + p_adapter_id_str, p->mn_instance, n_module_version_packed64); + break; + default: + NT_LOG(ERR, NTHW, + "%s: MAC_PCS_XXV instance=%d: version=0x%08lX: unsupported module version\n", + p_adapter_id_str, p->mn_instance, n_module_version_packed64); + return -1; + } + + assert(n_channels == 1 || n_channels == 2 || n_channels == 4); + + /* Register MAC_PCS_XXV_CORE_CONF_0 -- MAC_PCS_XXV_CORE_CONF_3 */ + if (n_channels < 4) { + /* Initialize regs/fields for sub-module/channel 0 */ + rf = &p->regs[0]; + r = get_register(module, MAC_PCS_XXV_CORE_CONF_0); + + rf->mp_reg_core_conf = r; + rf->mp_fld_core_conf_rx_enable = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_RX_ENABLE); + rf->mp_fld_core_conf_rx_force_resync = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_RX_FORCE_RESYNC); + rf->mp_fld_core_conf_tx_enable = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_ENABLE); + rf->mp_fld_core_conf_tx_ins_fcs = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_INS_FCS); + rf->mp_fld_core_conf_tx_ign_fcs = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_IGN_FCS); + rf->mp_fld_core_conf_tx_send_lfi = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_SEND_LFI); + rf->mp_fld_core_conf_tx_send_rfi = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_SEND_RFI); + rf->mp_fld_core_conf_tx_send_idle = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_SEND_IDLE); + rf->mp_fld_core_conf_inline_mode = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_INLINE_MODE); + rf->mp_fld_core_conf_line_loopback = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_LINE_LOOPBACK); + rf->mp_fld_core_conf_ts_at_eop = + get_field(r, MAC_PCS_XXV_CORE_CONF_0_TS_AT_EOP); + } + + if (n_channels >= 2) { + /* Initialize regs/fields for sub-module/channel 1 */ + rf = &p->regs[1]; + r = get_register(module, MAC_PCS_XXV_CORE_CONF_1); + + rf->mp_reg_core_conf = r; + rf->mp_fld_core_conf_rx_enable = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_RX_ENABLE); + rf->mp_fld_core_conf_rx_force_resync = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_RX_FORCE_RESYNC); + rf->mp_fld_core_conf_tx_enable = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_ENABLE); + rf->mp_fld_core_conf_tx_ins_fcs = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_INS_FCS); + rf->mp_fld_core_conf_tx_ign_fcs = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_IGN_FCS); + rf->mp_fld_core_conf_tx_send_lfi = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_SEND_LFI); + rf->mp_fld_core_conf_tx_send_rfi = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_SEND_RFI); + rf->mp_fld_core_conf_tx_send_idle = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_SEND_IDLE); + rf->mp_fld_core_conf_inline_mode = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_INLINE_MODE); + rf->mp_fld_core_conf_line_loopback = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_LINE_LOOPBACK); + rf->mp_fld_core_conf_ts_at_eop = + get_field(r, MAC_PCS_XXV_CORE_CONF_1_TS_AT_EOP); + } + + if (n_channels == 4) { + /* Initialize regs/fields for sub-module/channel 2 */ + rf = &p->regs[2]; + r = get_register(module, MAC_PCS_XXV_CORE_CONF_2); + + rf->mp_reg_core_conf = r; + rf->mp_fld_core_conf_rx_enable = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_RX_ENABLE); + rf->mp_fld_core_conf_rx_force_resync = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_RX_FORCE_RESYNC); + rf->mp_fld_core_conf_tx_enable = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_ENABLE); + rf->mp_fld_core_conf_tx_ins_fcs = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_INS_FCS); + rf->mp_fld_core_conf_tx_ign_fcs = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_IGN_FCS); + rf->mp_fld_core_conf_tx_send_lfi = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_SEND_LFI); + rf->mp_fld_core_conf_tx_send_rfi = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_SEND_RFI); + rf->mp_fld_core_conf_tx_send_idle = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_SEND_IDLE); + rf->mp_fld_core_conf_inline_mode = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_INLINE_MODE); + rf->mp_fld_core_conf_line_loopback = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_LINE_LOOPBACK); + rf->mp_fld_core_conf_ts_at_eop = + get_field(r, MAC_PCS_XXV_CORE_CONF_2_TS_AT_EOP); + + /* Initialize regs/fields for sub-module/channel 3 */ + rf = &p->regs[3]; + r = get_register(module, MAC_PCS_XXV_CORE_CONF_3); + + rf->mp_reg_core_conf = r; + rf->mp_fld_core_conf_rx_enable = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_RX_ENABLE); + rf->mp_fld_core_conf_rx_force_resync = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_RX_FORCE_RESYNC); + rf->mp_fld_core_conf_tx_enable = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_ENABLE); + rf->mp_fld_core_conf_tx_ins_fcs = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_INS_FCS); + rf->mp_fld_core_conf_tx_ign_fcs = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_IGN_FCS); + rf->mp_fld_core_conf_tx_send_lfi = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_SEND_LFI); + rf->mp_fld_core_conf_tx_send_rfi = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_SEND_RFI); + rf->mp_fld_core_conf_tx_send_idle = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_SEND_IDLE); + rf->mp_fld_core_conf_inline_mode = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_INLINE_MODE); + rf->mp_fld_core_conf_line_loopback = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_LINE_LOOPBACK); + rf->mp_fld_core_conf_ts_at_eop = + get_field(r, MAC_PCS_XXV_CORE_CONF_3_TS_AT_EOP); + } + + /* + * Registers MAC_PCS_XXV_ANEG_CONFIG_0 -- MAC_PCS_XXV_ANEG_CONFIG_3 + * and MAC_PCS_XXV_ANEG_ABILITY_0 -- MAC_PCS_XXV_ANEG_ABILITY_3 + * and MAC_PCS_XXV_LT_CONF_0 -- MAC_PCS_XXV_LT_CONF_3 + */ + if (!m_mac8x10_g && n_channels < 4) { + /* 2 x 10 25 G */ + /* ANEG_CONFIG */ + rf = &p->regs[0]; + + r = get_register(module, MAC_PCS_XXV_ANEG_CONFIG_0); + rf->mp_reg_aneg_config = r; + rf->mp_fld_aneg_config_enable = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_ENABLE); + rf->mp_fld_aneg_config_bypass = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_BYPASS); + rf->mp_fld_aneg_config_restart = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_RESTART); + rf->mp_fld_aneg_config_pseudo = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_PSEUDO); + rf->mp_fld_aneg_config_nonce_seed = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_NONCE_SEED); + rf->mp_fld_aneg_config_remote_fault = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_REMOTE_FAULT); + rf->mp_fld_aneg_config_pause = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_PAUSE); + rf->mp_fld_aneg_config_asmdir = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_ASMDIR); + rf->mp_fld_aneg_config_fec74_request10_g = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_FEC74_REQUEST_10G); + rf->mp_fld_aneg_config_hide_fec74 = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_HIDE_FEC74); + rf->mp_fld_aneg_config_fec74_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_FEC74_REQUEST); + rf->mp_fld_aneg_config_fec91_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_FEC91_REQUEST); + rf->mp_fld_aneg_config_fec91_ability = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_FEC91_ABILITY); + rf->mp_fld_aneg_config_rs_fec_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_RS_FEC_REQUEST); + rf->mp_fld_aneg_config_sw_fec_overwrite = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_SW_FEC_OVERWRITE); + rf->mp_fld_aneg_config_sw_speed_overwrite = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_SW_SPEED_OVERWRITE); + + /* ANEG_ABILITY */ + r = get_register(module, MAC_PCS_XXV_ANEG_ABILITY_0); + rf->mp_reg_aneg_ability = r; + + rf->mp_fld_aneg_ability25_g_base_cr = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_BASE25G_CR); + if (!rf->mp_fld_aneg_ability25_g_base_cr) { + rf->mp_fld_aneg_ability25_g_base_cr = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_25GBASE_CR); + } + + rf->mp_fld_aneg_ability25_g_base_crs = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_BASE25G_CR_S); + if (!rf->mp_fld_aneg_ability25_g_base_crs) { + rf->mp_fld_aneg_ability25_g_base_crs = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_25GBASE_CR_S); + } + + rf->mp_fld_aneg_ability25_g_base_cr1 = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_BASE25G_CR1); + if (!rf->mp_fld_aneg_ability25_g_base_cr1) { + rf->mp_fld_aneg_ability25_g_base_cr1 = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_25GBASE_CR1); + } + + /* LT_CONF */ + r = get_register(module, MAC_PCS_XXV_LT_CONF_0); + rf->mp_reg_lt_conf = r; + rf->mp_fld_lt_conf_enable = + get_field(r, MAC_PCS_XXV_LT_CONF_0_ENABLE); + rf->mp_fld_lt_conf_restart = + get_field(r, MAC_PCS_XXV_LT_CONF_0_RESTART); + rf->mp_fld_lt_conf_seed = get_field(r, MAC_PCS_XXV_LT_CONF_0_SEED); + } + + if (!m_mac8x10_g && n_channels >= 2) { + /* 2 x 10 25 G */ + /* ANEG_CONFIG */ + + /* Initialize regs/fields for sub-module/channel 1 */ + rf = &p->regs[1]; + + r = get_register(module, MAC_PCS_XXV_ANEG_CONFIG_1); + rf->mp_reg_aneg_config = r; + rf->mp_fld_aneg_config_enable = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_ENABLE); + rf->mp_fld_aneg_config_bypass = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_BYPASS); + rf->mp_fld_aneg_config_restart = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_RESTART); + rf->mp_fld_aneg_config_pseudo = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_PSEUDO); + rf->mp_fld_aneg_config_nonce_seed = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_NONCE_SEED); + rf->mp_fld_aneg_config_remote_fault = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_REMOTE_FAULT); + rf->mp_fld_aneg_config_pause = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_PAUSE); + rf->mp_fld_aneg_config_asmdir = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_ASMDIR); + rf->mp_fld_aneg_config_fec74_request10_g = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_FEC74_REQUEST_10G); + rf->mp_fld_aneg_config_hide_fec74 = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_HIDE_FEC74); + rf->mp_fld_aneg_config_fec74_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_FEC74_REQUEST); + rf->mp_fld_aneg_config_fec91_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_FEC91_REQUEST); + rf->mp_fld_aneg_config_fec91_ability = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_FEC91_ABILITY); + rf->mp_fld_aneg_config_rs_fec_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_RS_FEC_REQUEST); + rf->mp_fld_aneg_config_sw_fec_overwrite = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_SW_FEC_OVERWRITE); + rf->mp_fld_aneg_config_sw_speed_overwrite = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_SW_SPEED_OVERWRITE); + + /* ANEG_ABILITY */ + r = get_register(module, MAC_PCS_XXV_ANEG_ABILITY_1); + rf->mp_reg_aneg_ability = r; + + rf->mp_fld_aneg_ability25_g_base_cr = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_BASE25G_CR); + if (!rf->mp_fld_aneg_ability25_g_base_cr) { + rf->mp_fld_aneg_ability25_g_base_cr = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_25GBASE_CR); + } + + rf->mp_fld_aneg_ability25_g_base_crs = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_BASE25G_CR_S); + if (!rf->mp_fld_aneg_ability25_g_base_crs) { + rf->mp_fld_aneg_ability25_g_base_crs = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_25GBASE_CR_S); + } + + rf->mp_fld_aneg_ability25_g_base_cr1 = + query_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_BASE25G_CR1); + if (!rf->mp_fld_aneg_ability25_g_base_cr1) { + rf->mp_fld_aneg_ability25_g_base_cr1 = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_25GBASE_CR1); + } + + /* LT_CONF */ + r = get_register(module, MAC_PCS_XXV_LT_CONF_1); + rf->mp_reg_lt_conf = r; + rf->mp_fld_lt_conf_enable = + get_field(r, MAC_PCS_XXV_LT_CONF_1_ENABLE); + rf->mp_fld_lt_conf_restart = + get_field(r, MAC_PCS_XXV_LT_CONF_1_RESTART); + rf->mp_fld_lt_conf_seed = get_field(r, MAC_PCS_XXV_LT_CONF_1_SEED); + } + + if (!m_mac8x10_g && n_channels == 4) { + /* Initialize regs/fields for sub-module/channel 2 */ + rf = &p->regs[2]; + + r = get_register(module, MAC_PCS_XXV_ANEG_CONFIG_2); + rf->mp_reg_aneg_config = r; + rf->mp_fld_aneg_config_enable = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_ENABLE); + rf->mp_fld_aneg_config_bypass = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_BYPASS); + rf->mp_fld_aneg_config_restart = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_RESTART); + rf->mp_fld_aneg_config_pseudo = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_PSEUDO); + rf->mp_fld_aneg_config_nonce_seed = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_NONCE_SEED); + rf->mp_fld_aneg_config_remote_fault = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_REMOTE_FAULT); + rf->mp_fld_aneg_config_pause = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_PAUSE); + rf->mp_fld_aneg_config_asmdir = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_ASMDIR); + rf->mp_fld_aneg_config_fec74_request10_g = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_FEC74_REQUEST_10G); + rf->mp_fld_aneg_config_hide_fec74 = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_HIDE_FEC74); + rf->mp_fld_aneg_config_fec74_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_FEC74_REQUEST); + rf->mp_fld_aneg_config_fec91_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_FEC91_REQUEST); + rf->mp_fld_aneg_config_fec91_ability = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_FEC91_ABILITY); + rf->mp_fld_aneg_config_rs_fec_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_RS_FEC_REQUEST); + rf->mp_fld_aneg_config_sw_fec_overwrite = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_SW_FEC_OVERWRITE); + rf->mp_fld_aneg_config_sw_speed_overwrite = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_SW_SPEED_OVERWRITE); + + /* ANEG_ABILITY */ + r = get_register(module, MAC_PCS_XXV_ANEG_ABILITY_2); + rf->mp_reg_aneg_ability = r; + rf->mp_fld_aneg_ability25_g_base_cr = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_2_25GBASE_CR); + rf->mp_fld_aneg_ability25_g_base_crs = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_2_25GBASE_CR_S); + rf->mp_fld_aneg_ability25_g_base_cr1 = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_2_25GBASE_CR1); + + /* LT_CONF */ + r = get_register(module, MAC_PCS_XXV_LT_CONF_2); + rf->mp_reg_lt_conf = r; + rf->mp_fld_lt_conf_enable = + get_field(r, MAC_PCS_XXV_LT_CONF_2_ENABLE); + rf->mp_fld_lt_conf_restart = + get_field(r, MAC_PCS_XXV_LT_CONF_2_RESTART); + rf->mp_fld_lt_conf_seed = get_field(r, MAC_PCS_XXV_LT_CONF_2_SEED); + + /* Initialize regs/fields for sub-module/channel 3 */ + rf = &p->regs[3]; + + r = get_register(module, MAC_PCS_XXV_ANEG_CONFIG_3); + rf->mp_reg_aneg_config = r; + rf->mp_fld_aneg_config_enable = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_ENABLE); + rf->mp_fld_aneg_config_bypass = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_BYPASS); + rf->mp_fld_aneg_config_restart = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_RESTART); + rf->mp_fld_aneg_config_pseudo = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_PSEUDO); + rf->mp_fld_aneg_config_nonce_seed = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_NONCE_SEED); + rf->mp_fld_aneg_config_remote_fault = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_REMOTE_FAULT); + rf->mp_fld_aneg_config_pause = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_PAUSE); + rf->mp_fld_aneg_config_asmdir = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_ASMDIR); + rf->mp_fld_aneg_config_fec74_request10_g = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_FEC74_REQUEST_10G); + rf->mp_fld_aneg_config_hide_fec74 = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_HIDE_FEC74); + rf->mp_fld_aneg_config_fec74_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_FEC74_REQUEST); + rf->mp_fld_aneg_config_fec91_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_FEC91_REQUEST); + rf->mp_fld_aneg_config_fec91_ability = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_FEC91_ABILITY); + rf->mp_fld_aneg_config_rs_fec_request = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_RS_FEC_REQUEST); + rf->mp_fld_aneg_config_sw_fec_overwrite = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_SW_FEC_OVERWRITE); + rf->mp_fld_aneg_config_sw_speed_overwrite = + get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_SW_SPEED_OVERWRITE); + + /* ANEG_ABILITY */ + r = get_register(module, MAC_PCS_XXV_ANEG_ABILITY_3); + rf->mp_reg_aneg_ability = r; + rf->mp_fld_aneg_ability25_g_base_cr = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_3_25GBASE_CR); + rf->mp_fld_aneg_ability25_g_base_crs = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_3_25GBASE_CR_S); + rf->mp_fld_aneg_ability25_g_base_cr1 = + get_field(r, MAC_PCS_XXV_ANEG_ABILITY_3_25GBASE_CR1); + + /* LT_CONF */ + r = get_register(module, MAC_PCS_XXV_LT_CONF_3); + rf->mp_reg_lt_conf = r; + rf->mp_fld_lt_conf_enable = + get_field(r, MAC_PCS_XXV_LT_CONF_3_ENABLE); + rf->mp_fld_lt_conf_restart = + get_field(r, MAC_PCS_XXV_LT_CONF_3_RESTART); + rf->mp_fld_lt_conf_seed = get_field(r, MAC_PCS_XXV_LT_CONF_3_SEED); + } + + /* + * Registers MAC_PCS_XXV_SUB_RST_0 -- MAC_PCS_XXV_SUB_RST_3 + * and MAC_PCS_XXV_SUB_RST_STATUS_0 -- MAC_PCS_XXV_SUB_RST_STATUS_3 + */ + if (n_channels < 4) { + /* Initialize regs/fields for sub-module/channel 0 */ + rf = &p->regs[0]; + r = get_register(module, MAC_PCS_XXV_SUB_RST_0); + + rf->mp_reg_sub_rst = r; + rf->mp_fld_sub_rst_rx_mac_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_MAC_PCS); + rf->mp_fld_sub_rst_tx_mac_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_0_TX_MAC_PCS); + rf->mp_fld_sub_rst_rx_gt_data = + get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_GT_DATA); + rf->mp_fld_sub_rst_tx_gt_data = + get_field(r, MAC_PCS_XXV_SUB_RST_0_TX_GT_DATA); + rf->mp_fld_sub_rst_rx_buf = + get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_BUF); + rf->mp_fld_sub_rst_rx_pma = + get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_PMA); + rf->mp_fld_sub_rst_tx_pma = + get_field(r, MAC_PCS_XXV_SUB_RST_0_TX_PMA); + rf->mp_fld_sub_rst_rx_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_PCS); + rf->mp_fld_sub_rst_tx_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_0_TX_PCS); + rf->mp_fld_sub_rst_an_lt = get_field(r, MAC_PCS_XXV_SUB_RST_0_AN_LT); + rf->mp_fld_sub_rst_speed_ctrl = + query_field(r, MAC_PCS_XXV_SUB_RST_0_SPEED_CTRL); + + r = get_register(module, MAC_PCS_XXV_SUB_RST_STATUS_0); + rf->mp_reg_sub_rst_status = r; + rf->mp_fld_sub_rst_status_user_rx_rst = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_0_USER_RX_RST); + rf->mp_fld_sub_rst_status_user_tx_rst = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_0_USER_TX_RST); + rf->mp_fld_sub_rst_status_qpll_lock = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_0_QPLL_LOCK); + } + + if (n_channels >= 2) { + /* Initialize regs/fields for sub-module/channel 1 */ + rf = &p->regs[1]; + r = get_register(module, MAC_PCS_XXV_SUB_RST_1); + + rf->mp_reg_sub_rst = r; + rf->mp_fld_sub_rst_rx_mac_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_MAC_PCS); + rf->mp_fld_sub_rst_tx_mac_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_1_TX_MAC_PCS); + rf->mp_fld_sub_rst_rx_gt_data = + get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_GT_DATA); + rf->mp_fld_sub_rst_tx_gt_data = + get_field(r, MAC_PCS_XXV_SUB_RST_1_TX_GT_DATA); + rf->mp_fld_sub_rst_rx_buf = + get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_BUF); + rf->mp_fld_sub_rst_rx_pma = + get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_PMA); + rf->mp_fld_sub_rst_tx_pma = + get_field(r, MAC_PCS_XXV_SUB_RST_1_TX_PMA); + rf->mp_fld_sub_rst_rx_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_PCS); + rf->mp_fld_sub_rst_tx_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_1_TX_PCS); + rf->mp_fld_sub_rst_an_lt = get_field(r, MAC_PCS_XXV_SUB_RST_1_AN_LT); + rf->mp_fld_sub_rst_speed_ctrl = + query_field(r, MAC_PCS_XXV_SUB_RST_1_SPEED_CTRL); + + r = get_register(module, MAC_PCS_XXV_SUB_RST_STATUS_1); + rf->mp_reg_sub_rst_status = r; + rf->mp_fld_sub_rst_status_user_rx_rst = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_1_USER_RX_RST); + rf->mp_fld_sub_rst_status_user_tx_rst = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_1_USER_TX_RST); + rf->mp_fld_sub_rst_status_qpll_lock = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_1_QPLL_LOCK); + } + + if (n_channels == 4) { + /* Initialize regs/fields for sub-module/channel 2 */ + rf = &p->regs[2]; + r = get_register(module, MAC_PCS_XXV_SUB_RST_2); + + rf->mp_reg_sub_rst = r; + rf->mp_fld_sub_rst_rx_mac_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_MAC_PCS); + rf->mp_fld_sub_rst_tx_mac_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_2_TX_MAC_PCS); + rf->mp_fld_sub_rst_rx_gt_data = + get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_GT_DATA); + rf->mp_fld_sub_rst_tx_gt_data = + get_field(r, MAC_PCS_XXV_SUB_RST_2_TX_GT_DATA); + rf->mp_fld_sub_rst_rx_buf = + get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_BUF); + rf->mp_fld_sub_rst_rx_pma = + get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_PMA); + rf->mp_fld_sub_rst_tx_pma = + get_field(r, MAC_PCS_XXV_SUB_RST_2_TX_PMA); + rf->mp_fld_sub_rst_rx_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_PCS); + rf->mp_fld_sub_rst_tx_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_2_TX_PCS); + rf->mp_fld_sub_rst_an_lt = get_field(r, MAC_PCS_XXV_SUB_RST_2_AN_LT); + rf->mp_fld_sub_rst_speed_ctrl = + query_field(r, MAC_PCS_XXV_SUB_RST_2_SPEED_CTRL); + + r = get_register(module, MAC_PCS_XXV_SUB_RST_STATUS_2); + rf->mp_reg_sub_rst_status = r; + rf->mp_fld_sub_rst_status_user_rx_rst = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_2_USER_RX_RST); + rf->mp_fld_sub_rst_status_user_tx_rst = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_2_USER_TX_RST); + rf->mp_fld_sub_rst_status_qpll_lock = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_2_QPLL_LOCK); + + /* Initialize regs/fields for sub-module/channel 3 */ + rf = &p->regs[3]; + r = get_register(module, MAC_PCS_XXV_SUB_RST_3); + + rf->mp_reg_sub_rst = r; + rf->mp_fld_sub_rst_rx_mac_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_MAC_PCS); + rf->mp_fld_sub_rst_tx_mac_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_3_TX_MAC_PCS); + rf->mp_fld_sub_rst_rx_gt_data = + get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_GT_DATA); + rf->mp_fld_sub_rst_tx_gt_data = + get_field(r, MAC_PCS_XXV_SUB_RST_3_TX_GT_DATA); + rf->mp_fld_sub_rst_rx_buf = + get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_BUF); + rf->mp_fld_sub_rst_rx_pma = + get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_PMA); + rf->mp_fld_sub_rst_tx_pma = + get_field(r, MAC_PCS_XXV_SUB_RST_3_TX_PMA); + rf->mp_fld_sub_rst_rx_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_PCS); + rf->mp_fld_sub_rst_tx_pcs = + get_field(r, MAC_PCS_XXV_SUB_RST_3_TX_PCS); + rf->mp_fld_sub_rst_an_lt = get_field(r, MAC_PCS_XXV_SUB_RST_3_AN_LT); + rf->mp_fld_sub_rst_speed_ctrl = + query_field(r, MAC_PCS_XXV_SUB_RST_3_SPEED_CTRL); + + r = get_register(module, MAC_PCS_XXV_SUB_RST_STATUS_3); + rf->mp_reg_sub_rst_status = r; + rf->mp_fld_sub_rst_status_user_rx_rst = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_3_USER_RX_RST); + rf->mp_fld_sub_rst_status_user_tx_rst = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_3_USER_TX_RST); + rf->mp_fld_sub_rst_status_qpll_lock = + get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_3_QPLL_LOCK); + } + + /* Registers MAC_PCS_XXV_LINK_SUMMARY_0 -- MAC_PCS_XXV_LINK_SUMMARY_3 */ + if (n_channels < 4) { + /* Initialize regs/fields for sub-module/channel 0 */ + rf = &p->regs[0]; + r = get_register(module, MAC_PCS_XXV_LINK_SUMMARY_0); + + rf->mp_reg_link_summary = r; + rf->mp_fld_link_summary_nt_phy_link_state = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_NT_PHY_LINK_STATE); + rf->mp_fld_link_summary_ll_nt_phy_link_state = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LL_PHY_LINK_STATE); + rf->mp_fld_link_summary_abs = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_ABS); + rf->mp_fld_link_summary_lh_abs = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_ABS); + rf->mp_fld_link_summary_link_down_cnt = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LINK_DOWN_CNT); + if (!m_mac8x10_g) { + rf->mp_fld_link_summary_ll_rx_fec74_lock = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LL_RX_FEC74_LOCK); + rf->mp_fld_link_summary_lh_rx_rsfec_hi_ser = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_RX_RSFEC_HI_SER); + rf->mp_fld_link_summary_ll_rx_rsfec_lane_alignment = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LL_RX_RSFEC_LANE_ALIGNMENT); + rf->mp_fld_link_summary_ll_tx_rsfec_lane_alignment = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LL_TX_RSFEC_LANE_ALIGNMENT); + rf->mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_RX_PCS_VALID_CTRL_CODE); + } + rf->mp_fld_link_summary_ll_rx_block_lock = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LL_RX_BLOCK_LOCK); + rf->mp_fld_link_summary_lh_rx_high_bit_error_rate = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_RX_HIGH_BIT_ERROR_RATE); + ; + rf->mp_fld_link_summary_lh_internal_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_INTERNAL_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_received_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_RECEIVED_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_remote_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_REMOTE_FAULT); + rf->mp_fld_link_summary_nim_interr = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_NIM_INTERR); + } + + if (n_channels >= 2) { + /* Initialize regs/fields for sub-module/channel 1 */ + rf = &p->regs[1]; + r = get_register(module, MAC_PCS_XXV_LINK_SUMMARY_1); + + rf->mp_reg_link_summary = r; + rf->mp_fld_link_summary_nt_phy_link_state = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_NT_PHY_LINK_STATE); + rf->mp_fld_link_summary_ll_nt_phy_link_state = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LL_PHY_LINK_STATE); + rf->mp_fld_link_summary_abs = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_ABS); + rf->mp_fld_link_summary_lh_abs = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_ABS); + rf->mp_fld_link_summary_link_down_cnt = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LINK_DOWN_CNT); + if (!m_mac8x10_g) { + rf->mp_fld_link_summary_ll_rx_fec74_lock = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LL_RX_FEC74_LOCK); + rf->mp_fld_link_summary_lh_rx_rsfec_hi_ser = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_RX_RSFEC_HI_SER); + rf->mp_fld_link_summary_ll_rx_rsfec_lane_alignment = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LL_RX_RSFEC_LANE_ALIGNMENT); + rf->mp_fld_link_summary_ll_tx_rsfec_lane_alignment = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LL_TX_RSFEC_LANE_ALIGNMENT); + rf->mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_RX_PCS_VALID_CTRL_CODE); + } + rf->mp_fld_link_summary_ll_rx_block_lock = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LL_RX_BLOCK_LOCK); + rf->mp_fld_link_summary_lh_rx_high_bit_error_rate = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_RX_HIGH_BIT_ERROR_RATE); + ; + rf->mp_fld_link_summary_lh_internal_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_INTERNAL_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_received_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_RECEIVED_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_remote_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_REMOTE_FAULT); + rf->mp_fld_link_summary_nim_interr = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_NIM_INTERR); + } + + if (n_channels == 4) { + /* Initialize regs/fields for sub-module/channel 2 */ + rf = &p->regs[2]; + r = get_register(module, MAC_PCS_XXV_LINK_SUMMARY_2); + + rf->mp_reg_link_summary = r; + rf->mp_fld_link_summary_nt_phy_link_state = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_NT_PHY_LINK_STATE); + rf->mp_fld_link_summary_ll_nt_phy_link_state = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LL_PHY_LINK_STATE); + rf->mp_fld_link_summary_abs = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_ABS); + rf->mp_fld_link_summary_lh_abs = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_ABS); + rf->mp_fld_link_summary_link_down_cnt = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LINK_DOWN_CNT); + if (!m_mac8x10_g) { + rf->mp_fld_link_summary_ll_rx_fec74_lock = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LL_RX_FEC74_LOCK); + rf->mp_fld_link_summary_lh_rx_rsfec_hi_ser = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_RX_RSFEC_HI_SER); + rf->mp_fld_link_summary_ll_rx_rsfec_lane_alignment = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LL_RX_RSFEC_LANE_ALIGNMENT); + rf->mp_fld_link_summary_ll_tx_rsfec_lane_alignment = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LL_TX_RSFEC_LANE_ALIGNMENT); + rf->mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_RX_PCS_VALID_CTRL_CODE); + } + rf->mp_fld_link_summary_ll_rx_block_lock = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LL_RX_BLOCK_LOCK); + rf->mp_fld_link_summary_lh_rx_high_bit_error_rate = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_RX_HIGH_BIT_ERROR_RATE); + ; + rf->mp_fld_link_summary_lh_internal_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_INTERNAL_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_received_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_RECEIVED_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_remote_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_REMOTE_FAULT); + rf->mp_fld_link_summary_nim_interr = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_NIM_INTERR); + + /* Initialize regs/fields for sub-module/channel 3 */ + rf = &p->regs[3]; + r = get_register(module, MAC_PCS_XXV_LINK_SUMMARY_3); + + rf->mp_reg_link_summary = r; + rf->mp_fld_link_summary_nt_phy_link_state = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_NT_PHY_LINK_STATE); + rf->mp_fld_link_summary_ll_nt_phy_link_state = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LL_PHY_LINK_STATE); + rf->mp_fld_link_summary_abs = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_ABS); + rf->mp_fld_link_summary_lh_abs = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_ABS); + rf->mp_fld_link_summary_link_down_cnt = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LINK_DOWN_CNT); + if (!m_mac8x10_g) { + rf->mp_fld_link_summary_ll_rx_fec74_lock = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LL_RX_FEC74_LOCK); + rf->mp_fld_link_summary_lh_rx_rsfec_hi_ser = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_RX_RSFEC_HI_SER); + rf->mp_fld_link_summary_ll_rx_rsfec_lane_alignment = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LL_RX_RSFEC_LANE_ALIGNMENT); + rf->mp_fld_link_summary_ll_tx_rsfec_lane_alignment = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LL_TX_RSFEC_LANE_ALIGNMENT); + rf->mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_RX_PCS_VALID_CTRL_CODE); + } + rf->mp_fld_link_summary_ll_rx_block_lock = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LL_RX_BLOCK_LOCK); + rf->mp_fld_link_summary_lh_rx_high_bit_error_rate = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_RX_HIGH_BIT_ERROR_RATE); + ; + rf->mp_fld_link_summary_lh_internal_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_INTERNAL_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_received_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_RECEIVED_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_local_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_LOCAL_FAULT); + rf->mp_fld_link_summary_lh_remote_fault = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_REMOTE_FAULT); + rf->mp_fld_link_summary_nim_interr = + get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_NIM_INTERR); + } + + /* + * Registers MAC_PCS_XXV_GTY_LOOP_0 -- MAC_PCS_XXV_GTY_LOOP_3 + * and MAC_PCS_XXV_GTY_CTL_RX_0 -- MAC_PCS_XXV_GTY_CTL_RX_3 + * and MAC_PCS_XXV_GTY_CTL_TX_0 -- MAC_PCS_XXV_GTY_CTL_TX_3 + * and MAC_PCS_XXV_LINK_SPEED_0 -- MAC_PCS_XXV_LINK_SPEED_3 + * and MAC_PCS_XXV_RS_FEC_CONF_0 -- MAC_PCS_XXV_RS_FEC_CONF_0 + */ + if (n_channels < 4) { + /* Initialize regs/fields for sub-module/channel 0 */ + rf = &p->regs[0]; + + r = get_register(module, MAC_PCS_XXV_GTY_LOOP_0); + rf->mp_reg_gty_loop = r; + rf->mp_fld_gty_loop_gt_loop = + get_field(r, MAC_PCS_XXV_GTY_LOOP_0_GT_LOOP); + + r = get_register(module, MAC_PCS_XXV_GTY_CTL_RX_0); + rf->mp_reg_gty_ctl_rx = r; + rf->mp_fld_gty_ctl_rx_polarity = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_0_POLARITY); + rf->mp_fld_gty_ctl_rx_lpm_en = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_0_LPM_EN); + rf->mp_fld_gty_ctl_rx_equa_rst = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_0_EQUA_RST); + + r = get_register(module, MAC_PCS_XXV_GTY_CTL_TX_0); + rf->mp_fld_gty_ctl_tx_polarity = + get_field(r, MAC_PCS_XXV_GTY_CTL_TX_0_POLARITY); + rf->mp_fld_gty_ctl_tx_inhibit = + get_field(r, MAC_PCS_XXV_GTY_CTL_TX_0_INHIBIT); + + if (!m_mac8x10_g) { + r = get_register(module, MAC_PCS_XXV_LINK_SPEED_0); + rf->mp_reg_link_speed = + get_register(module, MAC_PCS_XXV_LINK_SPEED_0); + + rf->mp_fld_link_speed10_g = + query_field(r, MAC_PCS_XXV_LINK_SPEED_0_SPEED); + if (!rf->mp_fld_link_speed10_g) { + rf->mp_fld_link_speed10_g = + get_field(r, MAC_PCS_XXV_LINK_SPEED_0_10G); + } + + rf->mp_fld_link_speed_toggle = + get_field(r, MAC_PCS_XXV_LINK_SPEED_0_TOGGLE); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_CONF_0); + rf->mp_reg_rs_fec_conf = r; + rf->mp_fld_rs_fec_conf_rs_fec_enable = + get_field(r, MAC_PCS_XXV_RS_FEC_CONF_0_RS_FEC_ENABLE); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_CCW_CNT_0); + rf->mp_reg_rs_fec_ccw = r; + rf->mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt = + get_field(r, MAC_PCS_XXV_RS_FEC_CCW_CNT_0_RS_FEC_CCW_CNT); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_UCW_CNT_0); + rf->mp_reg_rs_fec_ucw = r; + rf->mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt = + get_field(r, MAC_PCS_XXV_RS_FEC_UCW_CNT_0_RS_FEC_UCW_CNT); + } + } + + if (n_channels >= 2) { + /* Initialize regs/fields for sub-module/channel 1 */ + rf = &p->regs[1]; + + r = get_register(module, MAC_PCS_XXV_GTY_LOOP_1); + rf->mp_reg_gty_loop = r; + rf->mp_fld_gty_loop_gt_loop = + get_field(r, MAC_PCS_XXV_GTY_LOOP_1_GT_LOOP); + + r = get_register(module, MAC_PCS_XXV_GTY_CTL_RX_1); + rf->mp_reg_gty_ctl_rx = r; + rf->mp_fld_gty_ctl_rx_polarity = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_1_POLARITY); + rf->mp_fld_gty_ctl_rx_lpm_en = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_1_LPM_EN); + rf->mp_fld_gty_ctl_rx_equa_rst = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_1_EQUA_RST); + + r = get_register(module, MAC_PCS_XXV_GTY_CTL_TX_1); + rf->mp_fld_gty_ctl_tx_polarity = + get_field(r, MAC_PCS_XXV_GTY_CTL_TX_1_POLARITY); + rf->mp_fld_gty_ctl_tx_inhibit = + get_field(r, MAC_PCS_XXV_GTY_CTL_TX_1_INHIBIT); + + if (!m_mac8x10_g) { + r = get_register(module, MAC_PCS_XXV_LINK_SPEED_1); + rf->mp_reg_link_speed = + get_register(module, MAC_PCS_XXV_LINK_SPEED_1); + + rf->mp_fld_link_speed10_g = + get_field(r, MAC_PCS_XXV_LINK_SPEED_1_SPEED); + if (!rf->mp_fld_link_speed10_g) { + rf->mp_fld_link_speed10_g = + get_field(r, MAC_PCS_XXV_LINK_SPEED_1_10G); + } + rf->mp_fld_link_speed_toggle = + get_field(r, MAC_PCS_XXV_LINK_SPEED_1_TOGGLE); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_CONF_1); + rf->mp_reg_rs_fec_conf = r; + rf->mp_fld_rs_fec_conf_rs_fec_enable = + get_field(r, MAC_PCS_XXV_RS_FEC_CONF_1_RS_FEC_ENABLE); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_CCW_CNT_1); + rf->mp_reg_rs_fec_ccw = r; + rf->mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt = + get_field(r, MAC_PCS_XXV_RS_FEC_CCW_CNT_1_RS_FEC_CCW_CNT); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_UCW_CNT_1); + rf->mp_reg_rs_fec_ucw = r; + rf->mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt = + get_field(r, MAC_PCS_XXV_RS_FEC_UCW_CNT_1_RS_FEC_UCW_CNT); + } + } + + if (n_channels == 4) { + /* Initialize regs/fields for sub-module/channel 2 */ + rf = &p->regs[2]; + + r = get_register(module, MAC_PCS_XXV_GTY_LOOP_2); + rf->mp_reg_gty_loop = r; + rf->mp_fld_gty_loop_gt_loop = + get_field(r, MAC_PCS_XXV_GTY_LOOP_2_GT_LOOP); + + r = get_register(module, MAC_PCS_XXV_GTY_CTL_RX_2); + rf->mp_reg_gty_ctl_rx = r; + rf->mp_fld_gty_ctl_rx_polarity = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_2_POLARITY); + rf->mp_fld_gty_ctl_rx_lpm_en = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_2_LPM_EN); + rf->mp_fld_gty_ctl_rx_equa_rst = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_2_EQUA_RST); + + r = get_register(module, MAC_PCS_XXV_GTY_CTL_TX_2); + rf->mp_fld_gty_ctl_tx_polarity = + get_field(r, MAC_PCS_XXV_GTY_CTL_TX_2_POLARITY); + rf->mp_fld_gty_ctl_tx_inhibit = + get_field(r, MAC_PCS_XXV_GTY_CTL_TX_2_INHIBIT); + + if (!m_mac8x10_g) { + r = get_register(module, MAC_PCS_XXV_LINK_SPEED_2); + rf->mp_reg_link_speed = + get_register(module, MAC_PCS_XXV_LINK_SPEED_2); + + rf->mp_fld_link_speed10_g = + get_field(r, MAC_PCS_XXV_LINK_SPEED_2_SPEED); + if (!rf->mp_fld_link_speed10_g) { + rf->mp_fld_link_speed10_g = + get_field(r, MAC_PCS_XXV_LINK_SPEED_2_10G); + } + + rf->mp_fld_link_speed_toggle = + get_field(r, MAC_PCS_XXV_LINK_SPEED_2_TOGGLE); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_CONF_2); + rf->mp_reg_rs_fec_conf = r; + rf->mp_fld_rs_fec_conf_rs_fec_enable = + get_field(r, MAC_PCS_XXV_RS_FEC_CONF_2_RS_FEC_ENABLE); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_CCW_CNT_2); + rf->mp_reg_rs_fec_ccw = r; + rf->mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt = + get_field(r, MAC_PCS_XXV_RS_FEC_CCW_CNT_2_RS_FEC_CCW_CNT); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_UCW_CNT_2); + rf->mp_reg_rs_fec_ucw = r; + rf->mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt = + get_field(r, MAC_PCS_XXV_RS_FEC_UCW_CNT_2_RS_FEC_UCW_CNT); + } + + /* Initialize regs/fields for sub-module/channel 3 */ + rf = &p->regs[3]; + + r = get_register(module, MAC_PCS_XXV_GTY_LOOP_3); + rf->mp_reg_gty_loop = r; + rf->mp_fld_gty_loop_gt_loop = + get_field(r, MAC_PCS_XXV_GTY_LOOP_3_GT_LOOP); + + r = get_register(module, MAC_PCS_XXV_GTY_CTL_RX_3); + rf->mp_reg_gty_ctl_rx = r; + rf->mp_fld_gty_ctl_rx_polarity = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_3_POLARITY); + rf->mp_fld_gty_ctl_rx_lpm_en = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_3_LPM_EN); + rf->mp_fld_gty_ctl_rx_equa_rst = + get_field(r, MAC_PCS_XXV_GTY_CTL_RX_3_EQUA_RST); + + r = get_register(module, MAC_PCS_XXV_GTY_CTL_TX_3); + rf->mp_fld_gty_ctl_tx_polarity = + get_field(r, MAC_PCS_XXV_GTY_CTL_TX_3_POLARITY); + rf->mp_fld_gty_ctl_tx_inhibit = + get_field(r, MAC_PCS_XXV_GTY_CTL_TX_3_INHIBIT); + + if (!m_mac8x10_g) { + r = get_register(module, MAC_PCS_XXV_LINK_SPEED_3); + rf->mp_reg_link_speed = + get_register(module, MAC_PCS_XXV_LINK_SPEED_3); + + rf->mp_fld_link_speed10_g = + get_field(r, MAC_PCS_XXV_LINK_SPEED_3_SPEED); + if (!rf->mp_fld_link_speed10_g) { + rf->mp_fld_link_speed10_g = + get_field(r, MAC_PCS_XXV_LINK_SPEED_3_10G); + } + rf->mp_fld_link_speed_toggle = + get_field(r, MAC_PCS_XXV_LINK_SPEED_3_TOGGLE); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_CONF_3); + rf->mp_reg_rs_fec_conf = r; + rf->mp_fld_rs_fec_conf_rs_fec_enable = + get_field(r, MAC_PCS_XXV_RS_FEC_CONF_3_RS_FEC_ENABLE); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_CCW_CNT_3); + rf->mp_reg_rs_fec_ccw = r; + rf->mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt = + get_field(r, MAC_PCS_XXV_RS_FEC_CCW_CNT_3_RS_FEC_CCW_CNT); + + r = get_register(module, MAC_PCS_XXV_RS_FEC_UCW_CNT_3); + rf->mp_reg_rs_fec_ucw = r; + rf->mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt = + get_field(r, MAC_PCS_XXV_RS_FEC_UCW_CNT_3_RS_FEC_UCW_CNT); + } + } + + /* + * Registers MAC_PCS_XXV_DEBOUNCE_CTRL_0 -- MAC_PCS_XXV_DEBOUNCE_CTRL_3 + * and MAC_PCS_XXV_TIMESTAMP_COMP_0 -- MAC_PCS_XXV_TIMESTAMP_COMP_3 + * and MAC_PCS_XXV_GTY_PRE_CURSOR_0 -- MAC_PCS_XXV_GTY_PRE_CURSOR_3 + * and MAC_PCS_XXV_GTY_DIFF_CTL_0 -- MAC_PCS_XXV_GTY_DIFF_CTL_0 + * and MAC_PCS_XXV_GTY_POST_CURSOR_0 -- MAC_PCS_XXV_GTY_POST_CURSOR_3 + */ + if (n_channels < 4) { + /* Initialize regs/fields for sub-module/channel 0 */ + rf = &p->regs[0]; + + r = get_register(module, MAC_PCS_XXV_DEBOUNCE_CTRL_0); + + rf->mp_reg_debounce_ctrl = r; + rf->mp_field_debounce_ctrl_nt_port_ctrl = + get_field(r, MAC_PCS_XXV_DEBOUNCE_CTRL_0_NT_PORT_CTRL); + + r = get_register(module, MAC_PCS_XXV_TIMESTAMP_COMP_0); + rf->mp_reg_timestamp_comp = r; + rf->mp_field_timestamp_comp_rx_dly = + get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_0_RX_DLY); + rf->mp_field_timestamp_comp_tx_dly = + get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_0_TX_DLY); + + /* GTY_PRE_CURSOR */ + r = get_register(p->mp_mod_mac_pcs_xxv, + MAC_PCS_XXV_GTY_PRE_CURSOR_0); + rf->mp_reg_gty_pre_cursor = r; + rf->mp_field_gty_pre_cursor_tx_pre_csr = + get_field(r, MAC_PCS_XXV_GTY_PRE_CURSOR_0_TX_PRE_CSR); + + /* GTY_DIFF_CTL */ + r = get_register(module, MAC_PCS_XXV_GTY_DIFF_CTL_0); + rf->mp_reg_gty_diff_ctl = r; + rf->mp_field_gty_gty_diff_ctl_tx_diff_ctl = + get_field(r, MAC_PCS_XXV_GTY_DIFF_CTL_0_TX_DIFF_CTL); + + /* GTY_POST_CURSOR */ + r = get_register(module, MAC_PCS_XXV_GTY_POST_CURSOR_0); + rf->mp_reg_gty_post_cursor = r; + rf->mp_field_gty_post_cursor_tx_post_csr = + get_field(r, MAC_PCS_XXV_GTY_POST_CURSOR_0_TX_POST_CSR); + } + + if (n_channels >= 2) { + /* Initialize regs/fields for sub-module/channel 1 */ + rf = &p->regs[1]; + + r = get_register(module, MAC_PCS_XXV_DEBOUNCE_CTRL_1); + + rf->mp_reg_debounce_ctrl = r; + rf->mp_field_debounce_ctrl_nt_port_ctrl = + get_field(r, MAC_PCS_XXV_DEBOUNCE_CTRL_1_NT_PORT_CTRL); + + r = get_register(module, MAC_PCS_XXV_TIMESTAMP_COMP_1); + rf->mp_reg_timestamp_comp = r; + rf->mp_field_timestamp_comp_rx_dly = + get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_1_RX_DLY); + rf->mp_field_timestamp_comp_tx_dly = + get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_1_TX_DLY); + + /* GTY_PRE_CURSOR */ + r = get_register(p->mp_mod_mac_pcs_xxv, + MAC_PCS_XXV_GTY_PRE_CURSOR_1); + rf->mp_reg_gty_pre_cursor = r; + rf->mp_field_gty_pre_cursor_tx_pre_csr = + get_field(r, MAC_PCS_XXV_GTY_PRE_CURSOR_1_TX_PRE_CSR); + + /* GTY_DIFF_CTL */ + r = get_register(module, MAC_PCS_XXV_GTY_DIFF_CTL_1); + rf->mp_reg_gty_diff_ctl = r; + rf->mp_field_gty_gty_diff_ctl_tx_diff_ctl = + get_field(r, MAC_PCS_XXV_GTY_DIFF_CTL_1_TX_DIFF_CTL); + + /* GTY_POST_CURSOR */ + r = get_register(module, MAC_PCS_XXV_GTY_POST_CURSOR_1); + rf->mp_reg_gty_post_cursor = r; + rf->mp_field_gty_post_cursor_tx_post_csr = + get_field(r, MAC_PCS_XXV_GTY_POST_CURSOR_1_TX_POST_CSR); + } + + if (n_channels == 4) { + /* Initialize regs/fields for sub-module/channel 2 */ + rf = &p->regs[2]; + + r = get_register(module, MAC_PCS_XXV_DEBOUNCE_CTRL_2); + + rf->mp_reg_debounce_ctrl = r; + rf->mp_field_debounce_ctrl_nt_port_ctrl = + get_field(r, MAC_PCS_XXV_DEBOUNCE_CTRL_2_NT_PORT_CTRL); + + r = get_register(module, MAC_PCS_XXV_TIMESTAMP_COMP_2); + rf->mp_reg_timestamp_comp = r; + rf->mp_field_timestamp_comp_rx_dly = + get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_2_RX_DLY); + rf->mp_field_timestamp_comp_tx_dly = + get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_2_TX_DLY); + + /* GTY_PRE_CURSOR */ + r = get_register(p->mp_mod_mac_pcs_xxv, + MAC_PCS_XXV_GTY_PRE_CURSOR_2); + rf->mp_reg_gty_pre_cursor = r; + rf->mp_field_gty_pre_cursor_tx_pre_csr = + get_field(r, MAC_PCS_XXV_GTY_PRE_CURSOR_2_TX_PRE_CSR); + + /* GTY_DIFF_CTL */ + r = get_register(module, MAC_PCS_XXV_GTY_DIFF_CTL_2); + rf->mp_reg_gty_diff_ctl = r; + rf->mp_field_gty_gty_diff_ctl_tx_diff_ctl = + get_field(r, MAC_PCS_XXV_GTY_DIFF_CTL_2_TX_DIFF_CTL); + + /* GTY_POST_CURSOR */ + r = get_register(module, MAC_PCS_XXV_GTY_POST_CURSOR_2); + rf->mp_reg_gty_post_cursor = r; + rf->mp_field_gty_post_cursor_tx_post_csr = + get_field(r, MAC_PCS_XXV_GTY_POST_CURSOR_2_TX_POST_CSR); + + /* Initialize regs/fields for sub-module/channel 3 */ + rf = &p->regs[3]; + + r = get_register(module, MAC_PCS_XXV_DEBOUNCE_CTRL_3); + + rf->mp_reg_debounce_ctrl = r; + rf->mp_field_debounce_ctrl_nt_port_ctrl = + get_field(r, MAC_PCS_XXV_DEBOUNCE_CTRL_3_NT_PORT_CTRL); + + r = get_register(module, MAC_PCS_XXV_TIMESTAMP_COMP_3); + rf->mp_reg_timestamp_comp = r; + rf->mp_field_timestamp_comp_rx_dly = + get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_3_RX_DLY); + rf->mp_field_timestamp_comp_tx_dly = + get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_3_TX_DLY); + + /* GTY_PRE_CURSOR */ + r = get_register(p->mp_mod_mac_pcs_xxv, + MAC_PCS_XXV_GTY_PRE_CURSOR_3); + rf->mp_reg_gty_pre_cursor = r; + rf->mp_field_gty_pre_cursor_tx_pre_csr = + get_field(r, MAC_PCS_XXV_GTY_PRE_CURSOR_3_TX_PRE_CSR); + + /* GTY_DIFF_CTL */ + r = get_register(module, MAC_PCS_XXV_GTY_DIFF_CTL_3); + rf->mp_reg_gty_diff_ctl = r; + rf->mp_field_gty_gty_diff_ctl_tx_diff_ctl = + get_field(r, MAC_PCS_XXV_GTY_DIFF_CTL_3_TX_DIFF_CTL); + + /* GTY_POST_CURSOR */ + r = get_register(module, MAC_PCS_XXV_GTY_POST_CURSOR_3); + rf->mp_reg_gty_post_cursor = r; + rf->mp_field_gty_post_cursor_tx_post_csr = + get_field(r, MAC_PCS_XXV_GTY_POST_CURSOR_3_TX_POST_CSR); + } + return 0; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.h b/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.h new file mode 100644 index 0000000000..5a38494f7e --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.h @@ -0,0 +1,291 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef NTHW_MAC_PCS_XXV_H_ +#define NTHW_MAC_PCS_XXV_H_ + +#include +#include +#include "nthw_fpga_model.h" + +enum nthw_mac_pcs_xxv_led_mode_e { + NTHW_MAC_PCS_XXV_LED_AUTO = 0x00, + NTHW_MAC_PCS_XXV_LED_ON = 0x01, + NTHW_MAC_PCS_XXV_LED_OFF = 0x02, + NTHW_MAC_PCS_XXV_LED_PORTID = 0x03, +}; + +enum nthw_mac_pcs_xxv_dac_mode_e { + NTHW_MAC_PCS_XXV_DAC_OFF = 0x00, + NTHW_MAC_PCS_XXV_DAC_CA_25G_N = 0x01, + NTHW_MAC_PCS_XXV_DAC_CA_25G_S = 0x02, + NTHW_MAC_PCS_XXV_DAC_CA_25G_L = 0x03, +}; + +struct nthw_mac_pcs_xxv { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_mac_pcs_xxv; + int mn_instance; + + uint8_t m_port_no; + +#define NTHW_MAC_PCS_XXV_NUM_ELEMS 4 + struct nthw_mac_pcs_xxv__registers_fields { + /* CORE_CONF */ + nt_register_t *mp_reg_core_conf; + nt_field_t *mp_fld_core_conf_rx_enable; + nt_field_t *mp_fld_core_conf_rx_force_resync; + nt_field_t *mp_fld_core_conf_tx_enable; + nt_field_t *mp_fld_core_conf_tx_ins_fcs; + nt_field_t *mp_fld_core_conf_tx_ign_fcs; + nt_field_t *mp_fld_core_conf_tx_send_lfi; + nt_field_t *mp_fld_core_conf_tx_send_rfi; + nt_field_t *mp_fld_core_conf_tx_send_idle; + nt_field_t *mp_fld_core_conf_inline_mode; + nt_field_t *mp_fld_core_conf_line_loopback; + nt_field_t *mp_fld_core_conf_ts_at_eop; + + /* ANEG_CONFIG */ + nt_register_t *mp_reg_aneg_config; + nt_field_t *mp_fld_aneg_config_enable; + nt_field_t *mp_fld_aneg_config_bypass; + nt_field_t *mp_fld_aneg_config_restart; + nt_field_t *mp_fld_aneg_config_pseudo; + nt_field_t *mp_fld_aneg_config_nonce_seed; + nt_field_t *mp_fld_aneg_config_remote_fault; + nt_field_t *mp_fld_aneg_config_pause; + nt_field_t *mp_fld_aneg_config_asmdir; + nt_field_t *mp_fld_aneg_config_fec74_request10_g; + nt_field_t *mp_fld_aneg_config_hide_fec74; + nt_field_t *mp_fld_aneg_config_fec74_request; + nt_field_t *mp_fld_aneg_config_fec91_request; + nt_field_t *mp_fld_aneg_config_fec91_ability; + nt_field_t *mp_fld_aneg_config_rs_fec_request; + nt_field_t *mp_fld_aneg_config_sw_fec_overwrite; + nt_field_t *mp_fld_aneg_config_sw_speed_overwrite; + + /* ANEG_ABILITY */ + nt_register_t *mp_reg_aneg_ability; + nt_field_t *mp_fld_aneg_ability25_g_base_cr; + nt_field_t *mp_fld_aneg_ability25_g_base_crs; + nt_field_t *mp_fld_aneg_ability25_g_base_cr1; + + /* LT_CONF */ + nt_register_t *mp_reg_lt_conf; + nt_field_t *mp_fld_lt_conf_enable; + nt_field_t *mp_fld_lt_conf_restart; + nt_field_t *mp_fld_lt_conf_seed; + + /* SUB_RST */ + nt_register_t *mp_reg_sub_rst; + nt_field_t *mp_fld_sub_rst_rx_mac_pcs; + nt_field_t *mp_fld_sub_rst_tx_mac_pcs; + nt_field_t *mp_fld_sub_rst_rx_gt_data; + nt_field_t *mp_fld_sub_rst_tx_gt_data; + nt_field_t *mp_fld_sub_rst_rx_buf; + nt_field_t *mp_fld_sub_rst_rx_pma; + nt_field_t *mp_fld_sub_rst_tx_pma; + nt_field_t *mp_fld_sub_rst_rx_pcs; + nt_field_t *mp_fld_sub_rst_tx_pcs; + nt_field_t *mp_fld_sub_rst_an_lt; + nt_field_t *mp_fld_sub_rst_speed_ctrl; + + /* SUB_RST_STATUS */ + nt_register_t *mp_reg_sub_rst_status; + nt_field_t *mp_fld_sub_rst_status_user_rx_rst; + nt_field_t *mp_fld_sub_rst_status_user_tx_rst; + nt_field_t *mp_fld_sub_rst_status_qpll_lock; + + /* LINK_SUMMARY */ + nt_register_t *mp_reg_link_summary; + nt_field_t *mp_fld_link_summary_nt_phy_link_state; + nt_field_t *mp_fld_link_summary_ll_nt_phy_link_state; + nt_field_t *mp_fld_link_summary_abs; + nt_field_t *mp_fld_link_summary_lh_abs; + nt_field_t *mp_fld_link_summary_link_down_cnt; + /* Begin 2 x 10/25 Gbps only fields: */ + nt_field_t *mp_fld_link_summary_ll_rx_fec74_lock; + nt_field_t *mp_fld_link_summary_lh_rx_rsfec_hi_ser; + nt_field_t *mp_fld_link_summary_ll_rx_rsfec_lane_alignment; + nt_field_t *mp_fld_link_summary_ll_tx_rsfec_lane_alignment; + nt_field_t *mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code; + /* End 2 x 10/25 Gbps only fields. */ + nt_field_t *mp_fld_link_summary_ll_rx_block_lock; + nt_field_t *mp_fld_link_summary_lh_rx_high_bit_error_rate; + nt_field_t *mp_fld_link_summary_lh_internal_local_fault; + nt_field_t *mp_fld_link_summary_lh_received_local_fault; + nt_field_t *mp_fld_link_summary_lh_local_fault; + nt_field_t *mp_fld_link_summary_lh_remote_fault; + nt_field_t *mp_fld_link_summary_lh_tx_local_fault; + nt_field_t *mp_fld_link_summary_nim_interr; + + /* GTY_LOOP */ + nt_register_t *mp_reg_gty_loop; + nt_field_t *mp_fld_gty_loop_gt_loop; + + /* GTY_CTL_RX */ + nt_register_t *mp_reg_gty_ctl_rx; + nt_field_t *mp_fld_gty_ctl_rx_polarity; + nt_field_t *mp_fld_gty_ctl_rx_lpm_en; + nt_field_t *mp_fld_gty_ctl_rx_equa_rst; + + /* GTY_CTL_TX */ + nt_register_t *mp_reg_gty_ctl_tx; + nt_field_t *mp_fld_gty_ctl_tx_polarity; + nt_field_t *mp_fld_gty_ctl_tx_inhibit; + + /* LINK_SPEED */ + nt_register_t *mp_reg_link_speed; + nt_field_t *mp_fld_link_speed10_g; + nt_field_t *mp_fld_link_speed_toggle; + + /* RS_FEC_CONF */ + nt_register_t *mp_reg_rs_fec_conf; + nt_field_t *mp_fld_rs_fec_conf_rs_fec_enable; + + /* DEBOUNCE_CTRL */ + nt_register_t *mp_reg_debounce_ctrl; + nt_field_t *mp_field_debounce_ctrl_nt_port_ctrl; + + /* FEC_CCW_CNT */ + nt_register_t *mp_reg_rs_fec_ccw; + nt_field_t *mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt; + + /* FEC_UCW_CNT */ + nt_register_t *mp_reg_rs_fec_ucw; + nt_field_t *mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt; + + /* TIMESTAMP_COMP */ + nt_register_t *mp_reg_timestamp_comp; + nt_field_t *mp_field_timestamp_comp_rx_dly; + nt_field_t *mp_field_timestamp_comp_tx_dly; + + /* GTY_PRE_CURSOR */ + nt_register_t *mp_reg_gty_pre_cursor; + nt_field_t *mp_field_gty_pre_cursor_tx_pre_csr; + + /* GTY_DIFF_CTL */ + nt_register_t *mp_reg_gty_diff_ctl; + nt_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl; + + /* GTY_POST_CURSOR */ + nt_register_t *mp_reg_gty_post_cursor; + nt_field_t *mp_field_gty_post_cursor_tx_post_csr; + } regs[NTHW_MAC_PCS_XXV_NUM_ELEMS]; +}; + +typedef struct nthw_mac_pcs_xxv nthw_mac_pcs_xxv_t; +typedef struct nthw_mac_pcs_xxv nthw_mac_pcs_xxv; + +nthw_mac_pcs_xxv_t *nthw_mac_pcs_xxv_new(void); +void nthw_mac_pcs_xxv_delete(nthw_mac_pcs_xxv_t *p); +int nthw_mac_pcs_xxv_init(nthw_mac_pcs_xxv_t *p, nt_fpga_t *p_fpga, int n_instance, + int n_channels); + +void nthw_mac_pcs_xxv_get_link_summary(nthw_mac_pcs_xxv_t *p, + uint32_t *p_abs, uint32_t *p_nt_phy_link_state, + uint32_t *p_lh_abs, uint32_t *p_ll_nt_phy_link_state, uint32_t *p_link_down_cnt, + uint32_t *p_nim_interr, uint32_t *p_lh_local_fault, uint32_t *p_lh_remote_fault, + uint32_t *p_lh_internal_local_fault, uint32_t *p_lh_received_local_fault, + uint8_t index); + +uint8_t nthw_mac_pcs_xxv_get_port_no(const nthw_mac_pcs_xxv_t *p, uint8_t index); + +void nthw_mac_pcs_xxv_set_port_no(nthw_mac_pcs_xxv_t *p, uint8_t port_no); + +void nthw_mac_pcs_xxv_set_tx_enable(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index); +void nthw_mac_pcs_xxv_set_rx_enable(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index); +void nthw_mac_pcs_xxv_rx_force_resync(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +void nthw_mac_pcs_xxv_reset_rx_gt_data(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_reset_tx_gt_data(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +void nthw_mac_pcs_xxv_reset_an_lt(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index); +void nthw_mac_pcs_xxv_reset_speed_ctrl(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +void nthw_mac_pcs_xxv_set_tx_send_rfi(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index); +void nthw_mac_pcs_xxv_set_tx_send_lfi(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index); +void nthw_mac_pcs_xxv_set_tx_send_lfi_tx_send_rfi(nthw_mac_pcs_xxv_t *p, bool enable_lfi, + bool enable_rfi, uint8_t index); + +bool nthw_mac_pcs_xxv_is_dfe_enabled(nthw_mac_pcs_xxv_t *p, uint8_t index); +void nthw_mac_pcs_xxv_set_dfe(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index); + +void nthw_mac_pcs_xxv_set_rx_gty_polarity(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_tx_gty_polarity(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +void nthw_mac_pcs_xxv_set_tx_gty_inhibit(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +void nthw_mac_pcs_xxv_set_host_loopback(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_line_loopback(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +bool nthw_mac_pcs_xxv_is_user_rx_rst(nthw_mac_pcs_xxv_t *p, uint8_t index); +bool nthw_mac_pcs_xxv_is_user_tx_rst(nthw_mac_pcs_xxv_t *p, uint8_t index); + +bool nthw_mac_pcs_xxv_is_qpll_lock(nthw_mac_pcs_xxv_t *p, uint8_t index); +bool nthw_mac_pcs_xxv_is_sub_rst_ready(nthw_mac_pcs_xxv_t *p, uint8_t index); +bool nthw_mac_pcs_xxv_is_aneg_enabled(nthw_mac_pcs_xxv_t *p, uint8_t index); + +void nthw_mac_pcs_xxv_set_tx_send_idle(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_tx_ins_fcs(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index); + +bool nthw_mac_pcs_xxv_get_link_speed10_g(nthw_mac_pcs_xxv_t *p, uint8_t index); +void nthw_mac_pcs_xxv_set_link_speed10_g(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_link_speed_toggle(nthw_mac_pcs_xxv_t *p, uint8_t index); + +void nthw_mac_pcs_xxv_set_rs_fec_conf_rs_fec_enable(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +void nthw_mac_pcs_xxv_set_led_mode(nthw_mac_pcs_xxv_t *p, uint8_t mode, uint8_t index); + +void nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_tx_mac_pcs_rst(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +void nthw_mac_pcs_xxv_reset_fec_counters(nthw_mac_pcs_xxv_t *p, uint8_t index); + +void nthw_mac_pcs_xxv_set_gty_diff(nthw_mac_pcs_xxv_t *p, uint8_t value, uint8_t index); +void nthw_mac_pcs_xxv_set_gty_pre(nthw_mac_pcs_xxv_t *p, uint8_t value, uint8_t index); +void nthw_mac_pcs_xxv_set_gty_post(nthw_mac_pcs_xxv_t *p, uint8_t value, uint8_t index); + +void nthw_mac_pcs_xxv_set_ts_at_eop(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index); + +void nthw_mac_pcs_xxv_set_aneg_config_enable(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_aneg_config_bypass(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_lt_conf_enable(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +void nthw_mac_pcs_xxv_set_dac_mode(nthw_mac_pcs_xxv_t *p, uint8_t dac_mode, + uint8_t index); + +void nthw_mac_pcs_xxv_set_timestamp_comp_rx(nthw_mac_pcs_xxv_t *p, uint16_t rx_dly, + uint8_t index); +void nthw_mac_pcs_xxv_set_timestamp_comp_tx(nthw_mac_pcs_xxv_t *p, uint16_t tx_dly, + uint8_t index); + +void nthw_mac_pcs_xxv_set_aneg_config_fec91_request(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_aneg_config_rs_fec_request(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); +void nthw_mac_pcs_xxv_set_aneg_config_fec74_request(nthw_mac_pcs_xxv_t *p, bool enable, + uint8_t index); + +bool nthw_mac_pcs_xxv_get_ll_rx_fec74_lock(nthw_mac_pcs_xxv_t *p, uint8_t index); +bool nthw_mac_pcs_xxv_get_ll_rx_rsfec_lane_alignment(nthw_mac_pcs_xxv_t *p, uint8_t index); + +#endif /* NTHW_MAC_PCS_XXV_H_ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.c b/drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.c new file mode 100644 index 0000000000..92089d2fa3 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.c @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_pci_rd_tg.h" + +nthw_pci_rd_tg_t *nthw_pci_rd_tg_new(void) +{ + nthw_pci_rd_tg_t *p = malloc(sizeof(nthw_pci_rd_tg_t)); + + if (p) + memset(p, 0, sizeof(nthw_pci_rd_tg_t)); + return p; +} + +void nthw_pci_rd_tg_delete(nthw_pci_rd_tg_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_pci_rd_tg_t)); + free(p); + } +} + +int nthw_pci_rd_tg_init(nthw_pci_rd_tg_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + nt_module_t *mod = fpga_query_module(p_fpga, MOD_PCI_RD_TG, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: PCI_RD_TG %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_pci_rd_tg = mod; + + p->mn_param_pci_ta_tg_present = + fpga_get_product_param(p_fpga, NT_PCI_TA_TG_PRESENT, 1); + + p->mp_reg_pci_rd_tg_rd_data0 = + module_get_register(p->mp_mod_pci_rd_tg, PCI_RD_TG_TG_RDDATA0); + p->mp_fld_pci_rd_tg_phys_addr_low = + register_get_field(p->mp_reg_pci_rd_tg_rd_data0, + PCI_RD_TG_TG_RDDATA0_PHYS_ADDR_LOW); + + p->mp_reg_pci_rd_tg_rd_data1 = + module_get_register(p->mp_mod_pci_rd_tg, PCI_RD_TG_TG_RDDATA1); + p->mp_fld_pci_rd_tg_phys_addr_high = + register_get_field(p->mp_reg_pci_rd_tg_rd_data1, + PCI_RD_TG_TG_RDDATA1_PHYS_ADDR_HIGH); + + p->mp_reg_pci_rd_tg_rd_data2 = + module_get_register(p->mp_mod_pci_rd_tg, PCI_RD_TG_TG_RDDATA2); + p->mp_fld_pci_rd_tg_req_size = + register_get_field(p->mp_reg_pci_rd_tg_rd_data2, PCI_RD_TG_TG_RDDATA2_REQ_SIZE); + p->mp_fld_pci_rd_tg_wait = + register_get_field(p->mp_reg_pci_rd_tg_rd_data2, PCI_RD_TG_TG_RDDATA2_WAIT); + p->mp_fld_pci_rd_tg_wrap = + register_get_field(p->mp_reg_pci_rd_tg_rd_data2, PCI_RD_TG_TG_RDDATA2_WRAP); + /* optional VF host id */ + p->mp_fld_pci_rd_tg_req_hid = + register_query_field(p->mp_reg_pci_rd_tg_rd_data2, PCI_RD_TG_TG_RDDATA2_REQ_HID); + + p->mp_reg_pci_rd_tg_rd_addr = + module_get_register(p->mp_mod_pci_rd_tg, PCI_RD_TG_TG_RDADDR); + p->mp_fld_pci_rd_tg_ram_addr = + register_get_field(p->mp_reg_pci_rd_tg_rd_addr, PCI_RD_TG_TG_RDADDR_RAM_ADDR); + + p->mp_reg_pci_rd_tg_rd_run = + module_get_register(p->mp_mod_pci_rd_tg, PCI_RD_TG_TG_RD_RUN); + p->mp_fld_pci_rd_tg_run_iteration = + register_get_field(p->mp_reg_pci_rd_tg_rd_run, PCI_RD_TG_TG_RD_RUN_RD_ITERATION); + + p->mp_reg_pci_rd_tg_rd_ctrl = + module_get_register(p->mp_mod_pci_rd_tg, PCI_RD_TG_TG_CTRL); + p->mp_fld_pci_rd_tg_ctrl_rdy = + register_get_field(p->mp_reg_pci_rd_tg_rd_ctrl, PCI_RD_TG_TG_CTRL_TG_RD_RDY); + + return 0; +} + +void nthw_pci_rd_tg_set_phys_addr(nthw_pci_rd_tg_t *p, uint64_t n_phys_addr) +{ + field_set_val_flush32(p->mp_fld_pci_rd_tg_phys_addr_low, + (uint32_t)(n_phys_addr & ((1UL << 32) - 1))); + field_set_val_flush32(p->mp_fld_pci_rd_tg_phys_addr_high, + (uint32_t)((n_phys_addr >> 32) & ((1UL << 32) - 1))); +} + +void nthw_pci_rd_tg_set_ram_addr(nthw_pci_rd_tg_t *p, int n_ram_addr) +{ + field_set_val_flush32(p->mp_fld_pci_rd_tg_ram_addr, n_ram_addr); +} + +void nthw_pci_rd_tg_set_ram_data(nthw_pci_rd_tg_t *p, uint32_t req_size, bool wait, + bool wrap) +{ + field_set_val32(p->mp_fld_pci_rd_tg_req_size, req_size); + field_set_val32(p->mp_fld_pci_rd_tg_wait, wait); + field_set_val32(p->mp_fld_pci_rd_tg_wrap, wrap); + field_flush_register(p->mp_fld_pci_rd_tg_wrap); +} + +void nthw_pci_rd_tg_set_run(nthw_pci_rd_tg_t *p, int n_iterations) +{ + field_set_val_flush32(p->mp_fld_pci_rd_tg_run_iteration, n_iterations); +} + +uint32_t nthw_pci_rd_tg_get_ctrl_rdy(nthw_pci_rd_tg_t *p) +{ + return field_get_updated(p->mp_fld_pci_rd_tg_ctrl_rdy); +} diff --git a/drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.h b/drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.h new file mode 100644 index 0000000000..b1c912f0f3 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pci_rd_tg.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_PCI_RD_TG_H__ +#define __NTHW_PCI_RD_TG_H__ + +struct nthw_pci_rd_tg { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_pci_rd_tg; + int mn_instance; + + int mn_param_pci_ta_tg_present; + + nt_register_t *mp_reg_pci_rd_tg_rd_data0; + nt_field_t *mp_fld_pci_rd_tg_phys_addr_low; + + nt_register_t *mp_reg_pci_rd_tg_rd_data1; + nt_field_t *mp_fld_pci_rd_tg_phys_addr_high; + + nt_register_t *mp_reg_pci_rd_tg_rd_data2; + nt_field_t *mp_fld_pci_rd_tg_req_size; + nt_field_t *mp_fld_pci_rd_tg_req_hid; + nt_field_t *mp_fld_pci_rd_tg_wait; + nt_field_t *mp_fld_pci_rd_tg_wrap; + + nt_register_t *mp_reg_pci_rd_tg_rd_addr; + nt_field_t *mp_fld_pci_rd_tg_ram_addr; + + nt_register_t *mp_reg_pci_rd_tg_rd_run; + nt_field_t *mp_fld_pci_rd_tg_run_iteration; + + nt_register_t *mp_reg_pci_rd_tg_rd_ctrl; + nt_field_t *mp_fld_pci_rd_tg_ctrl_rdy; +}; + +typedef struct nthw_pci_rd_tg nthw_pci_rd_tg_t; +typedef struct nthw_pci_rd_tg nthw_pci_rd_tg; + +nthw_pci_rd_tg_t *nthw_pci_rd_tg_new(void); +void nthw_pci_rd_tg_delete(nthw_pci_rd_tg_t *p); +int nthw_pci_rd_tg_init(nthw_pci_rd_tg_t *p, nt_fpga_t *p_fpga, int n_instance); + +void nthw_pci_rd_tg_set_phys_addr(nthw_pci_rd_tg_t *p, uint64_t n_phys_addr); +void nthw_pci_rd_tg_set_ram_addr(nthw_pci_rd_tg_t *p, int n_ram_addr); +void nthw_pci_rd_tg_set_ram_data(nthw_pci_rd_tg_t *p, uint32_t req_size, bool wait, + bool wrap); +void nthw_pci_rd_tg_set_run(nthw_pci_rd_tg_t *p, int n_iterations); +uint32_t nthw_pci_rd_tg_get_ctrl_rdy(nthw_pci_rd_tg_t *p); + +#endif /* __NTHW_PCI_RD_TG_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_pci_ta.c b/drivers/net/ntnic/nthw/core/nthw_pci_ta.c new file mode 100644 index 0000000000..17e30a670d --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pci_ta.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_pci_ta.h" + +nthw_pci_ta_t *nthw_pci_ta_new(void) +{ + nthw_pci_ta_t *p = malloc(sizeof(nthw_pci_ta_t)); + + if (p) + memset(p, 0, sizeof(nthw_pci_ta_t)); + return p; +} + +void nthw_pci_ta_delete(nthw_pci_ta_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_pci_ta_t)); + free(p); + } +} + +int nthw_pci_ta_init(nthw_pci_ta_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + nt_module_t *mod = fpga_query_module(p_fpga, MOD_PCI_TA, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: PCI_TA %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_pci_ta = mod; + + p->mn_param_pci_ta_tg_present = + fpga_get_product_param(p_fpga, NT_PCI_TA_TG_PRESENT, 1); + + p->mp_reg_pci_ta_ctrl = module_get_register(p->mp_mod_pci_ta, PCI_TA_CONTROL); + p->mp_fld_pci_ta_ctrl_enable = + register_get_field(p->mp_reg_pci_ta_ctrl, PCI_TA_CONTROL_ENABLE); + + p->mp_reg_pci_ta_packet_good = + module_get_register(p->mp_mod_pci_ta, PCI_TA_PACKET_GOOD); + p->mp_fld_pci_ta_packet_good_amount = + register_get_field(p->mp_reg_pci_ta_packet_good, PCI_TA_PACKET_GOOD_AMOUNT); + + p->mp_reg_pci_ta_packet_bad = + module_get_register(p->mp_mod_pci_ta, PCI_TA_PACKET_BAD); + p->mp_fld_pci_ta_packet_bad_amount = + register_get_field(p->mp_reg_pci_ta_packet_bad, PCI_TA_PACKET_BAD_AMOUNT); + + p->mp_reg_pci_ta_length_error = + module_get_register(p->mp_mod_pci_ta, PCI_TA_LENGTH_ERROR); + p->mp_fld_pci_ta_length_error_amount = + register_get_field(p->mp_reg_pci_ta_length_error, PCI_TA_LENGTH_ERROR_AMOUNT); + + p->mp_reg_pci_ta_payload_error = + module_get_register(p->mp_mod_pci_ta, PCI_TA_PAYLOAD_ERROR); + p->mp_fld_pci_ta_payload_error_amount = + register_get_field(p->mp_reg_pci_ta_payload_error, PCI_TA_PAYLOAD_ERROR_AMOUNT); + + return 0; +} + +void nthw_pci_ta_set_control_enable(nthw_pci_ta_t *p, uint32_t val) +{ + field_set_val_flush32(p->mp_fld_pci_ta_ctrl_enable, val); +} + +void nthw_pci_ta_get_packet_good(nthw_pci_ta_t *p, uint32_t *val) +{ + *val = field_get_updated(p->mp_fld_pci_ta_packet_good_amount); +} + +void nthw_pci_ta_get_packet_bad(nthw_pci_ta_t *p, uint32_t *val) +{ + *val = field_get_updated(p->mp_fld_pci_ta_packet_bad_amount); +} + +void nthw_pci_ta_get_length_error(nthw_pci_ta_t *p, uint32_t *val) +{ + *val = field_get_updated(p->mp_fld_pci_ta_length_error_amount); +} + +void nthw_pci_ta_get_payload_error(nthw_pci_ta_t *p, uint32_t *val) +{ + *val = field_get_updated(p->mp_fld_pci_ta_payload_error_amount); +} diff --git a/drivers/net/ntnic/nthw/core/nthw_pci_ta.h b/drivers/net/ntnic/nthw/core/nthw_pci_ta.h new file mode 100644 index 0000000000..7968cad9fa --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pci_ta.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_PCI_TA_H__ +#define __NTHW_PCI_TA_H__ + +struct nthw_pci_ta { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_pci_ta; + int mn_instance; + + int mn_param_pci_ta_tg_present; + + nt_register_t *mp_reg_pci_ta_ctrl; + nt_field_t *mp_fld_pci_ta_ctrl_enable; + nt_register_t *mp_reg_pci_ta_packet_good; + nt_field_t *mp_fld_pci_ta_packet_good_amount; + nt_register_t *mp_reg_pci_ta_packet_bad; + nt_field_t *mp_fld_pci_ta_packet_bad_amount; + nt_register_t *mp_reg_pci_ta_length_error; + nt_field_t *mp_fld_pci_ta_length_error_amount; + nt_register_t *mp_reg_pci_ta_payload_error; + nt_field_t *mp_fld_pci_ta_payload_error_amount; +}; + +typedef struct nthw_pci_ta nthw_pci_ta_t; +typedef struct nthw_pci_ta nthw_pci_ta; + +nthw_pci_ta_t *nthw_pci_ta_new(void); +void nthw_pci_ta_delete(nthw_pci_ta_t *p); +int nthw_pci_ta_init(nthw_pci_ta_t *p, nt_fpga_t *p_fpga, int n_instance); + +void nthw_pci_ta_set_control_enable(nthw_pci_ta_t *p, uint32_t val); +void nthw_pci_ta_get_packet_good(nthw_pci_ta_t *p, uint32_t *val); +void nthw_pci_ta_get_packet_bad(nthw_pci_ta_t *p, uint32_t *val); +void nthw_pci_ta_get_length_error(nthw_pci_ta_t *p, uint32_t *val); +void nthw_pci_ta_get_payload_error(nthw_pci_ta_t *p, uint32_t *val); + +#endif /* __NTHW_PCI_TA_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.c b/drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.c new file mode 100644 index 0000000000..f830a586b2 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.c @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_pci_wr_tg.h" + +nthw_pci_wr_tg_t *nthw_pci_wr_tg_new(void) +{ + nthw_pci_wr_tg_t *p = malloc(sizeof(nthw_pci_wr_tg_t)); + + if (p) + memset(p, 0, sizeof(nthw_pci_wr_tg_t)); + return p; +} + +void nthw_pci_wr_tg_delete(nthw_pci_wr_tg_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_pci_wr_tg_t)); + free(p); + } +} + +int nthw_pci_wr_tg_init(nthw_pci_wr_tg_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + nt_module_t *mod = fpga_query_module(p_fpga, MOD_PCI_WR_TG, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: PCI_WR_TG %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_pci_wr_tg = mod; + + p->mn_param_pci_ta_tg_present = + fpga_get_product_param(p_fpga, NT_PCI_TA_TG_PRESENT, 1); + + p->mp_reg_pci_wr_tg_data0 = + module_get_register(p->mp_mod_pci_wr_tg, PCI_WR_TG_TG_WRDATA0); + p->mp_fld_pci_wr_tg_phys_addr_low = + register_get_field(p->mp_reg_pci_wr_tg_data0, PCI_WR_TG_TG_WRDATA0_PHYS_ADDR_LOW); + + p->mp_reg_pci_wr_tg_data1 = + module_get_register(p->mp_mod_pci_wr_tg, PCI_WR_TG_TG_WRDATA1); + p->mp_fld_pci_wr_tg_phys_addr_high = + register_get_field(p->mp_reg_pci_wr_tg_data1, PCI_WR_TG_TG_WRDATA1_PHYS_ADDR_HIGH); + + p->mp_reg_pci_wr_tg_data2 = + module_get_register(p->mp_mod_pci_wr_tg, PCI_WR_TG_TG_WRDATA2); + p->mp_fld_pci_wr_tg_req_size = + register_get_field(p->mp_reg_pci_wr_tg_data2, PCI_WR_TG_TG_WRDATA2_REQ_SIZE); + p->mp_fld_pci_wr_tg_inc_mode = + register_get_field(p->mp_reg_pci_wr_tg_data2, PCI_WR_TG_TG_WRDATA2_INC_MODE); + p->mp_fld_pci_wr_tg_wait = + register_get_field(p->mp_reg_pci_wr_tg_data2, PCI_WR_TG_TG_WRDATA2_WAIT); + p->mp_fld_pci_wr_tg_wrap = + register_get_field(p->mp_reg_pci_wr_tg_data2, PCI_WR_TG_TG_WRDATA2_WRAP); + /* optional VF host id */ + p->mp_fld_pci_wr_tg_req_hid = + register_query_field(p->mp_reg_pci_wr_tg_data2, PCI_WR_TG_TG_WRDATA2_REQ_HID); + + p->mp_reg_pci_wr_tg_addr = + module_get_register(p->mp_mod_pci_wr_tg, PCI_WR_TG_TG_WRADDR); + p->mp_fld_pci_wr_tg_ram_addr = + register_get_field(p->mp_reg_pci_wr_tg_addr, PCI_WR_TG_TG_WRADDR_RAM_ADDR); + + p->mp_reg_pci_wr_tg_run = + module_get_register(p->mp_mod_pci_wr_tg, PCI_WR_TG_TG_WR_RUN); + p->mp_fld_pci_wr_tg_run_iteration = + register_get_field(p->mp_reg_pci_wr_tg_run, PCI_WR_TG_TG_WR_RUN_WR_ITERATION); + + p->mp_reg_pci_wr_tg_ctrl = + module_get_register(p->mp_mod_pci_wr_tg, PCI_WR_TG_TG_CTRL); + p->mp_fld_pci_wr_tg_ctrl_rdy = + register_get_field(p->mp_reg_pci_wr_tg_ctrl, PCI_WR_TG_TG_CTRL_TG_WR_RDY); + + p->mp_reg_pci_wr_tg_seq = + module_get_register(p->mp_mod_pci_wr_tg, PCI_WR_TG_TG_SEQ); + p->mp_fld_pci_wr_tg_seq_sequence = + register_get_field(p->mp_reg_pci_wr_tg_seq, PCI_WR_TG_TG_SEQ_SEQUENCE); + + return 0; +} + +void nthw_pci_wr_tg_set_phys_addr(nthw_pci_wr_tg_t *p, uint64_t n_phys_addr) +{ + field_set_val_flush32(p->mp_fld_pci_wr_tg_phys_addr_low, + (uint32_t)(n_phys_addr & ((1UL << 32) - 1))); + field_set_val_flush32(p->mp_fld_pci_wr_tg_phys_addr_high, + (uint32_t)((n_phys_addr >> 32) & ((1UL << 32) - 1))); +} + +void nthw_pci_wr_tg_set_ram_addr(nthw_pci_wr_tg_t *p, int n_ram_addr) +{ + field_set_val_flush32(p->mp_fld_pci_wr_tg_ram_addr, n_ram_addr); +} + +void nthw_pci_wr_tg_set_ram_data(nthw_pci_wr_tg_t *p, uint32_t req_size, bool wait, + bool wrap, bool inc) +{ + field_set_val32(p->mp_fld_pci_wr_tg_req_size, req_size); + field_set_val32(p->mp_fld_pci_wr_tg_wait, wait); + field_set_val32(p->mp_fld_pci_wr_tg_wrap, wrap); + field_set_val32(p->mp_fld_pci_wr_tg_inc_mode, inc); + field_flush_register(p->mp_fld_pci_wr_tg_inc_mode); +} + +void nthw_pci_wr_tg_set_run(nthw_pci_wr_tg_t *p, int n_iterations) +{ + field_set_val_flush32(p->mp_fld_pci_wr_tg_run_iteration, n_iterations); +} + +uint32_t nthw_pci_wr_tg_get_ctrl_rdy(nthw_pci_wr_tg_t *p) +{ + return field_get_updated(p->mp_fld_pci_wr_tg_ctrl_rdy); +} diff --git a/drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.h b/drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.h new file mode 100644 index 0000000000..535b39526e --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pci_wr_tg.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_PCI_WR_TG_H__ +#define __NTHW_PCI_WR_TG_H__ + +struct nthw_pci_wr_tg { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_pci_wr_tg; + int mn_instance; + + int mn_param_pci_ta_tg_present; + + nt_register_t *mp_reg_pci_wr_tg_data0; + nt_field_t *mp_fld_pci_wr_tg_phys_addr_low; + + nt_register_t *mp_reg_pci_wr_tg_data1; + nt_field_t *mp_fld_pci_wr_tg_phys_addr_high; + + nt_register_t *mp_reg_pci_wr_tg_data2; + nt_field_t *mp_fld_pci_wr_tg_req_size; + nt_field_t *mp_fld_pci_wr_tg_req_hid; + nt_field_t *mp_fld_pci_wr_tg_inc_mode; + nt_field_t *mp_fld_pci_wr_tg_wait; + nt_field_t *mp_fld_pci_wr_tg_wrap; + + nt_register_t *mp_reg_pci_wr_tg_addr; + nt_field_t *mp_fld_pci_wr_tg_ram_addr; + + nt_register_t *mp_reg_pci_wr_tg_run; + nt_field_t *mp_fld_pci_wr_tg_run_iteration; + + nt_register_t *mp_reg_pci_wr_tg_ctrl; + nt_field_t *mp_fld_pci_wr_tg_ctrl_rdy; + + nt_register_t *mp_reg_pci_wr_tg_seq; + nt_field_t *mp_fld_pci_wr_tg_seq_sequence; +}; + +typedef struct nthw_pci_wr_tg nthw_pci_wr_tg_t; +typedef struct nthw_pci_wr_tg nthw_pci_wr_tg; + +nthw_pci_wr_tg_t *nthw_pci_wr_tg_new(void); +void nthw_pci_wr_tg_delete(nthw_pci_wr_tg_t *p); +int nthw_pci_wr_tg_init(nthw_pci_wr_tg_t *p, nt_fpga_t *p_fpga, int n_instance); + +void nthw_pci_wr_tg_set_phys_addr(nthw_pci_wr_tg_t *p, uint64_t n_phys_addr); +void nthw_pci_wr_tg_set_ram_addr(nthw_pci_wr_tg_t *p, int n_ram_addr); +void nthw_pci_wr_tg_set_ram_data(nthw_pci_wr_tg_t *p, uint32_t req_size, bool wait, + bool wrap, bool inc); +void nthw_pci_wr_tg_set_run(nthw_pci_wr_tg_t *p, int n_iterations); +uint32_t nthw_pci_wr_tg_get_ctrl_rdy(nthw_pci_wr_tg_t *p); + +#endif /* __NTHW_PCI_WR_TG_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_pcie3.c b/drivers/net/ntnic/nthw/core/nthw_pcie3.c new file mode 100644 index 0000000000..07ad784695 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pcie3.c @@ -0,0 +1,274 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_pcie3.h" + +#define NTHW_TG_REF_FREQ (250000000ULL) + +nthw_pcie3_t *nthw_pcie3_new(void) +{ + nthw_pcie3_t *p = malloc(sizeof(nthw_pcie3_t)); + + if (p) + memset(p, 0, sizeof(nthw_pcie3_t)); + return p; +} + +void nthw_pcie3_delete(nthw_pcie3_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_pcie3_t)); + free(p); + } +} + +int nthw_pcie3_init(nthw_pcie3_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + nt_module_t *mod = fpga_query_module(p_fpga, MOD_PCIE3, n_instance); + + if (p == NULL) + return (mod == NULL ? -1 : 0); + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: PCIE3 %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_pcie3 = mod; + + /* PCIe3 */ + p->mp_reg_stat_ctrl = module_get_register(p->mp_mod_pcie3, PCIE3_STAT_CTRL); + p->mp_fld_stat_ctrl_ena = + register_get_field(p->mp_reg_stat_ctrl, PCIE3_STAT_CTRL_STAT_ENA); + p->mp_fld_stat_ctrl_req = + register_get_field(p->mp_reg_stat_ctrl, PCIE3_STAT_CTRL_STAT_REQ); + + p->mp_reg_stat_rx = module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RX); + p->mp_fld_stat_rx_counter = + register_get_field(p->mp_reg_stat_rx, PCIE3_STAT_RX_COUNTER); + + p->mp_reg_stat_tx = module_get_register(p->mp_mod_pcie3, PCIE3_STAT_TX); + p->mp_fld_stat_tx_counter = + register_get_field(p->mp_reg_stat_tx, PCIE3_STAT_TX_COUNTER); + + p->mp_reg_stat_ref_clk = + module_get_register(p->mp_mod_pcie3, PCIE3_STAT_REFCLK); + p->mp_fld_stat_ref_clk_ref_clk = + register_get_field(p->mp_reg_stat_ref_clk, PCIE3_STAT_REFCLK_REFCLK250); + + p->mp_reg_stat_rq_rdy = + module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RQ_RDY); + p->mp_fld_stat_rq_rdy_counter = + register_get_field(p->mp_reg_stat_rq_rdy, PCIE3_STAT_RQ_RDY_COUNTER); + + p->mp_reg_stat_rq_vld = + module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RQ_VLD); + p->mp_fld_stat_rq_vld_counter = + register_get_field(p->mp_reg_stat_rq_vld, PCIE3_STAT_RQ_VLD_COUNTER); + + p->mp_reg_status0 = module_get_register(p->mp_mod_pcie3, PCIE3_STATUS0); + p->mp_fld_status0_tags_in_use = + register_get_field(p->mp_reg_status0, PCIE3_STATUS0_TAGS_IN_USE); + + p->mp_reg_rp_to_ep_err = + module_get_register(p->mp_mod_pcie3, PCIE3_RP_TO_EP_ERR); + p->mp_fld_rp_to_ep_err_cor = + register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_COR); + p->mp_fld_rp_to_ep_err_non_fatal = + register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_NONFATAL); + p->mp_fld_rp_to_ep_err_fatal = + register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_FATAL); + + p->mp_reg_ep_to_rp_err = + module_get_register(p->mp_mod_pcie3, PCIE3_EP_TO_RP_ERR); + p->mp_fld_ep_to_rp_err_cor = register_get_field(p->mp_reg_ep_to_rp_err, + PCIE3_EP_TO_RP_ERR_ERR_COR); + p->mp_fld_ep_to_rp_err_non_fatal = + register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_NONFATAL); + p->mp_fld_ep_to_rp_err_fatal = + register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_FATAL); + + p->mp_reg_sample_time = + module_get_register(p->mp_mod_pcie3, PCIE3_SAMPLE_TIME); + p->mp_fld_sample_time = + register_get_field(p->mp_reg_sample_time, PCIE3_SAMPLE_TIME_SAMPLE_TIME); + + p->mp_reg_pci_end_point = + module_get_register(p->mp_mod_pcie3, PCIE3_PCI_ENDPOINT); + p->mp_fld_pci_end_point_if_id = + register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_IF_ID); + p->mp_fld_pci_end_point_send_msg = + register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_SEND_MSG); + p->mp_fld_pci_end_point_get_msg = + register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_GET_MSG); + p->mp_fld_pci_end_point_dmae_p0_allow_mask = + register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_DMA_EP0_ALLOW_MASK); + p->mp_fld_pci_end_point_dmae_p1_allow_mask = + register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_DMA_EP1_ALLOW_MASK); + if (p->mp_reg_pci_end_point) + register_update(p->mp_reg_pci_end_point); + + p->mp_reg_pci_test0 = module_get_register(p->mp_mod_pcie3, PCIE3_PCI_TEST0); + p->mp_fld_pci_test0 = + register_get_field(p->mp_reg_pci_test0, PCIE3_PCI_TEST0_DATA); + if (p->mp_reg_pci_test0) + register_update(p->mp_reg_pci_test0); + + p->mp_reg_pci_test1 = module_get_register(p->mp_mod_pcie3, PCIE3_PCI_TEST1); + p->mp_fld_pci_test1 = + register_get_field(p->mp_reg_pci_test1, PCIE3_PCI_TEST1_DATA); + if (p->mp_reg_pci_test1) + register_update(p->mp_reg_pci_test1); + + p->mp_reg_pci_e3_mark_adr_lsb = + module_get_register(p->mp_mod_pcie3, PCIE3_MARKADR_LSB); + p->mp_fld_pci_e3_mark_adr_lsb_adr = + register_get_field(p->mp_reg_pci_e3_mark_adr_lsb, PCIE3_MARKADR_LSB_ADR); + if (p->mp_reg_pci_e3_mark_adr_lsb) + register_update(p->mp_reg_pci_e3_mark_adr_lsb); + + p->mp_reg_pci_e3_mark_adr_msb = + module_get_register(p->mp_mod_pcie3, PCIE3_MARKADR_MSB); + p->mp_fld_pci_e3_mark_adr_msb_adr = + register_get_field(p->mp_reg_pci_e3_mark_adr_msb, PCIE3_MARKADR_MSB_ADR); + if (p->mp_reg_pci_e3_mark_adr_msb) + register_update(p->mp_reg_pci_e3_mark_adr_msb); + + /* Initial setup - disable markerscheme and bifurcation */ + if (p->mp_fld_pci_end_point_dmae_p0_allow_mask) + field_clr_flush(p->mp_fld_pci_end_point_dmae_p0_allow_mask); + + if (p->mp_fld_pci_end_point_dmae_p1_allow_mask) + field_clr_flush(p->mp_fld_pci_end_point_dmae_p1_allow_mask); + + if (p->mp_fld_pci_e3_mark_adr_lsb_adr) + field_set_val_flush32(p->mp_fld_pci_e3_mark_adr_lsb_adr, 0UL); + + if (p->mp_fld_pci_e3_mark_adr_msb_adr) + field_set_val_flush32(p->mp_fld_pci_e3_mark_adr_msb_adr, 0UL); + + if (p->mp_fld_pci_end_point_dmae_p0_allow_mask) + field_set_flush(p->mp_fld_pci_end_point_dmae_p0_allow_mask); + + if (p->mp_fld_pci_end_point_dmae_p1_allow_mask) + field_clr_flush(p->mp_fld_pci_end_point_dmae_p1_allow_mask); + return 0; +}; + +int nthw_pcie3_trigger_sample_time(nthw_pcie3_t *p) +{ + field_set_val_flush32(p->mp_fld_sample_time, 0xfee1dead); + + return 0; +} + +int nthw_pcie3_stat_req_enable(nthw_pcie3_t *p) +{ + field_set_all(p->mp_fld_stat_ctrl_ena); + field_set_all(p->mp_fld_stat_ctrl_req); + field_flush_register(p->mp_fld_stat_ctrl_req); + return 0; +} + +int nthw_pcie3_stat_req_disable(nthw_pcie3_t *p) +{ + field_clr_all(p->mp_fld_stat_ctrl_ena); + field_set_all(p->mp_fld_stat_ctrl_req); + field_flush_register(p->mp_fld_stat_ctrl_req); + return 0; +} + +int nthw_pcie3_get_stat(nthw_pcie3_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt, + uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, + uint32_t *p_tg_ref_freq, uint32_t *p_tag_use_cnt, + uint32_t *p_rq_rdy_cnt, uint32_t *p_rq_vld_cnt) +{ + *p_rx_cnt = field_get_updated(p->mp_fld_stat_rx_counter); + *p_tx_cnt = field_get_updated(p->mp_fld_stat_tx_counter); + + *p_ref_clk_cnt = field_get_updated(p->mp_fld_stat_ref_clk_ref_clk); + + *p_tg_unit_size = NTHW_TG_CNT_SIZE; + *p_tg_ref_freq = NTHW_TG_REF_FREQ; + + *p_tag_use_cnt = field_get_updated(p->mp_fld_status0_tags_in_use); + + *p_rq_rdy_cnt = field_get_updated(p->mp_fld_stat_rq_rdy_counter); + *p_rq_vld_cnt = field_get_updated(p->mp_fld_stat_rq_vld_counter); + + return 0; +} + +int nthw_pcie3_get_stat_rate(nthw_pcie3_t *p, uint64_t *p_pci_rx_rate, + uint64_t *p_pci_tx_rate, uint64_t *p_ref_clk_cnt, + uint64_t *p_tag_use_cnt, uint64_t *p_pci_nt_bus_util, + uint64_t *p_pci_xil_bus_util) +{ + uint32_t rx_cnt, tx_cnt, ref_clk_cnt; + uint32_t tg_unit_size, tg_ref_freq; + uint32_t tag_use_cnt, rq_rdy_cnt, rq_vld_cnt; + + nthw_pcie3_get_stat(p, &rx_cnt, &tx_cnt, &ref_clk_cnt, &tg_unit_size, + &tg_ref_freq, &tag_use_cnt, &rq_rdy_cnt, &rq_vld_cnt); + + if (ref_clk_cnt) { + uint64_t nt_bus_util, xil_bus_util; + uint64_t rx_rate, tx_rate; + + rx_rate = ((uint64_t)rx_cnt * tg_unit_size * tg_ref_freq) / + (uint64_t)ref_clk_cnt; + *p_pci_rx_rate = rx_rate; + + tx_rate = ((uint64_t)tx_cnt * tg_unit_size * tg_ref_freq) / + (uint64_t)ref_clk_cnt; + *p_pci_tx_rate = tx_rate; + + *p_ref_clk_cnt = ref_clk_cnt; + + *p_tag_use_cnt = tag_use_cnt; + + nt_bus_util = + ((uint64_t)rq_vld_cnt * 1000000ULL) / (uint64_t)ref_clk_cnt; + *p_pci_nt_bus_util = nt_bus_util; + xil_bus_util = + ((uint64_t)rq_rdy_cnt * 1000000ULL) / (uint64_t)ref_clk_cnt; + *p_pci_xil_bus_util = xil_bus_util; + } else { + *p_ref_clk_cnt = 0; + *p_pci_nt_bus_util = 0; + *p_pci_xil_bus_util = 0; + } + + return 0; +} + +int nthw_pcie3_end_point_counters_sample_pre(nthw_pcie3_t *p, + struct nthw_hif_end_point_counters *epc) +{ + NT_LOG(DBG, NTHW, "%s:%u: empty function\n", __func__, __LINE__); + + (void)p; + (void)epc; + + return 0; +} + +int nthw_pcie3_end_point_counters_sample_post(nthw_pcie3_t *p, + struct nthw_hif_end_point_counters *epc) +{ + NT_LOG(DBG, NTHW, "%s:%u:\n", __func__, __LINE__); + assert(epc); + nthw_pcie3_get_stat_rate(p, &epc->cur_tx, &epc->cur_rx, &epc->n_ref_clk_cnt, + &epc->n_tags_in_use, &epc->cur_pci_nt_util, + &epc->cur_pci_xil_util); + return 0; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_pcie3.h b/drivers/net/ntnic/nthw/core/nthw_pcie3.h new file mode 100644 index 0000000000..beb79a9577 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pcie3.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_PCIE3_H__ +#define __NTHW_PCIE3_H__ + +struct nthw_pcie3 { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_pcie3; + int mn_instance; + + nt_register_t *mp_reg_stat_ctrl; + nt_field_t *mp_fld_stat_ctrl_req; + nt_field_t *mp_fld_stat_ctrl_ena; + + nt_register_t *mp_reg_stat_rx; + nt_field_t *mp_fld_stat_rx_counter; + + nt_register_t *mp_reg_stat_tx; + nt_field_t *mp_fld_stat_tx_counter; + + nt_register_t *mp_reg_stat_rq_rdy; + nt_field_t *mp_fld_stat_rq_rdy_counter; + + nt_register_t *mp_reg_stat_rq_vld; + nt_field_t *mp_fld_stat_rq_vld_counter; + + nt_register_t *mp_reg_status0; + nt_field_t *mp_fld_status0_tags_in_use; + + nt_register_t *mp_reg_stat_ref_clk; + nt_field_t *mp_fld_stat_ref_clk_ref_clk; + + nt_register_t *mp_reg_rp_to_ep_err; + nt_field_t *mp_fld_rp_to_ep_err_cor; + nt_field_t *mp_fld_rp_to_ep_err_non_fatal; + nt_field_t *mp_fld_rp_to_ep_err_fatal; + + nt_register_t *mp_reg_ep_to_rp_err; + nt_field_t *mp_fld_ep_to_rp_err_cor; + nt_field_t *mp_fld_ep_to_rp_err_non_fatal; + nt_field_t *mp_fld_ep_to_rp_err_fatal; + + nt_register_t *mp_reg_sample_time; + nt_field_t *mp_fld_sample_time; + + nt_register_t *mp_reg_pci_end_point; + nt_field_t *mp_fld_pci_end_point_if_id; + nt_field_t *mp_fld_pci_end_point_send_msg; + nt_field_t *mp_fld_pci_end_point_get_msg; + nt_field_t *mp_fld_pci_end_point_dmae_p0_allow_mask; + nt_field_t *mp_fld_pci_end_point_dmae_p1_allow_mask; + + nt_register_t *mp_reg_pci_e3_mark_adr_lsb; + nt_field_t *mp_fld_pci_e3_mark_adr_lsb_adr; + + nt_register_t *mp_reg_pci_e3_mark_adr_msb; + nt_field_t *mp_fld_pci_e3_mark_adr_msb_adr; + + nt_register_t *mp_reg_pci_test0; + nt_field_t *mp_fld_pci_test0; + + nt_register_t *mp_reg_pci_test1; + nt_field_t *mp_fld_pci_test1; + + nt_register_t *mp_reg_pci_test2; + nt_field_t *mp_fld_pci_test2; + + nt_register_t *mp_reg_pci_test3; + nt_field_t *mp_fld_pci_test3; +}; + +typedef struct nthw_pcie3 nthw_pcie3_t; +typedef struct nthw_pcie3 nthw_pcie3; + +nthw_pcie3_t *nthw_pcie3_new(void); +void nthw_pcie3_delete(nthw_pcie3_t *p); +int nthw_pcie3_init(nthw_pcie3_t *p, nt_fpga_t *p_fpga, int n_instance); + +int nthw_pcie3_trigger_sample_time(nthw_pcie3_t *p); + +int nthw_pcie3_stat_req_enable(nthw_pcie3_t *p); +int nthw_pcie3_stat_req_disable(nthw_pcie3_t *p); + +int nthw_pcie3_get_stat(nthw_pcie3_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt, + uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, + uint32_t *p_tg_ref_freq, uint32_t *p_tag_use_cnt, + uint32_t *p_rq_rdy_cnt, uint32_t *p_rq_vld_cnt); +int nthw_pcie3_get_stat_rate(nthw_pcie3_t *p, uint64_t *p_pci_rx_rate, + uint64_t *p_pci_tx_rate, uint64_t *p_ref_clk_cnt, + uint64_t *p_tag_use_cnt, uint64_t *p_pci_nt_bus_util, + uint64_t *p_pci_xil_bus_util); + +int nthw_pcie3_end_point_counters_sample_pre(nthw_pcie3_t *p, + struct nthw_hif_end_point_counters *epc); +int nthw_pcie3_end_point_counters_sample_post(nthw_pcie3_t *p, + struct nthw_hif_end_point_counters *epc); + +#endif /* __NTHW_PCIE3_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_sdc.c b/drivers/net/ntnic/nthw/core/nthw_sdc.c new file mode 100644 index 0000000000..0547b92c47 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_sdc.c @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_sdc.h" + +nthw_sdc_t *nthw_sdc_new(void) +{ + nthw_sdc_t *p = malloc(sizeof(nthw_sdc_t)); + + if (p) + memset(p, 0, sizeof(nthw_sdc_t)); + return p; +} + +void nthw_sdc_delete(nthw_sdc_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_sdc_t)); + free(p); + } +} + +int nthw_sdc_init(nthw_sdc_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + nt_module_t *mod = fpga_query_module(p_fpga, MOD_SDC, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: SDC %d: no such instance\n", + p_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_sdc = mod; + + { + nt_register_t *p_reg; + + p_reg = module_get_register(p->mp_mod_sdc, SDC_CTRL); + p->mp_fld_ctrl_init = register_get_field(p_reg, SDC_CTRL_INIT); + p->mp_fld_ctrl_run_test = + register_get_field(p_reg, SDC_CTRL_RUN_TEST); + p->mp_fld_ctrl_stop_client = + register_get_field(p_reg, SDC_CTRL_STOP_CLIENT); + p->mp_fld_ctrl_test_enable = + register_get_field(p_reg, SDC_CTRL_TEST_EN); + + p_reg = module_get_register(p->mp_mod_sdc, SDC_STAT); + p->mp_fld_stat_calib = register_get_field(p_reg, SDC_STAT_CALIB); + p->mp_fld_stat_cell_cnt_stopped = + register_get_field(p_reg, SDC_STAT_CELL_CNT_STOPPED); + p->mp_fld_stat_err_found = + register_get_field(p_reg, SDC_STAT_ERR_FOUND); + p->mp_fld_stat_init_done = + register_get_field(p_reg, SDC_STAT_INIT_DONE); + p->mp_fld_stat_mmcm_lock = + register_get_field(p_reg, SDC_STAT_MMCM_LOCK); + p->mp_fld_stat_pll_lock = + register_get_field(p_reg, SDC_STAT_PLL_LOCK); + p->mp_fld_stat_resetting = + register_get_field(p_reg, SDC_STAT_RESETTING); + + p_reg = module_get_register(p->mp_mod_sdc, SDC_CELL_CNT); + p->mp_fld_cell_cnt = + register_get_field(p_reg, SDC_CELL_CNT_CELL_CNT); + + p_reg = module_get_register(p->mp_mod_sdc, SDC_CELL_CNT_PERIOD); + p->mp_fld_cell_cnt_period = + register_get_field(p_reg, SDC_CELL_CNT_PERIOD_CELL_CNT_PERIOD); + + p_reg = module_get_register(p->mp_mod_sdc, SDC_FILL_LVL); + p->mp_fld_fill_level = + register_get_field(p_reg, SDC_FILL_LVL_FILL_LVL); + + p_reg = module_get_register(p->mp_mod_sdc, SDC_MAX_FILL_LVL); + p->mp_fld_max_fill_level = + register_get_field(p_reg, SDC_MAX_FILL_LVL_MAX_FILL_LVL); + } + return 0; +} + +int nthw_sdc_get_states(nthw_sdc_t *p, uint64_t *pn_result_mask) +{ + int n_err_cnt = 0; + uint64_t n_mask = 0; + uint32_t val; + uint32_t val_mask; + int n_val_width; + + if (!p || !pn_result_mask) + return -1; + + val = field_get_updated(p->mp_fld_stat_calib); + n_val_width = field_get_bit_width(p->mp_fld_stat_calib); + val_mask = ((1 << n_val_width) - 1); + n_mask = (n_mask << n_val_width) | (val & val_mask); + if (val != val_mask) + n_err_cnt++; + + val = field_get_updated(p->mp_fld_stat_init_done); + n_val_width = field_get_bit_width(p->mp_fld_stat_init_done); + val_mask = ((1 << n_val_width) - 1); + n_mask = (n_mask << n_val_width) | (val & val_mask); + if (val != val_mask) + n_err_cnt++; + + val = field_get_updated(p->mp_fld_stat_mmcm_lock); + n_val_width = field_get_bit_width(p->mp_fld_stat_mmcm_lock); + val_mask = ((1 << n_val_width) - 1); + n_mask = (n_mask << n_val_width) | (val & val_mask); + if (val != val_mask) + n_err_cnt++; + + val = field_get_updated(p->mp_fld_stat_pll_lock); + n_val_width = field_get_bit_width(p->mp_fld_stat_pll_lock); + val_mask = ((1 << n_val_width) - 1); + n_mask = (n_mask << n_val_width) | (val & val_mask); + if (val != val_mask) + n_err_cnt++; + + val = field_get_updated(p->mp_fld_stat_resetting); + n_val_width = field_get_bit_width(p->mp_fld_stat_resetting); + val_mask = ((1 << n_val_width) - 1); + n_mask = (n_mask << n_val_width) | (val & val_mask); + if (val != 0) + n_err_cnt++; + + if (pn_result_mask) + *pn_result_mask = n_mask; + + return n_err_cnt; /* 0 = all ok */ +} + +int nthw_sdc_wait_states(nthw_sdc_t *p, const int n_poll_iterations, + const int n_poll_interval) +{ + int res; + int n_err_cnt = 0; + + res = field_wait_set_all32(p->mp_fld_stat_calib, n_poll_iterations, + n_poll_interval); + if (res) + n_err_cnt++; + + res = field_wait_set_all32(p->mp_fld_stat_init_done, n_poll_iterations, + n_poll_interval); + if (res) + n_err_cnt++; + + res = field_wait_set_all32(p->mp_fld_stat_mmcm_lock, n_poll_iterations, + n_poll_interval); + if (res) + n_err_cnt++; + + res = field_wait_set_all32(p->mp_fld_stat_pll_lock, n_poll_iterations, + n_poll_interval); + if (res) + n_err_cnt++; + + res = field_wait_clr_all32(p->mp_fld_stat_resetting, n_poll_iterations, + n_poll_interval); + if (res) + n_err_cnt++; + + return n_err_cnt; /* 0 = all ok */ +} diff --git a/drivers/net/ntnic/nthw/core/nthw_sdc.h b/drivers/net/ntnic/nthw/core/nthw_sdc.h new file mode 100644 index 0000000000..e6c08ffbc3 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_sdc.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_SDC_H__ +#define __NTHW_SDC_H__ + +struct nthw_sdc { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_sdc; + int mn_instance; + + nt_field_t *mp_fld_ctrl_init; + nt_field_t *mp_fld_ctrl_run_test; + nt_field_t *mp_fld_ctrl_stop_client; + nt_field_t *mp_fld_ctrl_test_enable; + + nt_field_t *mp_fld_stat_calib; + nt_field_t *mp_fld_stat_cell_cnt_stopped; + nt_field_t *mp_fld_stat_err_found; + nt_field_t *mp_fld_stat_init_done; + nt_field_t *mp_fld_stat_mmcm_lock; + nt_field_t *mp_fld_stat_pll_lock; + nt_field_t *mp_fld_stat_resetting; + + nt_field_t *mp_fld_cell_cnt; + nt_field_t *mp_fld_cell_cnt_period; + nt_field_t *mp_fld_fill_level; + nt_field_t *mp_fld_max_fill_level; +}; + +typedef struct nthw_sdc nthw_sdc_t; +typedef struct nthw_sdc nthw_sdc; + +nthw_sdc_t *nthw_sdc_new(void); +int nthw_sdc_init(nthw_sdc_t *p, nt_fpga_t *p_fpga, int n_instance); +void nthw_sdc_delete(nthw_sdc_t *p); + +int nthw_sdc_wait_states(nthw_sdc_t *p, const int n_poll_iterations, + const int n_poll_interval); +int nthw_sdc_get_states(nthw_sdc_t *p, uint64_t *pn_result_mask); + +#endif /* __NTHW_SDC_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_si5340.c b/drivers/net/ntnic/nthw/core/nthw_si5340.c new file mode 100644 index 0000000000..3337f1f9e3 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_si5340.c @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + * + * This file implements Si5340 clock synthesizer support. + * The implementation is generic and must be tailored to a specific use by the + * correct initialization data. + */ + +#include "nt_util.h" +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_si5340.h" + +#define SI5340_WAIT_US(x) NT_OS_WAIT_USEC(x) + +#define SI5340_LOG_DEBUG(...) NT_LOG(DBG, NTHW, __VA_ARGS__) +#define SI5340_LOG_INFO(...) NT_LOG(INF, NTHW, __VA_ARGS__) +#define SI5340_LOG_WARN(...) NT_LOG(WRN, NTHW, __VA_ARGS__) +#define SI5340_LOG_ERROR(...) NT_LOG(ERR, NTHW, __VA_ARGS__) + +#define SI5340_PAGE_REG_ADDR (0x01) + +nthw_si5340_t *nthw_si5340_new(void) +{ + nthw_si5340_t *p = malloc(sizeof(nthw_si5340_t)); + + if (p) + memset(p, 0, sizeof(nthw_si5340_t)); + return p; +} + +int nthw_si5340_init(nthw_si5340_t *p, nthw_iic_t *p_nthw_iic, uint8_t n_iic_addr) +{ + uint8_t data; + + p->mp_nthw_iic = p_nthw_iic; + p->mn_iic_addr = n_iic_addr; + p->mn_clk_cfg = -1; + + p->m_si5340_page = 0; + data = p->m_si5340_page; + nthw_iic_write_data(p->mp_nthw_iic, p->mn_iic_addr, SI5340_PAGE_REG_ADDR, 1, + &data); + + return 0; +} + +void nthw_si5340_delete(nthw_si5340_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_si5340_t)); + free(p); + } +} + +/* + * Read access (via I2C) to the clock synthesizer IC. The IC is located at I2C + * 7bit address 0x74 + */ +static uint8_t nthw_si5340_read(nthw_si5340_t *p, uint16_t reg_addr) +{ + const uint8_t offset_adr = (uint8_t)(reg_addr & 0xff); + uint8_t page = (uint8_t)((reg_addr >> 8) & 0xff); + uint8_t data; + + /* check if we are on the right page */ + if (page != p->m_si5340_page) { + nthw_iic_write_data(p->mp_nthw_iic, p->mn_iic_addr, + SI5340_PAGE_REG_ADDR, 1, &page); + p->m_si5340_page = page; + } + nthw_iic_read_data(p->mp_nthw_iic, p->mn_iic_addr, offset_adr, 1, &data); + return data; +} + +/* + * Write access (via I2C) to the clock synthesizer IC. The IC is located at I2C + * 7 bit address 0x74 + */ +static int nthw_si5340_write(nthw_si5340_t *p, uint16_t reg_addr, uint8_t data) +{ + const uint8_t offset_adr = (uint8_t)(reg_addr & 0xff); + uint8_t page = (uint8_t)((reg_addr >> 8) & 0xff); + + /* check if we are on the right page */ + if (page != p->m_si5340_page) { + nthw_iic_write_data(p->mp_nthw_iic, p->mn_iic_addr, + SI5340_PAGE_REG_ADDR, 1, &page); + p->m_si5340_page = page; + } + nthw_iic_write_data(p->mp_nthw_iic, p->mn_iic_addr, offset_adr, 1, &data); + + return 0; +} + +static int nthw_si5340_cfg(nthw_si5340_t *p, const void *p_data, int data_cnt, + clk_profile_data_fmt_t data_format) +{ + const char *const p_adapter_id_str = + p->mp_nthw_iic->mp_fpga->p_fpga_info->mp_adapter_id_str; + int i; + uint16_t addr; + uint8_t value; + uint8_t ctrl_value; + + NT_LOG(DBG, NTHW, "%s: %s: data_cnt = %d, dataFormat = %d\n", + p_adapter_id_str, __func__, data_cnt, data_format); + + for (i = 0; i < data_cnt; i++) { + if (data_format == CLK_PROFILE_DATA_FMT_1) { + addr = ((const clk_profile_data_fmt1_t *)p_data)->reg_addr; + value = ((const clk_profile_data_fmt1_t *)p_data)->reg_val; + p_data = ((const clk_profile_data_fmt1_t *)p_data) + 1; + } else if (data_format == CLK_PROFILE_DATA_FMT_2) { + addr = (uint16_t)(((const clk_profile_data_fmt2_t *)p_data) + ->reg_addr); + value = ((const clk_profile_data_fmt2_t *)p_data)->reg_val; + p_data = ((const clk_profile_data_fmt2_t *)p_data) + 1; + } else { + NT_LOG(ERR, NTHW, + "%s: Unhandled Si5340 data format (%d)\n", + p_adapter_id_str, data_format); + return -1; + } + + if (addr == 0x0006) { + /* Wait 300ms before continuing. See NT200E3-2-PTP_U23_Si5340_adr0_v2.h */ + NT_OS_WAIT_USEC(300000); + } + + nthw_si5340_write(p, addr, value); + + if (addr == 0x001C) { + /* skip readback for "soft reset" register */ + continue; + } + + ctrl_value = nthw_si5340_read(p, addr); + + if (ctrl_value != value) { + NT_LOG(ERR, NTHW, + "%s: Si5340 configuration readback check failed. (Addr = 0x%04X, Write = 0x%02X, Read = 0x%02X)\n", + p_adapter_id_str, addr, value, ctrl_value); + return -1; + } + } + return 0; +} + +int nthw_si5340_config(nthw_si5340_t *p, const void *p_data, int data_cnt, + clk_profile_data_fmt_t data_format) +{ + const char *const p_adapter_id_str = + p->mp_nthw_iic->mp_fpga->p_fpga_info->mp_adapter_id_str; + int i; + bool success = false; + uint8_t status, sticky; + uint8_t design_id[9]; + + (void)nthw_si5340_cfg(p, p_data, data_cnt, data_format); + + /* Check if DPLL is locked and SYS is calibrated */ + for (i = 0; i < 5; i++) { + status = nthw_si5340_read(p, 0x0c); + sticky = nthw_si5340_read(p, 0x11); + nthw_si5340_write(p, 0x11, 0x00); + + if (((status & 0x09) == 0x00) && ((sticky & 0x09) == 0x00)) { + success = true; + break; + } + NT_OS_WAIT_USEC(1000000); /* 1 sec */ + } + + if (!success) { + NT_LOG(ERR, NTHW, + "%s: Si5340 configuration failed. (Status = 0x%02X, Sticky = 0x%02X)\n", + p_adapter_id_str, status, sticky); + return -1; + } + + for (i = 0; i < (int)sizeof(design_id) - 1; i++) + design_id[i] = nthw_si5340_read(p, (uint16_t)(0x26B + i)); + design_id[sizeof(design_id) - 1] = 0; + + (void)design_id; /* Only used in debug mode */ + NT_LOG(DBG, NTHW, "%s: Si5340.DesignId = %s\n", p_adapter_id_str, + design_id); + + return 0; +} + +int nthw_si5340_config_fmt1(nthw_si5340_t *p, const clk_profile_data_fmt1_t *p_data, + const int data_cnt) +{ + return nthw_si5340_config(p, p_data, data_cnt, CLK_PROFILE_DATA_FMT_1); +} + +int nthw_si5340_config_fmt2(nthw_si5340_t *p, const clk_profile_data_fmt2_t *p_data, + const int data_cnt) +{ + return nthw_si5340_config(p, p_data, data_cnt, CLK_PROFILE_DATA_FMT_2); +} diff --git a/drivers/net/ntnic/nthw/core/nthw_si5340.h b/drivers/net/ntnic/nthw/core/nthw_si5340.h new file mode 100644 index 0000000000..f588b5b825 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_si5340.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_SI5340_H__ +#define __NTHW_SI5340_H__ + +#include "nthw_clock_profiles.h" + +#define SI5340_SUCCESS (0) +#define SI5340_FAILED (999) +#define SI5340_TIMEOUT (666) + +struct nthw_si5340 { + uint8_t mn_iic_addr; + nthw_iic_t *mp_nthw_iic; + int mn_clk_cfg; + uint8_t m_si5340_page; +}; + +typedef struct nthw_si5340 nthw_si5340_t; + +nthw_si5340_t *nthw_si5340_new(void); +int nthw_si5340_init(nthw_si5340_t *p, nthw_iic_t *p_nthw_iic, uint8_t n_iic_addr); +void nthw_si5340_delete(nthw_si5340_t *p); + +int nthw_si5340_config(nthw_si5340_t *p, const void *p_data, int data_cnt, + clk_profile_data_fmt_t data_format); +int nthw_si5340_config_fmt1(nthw_si5340_t *p, const clk_profile_data_fmt1_t *p_data, + const int data_cnt); +int nthw_si5340_config_fmt2(nthw_si5340_t *p, const clk_profile_data_fmt2_t *p_data, + const int data_cnt); + +#endif /* __NTHW_SI5338_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_spi_v3.c b/drivers/net/ntnic/nthw/core/nthw_spi_v3.c new file mode 100644 index 0000000000..454c9b73b8 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_spi_v3.c @@ -0,0 +1,380 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_fpga.h" + +#include "nthw_spi_v3.h" + +#include + +#undef SPI_V3_DEBUG_PRINT + +nthw_spi_v3_t *nthw_spi_v3_new(void) +{ + nthw_spi_v3_t *p = malloc(sizeof(nthw_spi_v3_t)); + + if (p) + memset(p, 0, sizeof(nthw_spi_v3_t)); + return p; +} + +void nthw_spi_v3_delete(nthw_spi_v3_t *p) +{ + if (p) { + if (p->mp_spim_mod) { + nthw_spim_delete(p->mp_spim_mod); + p->mp_spim_mod = NULL; + } + + if (p->mp_spis_mod) { + nthw_spis_delete(p->mp_spis_mod); + p->mp_spis_mod = NULL; + } + + memset(p, 0, sizeof(nthw_spi_v3_t)); + free(p); + } +} + +int nthw_spi_v3_set_timeout(nthw_spi_v3_t *p, int time_out) +{ + p->m_time_out = time_out; + return 0; +} + +int nthw_spi_v3_get_version(nthw_spi_v3_t *p) +{ + (void)p; + return 3; +} + +/* + * Wait until Tx data have been sent after they have been placed in the Tx FIFO. + */ +static int wait_for_tx_data_sent(nthw_spim_t *p_spim_mod, uint64_t time_out) +{ + int result; + bool empty; + uint64_t start_time; + uint64_t cur_time; + + start_time = NT_OS_GET_TIME_MONOTONIC_COUNTER(); + + while (true) { + NT_OS_WAIT_USEC(1000); /* Every 1ms */ + + result = nthw_spim_get_tx_fifo_empty(p_spim_mod, &empty); + if (result != 0) { + NT_LOG(WRN, NTHW, + "nthw_spim_get_tx_fifo_empty failed\n"); + return result; + } + + if (empty) + break; + + cur_time = NT_OS_GET_TIME_MONOTONIC_COUNTER(); + if ((cur_time - start_time) > time_out) { + NT_LOG(WRN, NTHW, "%s: Timed out\n", __func__); + return -1; + } + } + + return 0; +} + +/* + * Wait until Rx data have been received. + */ +static int wait_for_rx_data_ready(nthw_spis_t *p_spis_mod, uint64_t time_out) +{ + int result; + bool empty; + uint64_t start_time; + uint64_t cur_time; + + start_time = NT_OS_GET_TIME_MONOTONIC_COUNTER(); + + /* Wait for data to become ready in the Rx FIFO */ + while (true) { + NT_OS_WAIT_USEC(10000); /* Every 10ms */ + + result = nthw_spis_get_rx_fifo_empty(p_spis_mod, &empty); + if (result != 0) { + NT_LOG(WRN, NTHW, "nthw_spis_get_rx_empty failed\n"); + return result; + } + + if (!empty) + break; + + cur_time = NT_OS_GET_TIME_MONOTONIC_COUNTER(); + if ((cur_time - start_time) > time_out) { + NT_LOG(WRN, NTHW, "%s: Timed out\n", __func__); + return -1; + } + } + + return 0; +} + +#ifdef SPI_V3_DEBUG_PRINT +static void dump_hex(uint8_t *p_data, uint16_t count) +{ + int i; + int j = 0; + char tmp_str[128]; + + for (i = 0; i < count; i++) { + sprintf(&tmp_str[j * 3], "%02X ", *(p_data++)); + j++; + + if (j == 16 || (i == count - 1)) { + tmp_str[j * 3 - 1] = '\0'; + NT_LOG(DBG, NTHW, " %s\n", tmp_str); + j = 0; + } + } +} +#endif + +int nthw_spi_v3_init(nthw_spi_v3_t *p, nt_fpga_t *p_fpga, int n_instance_no) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + uint32_t result; + + p->mn_instance_no = n_instance_no; + + nthw_spi_v3_set_timeout(p, 1); + + /* Initialize SPIM module */ + p->mp_spim_mod = nthw_spim_new(); + + result = nthw_spim_init(p->mp_spim_mod, p_fpga, n_instance_no); + if (result != 0) { + NT_LOG(ERR, NTHW, "%s: nthw_spis_init failed: %d\n", + p_adapter_id_str, result); + } + + /* Initialize SPIS module */ + p->mp_spis_mod = nthw_spis_new(); + + result = nthw_spis_init(p->mp_spis_mod, p_fpga, n_instance_no); + if (result != 0) { + NT_LOG(ERR, NTHW, "%s: nthw_spim_init failed: %d\n", + p_adapter_id_str, result); + } + + /* Reset SPIM and SPIS modules */ + result = nthw_spim_reset(p->mp_spim_mod); + if (result != 0) { + NT_LOG(ERR, NTHW, "%s: nthw_spim_reset failed: %d\n", + p_adapter_id_str, result); + } + + result = nthw_spis_reset(p->mp_spis_mod); + if (result != 0) { + NT_LOG(ERR, NTHW, "%s: nthw_spis_reset failed: %d\n", + p_adapter_id_str, result); + } + + return result; +} + +/* + * Send Tx data using the SPIM module and receive any data using the SPIS module. + * The data are sent and received being wrapped into a SPI v3 container. + */ +int nthw_spi_v3_transfer(nthw_spi_v3_t *p, uint16_t opcode, + struct tx_rx_buf *tx_buf, struct tx_rx_buf *rx_buf) +{ + const uint16_t max_payload_rx_size = rx_buf->size; + int result = 0; + +#pragma pack(push, 1) + union { + uint32_t raw; + + struct { + uint16_t opcode; + uint16_t size; + }; + } spi_tx_hdr; + + union { + uint32_t raw; + + struct { + uint16_t error_code; + uint16_t size; + }; + } spi_rx_hdr; +#pragma pack(pop) + +#ifdef SPI_V3_DEBUG_PRINT + NT_LOG(DBG, NTHW, "%s: Started\n", __func__); +#endif + + /* Disable transmission from Tx FIFO */ + result = nthw_spim_enable(p->mp_spim_mod, false); + if (result != 0) { + NT_LOG(WRN, NTHW, "nthw_spim_enable failed\n"); + return result; + } + + /* Enable SPIS module */ + result = nthw_spis_enable(p->mp_spis_mod, true); + if (result != 0) { + NT_LOG(WRN, NTHW, "nthw_spis_enable failed\n"); + return result; + } + + /* Put data into Tx FIFO */ + spi_tx_hdr.opcode = opcode; + spi_tx_hdr.size = tx_buf->size; + +#ifdef SPI_V3_DEBUG_PRINT + NT_LOG(DBG, NTHW, "opcode=0x%04X tx_bufsize=0x%04X rx_bufsize=0x%04X\n", + opcode, tx_buf->size, rx_buf->size); + +#endif /* SPI_V3_DEBUG_PRINT */ + + result = nthw_spim_write_tx_fifo(p->mp_spim_mod, htonl(spi_tx_hdr.raw)); + if (result != 0) { + NT_LOG(WRN, NTHW, "nthw_spim_write_tx_fifo failed\n"); + return result; + } + + { + uint8_t *tx_data = (uint8_t *)tx_buf->p_buf; + uint16_t tx_size = tx_buf->size; + uint16_t count; + uint32_t value; + + while (tx_size > 0) { + if (tx_size > 4) { + count = 4; + } else { + count = tx_size; + value = 0; + } + + memcpy(&value, tx_data, count); + + result = nthw_spim_write_tx_fifo(p->mp_spim_mod, + htonl(value)); + if (result != 0) { + NT_LOG(WRN, NTHW, + "nthw_spim_write_tx_fifo failed\n"); + return result; + } + + tx_size = (uint16_t)(tx_size - count); + tx_data += count; + } + } + + /* Enable Tx FIFO */ + result = nthw_spim_enable(p->mp_spim_mod, true); + if (result != 0) { + NT_LOG(WRN, NTHW, "nthw_spim_enable failed\n"); + return result; + } + + result = wait_for_tx_data_sent(p->mp_spim_mod, p->m_time_out); + if (result != 0) + return result; + +#ifdef SPI_V3_DEBUG_PRINT + NT_LOG(DBG, NTHW, "%s: SPI header and payload data have been sent\n", + __func__); +#endif + + { + /* + * Start receiving data + * The first data to read is the header + */ + uint16_t rx_size = sizeof(spi_rx_hdr.raw); + uint8_t *rx_data = (uint8_t *)rx_buf->p_buf; + bool rx_hdr_read = false; + + rx_buf->size = 0; + + while (true) { + uint16_t count; + uint32_t value; + + if (!rx_hdr_read) { /* Read the header */ + result = wait_for_rx_data_ready(p->mp_spis_mod, + p->m_time_out); + if (result != 0) + return result; + + result = nthw_spis_read_rx_fifo(p->mp_spis_mod, + &spi_rx_hdr.raw); + if (result != 0) { + NT_LOG(WRN, NTHW, + "nthw_spis_read_rx_fifo failed\n"); + return result; + } + + spi_rx_hdr.raw = ntohl(spi_rx_hdr.raw); + rx_size = spi_rx_hdr.size; + rx_hdr_read = true; /* Next time read payload */ + +#ifdef SPI_V3_DEBUG_PRINT + NT_LOG(DBG, NTHW, + " spi_rx_hdr.error_code = 0x%04X, spi_rx_hdr.size = 0x%04X\n", + spi_rx_hdr.error_code, spi_rx_hdr.size); +#endif + + if (spi_rx_hdr.error_code != 0) { + result = -1; /* NT_ERROR_AVR_OPCODE_RETURNED_ERROR; */ + break; + } + + if (rx_size > max_payload_rx_size) { + result = 1; /* NT_ERROR_AVR_RX_BUFFER_TOO_SMALL; */ + break; + } + } else { /* Read the payload */ + count = (uint16_t)(rx_size < 4U ? rx_size : 4U); + + if (count == 0) + break; + + result = wait_for_rx_data_ready(p->mp_spis_mod, + p->m_time_out); + if (result != 0) + return result; + + result = nthw_spis_read_rx_fifo(p->mp_spis_mod, + &value); + if (result != 0) { + NT_LOG(WRN, NTHW, + "nthw_spis_read_rx_fifo failed\n"); + return result; + } + + value = ntohl(value); /* Convert to host endian */ + memcpy(rx_data, &value, count); + rx_buf->size = (uint16_t)(rx_buf->size + count); + rx_size = (uint16_t)(rx_size - count); + rx_data += count; + } + } + } + +#ifdef SPI_V3_DEBUG_PRINT + NT_LOG(DBG, NTHW, " RxData: %d\n", rx_buf->size); + dump_hex(rx_buf->p_buf, rx_buf->size); + NT_LOG(DBG, NTHW, "%s: Ended: %d\n", __func__, result); +#endif + + return result; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_spi_v3.h b/drivers/net/ntnic/nthw/core/nthw_spi_v3.h new file mode 100644 index 0000000000..c54379a273 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_spi_v3.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NT4GA_SPI_V3__ +#define __NT4GA_SPI_V3__ + +/* Must include v1.x series. The first v1.0a only had 248 bytes of storage. v2.0x have 255 */ +#define MAX_AVR_CONTAINER_SIZE (248) + +enum avr_opcodes { + AVR_OP_NOP = 0, /* v2 NOP command */ + /* version handlers */ + AVR_OP_VERSION = 1, + AVR_OP_SPI_VERSION = 2, /* v2.0+ command Get protocol version */ + AVR_OP_SYSINFO = 3, + /* Ping handlers */ + AVR_OP_PING = 4, + AVR_OP_PING_DELAY = 5, + /* i2c handlers */ + AVR_OP_I2C_READ = 9, + AVR_OP_I2C_WRITE = 10, + AVR_OP_I2C_RANDOM_READ = 11, + /* VPD handlers */ + AVR_OP_VPD_READ = 19, + AVR_OP_VPD_WRITE = 20, + /* SENSOR handlers */ + AVR_OP_SENSOR_FETCH = 28, + /* The following command are only relevant to V3 */ + AVR_OP_SENSOR_MON_CONTROL = 42, + AVR_OP_SENSOR_MON_SETUP = 43, + /* special version handler */ + AVR_OP_SYSINFO_2 = 62, +}; + +#define GEN2_AVR_IDENT_SIZE (20) +#define GEN2_AVR_VERSION_SIZE (50) + +#define GEN2_PN_SIZE (13) +#define GEN2_PBA_SIZE (16) +#define GEN2_SN_SIZE (10) +#define GEN2_BNAME_SIZE (14) +#define GEN2_PLATFORM_SIZE (72) +#define GEN2_VPD_SIZE_TOTAL \ + (1 + GEN2_PN_SIZE + GEN2_PBA_SIZE + GEN2_SN_SIZE + GEN2_BNAME_SIZE + \ + GEN2_PLATFORM_SIZE + 2) + +typedef struct vpd_eeprom_s { + uint8_t psu_hw_version; /* Hw revision - MUST NEVER ne overwritten. */ + /* Vital Product Data: P/N (13bytes ascii 0-9) */ + uint8_t vpd_pn[GEN2_PN_SIZE]; + /* Vital Product Data: PBA (16bytes ascii 0-9) */ + uint8_t vpd_pba[GEN2_PBA_SIZE]; + /* Vital Product Data: S/N (10bytes ascii 0-9) */ + uint8_t vpd_sn[GEN2_SN_SIZE]; + /* Vital Product Data: Board Name (10bytes ascii) (e.g. "ntmainb1e2" or "ntfront20b1") */ + uint8_t vpd_board_name[GEN2_BNAME_SIZE]; + /* + * Vital Product Data: Other (72bytes of MAC addresses or other stuff.. (gives up to 12 mac + * addresses) + */ + uint8_t vpd_platform_section[GEN2_PLATFORM_SIZE]; + /* CRC16 checksum of all of above. This field is not included in the checksum */ + uint16_t crc16; +} vpd_eeprom_t; + +typedef struct { + uint8_t psu_hw_revision; + char board_type[GEN2_BNAME_SIZE + 1]; + char product_id[GEN2_PN_SIZE + 1]; + char pba_id[GEN2_PBA_SIZE + 1]; + char serial_number[GEN2_SN_SIZE + 1]; + uint8_t product_family; + uint32_t feature_mask; + uint32_t invfeature_mask; + uint8_t no_of_macs; + uint8_t mac_address[6]; + uint16_t custom_id; + uint8_t user_id[8]; +} board_info_t; + +struct tx_rx_buf { + uint16_t size; + void *p_buf; +}; + +struct nthw__spi__v3 { + int m_time_out; + int mn_instance_no; + nthw_spim_t *mp_spim_mod; + nthw_spis_t *mp_spis_mod; +}; + +typedef struct nthw__spi__v3 nthw_spi_v3_t; +typedef struct nthw__spi__v3 nthw_spi_v3; + +nthw_spi_v3_t *nthw_spi_v3_new(void); +int nthw_spi_v3_init(nthw_spi_v3_t *p, nt_fpga_t *p_fpga, int n_instance_no); +void nthw_spi_v3_delete(nthw_spi_v3_t *p); + +int nthw_spi_v3_set_timeout(nthw_spi_v3_t *p, int time_out); +int nthw_spi_v3_get_version(nthw_spi_v3_t *p); +int nthw_spi_v3_transfer(nthw_spi_v3_t *p, uint16_t opcode, + struct tx_rx_buf *tx_buf, struct tx_rx_buf *rx_buf); + +#endif /* __NT4GA_SPI_V3__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_spim.c b/drivers/net/ntnic/nthw/core/nthw_spim.c new file mode 100644 index 0000000000..ece7db26e1 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_spim.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_spim.h" + +nthw_spim_t *nthw_spim_new(void) +{ + nthw_spim_t *p = malloc(sizeof(nthw_spim_t)); + + if (p) + memset(p, 0, sizeof(nthw_spim_t)); + return p; +} + +int nthw_spim_init(nthw_spim_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + nt_module_t *mod = fpga_query_module(p_fpga, MOD_SPIM, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: SPIM %d: no such instance\n", + p_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_spim = mod; + + /* SPIM is a primary communication channel - turn off debug by default */ + module_set_debug_mode(p->mp_mod_spim, 0x00); + + p->mp_reg_srr = module_get_register(p->mp_mod_spim, SPIM_SRR); + p->mp_fld_srr_rst = register_get_field(p->mp_reg_srr, SPIM_SRR_RST); + + p->mp_reg_cr = module_get_register(p->mp_mod_spim, SPIM_CR); + p->mp_fld_cr_loop = register_get_field(p->mp_reg_cr, SPIM_CR_LOOP); + p->mp_fld_cr_en = register_get_field(p->mp_reg_cr, SPIM_CR_EN); + p->mp_fld_cr_txrst = register_get_field(p->mp_reg_cr, SPIM_CR_TXRST); + p->mp_fld_cr_rxrst = register_get_field(p->mp_reg_cr, SPIM_CR_RXRST); + + p->mp_reg_sr = module_get_register(p->mp_mod_spim, SPIM_SR); + p->mp_fld_sr_done = register_get_field(p->mp_reg_sr, SPIM_SR_DONE); + p->mp_fld_sr_txempty = register_get_field(p->mp_reg_sr, SPIM_SR_TXEMPTY); + p->mp_fld_sr_rxempty = register_get_field(p->mp_reg_sr, SPIM_SR_RXEMPTY); + p->mp_fld_sr_txfull = register_get_field(p->mp_reg_sr, SPIM_SR_TXFULL); + p->mp_fld_sr_rxfull = register_get_field(p->mp_reg_sr, SPIM_SR_RXFULL); + p->mp_fld_sr_txlvl = register_get_field(p->mp_reg_sr, SPIM_SR_TXLVL); + p->mp_fld_sr_rxlvl = register_get_field(p->mp_reg_sr, SPIM_SR_RXLVL); + + p->mp_reg_dtr = module_get_register(p->mp_mod_spim, SPIM_DTR); + p->mp_fld_dtr_dtr = register_get_field(p->mp_reg_dtr, SPIM_DTR_DTR); + + p->mp_reg_drr = module_get_register(p->mp_mod_spim, SPIM_DRR); + p->mp_fld_drr_drr = register_get_field(p->mp_reg_drr, SPIM_DRR_DRR); + + p->mp_reg_cfg = module_get_register(p->mp_mod_spim, SPIM_CFG); + p->mp_fld_cfg_pre = register_get_field(p->mp_reg_cfg, SPIM_CFG_PRE); + + return 0; +} + +void nthw_spim_delete(nthw_spim_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_spim_t)); + free(p); + } +} + +uint32_t nthw_spim_reset(nthw_spim_t *p) +{ + register_update(p->mp_reg_srr); + field_set_val32(p->mp_fld_srr_rst, + 0x0A); /* 0x0A hardcoded value - see doc */ + register_flush(p->mp_reg_srr, 1); + + return 0; +} + +uint32_t nthw_spim_enable(nthw_spim_t *p, bool b_enable) +{ + field_update_register(p->mp_fld_cr_en); + + if (b_enable) + field_set_all(p->mp_fld_cr_en); + + else + field_clr_all(p->mp_fld_cr_en); + field_flush_register(p->mp_fld_cr_en); + + return 0; +} + +uint32_t nthw_spim_write_tx_fifo(nthw_spim_t *p, uint32_t n_data) +{ + field_set_val_flush32(p->mp_fld_dtr_dtr, n_data); + return 0; +} + +uint32_t nthw_spim_get_tx_fifo_empty(nthw_spim_t *p, bool *pb_empty) +{ + assert(pb_empty); + + *pb_empty = field_get_updated(p->mp_fld_sr_txempty) ? true : false; + + return 0; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_spim.h b/drivers/net/ntnic/nthw/core/nthw_spim.h new file mode 100644 index 0000000000..713751e563 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_spim.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_SPIM_H__ +#define __NTHW_SPIM_H__ + +struct nthw_spim { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_spim; + int mn_instance; + + nt_register_t *mp_reg_srr; + nt_field_t *mp_fld_srr_rst; + + nt_register_t *mp_reg_cr; + nt_field_t *mp_fld_cr_loop; + nt_field_t *mp_fld_cr_en; + nt_field_t *mp_fld_cr_txrst; + nt_field_t *mp_fld_cr_rxrst; + + nt_register_t *mp_reg_sr; + nt_field_t *mp_fld_sr_done; + nt_field_t *mp_fld_sr_txempty; + nt_field_t *mp_fld_sr_rxempty; + nt_field_t *mp_fld_sr_txfull; + nt_field_t *mp_fld_sr_rxfull; + nt_field_t *mp_fld_sr_txlvl; + nt_field_t *mp_fld_sr_rxlvl; + + nt_register_t *mp_reg_dtr; + nt_field_t *mp_fld_dtr_dtr; + + nt_register_t *mp_reg_drr; + nt_field_t *mp_fld_drr_drr; + nt_register_t *mp_reg_cfg; + nt_field_t *mp_fld_cfg_pre; +}; + +typedef struct nthw_spim nthw_spim_t; +typedef struct nthw_spim nthw_spim; + +nthw_spim_t *nthw_spim_new(void); +int nthw_spim_init(nthw_spim_t *p, nt_fpga_t *p_fpga, int n_instance); +void nthw_spim_delete(nthw_spim_t *p); + +uint32_t nthw_spim_reset(nthw_spim_t *p); +uint32_t nthw_spim_enable(nthw_spim_t *p, bool b_enable); +uint32_t nthw_spim_get_tx_fifo_empty(nthw_spim_t *p, bool *pb_empty); +uint32_t nthw_spim_write_tx_fifo(nthw_spim_t *p, uint32_t n_data); + +#endif /* __NTHW_SPIM_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_spis.c b/drivers/net/ntnic/nthw/core/nthw_spis.c new file mode 100644 index 0000000000..8799584194 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_spis.c @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_spis.h" + +nthw_spis_t *nthw_spis_new(void) +{ + nthw_spis_t *p = malloc(sizeof(nthw_spis_t)); + + if (p) + memset(p, 0, sizeof(nthw_spis_t)); + return p; +} + +int nthw_spis_init(nthw_spis_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + nt_module_t *mod = fpga_query_module(p_fpga, MOD_SPIS, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: SPIS %d: no such instance\n", + p_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_spis = mod; + + /* SPIS is a primary communication channel - turn off debug by default */ + module_set_debug_mode(p->mp_mod_spis, 0x00); + + p->mp_reg_srr = module_get_register(p->mp_mod_spis, SPIS_SRR); + p->mp_fld_srr_rst = register_get_field(p->mp_reg_srr, SPIS_SRR_RST); + + p->mp_reg_cr = module_get_register(p->mp_mod_spis, SPIS_CR); + p->mp_fld_cr_loop = register_get_field(p->mp_reg_cr, SPIS_CR_LOOP); + p->mp_fld_cr_en = register_get_field(p->mp_reg_cr, SPIS_CR_EN); + p->mp_fld_cr_txrst = register_get_field(p->mp_reg_cr, SPIS_CR_TXRST); + p->mp_fld_cr_rxrst = register_get_field(p->mp_reg_cr, SPIS_CR_RXRST); + p->mp_fld_cr_debug = register_get_field(p->mp_reg_cr, SPIS_CR_DEBUG); + + p->mp_reg_sr = module_get_register(p->mp_mod_spis, SPIS_SR); + p->mp_fld_sr_done = register_get_field(p->mp_reg_sr, SPIS_SR_DONE); + p->mp_fld_sr_txempty = register_get_field(p->mp_reg_sr, SPIS_SR_TXEMPTY); + p->mp_fld_sr_rxempty = register_get_field(p->mp_reg_sr, SPIS_SR_RXEMPTY); + p->mp_fld_sr_txfull = register_get_field(p->mp_reg_sr, SPIS_SR_TXFULL); + p->mp_fld_sr_rxfull = register_get_field(p->mp_reg_sr, SPIS_SR_RXFULL); + p->mp_fld_sr_txlvl = register_get_field(p->mp_reg_sr, SPIS_SR_TXLVL); + p->mp_fld_sr_rxlvl = register_get_field(p->mp_reg_sr, SPIS_SR_RXLVL); + p->mp_fld_sr_frame_err = + register_get_field(p->mp_reg_sr, SPIS_SR_FRAME_ERR); + p->mp_fld_sr_read_err = register_get_field(p->mp_reg_sr, SPIS_SR_READ_ERR); + p->mp_fld_sr_write_err = + register_get_field(p->mp_reg_sr, SPIS_SR_WRITE_ERR); + + p->mp_reg_dtr = module_get_register(p->mp_mod_spis, SPIS_DTR); + p->mp_fld_dtr_dtr = register_get_field(p->mp_reg_dtr, SPIS_DTR_DTR); + + p->mp_reg_drr = module_get_register(p->mp_mod_spis, SPIS_DRR); + p->mp_fld_drr_drr = register_get_field(p->mp_reg_drr, SPIS_DRR_DRR); + + p->mp_reg_ram_ctrl = module_get_register(p->mp_mod_spis, SPIS_RAM_CTRL); + p->mp_fld_ram_ctrl_adr = + register_get_field(p->mp_reg_ram_ctrl, SPIS_RAM_CTRL_ADR); + p->mp_fld_ram_ctrl_cnt = + register_get_field(p->mp_reg_ram_ctrl, SPIS_RAM_CTRL_CNT); + + p->mp_reg_ram_data = module_get_register(p->mp_mod_spis, SPIS_RAM_DATA); + p->mp_fld_ram_data_data = + register_get_field(p->mp_reg_ram_data, SPIS_RAM_DATA_DATA); + + return 0; +} + +void nthw_spis_delete(nthw_spis_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_spis_t)); + free(p); + } +} + +uint32_t nthw_spis_reset(nthw_spis_t *p) +{ + register_update(p->mp_reg_srr); + field_set_val32(p->mp_fld_srr_rst, + 0x0A); /* 0x0A hardcoded value - see doc */ + register_flush(p->mp_reg_srr, 1); + + return 0; +} + +uint32_t nthw_spis_enable(nthw_spis_t *p, bool b_enable) +{ + field_update_register(p->mp_fld_cr_en); + + if (b_enable) + field_set_all(p->mp_fld_cr_en); + + else + field_clr_all(p->mp_fld_cr_en); + field_flush_register(p->mp_fld_cr_en); + + return 0; +} + +uint32_t nthw_spis_get_rx_fifo_empty(nthw_spis_t *p, bool *pb_empty) +{ + assert(pb_empty); + + *pb_empty = field_get_updated(p->mp_fld_sr_rxempty) ? true : false; + + return 0; +} + +uint32_t nthw_spis_read_rx_fifo(nthw_spis_t *p, uint32_t *p_data) +{ + assert(p_data); + + *p_data = field_get_updated(p->mp_fld_drr_drr); + + return 0; +} + +uint32_t nthw_spis_read_sensor(nthw_spis_t *p, uint8_t n_result_idx, + uint32_t *p_sensor_result) +{ + assert(p_sensor_result); + + field_set_val32(p->mp_fld_ram_ctrl_adr, n_result_idx); + field_set_val32(p->mp_fld_ram_ctrl_cnt, 1); + register_flush(p->mp_reg_ram_ctrl, 1); + + *p_sensor_result = field_get_updated(p->mp_fld_ram_data_data); + + return 0; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_spis.h b/drivers/net/ntnic/nthw/core/nthw_spis.h new file mode 100644 index 0000000000..2ebe840c9e --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_spis.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_SPIS_H__ +#define __NTHW_SPIS_H__ + +struct nthw_spis { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_spis; + int mn_instance; + + nt_register_t *mp_reg_srr; + nt_field_t *mp_fld_srr_rst; + + nt_register_t *mp_reg_cr; + nt_field_t *mp_fld_cr_loop; + nt_field_t *mp_fld_cr_en; + nt_field_t *mp_fld_cr_txrst; + nt_field_t *mp_fld_cr_rxrst; + nt_field_t *mp_fld_cr_debug; + + nt_register_t *mp_reg_sr; + nt_field_t *mp_fld_sr_done; + nt_field_t *mp_fld_sr_txempty; + nt_field_t *mp_fld_sr_rxempty; + nt_field_t *mp_fld_sr_txfull; + nt_field_t *mp_fld_sr_rxfull; + nt_field_t *mp_fld_sr_txlvl; + nt_field_t *mp_fld_sr_rxlvl; + nt_field_t *mp_fld_sr_frame_err; + nt_field_t *mp_fld_sr_read_err; + nt_field_t *mp_fld_sr_write_err; + + nt_register_t *mp_reg_dtr; + nt_field_t *mp_fld_dtr_dtr; + + nt_register_t *mp_reg_drr; + nt_field_t *mp_fld_drr_drr; + + nt_register_t *mp_reg_ram_ctrl; + nt_field_t *mp_fld_ram_ctrl_adr; + nt_field_t *mp_fld_ram_ctrl_cnt; + + nt_register_t *mp_reg_ram_data; + nt_field_t *mp_fld_ram_data_data; +}; + +typedef struct nthw_spis nthw_spis_t; +typedef struct nthw_spis nthw_spis; + +nthw_spis_t *nthw_spis_new(void); +int nthw_spis_init(nthw_spis_t *p, nt_fpga_t *p_fpga, int n_instance); +void nthw_spis_delete(nthw_spis_t *p); + +uint32_t nthw_spis_reset(nthw_spis_t *p); +uint32_t nthw_spis_enable(nthw_spis_t *p, bool b_enable); +uint32_t nthw_spis_get_rx_fifo_empty(nthw_spis_t *p, bool *pb_empty); +uint32_t nthw_spis_read_rx_fifo(nthw_spis_t *p, uint32_t *p_data); +uint32_t nthw_spis_read_sensor(nthw_spis_t *p, uint8_t n_result_idx, + uint32_t *p_sensor_result); + +#endif /* __NTHW_SPIS_H__ */ diff --git a/drivers/net/ntnic/nthw/core/nthw_tsm.c b/drivers/net/ntnic/nthw/core/nthw_tsm.c new file mode 100644 index 0000000000..8ea4a4c440 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_tsm.c @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_tsm.h" + +nthw_tsm_t *nthw_tsm_new(void) +{ + nthw_tsm_t *p = malloc(sizeof(nthw_tsm_t)); + + if (p) + memset(p, 0, sizeof(nthw_tsm_t)); + return p; +} + +void nthw_tsm_delete(nthw_tsm_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_tsm_t)); + free(p); + } +} + +int nthw_tsm_init(nthw_tsm_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + nt_module_t *mod = fpga_query_module(p_fpga, MOD_TSM, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: TSM %d: no such instance\n", + p_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_tsm = mod; + + { + nt_register_t *p_reg; + + p_reg = module_get_register(p->mp_mod_tsm, TSM_CONFIG); + p->mp_fld_config_ts_format = + register_get_field(p_reg, TSM_CONFIG_TS_FORMAT); + + p_reg = module_get_register(p->mp_mod_tsm, TSM_TIMER_CTRL); + p->mp_fld_timer_ctrl_timer_en_t0 = + register_get_field(p_reg, TSM_TIMER_CTRL_TIMER_EN_T0); + p->mp_fld_timer_ctrl_timer_en_t1 = + register_get_field(p_reg, TSM_TIMER_CTRL_TIMER_EN_T1); + + p_reg = module_get_register(p->mp_mod_tsm, TSM_TIMER_T0); + p->mp_fld_timer_timer_t0_max_count = + register_get_field(p_reg, TSM_TIMER_T0_MAX_COUNT); + + p_reg = module_get_register(p->mp_mod_tsm, TSM_TIMER_T1); + p->mp_fld_timer_timer_t1_max_count = + register_get_field(p_reg, TSM_TIMER_T1_MAX_COUNT); + + p_reg = module_get_register(p->mp_mod_tsm, TSM_TIME_LO); + p->mp_reg_time_lo = module_get_register(p->mp_mod_tsm, TSM_TIME_LO); + p->mp_fld_time_lo = register_get_field(p_reg, TSM_TIME_LO_NS); + + p_reg = module_get_register(p->mp_mod_tsm, TSM_TIME_HI); + p->mp_reg_time_hi = module_get_register(p->mp_mod_tsm, TSM_TIME_HI); + p->mp_fld_time_hi = register_get_field(p_reg, TSM_TIME_HI_SEC); + + p_reg = module_get_register(p->mp_mod_tsm, TSM_TS_LO); + p->mp_reg_ts_lo = module_get_register(p->mp_mod_tsm, TSM_TS_LO); + p->mp_fld_ts_lo = register_get_field(p_reg, TSM_TS_LO_TIME); + + p_reg = module_get_register(p->mp_mod_tsm, TSM_TS_HI); + p->mp_reg_ts_hi = module_get_register(p->mp_mod_tsm, TSM_TS_HI); + p->mp_fld_ts_hi = register_get_field(p_reg, TSM_TS_HI_TIME); + } + return 0; +} + +int nthw_tsm_get_ts(nthw_tsm_t *p, uint64_t *p_ts) +{ + uint32_t n_ts_lo, n_ts_hi; + uint64_t val; + + if (!p_ts) + return -1; + + n_ts_lo = field_get_updated(p->mp_fld_ts_lo); + n_ts_hi = field_get_updated(p->mp_fld_ts_hi); + + val = ((((uint64_t)n_ts_hi) << 32UL) | n_ts_lo); + + if (p_ts) + *p_ts = val; + + return 0; +} + +int nthw_tsm_get_time(nthw_tsm_t *p, uint64_t *p_time) +{ + uint32_t n_time_lo, n_time_hi; + uint64_t val; + + if (!p_time) + return -1; + + n_time_lo = field_get_updated(p->mp_fld_time_lo); + n_time_hi = field_get_updated(p->mp_fld_time_hi); + + val = ((((uint64_t)n_time_hi) << 32UL) | n_time_lo); + + if (p_time) + *p_time = val; + + return 0; +} + +int nthw_tsm_set_time(nthw_tsm_t *p, uint64_t n_time) +{ + field_set_val_flush32(p->mp_fld_time_lo, (n_time & 0xFFFFFFFF)); + field_set_val_flush32(p->mp_fld_time_hi, + (uint32_t)((n_time >> 32) & 0xFFFFFFFF)); + return 0; +} + +int nthw_tsm_set_timer_t0_enable(nthw_tsm_t *p, bool b_enable) +{ + field_update_register(p->mp_fld_timer_ctrl_timer_en_t0); + if (b_enable) + field_set_flush(p->mp_fld_timer_ctrl_timer_en_t0); + + else + field_clr_flush(p->mp_fld_timer_ctrl_timer_en_t0); + return 0; +} + +int nthw_tsm_set_timer_t0_max_count(nthw_tsm_t *p, uint32_t n_timer_val) +{ + /* Timer T0 - stat toggle timer */ + field_update_register(p->mp_fld_timer_timer_t0_max_count); + field_set_val_flush32(p->mp_fld_timer_timer_t0_max_count, + n_timer_val); /* ns (50*1000*1000) */ + return 0; +} + +int nthw_tsm_set_timer_t1_enable(nthw_tsm_t *p, bool b_enable) +{ + field_update_register(p->mp_fld_timer_ctrl_timer_en_t1); + if (b_enable) + field_set_flush(p->mp_fld_timer_ctrl_timer_en_t1); + + else + field_clr_flush(p->mp_fld_timer_ctrl_timer_en_t1); + return 0; +} + +int nthw_tsm_set_timer_t1_max_count(nthw_tsm_t *p, uint32_t n_timer_val) +{ + /* Timer T1 - keep alive timer */ + field_update_register(p->mp_fld_timer_timer_t1_max_count); + field_set_val_flush32(p->mp_fld_timer_timer_t1_max_count, + n_timer_val); /* ns (100*1000*1000) */ + return 0; +} + +int nthw_tsm_set_config_ts_format(nthw_tsm_t *p, uint32_t n_val) +{ + field_update_register(p->mp_fld_config_ts_format); + /* 0x1: Native - 10ns units, start date: 1970-01-01. */ + field_set_val_flush32(p->mp_fld_config_ts_format, n_val); + return 0; +} diff --git a/drivers/net/ntnic/nthw/core/nthw_tsm.h b/drivers/net/ntnic/nthw/core/nthw_tsm.h new file mode 100644 index 0000000000..590e04c312 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_tsm.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_TSM_H__ +#define __NTHW_TSM_H__ + +struct nthw_tsm { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_tsm; + int mn_instance; + + nt_field_t *mp_fld_config_ts_format; + + nt_field_t *mp_fld_timer_ctrl_timer_en_t0; + nt_field_t *mp_fld_timer_ctrl_timer_en_t1; + + nt_field_t *mp_fld_timer_timer_t0_max_count; + + nt_field_t *mp_fld_timer_timer_t1_max_count; + + nt_register_t *mp_reg_ts_lo; + nt_field_t *mp_fld_ts_lo; + + nt_register_t *mp_reg_ts_hi; + nt_field_t *mp_fld_ts_hi; + + nt_register_t *mp_reg_time_lo; + nt_field_t *mp_fld_time_lo; + + nt_register_t *mp_reg_time_hi; + nt_field_t *mp_fld_time_hi; +}; + +typedef struct nthw_tsm nthw_tsm_t; +typedef struct nthw_tsm nthw_tsm; + +nthw_tsm_t *nthw_tsm_new(void); +void nthw_tsm_delete(nthw_tsm_t *p); +int nthw_tsm_init(nthw_tsm_t *p, nt_fpga_t *p_fpga, int n_instance); + +int nthw_tsm_get_ts(nthw_tsm_t *p, uint64_t *p_ts); +int nthw_tsm_get_time(nthw_tsm_t *p, uint64_t *p_time); +int nthw_tsm_set_time(nthw_tsm_t *p, uint64_t n_time); + +int nthw_tsm_set_timer_t0_enable(nthw_tsm_t *p, bool b_enable); +int nthw_tsm_set_timer_t0_max_count(nthw_tsm_t *p, uint32_t n_timer_val); +int nthw_tsm_set_timer_t1_enable(nthw_tsm_t *p, bool b_enable); +int nthw_tsm_set_timer_t1_max_count(nthw_tsm_t *p, uint32_t n_timer_val); + +int nthw_tsm_set_config_ts_format(nthw_tsm_t *p, uint32_t n_val); + +#endif /* __NTHW_TSM_H__ */ diff --git a/drivers/net/ntnic/nthw/nthw_dbs.c b/drivers/net/ntnic/nthw/nthw_dbs.c new file mode 100644 index 0000000000..9fc853da73 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_dbs.c @@ -0,0 +1,1301 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_dbs.h" + +#undef DBS_PRINT_REGS + +static void set_shadow_tx_qos_data(nthw_dbs_t *p, uint32_t index, uint32_t enable, + uint32_t ir, uint32_t bs); +static void flush_tx_qos_data(nthw_dbs_t *p, uint32_t index); +static void set_shadow_tx_qp_data(nthw_dbs_t *p, uint32_t index, + uint32_t virtual_port); +static void flush_tx_qp_data(nthw_dbs_t *p, uint32_t index); +static void set_shadow_tx_dr_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t host_id, + uint32_t queue_size, uint32_t port, + uint32_t header, uint32_t packed); +static void flush_tx_dr_data(nthw_dbs_t *p, uint32_t index); +static void set_shadow_rx_dr_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t host_id, + uint32_t queue_size, uint32_t header, + uint32_t packed); +static void flush_rx_dr_data(nthw_dbs_t *p, uint32_t index); +static void set_shadow_tx_uw_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t host_id, + uint32_t queue_size, uint32_t packed, + uint32_t int_enable, uint32_t vec, uint32_t istk, + uint32_t in_order); +static void flush_tx_uw_data(nthw_dbs_t *p, uint32_t index); +static void set_shadow_rx_uw_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t host_id, + uint32_t queue_size, uint32_t packed, + uint32_t int_enable, uint32_t vec, + uint32_t istk); +static void flush_rx_uw_data(nthw_dbs_t *p, uint32_t index); +static void set_shadow_rx_am_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t enable, + uint32_t host_id, uint32_t packed, + uint32_t int_enable); +static void flush_rx_am_data(nthw_dbs_t *p, uint32_t index); +static void set_shadow_tx_am_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t enable, + uint32_t host_id, uint32_t packed, + uint32_t int_enable); +static void flush_tx_am_data(nthw_dbs_t *p, uint32_t index); + +nthw_dbs_t *nthw_dbs_new(void) +{ + nthw_dbs_t *p = malloc(sizeof(nthw_dbs_t)); + + if (p) + memset(p, 0, sizeof(nthw_dbs_t)); + return p; +} + +void nthw_dbs_delete(nthw_dbs_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_dbs_t)); + free(p); + } +} + +int dbs_init(nthw_dbs_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + nt_module_t *mod = fpga_query_module(p_fpga, MOD_DBS, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: DBS %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_dbs = mod; + + p->mn_param_dbs_present = fpga_get_product_param(p_fpga, NT_DBS_PRESENT, 0); + if (p->mn_param_dbs_present == 0) { + NT_LOG(WRN, NTHW, + "%s: DBS %d: logical error: module found but not flagged at present\n", + p->mp_fpga->p_fpga_info->mp_adapter_id_str, p->mn_instance); + } + + p->mp_reg_rx_control = module_get_register(p->mp_mod_dbs, DBS_RX_CONTROL); + p->mp_fld_rx_control_last_queue = + register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_LQ); + p->mp_fld_rx_control_avail_monitor_enable = + register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_AME); + p->mp_fld_rx_control_avail_monitor_scan_speed = + register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_AMS); + p->mp_fld_rx_control_used_write_enable = + register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_UWE); + p->mp_fld_rx_control_used_writer_update_speed = + register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_UWS); + p->mp_fld_rx_control_rx_queues_enable = + register_get_field(p->mp_reg_rx_control, DBS_RX_CONTROL_QE); + + p->mp_reg_tx_control = module_get_register(p->mp_mod_dbs, DBS_TX_CONTROL); + p->mp_fld_tx_control_last_queue = + register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_LQ); + p->mp_fld_tx_control_avail_monitor_enable = + register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_AME); + p->mp_fld_tx_control_avail_monitor_scan_speed = + register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_AMS); + p->mp_fld_tx_control_used_write_enable = + register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_UWE); + p->mp_fld_tx_control_used_writer_update_speed = + register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_UWS); + p->mp_fld_tx_control_tx_queues_enable = + register_get_field(p->mp_reg_tx_control, DBS_TX_CONTROL_QE); + + p->mp_reg_rx_init = module_get_register(p->mp_mod_dbs, DBS_RX_INIT); + p->mp_fld_rx_init_init = + register_get_field(p->mp_reg_rx_init, DBS_RX_INIT_INIT); + p->mp_fld_rx_init_queue = + register_get_field(p->mp_reg_rx_init, DBS_RX_INIT_QUEUE); + p->mp_fld_rx_init_busy = + register_get_field(p->mp_reg_rx_init, DBS_RX_INIT_BUSY); + + p->mp_reg_rx_init_val = module_query_register(p->mp_mod_dbs, DBS_RX_INIT_VAL); + if (p->mp_reg_rx_init_val) { + p->mp_fld_rx_init_val_idx = register_query_field(p->mp_reg_rx_init_val, + DBS_RX_INIT_VAL_IDX); + p->mp_fld_rx_init_val_ptr = register_query_field(p->mp_reg_rx_init_val, + DBS_RX_INIT_VAL_PTR); + } + + p->mp_reg_rx_ptr = module_query_register(p->mp_mod_dbs, DBS_RX_PTR); + if (p->mp_reg_rx_ptr) { + p->mp_fld_rx_ptr_ptr = + register_query_field(p->mp_reg_rx_ptr, DBS_RX_PTR_PTR); + p->mp_fld_rx_ptr_queue = + register_query_field(p->mp_reg_rx_ptr, DBS_RX_PTR_QUEUE); + p->mp_fld_rx_ptr_valid = + register_query_field(p->mp_reg_rx_ptr, DBS_RX_PTR_VALID); + } + + p->mp_reg_tx_init = module_get_register(p->mp_mod_dbs, DBS_TX_INIT); + p->mp_fld_tx_init_init = + register_get_field(p->mp_reg_tx_init, DBS_TX_INIT_INIT); + p->mp_fld_tx_init_queue = + register_get_field(p->mp_reg_tx_init, DBS_TX_INIT_QUEUE); + p->mp_fld_tx_init_busy = + register_get_field(p->mp_reg_tx_init, DBS_TX_INIT_BUSY); + + p->mp_reg_tx_init_val = module_query_register(p->mp_mod_dbs, DBS_TX_INIT_VAL); + if (p->mp_reg_tx_init_val) { + p->mp_fld_tx_init_val_idx = register_query_field(p->mp_reg_tx_init_val, + DBS_TX_INIT_VAL_IDX); + p->mp_fld_tx_init_val_ptr = register_query_field(p->mp_reg_tx_init_val, + DBS_TX_INIT_VAL_PTR); + } + + p->mp_reg_tx_ptr = module_query_register(p->mp_mod_dbs, DBS_TX_PTR); + if (p->mp_reg_tx_ptr) { + p->mp_fld_tx_ptr_ptr = + register_query_field(p->mp_reg_tx_ptr, DBS_TX_PTR_PTR); + p->mp_fld_tx_ptr_queue = + register_query_field(p->mp_reg_tx_ptr, DBS_TX_PTR_QUEUE); + p->mp_fld_tx_ptr_valid = + register_query_field(p->mp_reg_tx_ptr, DBS_TX_PTR_VALID); + } + + p->mp_reg_rx_idle = module_query_register(p->mp_mod_dbs, DBS_RX_IDLE); + if (p->mp_reg_rx_idle) { + p->mp_fld_rx_idle_idle = + register_query_field(p->mp_reg_rx_idle, DBS_RX_IDLE_IDLE); + p->mp_fld_rx_idle_queue = + register_query_field(p->mp_reg_rx_idle, DBS_RX_IDLE_QUEUE); + p->mp_fld_rx_idle_busy = + register_query_field(p->mp_reg_rx_idle, DBS_RX_IDLE_BUSY); + } + + p->mp_reg_tx_idle = module_query_register(p->mp_mod_dbs, DBS_TX_IDLE); + if (p->mp_reg_tx_idle) { + p->mp_fld_tx_idle_idle = + register_query_field(p->mp_reg_tx_idle, DBS_TX_IDLE_IDLE); + p->mp_fld_tx_idle_queue = + register_query_field(p->mp_reg_tx_idle, DBS_TX_IDLE_QUEUE); + p->mp_fld_tx_idle_busy = + register_query_field(p->mp_reg_tx_idle, DBS_TX_IDLE_BUSY); + } + + p->mp_reg_rx_avail_monitor_control = + module_get_register(p->mp_mod_dbs, DBS_RX_AM_CTRL); + p->mp_fld_rx_avail_monitor_control_adr = + register_get_field(p->mp_reg_rx_avail_monitor_control, DBS_RX_AM_CTRL_ADR); + p->mp_fld_rx_avail_monitor_control_cnt = + register_get_field(p->mp_reg_rx_avail_monitor_control, DBS_RX_AM_CTRL_CNT); + + p->mp_reg_rx_avail_monitor_data = + module_get_register(p->mp_mod_dbs, DBS_RX_AM_DATA); + p->mp_fld_rx_avail_monitor_data_guest_physical_address = + register_get_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_GPA); + p->mp_fld_rx_avail_monitor_data_enable = + register_get_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_ENABLE); + p->mp_fld_rx_avail_monitor_data_host_id = + register_get_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_HID); + p->mp_fld_rx_avail_monitor_data_packed = + register_query_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_PCKED); + p->mp_fld_rx_avail_monitor_data_int = + register_query_field(p->mp_reg_rx_avail_monitor_data, DBS_RX_AM_DATA_INT); + + p->mp_reg_tx_avail_monitor_control = + module_get_register(p->mp_mod_dbs, DBS_TX_AM_CTRL); + p->mp_fld_tx_avail_monitor_control_adr = + register_get_field(p->mp_reg_tx_avail_monitor_control, DBS_TX_AM_CTRL_ADR); + p->mp_fld_tx_avail_monitor_control_cnt = + register_get_field(p->mp_reg_tx_avail_monitor_control, DBS_TX_AM_CTRL_CNT); + + p->mp_reg_tx_avail_monitor_data = + module_get_register(p->mp_mod_dbs, DBS_TX_AM_DATA); + p->mp_fld_tx_avail_monitor_data_guest_physical_address = + register_get_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_GPA); + p->mp_fld_tx_avail_monitor_data_enable = + register_get_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_ENABLE); + p->mp_fld_tx_avail_monitor_data_host_id = + register_get_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_HID); + p->mp_fld_tx_avail_monitor_data_packed = + register_query_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_PCKED); + p->mp_fld_tx_avail_monitor_data_int = + register_query_field(p->mp_reg_tx_avail_monitor_data, DBS_TX_AM_DATA_INT); + + p->mp_reg_rx_used_writer_control = + module_get_register(p->mp_mod_dbs, DBS_RX_UW_CTRL); + p->mp_fld_rx_used_writer_control_adr = + register_get_field(p->mp_reg_rx_used_writer_control, DBS_RX_UW_CTRL_ADR); + p->mp_fld_rx_used_writer_control_cnt = + register_get_field(p->mp_reg_rx_used_writer_control, DBS_RX_UW_CTRL_CNT); + + p->mp_reg_rx_used_writer_data = + module_get_register(p->mp_mod_dbs, DBS_RX_UW_DATA); + p->mp_fld_rx_used_writer_data_guest_physical_address = + register_get_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_GPA); + p->mp_fld_rx_used_writer_data_host_id = + register_get_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_HID); + p->mp_fld_rx_used_writer_data_queue_size = + register_get_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_QS); + p->mp_fld_rx_used_writer_data_packed = + register_query_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_PCKED); + p->mp_fld_rx_used_writer_data_int = + register_query_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_INT); + p->mp_fld_rx_used_writer_data_vec = + register_query_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_VEC); + p->mp_fld_rx_used_writer_data_istk = + register_query_field(p->mp_reg_rx_used_writer_data, DBS_RX_UW_DATA_ISTK); + + p->mp_reg_tx_used_writer_control = + module_get_register(p->mp_mod_dbs, DBS_TX_UW_CTRL); + p->mp_fld_tx_used_writer_control_adr = + register_get_field(p->mp_reg_tx_used_writer_control, DBS_TX_UW_CTRL_ADR); + p->mp_fld_tx_used_writer_control_cnt = + register_get_field(p->mp_reg_tx_used_writer_control, DBS_TX_UW_CTRL_CNT); + + p->mp_reg_tx_used_writer_data = + module_get_register(p->mp_mod_dbs, DBS_TX_UW_DATA); + p->mp_fld_tx_used_writer_data_guest_physical_address = + register_get_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_GPA); + p->mp_fld_tx_used_writer_data_host_id = + register_get_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_HID); + p->mp_fld_tx_used_writer_data_queue_size = + register_get_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_QS); + p->mp_fld_tx_used_writer_data_packed = + register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_PCKED); + p->mp_fld_tx_used_writer_data_int = + register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_INT); + p->mp_fld_tx_used_writer_data_vec = + register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_VEC); + p->mp_fld_tx_used_writer_data_istk = + register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_ISTK); + p->mp_fld_tx_used_writer_data_in_order = + register_query_field(p->mp_reg_tx_used_writer_data, DBS_TX_UW_DATA_INO); + + p->mp_reg_rx_descriptor_reader_control = + module_get_register(p->mp_mod_dbs, DBS_RX_DR_CTRL); + p->mp_fld_rx_descriptor_reader_control_adr = + register_get_field(p->mp_reg_rx_descriptor_reader_control, DBS_RX_DR_CTRL_ADR); + p->mp_fld_rx_descriptor_reader_control_cnt = + register_get_field(p->mp_reg_rx_descriptor_reader_control, DBS_RX_DR_CTRL_CNT); + + p->mp_reg_rx_descriptor_reader_data = + module_get_register(p->mp_mod_dbs, DBS_RX_DR_DATA); + p->mp_fld_rx_descriptor_reader_data_guest_physical_address = + register_get_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_GPA); + p->mp_fld_rx_descriptor_reader_data_host_id = + register_get_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_HID); + p->mp_fld_rx_descriptor_reader_data_queue_size = + register_get_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_QS); + p->mp_fld_rx_descriptor_reader_data_header = + register_get_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_HDR); + p->mp_fld_rx_descriptor_reader_data_packed = + register_query_field(p->mp_reg_rx_descriptor_reader_data, DBS_RX_DR_DATA_PCKED); + + p->mp_reg_tx_descriptor_reader_control = + module_get_register(p->mp_mod_dbs, DBS_TX_DR_CTRL); + p->mp_fld_tx_descriptor_reader_control_adr = + register_get_field(p->mp_reg_tx_descriptor_reader_control, DBS_TX_DR_CTRL_ADR); + p->mp_fld_tx_descriptor_reader_control_cnt = + register_get_field(p->mp_reg_tx_descriptor_reader_control, DBS_TX_DR_CTRL_CNT); + + p->mp_reg_tx_descriptor_reader_data = + module_get_register(p->mp_mod_dbs, DBS_TX_DR_DATA); + p->mp_fld_tx_descriptor_reader_data_guest_physical_address = + register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_GPA); + p->mp_fld_tx_descriptor_reader_data_host_id = + register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_HID); + p->mp_fld_tx_descriptor_reader_data_queue_size = + register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_QS); + p->mp_fld_tx_descriptor_reader_data_header = + register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_HDR); + p->mp_fld_tx_descriptor_reader_data_port = + register_get_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_PORT); + p->mp_fld_tx_descriptor_reader_data_packed = + register_query_field(p->mp_reg_tx_descriptor_reader_data, DBS_TX_DR_DATA_PCKED); + + p->mp_reg_tx_queue_property_control = + module_get_register(p->mp_mod_dbs, DBS_TX_QP_CTRL); + p->mp_fld_tx_queue_property_control_adr = + register_get_field(p->mp_reg_tx_queue_property_control, DBS_TX_QP_CTRL_ADR); + p->mp_fld_tx_queue_property_control_cnt = + register_get_field(p->mp_reg_tx_queue_property_control, DBS_TX_QP_CTRL_CNT); + + p->mp_reg_tx_queue_property_data = + module_get_register(p->mp_mod_dbs, DBS_TX_QP_DATA); + p->mp_fld_tx_queue_property_data_v_port = + register_get_field(p->mp_reg_tx_queue_property_data, DBS_TX_QP_DATA_VPORT); + + /* HW QoS Tx rate limiting policing RFC2697/RFC4111 */ + p->mp_reg_tx_queue_qos_control = + module_query_register(p->mp_mod_dbs, DBS_TX_QOS_CTRL); + p->mp_reg_tx_queue_qos_data = + module_query_register(p->mp_mod_dbs, DBS_TX_QOS_DATA); + if (p->mp_reg_tx_queue_qos_control) { + p->mp_reg_tx_queue_qos_control_adr = + register_query_field(p->mp_reg_tx_queue_qos_control, DBS_TX_QOS_CTRL_ADR); + p->mp_reg_tx_queue_qos_control_cnt = + register_query_field(p->mp_reg_tx_queue_qos_control, DBS_TX_QOS_CTRL_CNT); + + if (p->mp_reg_tx_queue_qos_data) { + p->mp_reg_tx_queue_qos_data_en = + register_query_field(p->mp_reg_tx_queue_qos_data, + DBS_TX_QOS_DATA_EN); + p->mp_reg_tx_queue_qos_data_ir = + register_query_field(p->mp_reg_tx_queue_qos_data, + DBS_TX_QOS_DATA_IR); + p->mp_reg_tx_queue_qos_data_bs = + register_query_field(p->mp_reg_tx_queue_qos_data, + DBS_TX_QOS_DATA_BS); + } + } + + p->mp_reg_tx_queue_qos_rate = + module_query_register(p->mp_mod_dbs, DBS_TX_QOS_RATE); + if (p->mp_reg_tx_queue_qos_rate) { + p->mp_reg_tx_queue_qos_rate_mul = + register_query_field(p->mp_reg_tx_queue_qos_rate, DBS_TX_QOS_RATE_MUL); + p->mp_reg_tx_queue_qos_rate_div = + register_query_field(p->mp_reg_tx_queue_qos_rate, DBS_TX_QOS_RATE_DIV); + } + + return 0; +} + +int dbs_reset_rx_control(nthw_dbs_t *p) +{ + field_set_val32(p->mp_fld_rx_control_last_queue, 0); + field_set_val32(p->mp_fld_rx_control_avail_monitor_enable, 0); + field_set_val32(p->mp_fld_rx_control_avail_monitor_scan_speed, 8); + field_set_val32(p->mp_fld_rx_control_used_write_enable, 0); + field_set_val32(p->mp_fld_rx_control_used_writer_update_speed, 5); + field_set_val32(p->mp_fld_rx_control_rx_queues_enable, 0); + register_flush(p->mp_reg_rx_control, 1); + return 0; +} + +int dbs_reset_tx_control(nthw_dbs_t *p) +{ + field_set_val32(p->mp_fld_tx_control_last_queue, 0); + field_set_val32(p->mp_fld_tx_control_avail_monitor_enable, 0); + field_set_val32(p->mp_fld_tx_control_avail_monitor_scan_speed, 5); + field_set_val32(p->mp_fld_tx_control_used_write_enable, 0); + field_set_val32(p->mp_fld_tx_control_used_writer_update_speed, 8); + field_set_val32(p->mp_fld_tx_control_tx_queues_enable, 0); + register_flush(p->mp_reg_tx_control, 1); + return 0; +} + +void dbs_reset(nthw_dbs_t *p) +{ + uint32_t i; + + NT_LOG(DBG, NTHW, "NthwDbs::%s: resetting DBS", __func__); + + dbs_reset_rx_control(p); + dbs_reset_tx_control(p); + + /* Reset RX memory banks and shado */ + for (i = 0; i < NT_DBS_RX_QUEUES_MAX; ++i) { + set_shadow_rx_am_data(p, i, 0, 0, 0, 0, 0); + flush_rx_am_data(p, i); + + set_shadow_rx_uw_data(p, i, 0, 0, 0, 0, 0, 0, 0); + flush_rx_uw_data(p, i); + + set_shadow_rx_dr_data(p, i, 0, 0, 0, 0, 0); + flush_rx_dr_data(p, i); + } + + /* Reset TX memory banks and shado */ + for (i = 0; i < NT_DBS_TX_QUEUES_MAX; ++i) { + set_shadow_tx_am_data(p, i, 0, 0, 0, 0, 0); + flush_tx_am_data(p, i); + + set_shadow_tx_uw_data(p, i, 0, 0, 0, 0, 0, 0, 0, 0); + flush_tx_uw_data(p, i); + + set_shadow_tx_dr_data(p, i, 0, 0, 0, 0, 0, 0); + flush_tx_dr_data(p, i); + + set_shadow_tx_qp_data(p, i, 0); + flush_tx_qp_data(p, i); + + set_shadow_tx_qos_data(p, i, 0, 0, 0); + flush_tx_qos_data(p, i); + } +} + +int set_rx_control(nthw_dbs_t *p, uint32_t last_queue, + uint32_t avail_monitor_enable, uint32_t avail_monitor_speed, + uint32_t used_write_enable, uint32_t used_write_speed, + uint32_t rx_queue_enable) +{ +#ifdef DBS_PRINT_REGS + printf("last_queue %u\n", last_queue); + printf("avail_monitor_enable %u\n", avail_monitor_enable); + printf("avail_monitor_speed %u\n", avail_monitor_speed); + printf("used_write_enable %u\n", used_write_enable); + printf("used_write_speed %u\n", used_write_speed); + printf("rx_queue_enable %u\n", rx_queue_enable); +#endif + + field_set_val32(p->mp_fld_rx_control_last_queue, last_queue); + field_set_val32(p->mp_fld_rx_control_avail_monitor_enable, avail_monitor_enable); + field_set_val32(p->mp_fld_rx_control_avail_monitor_scan_speed, + avail_monitor_speed); + field_set_val32(p->mp_fld_rx_control_used_write_enable, used_write_enable); + field_set_val32(p->mp_fld_rx_control_used_writer_update_speed, used_write_speed); + field_set_val32(p->mp_fld_rx_control_rx_queues_enable, rx_queue_enable); + register_flush(p->mp_reg_rx_control, 1); + return 0; +} + +int nthw_dbs_get_rx_control(nthw_dbs_t *p, uint32_t *last_queue, + uint32_t *avail_monitor_enable, + uint32_t *avail_monitor_speed, uint32_t *used_write_enable, + uint32_t *used_write_speed, uint32_t *rx_queue_enable) +{ + *last_queue = field_get_val32(p->mp_fld_rx_control_last_queue); + *avail_monitor_enable = + field_get_val32(p->mp_fld_rx_control_avail_monitor_enable); + *avail_monitor_speed = + field_get_val32(p->mp_fld_rx_control_avail_monitor_scan_speed); + *used_write_enable = field_get_val32(p->mp_fld_rx_control_used_write_enable); + *used_write_speed = + field_get_val32(p->mp_fld_rx_control_used_writer_update_speed); + *rx_queue_enable = field_get_val32(p->mp_fld_rx_control_rx_queues_enable); + return 0; +} + +int set_tx_control(nthw_dbs_t *p, uint32_t last_queue, + uint32_t avail_monitor_enable, uint32_t avail_monitor_speed, + uint32_t used_write_enable, uint32_t used_write_speed, + uint32_t tx_queue_enable) +{ +#ifdef DBS_PRINT_REGS + printf("last_queue %u\n", last_queue); + printf("avail_monitor_enable %u\n", avail_monitor_enable); + printf("avail_monitor_speed %u\n", avail_monitor_speed); + printf("used_write_enable %u\n", used_write_enable); + printf("used_write_speed %u\n", used_write_speed); +#endif + + field_set_val32(p->mp_fld_tx_control_last_queue, last_queue); + field_set_val32(p->mp_fld_tx_control_avail_monitor_enable, avail_monitor_enable); + field_set_val32(p->mp_fld_tx_control_avail_monitor_scan_speed, + avail_monitor_speed); + field_set_val32(p->mp_fld_tx_control_used_write_enable, used_write_enable); + field_set_val32(p->mp_fld_tx_control_used_writer_update_speed, used_write_speed); + field_set_val32(p->mp_fld_tx_control_tx_queues_enable, tx_queue_enable); + register_flush(p->mp_reg_tx_control, 1); + return 0; +} + +int nthw_dbs_get_tx_control(nthw_dbs_t *p, uint32_t *last_queue, + uint32_t *avail_monitor_enable, + uint32_t *avail_monitor_speed, uint32_t *used_write_enable, + uint32_t *used_write_speed, uint32_t *tx_queue_enable) +{ + *last_queue = field_get_val32(p->mp_fld_tx_control_last_queue); + *avail_monitor_enable = + field_get_val32(p->mp_fld_tx_control_avail_monitor_enable); + *avail_monitor_speed = + field_get_val32(p->mp_fld_tx_control_avail_monitor_scan_speed); + *used_write_enable = field_get_val32(p->mp_fld_tx_control_used_write_enable); + *used_write_speed = + field_get_val32(p->mp_fld_tx_control_used_writer_update_speed); + *tx_queue_enable = field_get_val32(p->mp_fld_tx_control_tx_queues_enable); + return 0; +} + +int set_rx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, + uint32_t init, uint32_t queue) +{ + if (p->mp_reg_rx_init_val) { + field_set_val32(p->mp_fld_rx_init_val_idx, start_idx); + field_set_val32(p->mp_fld_rx_init_val_ptr, start_ptr); + register_flush(p->mp_reg_rx_init_val, 1); + } + field_set_val32(p->mp_fld_rx_init_init, init); + field_set_val32(p->mp_fld_rx_init_queue, queue); + register_flush(p->mp_reg_rx_init, 1); + return 0; +} + +int get_rx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy) +{ + *init = field_get_val32(p->mp_fld_rx_init_init); + *queue = field_get_val32(p->mp_fld_rx_init_queue); + *busy = field_get_val32(p->mp_fld_rx_init_busy); + return 0; +} + +int set_tx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, + uint32_t init, uint32_t queue) +{ + if (p->mp_reg_tx_init_val) { + field_set_val32(p->mp_fld_tx_init_val_idx, start_idx); + field_set_val32(p->mp_fld_tx_init_val_ptr, start_ptr); + register_flush(p->mp_reg_tx_init_val, 1); + } + field_set_val32(p->mp_fld_tx_init_init, init); + field_set_val32(p->mp_fld_tx_init_queue, queue); + register_flush(p->mp_reg_tx_init, 1); + return 0; +} + +int get_tx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy) +{ + *init = field_get_val32(p->mp_fld_tx_init_init); + *queue = field_get_val32(p->mp_fld_tx_init_queue); + *busy = field_get_val32(p->mp_fld_tx_init_busy); + return 0; +} + +int set_rx_idle(nthw_dbs_t *p, uint32_t idle, uint32_t queue) + +{ + if (!p->mp_reg_rx_idle) + return -ENOTSUP; + + field_set_val32(p->mp_fld_rx_idle_idle, idle); + field_set_val32(p->mp_fld_rx_idle_queue, queue); + register_flush(p->mp_reg_rx_idle, 1); + return 0; +} + +int get_rx_idle(nthw_dbs_t *p, uint32_t *idle, uint32_t *queue, uint32_t *busy) +{ + if (!p->mp_reg_rx_idle) + return -ENOTSUP; + + *idle = field_get_updated(p->mp_fld_rx_idle_idle); + *queue = 0; + *busy = field_get_updated(p->mp_fld_rx_idle_busy); + return 0; +} + +int set_tx_idle(nthw_dbs_t *p, uint32_t idle, uint32_t queue) + +{ + if (!p->mp_reg_tx_idle) + return -ENOTSUP; + + field_set_val32(p->mp_fld_tx_idle_idle, idle); + field_set_val32(p->mp_fld_tx_idle_queue, queue); + register_flush(p->mp_reg_tx_idle, 1); + return 0; +} + +int get_tx_idle(nthw_dbs_t *p, uint32_t *idle, uint32_t *queue, uint32_t *busy) +{ + if (!p->mp_reg_tx_idle) + return -ENOTSUP; + + *idle = field_get_updated(p->mp_fld_tx_idle_idle); + *queue = 0; + *busy = field_get_updated(p->mp_fld_tx_idle_busy); + return 0; +} + +int set_rx_ptr_queue(nthw_dbs_t *p, uint32_t queue) +{ + if (!p->mp_reg_rx_ptr) + return -ENOTSUP; + + field_set_val32(p->mp_fld_rx_ptr_queue, queue); + register_flush(p->mp_reg_rx_ptr, 1); + return 0; +} + +int get_rx_ptr(nthw_dbs_t *p, uint32_t *ptr, uint32_t *queue, uint32_t *valid) +{ + if (!p->mp_reg_rx_ptr) + return -ENOTSUP; + + *ptr = field_get_updated(p->mp_fld_rx_ptr_ptr); + *queue = 0; + *valid = field_get_updated(p->mp_fld_rx_ptr_valid); + return 0; +} + +int set_tx_ptr_queue(nthw_dbs_t *p, uint32_t queue) +{ + if (!p->mp_reg_tx_ptr) + return -ENOTSUP; + + field_set_val32(p->mp_fld_tx_ptr_queue, queue); + register_flush(p->mp_reg_tx_ptr, 1); + return 0; +} + +int get_tx_ptr(nthw_dbs_t *p, uint32_t *ptr, uint32_t *queue, uint32_t *valid) +{ + if (!p->mp_reg_tx_ptr) + return -ENOTSUP; + + *ptr = field_get_updated(p->mp_fld_tx_ptr_ptr); + *queue = 0; + *valid = field_get_updated(p->mp_fld_tx_ptr_valid); + return 0; +} + +static void set_rx_am_data_index(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_fld_rx_avail_monitor_control_adr, index); + field_set_val32(p->mp_fld_rx_avail_monitor_control_cnt, 1); + register_flush(p->mp_reg_rx_avail_monitor_control, 1); +} + +static void +set_shadow_rx_am_data_guest_physical_address(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address) +{ + p->m_rx_am_shadow[index].guest_physical_address = guest_physical_address; +} + +static void nthw_dbs_set_shadow_rx_am_data_enable(nthw_dbs_t *p, uint32_t index, + uint32_t enable) +{ + p->m_rx_am_shadow[index].enable = enable; +} + +static void set_shadow_rx_am_data_host_id(nthw_dbs_t *p, uint32_t index, + uint32_t host_id) +{ + p->m_rx_am_shadow[index].host_id = host_id; +} + +static void set_shadow_rx_am_data_packed(nthw_dbs_t *p, uint32_t index, + uint32_t packed) +{ + p->m_rx_am_shadow[index].packed = packed; +} + +static void set_shadow_rx_am_data_int_enable(nthw_dbs_t *p, uint32_t index, + uint32_t int_enable) +{ + p->m_rx_am_shadow[index].int_enable = int_enable; +} + +static void set_shadow_rx_am_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t enable, + uint32_t host_id, uint32_t packed, + uint32_t int_enable) +{ + set_shadow_rx_am_data_guest_physical_address(p, index, guest_physical_address); + nthw_dbs_set_shadow_rx_am_data_enable(p, index, enable); + set_shadow_rx_am_data_host_id(p, index, host_id); + set_shadow_rx_am_data_packed(p, index, packed); + set_shadow_rx_am_data_int_enable(p, index, int_enable); +} + +static void flush_rx_am_data(nthw_dbs_t *p, uint32_t index) +{ + field_set_val(p->mp_fld_rx_avail_monitor_data_guest_physical_address, + (uint32_t *)&p->m_rx_am_shadow[index].guest_physical_address, + 2); + field_set_val32(p->mp_fld_rx_avail_monitor_data_enable, + p->m_rx_am_shadow[index].enable); + field_set_val32(p->mp_fld_rx_avail_monitor_data_host_id, + p->m_rx_am_shadow[index].host_id); + if (p->mp_fld_rx_avail_monitor_data_packed) { + field_set_val32(p->mp_fld_rx_avail_monitor_data_packed, + p->m_rx_am_shadow[index].packed); + } + if (p->mp_fld_rx_avail_monitor_data_int) { + field_set_val32(p->mp_fld_rx_avail_monitor_data_int, + p->m_rx_am_shadow[index].int_enable); + } + + set_rx_am_data_index(p, index); + register_flush(p->mp_reg_rx_avail_monitor_data, 1); +} + +int set_rx_am_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t enable, uint32_t host_id, uint32_t packed, + uint32_t int_enable) +{ + if (!p->mp_reg_rx_avail_monitor_data) + return -ENOTSUP; + + set_shadow_rx_am_data(p, index, guest_physical_address, enable, host_id, + packed, int_enable); + flush_rx_am_data(p, index); + return 0; +} + +static void set_tx_am_data_index(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_fld_tx_avail_monitor_control_adr, index); + field_set_val32(p->mp_fld_tx_avail_monitor_control_cnt, 1); + register_flush(p->mp_reg_tx_avail_monitor_control, 1); +} + +static void set_shadow_tx_am_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t enable, + uint32_t host_id, uint32_t packed, + uint32_t int_enable) +{ + p->m_tx_am_shadow[index].guest_physical_address = guest_physical_address; + p->m_tx_am_shadow[index].enable = enable; + p->m_tx_am_shadow[index].host_id = host_id; + p->m_tx_am_shadow[index].packed = packed; + p->m_tx_am_shadow[index].int_enable = int_enable; +} + +static void flush_tx_am_data(nthw_dbs_t *p, uint32_t index) +{ + field_set_val(p->mp_fld_tx_avail_monitor_data_guest_physical_address, + (uint32_t *)&p->m_tx_am_shadow[index].guest_physical_address, + 2); + field_set_val32(p->mp_fld_tx_avail_monitor_data_enable, + p->m_tx_am_shadow[index].enable); + field_set_val32(p->mp_fld_tx_avail_monitor_data_host_id, + p->m_tx_am_shadow[index].host_id); + if (p->mp_fld_tx_avail_monitor_data_packed) { + field_set_val32(p->mp_fld_tx_avail_monitor_data_packed, + p->m_tx_am_shadow[index].packed); + } + if (p->mp_fld_tx_avail_monitor_data_int) { + field_set_val32(p->mp_fld_tx_avail_monitor_data_int, + p->m_tx_am_shadow[index].int_enable); + } + + set_tx_am_data_index(p, index); + register_flush(p->mp_reg_tx_avail_monitor_data, 1); +} + +int set_tx_am_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t enable, uint32_t host_id, uint32_t packed, + uint32_t int_enable) +{ + if (!p->mp_reg_tx_avail_monitor_data) + return -ENOTSUP; + + set_shadow_tx_am_data(p, index, guest_physical_address, enable, host_id, + packed, int_enable); + flush_tx_am_data(p, index); + return 0; +} + +static void set_rx_uw_data_index(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_fld_rx_used_writer_control_adr, index); + field_set_val32(p->mp_fld_rx_used_writer_control_cnt, 1); + register_flush(p->mp_reg_rx_used_writer_control, 1); +} + +static void +set_shadow_rx_uw_data_guest_physical_address(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address) +{ + p->m_rx_uw_shadow[index].guest_physical_address = guest_physical_address; +} + +static void set_shadow_rx_uw_data_host_id(nthw_dbs_t *p, uint32_t index, + uint32_t host_id) +{ + p->m_rx_uw_shadow[index].host_id = host_id; +} + +static void set_shadow_rx_uw_data_queue_size(nthw_dbs_t *p, uint32_t index, + uint32_t queue_size) +{ + p->m_rx_uw_shadow[index].queue_size = queue_size; +} + +static void set_shadow_rx_uw_data_packed(nthw_dbs_t *p, uint32_t index, + uint32_t packed) +{ + p->m_rx_uw_shadow[index].packed = packed; +} + +static void set_shadow_rx_uw_data_int_enable(nthw_dbs_t *p, uint32_t index, + uint32_t int_enable) +{ + p->m_rx_uw_shadow[index].int_enable = int_enable; +} + +static void set_shadow_rx_uw_data_vec(nthw_dbs_t *p, uint32_t index, uint32_t vec) +{ + p->m_rx_uw_shadow[index].vec = vec; +} + +static void set_shadow_rx_uw_data_istk(nthw_dbs_t *p, uint32_t index, uint32_t istk) +{ + p->m_rx_uw_shadow[index].istk = istk; +} + +static void set_shadow_rx_uw_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t host_id, + uint32_t queue_size, uint32_t packed, + uint32_t int_enable, uint32_t vec, uint32_t istk) +{ + set_shadow_rx_uw_data_guest_physical_address(p, index, guest_physical_address); + set_shadow_rx_uw_data_host_id(p, index, host_id); + set_shadow_rx_uw_data_queue_size(p, index, queue_size); + set_shadow_rx_uw_data_packed(p, index, packed); + set_shadow_rx_uw_data_int_enable(p, index, int_enable); + set_shadow_rx_uw_data_vec(p, index, vec); + set_shadow_rx_uw_data_istk(p, index, istk); +} + +static void flush_rx_uw_data(nthw_dbs_t *p, uint32_t index) +{ + field_set_val(p->mp_fld_rx_used_writer_data_guest_physical_address, + (uint32_t *)&p->m_rx_uw_shadow[index].guest_physical_address, + 2); + field_set_val32(p->mp_fld_rx_used_writer_data_host_id, + p->m_rx_uw_shadow[index].host_id); + if (module_is_version_newer(p->mp_mod_dbs, 0, 8)) { + field_set_val32(p->mp_fld_rx_used_writer_data_queue_size, + (1U << p->m_rx_uw_shadow[index].queue_size) - 1U); + } else { + field_set_val32(p->mp_fld_rx_used_writer_data_queue_size, + p->m_rx_uw_shadow[index].queue_size); + } + if (p->mp_fld_rx_used_writer_data_packed) { + field_set_val32(p->mp_fld_rx_used_writer_data_packed, + p->m_rx_uw_shadow[index].packed); + } + if (p->mp_fld_rx_used_writer_data_int) { + field_set_val32(p->mp_fld_rx_used_writer_data_int, + p->m_rx_uw_shadow[index].int_enable); + field_set_val32(p->mp_fld_rx_used_writer_data_vec, + p->m_rx_uw_shadow[index].vec); + field_set_val32(p->mp_fld_rx_used_writer_data_istk, + p->m_rx_uw_shadow[index].istk); + } + + set_rx_uw_data_index(p, index); + register_flush(p->mp_reg_rx_used_writer_data, 1); +} + +int set_rx_uw_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t host_id, uint32_t queue_size, uint32_t packed, + uint32_t int_enable, uint32_t vec, uint32_t istk) +{ + if (!p->mp_reg_rx_used_writer_data) + return -ENOTSUP; + + set_shadow_rx_uw_data(p, index, guest_physical_address, host_id, queue_size, + packed, int_enable, vec, istk); + flush_rx_uw_data(p, index); + return 0; +} + +static void set_tx_uw_data_index(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_fld_tx_used_writer_control_adr, index); + field_set_val32(p->mp_fld_tx_used_writer_control_cnt, 1); + register_flush(p->mp_reg_tx_used_writer_control, 1); +} + +static void +set_shadow_tx_uw_data_guest_physical_address(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address) +{ + p->m_tx_uw_shadow[index].guest_physical_address = guest_physical_address; +} + +static void set_shadow_tx_uw_data_host_id(nthw_dbs_t *p, uint32_t index, + uint32_t host_id) +{ + p->m_tx_uw_shadow[index].host_id = host_id; +} + +static void set_shadow_tx_uw_data_queue_size(nthw_dbs_t *p, uint32_t index, + uint32_t queue_size) +{ + p->m_tx_uw_shadow[index].queue_size = queue_size; +} + +static void set_shadow_tx_uw_data_packed(nthw_dbs_t *p, uint32_t index, + uint32_t packed) +{ + p->m_tx_uw_shadow[index].packed = packed; +} + +static void set_shadow_tx_uw_data_int_enable(nthw_dbs_t *p, uint32_t index, + uint32_t int_enable) +{ + p->m_tx_uw_shadow[index].int_enable = int_enable; +} + +static void set_shadow_tx_uw_data_vec(nthw_dbs_t *p, uint32_t index, uint32_t vec) +{ + p->m_tx_uw_shadow[index].vec = vec; +} + +static void set_shadow_tx_uw_data_istk(nthw_dbs_t *p, uint32_t index, uint32_t istk) +{ + p->m_tx_uw_shadow[index].istk = istk; +} + +static void set_shadow_tx_uw_data_in_order(nthw_dbs_t *p, uint32_t index, + uint32_t in_order) +{ + p->m_tx_uw_shadow[index].in_order = in_order; +} + +static void set_shadow_tx_uw_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t host_id, + uint32_t queue_size, uint32_t packed, + uint32_t int_enable, uint32_t vec, uint32_t istk, + uint32_t in_order) +{ + set_shadow_tx_uw_data_guest_physical_address(p, index, guest_physical_address); + set_shadow_tx_uw_data_host_id(p, index, host_id); + set_shadow_tx_uw_data_queue_size(p, index, queue_size); + set_shadow_tx_uw_data_packed(p, index, packed); + set_shadow_tx_uw_data_int_enable(p, index, int_enable); + set_shadow_tx_uw_data_vec(p, index, vec); + set_shadow_tx_uw_data_istk(p, index, istk); + set_shadow_tx_uw_data_in_order(p, index, in_order); +} + +static void flush_tx_uw_data(nthw_dbs_t *p, uint32_t index) +{ + field_set_val(p->mp_fld_tx_used_writer_data_guest_physical_address, + (uint32_t *)&p->m_tx_uw_shadow[index].guest_physical_address, + 2); + field_set_val32(p->mp_fld_tx_used_writer_data_host_id, + p->m_tx_uw_shadow[index].host_id); + if (module_is_version_newer(p->mp_mod_dbs, 0, 8)) { + field_set_val32(p->mp_fld_tx_used_writer_data_queue_size, + (1U << p->m_tx_uw_shadow[index].queue_size) - 1U); + } else { + field_set_val32(p->mp_fld_tx_used_writer_data_queue_size, + p->m_tx_uw_shadow[index].queue_size); + } + if (p->mp_fld_tx_used_writer_data_packed) { + field_set_val32(p->mp_fld_tx_used_writer_data_packed, + p->m_tx_uw_shadow[index].packed); + } + if (p->mp_fld_tx_used_writer_data_int) { + field_set_val32(p->mp_fld_tx_used_writer_data_int, + p->m_tx_uw_shadow[index].int_enable); + field_set_val32(p->mp_fld_tx_used_writer_data_vec, + p->m_tx_uw_shadow[index].vec); + field_set_val32(p->mp_fld_tx_used_writer_data_istk, + p->m_tx_uw_shadow[index].istk); + } + if (p->mp_fld_tx_used_writer_data_in_order) { + field_set_val32(p->mp_fld_tx_used_writer_data_in_order, + p->m_tx_uw_shadow[index].in_order); + } + + set_tx_uw_data_index(p, index); + register_flush(p->mp_reg_tx_used_writer_data, 1); +} + +int set_tx_uw_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t host_id, uint32_t queue_size, uint32_t packed, + uint32_t int_enable, uint32_t vec, uint32_t istk, + uint32_t in_order) +{ + if (!p->mp_reg_tx_used_writer_data) + return -ENOTSUP; + + set_shadow_tx_uw_data(p, index, guest_physical_address, host_id, queue_size, + packed, int_enable, vec, istk, in_order); + flush_tx_uw_data(p, index); + return 0; +} + +static void set_rx_dr_data_index(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_fld_rx_descriptor_reader_control_adr, index); + field_set_val32(p->mp_fld_rx_descriptor_reader_control_cnt, 1); + register_flush(p->mp_reg_rx_descriptor_reader_control, 1); +} + +static void +set_shadow_rx_dr_data_guest_physical_address(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address) +{ + p->m_rx_dr_shadow[index].guest_physical_address = guest_physical_address; +} + +static void set_shadow_rx_dr_data_host_id(nthw_dbs_t *p, uint32_t index, + uint32_t host_id) +{ + p->m_rx_dr_shadow[index].host_id = host_id; +} + +static void set_shadow_rx_dr_data_queue_size(nthw_dbs_t *p, uint32_t index, + uint32_t queue_size) +{ + p->m_rx_dr_shadow[index].queue_size = queue_size; +} + +static void set_shadow_rx_dr_data_header(nthw_dbs_t *p, uint32_t index, + uint32_t header) +{ + p->m_rx_dr_shadow[index].header = header; +} + +static void set_shadow_rx_dr_data_packed(nthw_dbs_t *p, uint32_t index, + uint32_t packed) +{ + p->m_rx_dr_shadow[index].packed = packed; +} + +static void set_shadow_rx_dr_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t host_id, + uint32_t queue_size, uint32_t header, + uint32_t packed) +{ + set_shadow_rx_dr_data_guest_physical_address(p, index, guest_physical_address); + set_shadow_rx_dr_data_host_id(p, index, host_id); + set_shadow_rx_dr_data_queue_size(p, index, queue_size); + set_shadow_rx_dr_data_header(p, index, header); + set_shadow_rx_dr_data_packed(p, index, packed); +} + +static void flush_rx_dr_data(nthw_dbs_t *p, uint32_t index) +{ + field_set_val(p->mp_fld_rx_descriptor_reader_data_guest_physical_address, + (uint32_t *)&p->m_rx_dr_shadow[index].guest_physical_address, + 2); + field_set_val32(p->mp_fld_rx_descriptor_reader_data_host_id, + p->m_rx_dr_shadow[index].host_id); + if (module_is_version_newer(p->mp_mod_dbs, 0, 8)) { + field_set_val32(p->mp_fld_rx_descriptor_reader_data_queue_size, + (1U << p->m_rx_dr_shadow[index].queue_size) - 1U); + } else { + field_set_val32(p->mp_fld_rx_descriptor_reader_data_queue_size, + p->m_rx_dr_shadow[index].queue_size); + } + field_set_val32(p->mp_fld_rx_descriptor_reader_data_header, + p->m_rx_dr_shadow[index].header); + if (p->mp_fld_rx_descriptor_reader_data_packed) { + field_set_val32(p->mp_fld_rx_descriptor_reader_data_packed, + p->m_rx_dr_shadow[index].packed); + } + + set_rx_dr_data_index(p, index); + register_flush(p->mp_reg_rx_descriptor_reader_data, 1); +} + +int set_rx_dr_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t host_id, uint32_t queue_size, uint32_t header, + uint32_t packed) +{ + if (!p->mp_reg_rx_descriptor_reader_data) + return -ENOTSUP; + + set_shadow_rx_dr_data(p, index, guest_physical_address, host_id, queue_size, + header, packed); + flush_rx_dr_data(p, index); + return 0; +} + +static void set_tx_dr_data_index(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_fld_tx_descriptor_reader_control_adr, index); + field_set_val32(p->mp_fld_tx_descriptor_reader_control_cnt, 1); + register_flush(p->mp_reg_tx_descriptor_reader_control, 1); +} + +static void +set_shadow_tx_dr_data_guest_physical_address(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address) +{ + p->m_tx_dr_shadow[index].guest_physical_address = guest_physical_address; +} + +static void set_shadow_tx_dr_data_host_id(nthw_dbs_t *p, uint32_t index, + uint32_t host_id) +{ + p->m_tx_dr_shadow[index].host_id = host_id; +} + +static void set_shadow_tx_dr_data_queue_size(nthw_dbs_t *p, uint32_t index, + uint32_t queue_size) +{ + p->m_tx_dr_shadow[index].queue_size = queue_size; +} + +static void set_shadow_tx_dr_data_header(nthw_dbs_t *p, uint32_t index, + uint32_t header) +{ + p->m_tx_dr_shadow[index].header = header; +} + +static void set_shadow_tx_dr_data_port(nthw_dbs_t *p, uint32_t index, uint32_t port) +{ + p->m_tx_dr_shadow[index].port = port; +} + +static void set_shadow_tx_dr_data_packed(nthw_dbs_t *p, uint32_t index, + uint32_t packed) +{ + p->m_tx_dr_shadow[index].packed = packed; +} + +static void set_shadow_tx_dr_data(nthw_dbs_t *p, uint32_t index, + uint64_t guest_physical_address, uint32_t host_id, + uint32_t queue_size, uint32_t port, + uint32_t header, uint32_t packed) +{ + set_shadow_tx_dr_data_guest_physical_address(p, index, guest_physical_address); + set_shadow_tx_dr_data_host_id(p, index, host_id); + set_shadow_tx_dr_data_queue_size(p, index, queue_size); + set_shadow_tx_dr_data_header(p, index, header); + set_shadow_tx_dr_data_port(p, index, port); + set_shadow_tx_dr_data_packed(p, index, packed); +} + +static void flush_tx_dr_data(nthw_dbs_t *p, uint32_t index) +{ + field_set_val(p->mp_fld_tx_descriptor_reader_data_guest_physical_address, + (uint32_t *)&p->m_tx_dr_shadow[index].guest_physical_address, + 2); + field_set_val32(p->mp_fld_tx_descriptor_reader_data_host_id, + p->m_tx_dr_shadow[index].host_id); + if (module_is_version_newer(p->mp_mod_dbs, 0, 8)) { + field_set_val32(p->mp_fld_tx_descriptor_reader_data_queue_size, + (1U << p->m_tx_dr_shadow[index].queue_size) - 1U); + } else { + field_set_val32(p->mp_fld_tx_descriptor_reader_data_queue_size, + p->m_tx_dr_shadow[index].queue_size); + } + field_set_val32(p->mp_fld_tx_descriptor_reader_data_header, + p->m_tx_dr_shadow[index].header); + field_set_val32(p->mp_fld_tx_descriptor_reader_data_port, + p->m_tx_dr_shadow[index].port); + if (p->mp_fld_tx_descriptor_reader_data_packed) { + field_set_val32(p->mp_fld_tx_descriptor_reader_data_packed, + p->m_tx_dr_shadow[index].packed); + } + + set_tx_dr_data_index(p, index); + register_flush(p->mp_reg_tx_descriptor_reader_data, 1); +} + +int set_tx_dr_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t host_id, uint32_t queue_size, uint32_t port, + uint32_t header, uint32_t packed) +{ + if (!p->mp_reg_tx_descriptor_reader_data) + return -ENOTSUP; + + set_shadow_tx_dr_data(p, index, guest_physical_address, host_id, queue_size, + port, header, packed); + flush_tx_dr_data(p, index); + return 0; +} + +static void set_tx_qp_data_index(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_fld_tx_queue_property_control_adr, index); + field_set_val32(p->mp_fld_tx_queue_property_control_cnt, 1); + register_flush(p->mp_reg_tx_queue_property_control, 1); +} + +static void set_shadow_tx_qp_data_virtual_port(nthw_dbs_t *p, uint32_t index, + uint32_t virtual_port) +{ + p->m_tx_qp_shadow[index].virtual_port = virtual_port; +} + +static void set_shadow_tx_qp_data(nthw_dbs_t *p, uint32_t index, + uint32_t virtual_port) +{ + set_shadow_tx_qp_data_virtual_port(p, index, virtual_port); +} + +static void flush_tx_qp_data(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_fld_tx_queue_property_data_v_port, + p->m_tx_qp_shadow[index].virtual_port); + + set_tx_qp_data_index(p, index); + register_flush(p->mp_reg_tx_queue_property_data, 1); +} + +int nthw_dbs_set_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port) +{ + if (!p->mp_reg_tx_queue_property_data) + return -ENOTSUP; + + set_shadow_tx_qp_data(p, index, virtual_port); + flush_tx_qp_data(p, index); + return 0; +} + +static void set_tx_qos_data_index(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_reg_tx_queue_qos_control_adr, index); + field_set_val32(p->mp_reg_tx_queue_qos_control_cnt, 1); + register_flush(p->mp_reg_tx_queue_qos_control, 1); +} + +static void set_shadow_tx_qos_data_enable(nthw_dbs_t *p, uint32_t index, + uint32_t enable) +{ + p->m_tx_qos_shadow[index].enable = enable; +} + +static void set_shadow_tx_qos_data_ir(nthw_dbs_t *p, uint32_t index, uint32_t ir) +{ + p->m_tx_qos_shadow[index].ir = ir; +} + +static void set_shadow_tx_qos_data_bs(nthw_dbs_t *p, uint32_t index, uint32_t bs) +{ + p->m_tx_qos_shadow[index].bs = bs; +} + +static void set_shadow_tx_qos_data(nthw_dbs_t *p, uint32_t index, uint32_t enable, + uint32_t ir, uint32_t bs) +{ + set_shadow_tx_qos_data_enable(p, index, enable); + set_shadow_tx_qos_data_ir(p, index, ir); + set_shadow_tx_qos_data_bs(p, index, bs); +} + +static void flush_tx_qos_data(nthw_dbs_t *p, uint32_t index) +{ + field_set_val32(p->mp_reg_tx_queue_qos_data_en, p->m_tx_qos_shadow[index].enable); + field_set_val32(p->mp_reg_tx_queue_qos_data_ir, p->m_tx_qos_shadow[index].ir); + field_set_val32(p->mp_reg_tx_queue_qos_data_bs, p->m_tx_qos_shadow[index].bs); + + set_tx_qos_data_index(p, index); + register_flush(p->mp_reg_tx_queue_qos_data, 1); +} + +int set_tx_qos_data(nthw_dbs_t *p, uint32_t index, uint32_t enable, uint32_t ir, + uint32_t bs) +{ + if (!p->mp_reg_tx_queue_qos_data) + return -ENOTSUP; + + set_shadow_tx_qos_data(p, index, enable, ir, bs); + flush_tx_qos_data(p, index); + return 0; +} + +int set_tx_qos_rate(nthw_dbs_t *p, uint32_t mul, uint32_t div) +{ + if (!p->mp_reg_tx_queue_qos_rate) + return -ENOTSUP; + + field_set_val32(p->mp_reg_tx_queue_qos_rate_mul, mul); + field_set_val32(p->mp_reg_tx_queue_qos_rate_div, div); + register_flush(p->mp_reg_tx_queue_qos_rate, 1); + return 0; +} diff --git a/drivers/net/ntnic/nthw/nthw_dbs.h b/drivers/net/ntnic/nthw/nthw_dbs.h new file mode 100644 index 0000000000..d5891d7538 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_dbs.h @@ -0,0 +1,313 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef NTHW_DBS_HPP_ +#define NTHW_DBS_HPP_ + +#define NT_DBS_RX_QUEUES_MAX (128) +#define NT_DBS_TX_QUEUES_MAX (128) + +/* + * Struct for implementation of memory bank shadows + */ + +/* DBS_RX_AM_DATA */ +struct nthw_dbs_rx_am_data_s { + uint64_t guest_physical_address; + uint32_t enable; + uint32_t host_id; + uint32_t packed; + uint32_t int_enable; +}; + +/* DBS_TX_AM_DATA */ +struct nthw_dbs_tx_am_data_s { + uint64_t guest_physical_address; + uint32_t enable; + uint32_t host_id; + uint32_t packed; + uint32_t int_enable; +}; + +/* DBS_RX_UW_DATA */ +struct nthw_dbs_rx_uw_data_s { + uint64_t guest_physical_address; + uint32_t host_id; + uint32_t queue_size; + uint32_t packed; + uint32_t int_enable; + uint32_t vec; + uint32_t istk; +}; + +/* DBS_TX_UW_DATA */ +struct nthw_dbs_tx_uw_data_s { + uint64_t guest_physical_address; + uint32_t host_id; + uint32_t queue_size; + uint32_t packed; + uint32_t int_enable; + uint32_t vec; + uint32_t istk; + uint32_t in_order; +}; + +/* DBS_RX_DR_DATA */ +struct nthw_dbs_rx_dr_data_s { + uint64_t guest_physical_address; + uint32_t host_id; + uint32_t queue_size; + uint32_t header; + uint32_t packed; +}; + +/* DBS_TX_DR_DATA */ +struct nthw_dbs_tx_dr_data_s { + uint64_t guest_physical_address; + uint32_t host_id; + uint32_t queue_size; + uint32_t header; + uint32_t port; + uint32_t packed; +}; + +/* DBS_TX_QP_DATA */ +struct nthw_dbs_tx_qp_data_s { + uint32_t virtual_port; +}; + +struct nthw_dbs_tx_qos_data_s { + uint32_t enable; + uint32_t ir; + uint32_t bs; +}; + +struct nthw_dbs_s { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_dbs; + int mn_instance; + + int mn_param_dbs_present; + + nt_register_t *mp_reg_rx_control; + nt_field_t *mp_fld_rx_control_last_queue; + nt_field_t *mp_fld_rx_control_avail_monitor_enable; + nt_field_t *mp_fld_rx_control_avail_monitor_scan_speed; + nt_field_t *mp_fld_rx_control_used_write_enable; + nt_field_t *mp_fld_rx_control_used_writer_update_speed; + nt_field_t *mp_fld_rx_control_rx_queues_enable; + + nt_register_t *mp_reg_tx_control; + nt_field_t *mp_fld_tx_control_last_queue; + nt_field_t *mp_fld_tx_control_avail_monitor_enable; + nt_field_t *mp_fld_tx_control_avail_monitor_scan_speed; + nt_field_t *mp_fld_tx_control_used_write_enable; + nt_field_t *mp_fld_tx_control_used_writer_update_speed; + nt_field_t *mp_fld_tx_control_tx_queues_enable; + + nt_register_t *mp_reg_rx_init; + nt_field_t *mp_fld_rx_init_init; + nt_field_t *mp_fld_rx_init_queue; + nt_field_t *mp_fld_rx_init_busy; + + nt_register_t *mp_reg_rx_init_val; + nt_field_t *mp_fld_rx_init_val_idx; + nt_field_t *mp_fld_rx_init_val_ptr; + + nt_register_t *mp_reg_rx_ptr; + nt_field_t *mp_fld_rx_ptr_ptr; + nt_field_t *mp_fld_rx_ptr_queue; + nt_field_t *mp_fld_rx_ptr_valid; + + nt_register_t *mp_reg_tx_init; + nt_field_t *mp_fld_tx_init_init; + nt_field_t *mp_fld_tx_init_queue; + nt_field_t *mp_fld_tx_init_busy; + + nt_register_t *mp_reg_tx_init_val; + nt_field_t *mp_fld_tx_init_val_idx; + nt_field_t *mp_fld_tx_init_val_ptr; + + nt_register_t *mp_reg_tx_ptr; + nt_field_t *mp_fld_tx_ptr_ptr; + nt_field_t *mp_fld_tx_ptr_queue; + nt_field_t *mp_fld_tx_ptr_valid; + + nt_register_t *mp_reg_rx_idle; + nt_field_t *mp_fld_rx_idle_idle; + nt_field_t *mp_fld_rx_idle_queue; + nt_field_t *mp_fld_rx_idle_busy; + + nt_register_t *mp_reg_tx_idle; + nt_field_t *mp_fld_tx_idle_idle; + nt_field_t *mp_fld_tx_idle_queue; + nt_field_t *mp_fld_tx_idle_busy; + + nt_register_t *mp_reg_rx_avail_monitor_control; + nt_field_t *mp_fld_rx_avail_monitor_control_adr; + nt_field_t *mp_fld_rx_avail_monitor_control_cnt; + + nt_register_t *mp_reg_rx_avail_monitor_data; + nt_field_t *mp_fld_rx_avail_monitor_data_guest_physical_address; + nt_field_t *mp_fld_rx_avail_monitor_data_enable; + nt_field_t *mp_fld_rx_avail_monitor_data_host_id; + nt_field_t *mp_fld_rx_avail_monitor_data_packed; + nt_field_t *mp_fld_rx_avail_monitor_data_int; + + nt_register_t *mp_reg_tx_avail_monitor_control; + nt_field_t *mp_fld_tx_avail_monitor_control_adr; + nt_field_t *mp_fld_tx_avail_monitor_control_cnt; + + nt_register_t *mp_reg_tx_avail_monitor_data; + nt_field_t *mp_fld_tx_avail_monitor_data_guest_physical_address; + nt_field_t *mp_fld_tx_avail_monitor_data_enable; + nt_field_t *mp_fld_tx_avail_monitor_data_host_id; + nt_field_t *mp_fld_tx_avail_monitor_data_packed; + nt_field_t *mp_fld_tx_avail_monitor_data_int; + + nt_register_t *mp_reg_rx_used_writer_control; + nt_field_t *mp_fld_rx_used_writer_control_adr; + nt_field_t *mp_fld_rx_used_writer_control_cnt; + + nt_register_t *mp_reg_rx_used_writer_data; + nt_field_t *mp_fld_rx_used_writer_data_guest_physical_address; + nt_field_t *mp_fld_rx_used_writer_data_host_id; + nt_field_t *mp_fld_rx_used_writer_data_queue_size; + nt_field_t *mp_fld_rx_used_writer_data_packed; + nt_field_t *mp_fld_rx_used_writer_data_int; + nt_field_t *mp_fld_rx_used_writer_data_vec; + nt_field_t *mp_fld_rx_used_writer_data_istk; + + nt_register_t *mp_reg_tx_used_writer_control; + nt_field_t *mp_fld_tx_used_writer_control_adr; + nt_field_t *mp_fld_tx_used_writer_control_cnt; + + nt_register_t *mp_reg_tx_used_writer_data; + nt_field_t *mp_fld_tx_used_writer_data_guest_physical_address; + nt_field_t *mp_fld_tx_used_writer_data_host_id; + nt_field_t *mp_fld_tx_used_writer_data_queue_size; + nt_field_t *mp_fld_tx_used_writer_data_packed; + nt_field_t *mp_fld_tx_used_writer_data_int; + nt_field_t *mp_fld_tx_used_writer_data_vec; + nt_field_t *mp_fld_tx_used_writer_data_istk; + nt_field_t *mp_fld_tx_used_writer_data_in_order; + + nt_register_t *mp_reg_rx_descriptor_reader_control; + nt_field_t *mp_fld_rx_descriptor_reader_control_adr; + nt_field_t *mp_fld_rx_descriptor_reader_control_cnt; + + nt_register_t *mp_reg_rx_descriptor_reader_data; + nt_field_t *mp_fld_rx_descriptor_reader_data_guest_physical_address; + nt_field_t *mp_fld_rx_descriptor_reader_data_host_id; + nt_field_t *mp_fld_rx_descriptor_reader_data_queue_size; + nt_field_t *mp_fld_rx_descriptor_reader_data_header; + nt_field_t *mp_fld_rx_descriptor_reader_data_packed; + + nt_register_t *mp_reg_tx_descriptor_reader_control; + nt_field_t *mp_fld_tx_descriptor_reader_control_adr; + nt_field_t *mp_fld_tx_descriptor_reader_control_cnt; + + nt_register_t *mp_reg_tx_descriptor_reader_data; + nt_field_t *mp_fld_tx_descriptor_reader_data_guest_physical_address; + nt_field_t *mp_fld_tx_descriptor_reader_data_host_id; + nt_field_t *mp_fld_tx_descriptor_reader_data_queue_size; + nt_field_t *mp_fld_tx_descriptor_reader_data_port; + nt_field_t *mp_fld_tx_descriptor_reader_data_header; + nt_field_t *mp_fld_tx_descriptor_reader_data_packed; + + nt_register_t *mp_reg_tx_queue_property_control; + nt_field_t *mp_fld_tx_queue_property_control_adr; + nt_field_t *mp_fld_tx_queue_property_control_cnt; + + nt_register_t *mp_reg_tx_queue_property_data; + nt_field_t *mp_fld_tx_queue_property_data_v_port; + + nt_register_t *mp_reg_tx_queue_qos_control; + nt_field_t *mp_reg_tx_queue_qos_control_adr; + nt_field_t *mp_reg_tx_queue_qos_control_cnt; + + nt_register_t *mp_reg_tx_queue_qos_data; + nt_field_t *mp_reg_tx_queue_qos_data_en; + nt_field_t *mp_reg_tx_queue_qos_data_ir; + nt_field_t *mp_reg_tx_queue_qos_data_bs; + + nt_register_t *mp_reg_tx_queue_qos_rate; + nt_field_t *mp_reg_tx_queue_qos_rate_mul; + nt_field_t *mp_reg_tx_queue_qos_rate_div; + + struct nthw_dbs_rx_am_data_s m_rx_am_shadow[NT_DBS_RX_QUEUES_MAX]; + struct nthw_dbs_rx_uw_data_s m_rx_uw_shadow[NT_DBS_RX_QUEUES_MAX]; + struct nthw_dbs_rx_dr_data_s m_rx_dr_shadow[NT_DBS_RX_QUEUES_MAX]; + + struct nthw_dbs_tx_am_data_s m_tx_am_shadow[NT_DBS_TX_QUEUES_MAX]; + struct nthw_dbs_tx_uw_data_s m_tx_uw_shadow[NT_DBS_TX_QUEUES_MAX]; + struct nthw_dbs_tx_dr_data_s m_tx_dr_shadow[NT_DBS_TX_QUEUES_MAX]; + struct nthw_dbs_tx_qp_data_s m_tx_qp_shadow[NT_DBS_TX_QUEUES_MAX]; + struct nthw_dbs_tx_qos_data_s m_tx_qos_shadow[NT_DBS_TX_QUEUES_MAX]; +}; + +typedef struct nthw_dbs_s nthw_dbs_t; + +nthw_dbs_t *nthw_dbs_new(void); +void nthw_dbs_delete(nthw_dbs_t *p); +int dbs_init(nthw_dbs_t *p, nt_fpga_t *p_fpga, int n_instance); +void dbs_reset(nthw_dbs_t *p); + +int dbs_reset_rx_control(nthw_dbs_t *p); +int dbs_reset_tx_control(nthw_dbs_t *p); +int set_rx_control(nthw_dbs_t *p, uint32_t last_queue, + uint32_t avail_monitor_enable, uint32_t avail_monitor_speed, + uint32_t used_write_enable, uint32_t used_write_speed, + uint32_t rx_queue_enable); +int nthw_dbs_get_rx_control(nthw_dbs_t *p, uint32_t *last_queue, + uint32_t *avail_monitor_enable, + uint32_t *avail_monitor_speed, uint32_t *used_write_enable, + uint32_t *used_write_speed, uint32_t *rx_queue_enable); +int set_tx_control(nthw_dbs_t *p, uint32_t last_queue, + uint32_t avail_monitor_enable, uint32_t avail_monitor_speed, + uint32_t used_write_enable, uint32_t used_write_speed, + uint32_t tx_queue_enable); +int nthw_dbs_get_tx_control(nthw_dbs_t *p, uint32_t *last_queue, + uint32_t *avail_monitor_enable, + uint32_t *avail_monitor_speed, uint32_t *used_write_enable, + uint32_t *used_write_speed, uint32_t *tx_queue_enable); +int set_rx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, + uint32_t init, uint32_t queue); +int get_rx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy); +int set_tx_init(nthw_dbs_t *p, uint32_t start_idx, uint32_t start_ptr, + uint32_t init, uint32_t queue); +int get_tx_init(nthw_dbs_t *p, uint32_t *init, uint32_t *queue, uint32_t *busy); +int set_rx_idle(nthw_dbs_t *p, uint32_t idle, uint32_t queue); +int get_rx_idle(nthw_dbs_t *p, uint32_t *idle, uint32_t *queue, uint32_t *busy); +int set_tx_idle(nthw_dbs_t *p, uint32_t idle, uint32_t queue); +int get_tx_idle(nthw_dbs_t *p, uint32_t *idle, uint32_t *queue, uint32_t *busy); +int set_rx_ptr_queue(nthw_dbs_t *p, uint32_t queue); +int get_rx_ptr(nthw_dbs_t *p, uint32_t *ptr, uint32_t *queue, uint32_t *valid); +int set_tx_ptr_queue(nthw_dbs_t *p, uint32_t queue); +int get_tx_ptr(nthw_dbs_t *p, uint32_t *ptr, uint32_t *queue, uint32_t *valid); +int set_rx_am_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t enable, uint32_t host_id, uint32_t packed, + uint32_t int_enable); +int set_tx_am_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t enable, uint32_t host_id, uint32_t packed, + uint32_t int_enable); +int set_rx_uw_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t host_id, uint32_t queue_size, uint32_t packed, + uint32_t int_enable, uint32_t vec, uint32_t istk); +int set_tx_uw_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t host_id, uint32_t queue_size, uint32_t packed, + uint32_t int_enable, uint32_t vec, uint32_t istk, + uint32_t in_order); +int set_rx_dr_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t host_id, uint32_t queue_size, uint32_t header, + uint32_t packed); +int set_tx_dr_data(nthw_dbs_t *p, uint32_t index, uint64_t guest_physical_address, + uint32_t host_id, uint32_t queue_size, uint32_t port, + uint32_t header, uint32_t packed); +int nthw_dbs_set_tx_qp_data(nthw_dbs_t *p, uint32_t index, uint32_t virtual_port); +int set_tx_qos_data(nthw_dbs_t *p, uint32_t index, uint32_t enable, uint32_t ir, + uint32_t bs); +int set_tx_qos_rate(nthw_dbs_t *p, uint32_t mul, uint32_t div); + +#endif /* NTHW_DBS_H_ */ diff --git a/drivers/net/ntnic/nthw/nthw_drv.h b/drivers/net/ntnic/nthw/nthw_drv.h new file mode 100644 index 0000000000..7fdd9bf0e2 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_drv.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_DRV_H__ +#define __NTHW_DRV_H__ + +#include "nthw_profile.h" + +typedef enum nt_meta_port_type_e { + PORT_TYPE_PHYSICAL, + PORT_TYPE_VIRTUAL, + PORT_TYPE_OVERRIDE, +} nt_meta_port_type_t; + +#include "nthw_helper.h" +#include "nthw_platform_drv.h" +#include "nthw_fpga_model.h" +#include "nthw_stat.h" +#include "nthw_dbs.h" +#include "nthw_epp.h" +#include "nthw_core.h" + +typedef struct nthwhw_info_s { + /* From FW */ + int hw_id; + int hw_id_emulated; + char hw_plat_id_str[32]; + + struct vpd_info_s { + int mn_mac_addr_count; + uint64_t mn_mac_addr_value; + uint8_t ma_mac_addr_octets[6]; + } vpd_info; +} nthw_hw_info_t; + +typedef struct fpga_info_s { + uint64_t n_fpga_ident; + + int n_fpga_type_id; + int n_fpga_prod_id; + int n_fpga_ver_id; + int n_fpga_rev_id; + + int n_fpga_build_time; + + int n_fpga_debug_mode; + + int n_nims; + int n_phy_ports; + int n_phy_quads; + int n_rx_ports; + int n_tx_ports; + + enum fpga_info_profile profile; + + struct nt_fpga_s *mp_fpga; + + struct nthw_rac *mp_nthw_rac; + struct nthw_hif *mp_nthw_hif; + struct nthw_pcie3 *mp_nthw_pcie3; + struct nthw_tsm *mp_nthw_tsm; + + nthw_dbs_t *mp_nthw_dbs; + nthw_epp_t *mp_nthw_epp; + + uint8_t *bar0_addr; /* Needed for register read/write */ + size_t bar0_size; + + int adapter_no; /* Needed for nthw_rac DMA array indexing */ + uint32_t pciident; /* Needed for nthw_rac DMA memzone_reserve */ + int numa_node; /* Needed for nthw_rac DMA memzone_reserve */ + + char *mp_adapter_id_str; /* Pointer to string literal used in nthw log messages */ + + struct nthwhw_info_s nthw_hw_info; + + nthw_adapter_id_t n_nthw_adapter_id; + +} fpga_info_t; + +#endif /* __NTHW_DRV_H__ */ diff --git a/drivers/net/ntnic/nthw/nthw_epp.c b/drivers/net/ntnic/nthw/nthw_epp.c new file mode 100644 index 0000000000..fbe3993b25 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_epp.c @@ -0,0 +1,335 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_epp.h" + +#include /* ENOTSUP */ + +nthw_epp_t *nthw_epp_new(void) +{ + nthw_epp_t *p = malloc(sizeof(nthw_epp_t)); + + if (p) + memset(p, 0, sizeof(nthw_epp_t)); + return p; +} + +void nthw_epp_delete(nthw_epp_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_epp_t)); + free(p); + } +} + +int nthw_epp_present(nt_fpga_t *p_fpga, int n_instance) +{ + return nthw_epp_init(NULL, p_fpga, n_instance) == 0; +} + +int nthw_epp_init(nthw_epp_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + nt_module_t *mod = fpga_query_module(p_fpga, MOD_EPP, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: EPP %d: no such instance\n", + p_fpga->p_fpga_info->mp_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_epp = mod; + + p->mn_epp_categories = fpga_get_product_param(p_fpga, NT_EPP_CATEGORIES, 0); + + p->mp_reg_reciepe_memory_control = + module_get_register(p->mp_mod_epp, EPP_RCP_CTRL); + p->mp_fld_reciepe_memory_control_adr = + register_get_field(p->mp_reg_reciepe_memory_control, EPP_RCP_CTRL_ADR); + p->mp_fld_reciepe_memory_control_cnt = + register_get_field(p->mp_reg_reciepe_memory_control, EPP_RCP_CTRL_CNT); + + p->mp_reg_reciepe_memory_data = + module_get_register(p->mp_mod_epp, EPP_RCP_DATA); + p->mp_fld_reciepe_memory_data_tx_mtu_epp_enable = + register_get_field(p->mp_reg_reciepe_memory_data, EPP_RCP_DATA_TX_MTU_EPP_EN); + p->mp_fld_reciepe_memory_data_queue_mtu_epp_enable = + register_get_field(p->mp_reg_reciepe_memory_data, EPP_RCP_DATA_QUEUE_MTU_EPP_EN); + p->mp_fld_reciepe_memory_data_size_adjust_tx_port = + register_get_field(p->mp_reg_reciepe_memory_data, EPP_RCP_DATA_SIZE_ADJUST_TXP); + p->mp_fld_reciepe_memory_data_size_adjust_virtual_port = + register_get_field(p->mp_reg_reciepe_memory_data, EPP_RCP_DATA_SIZE_ADJUST_VPORT); + p->mp_fld_reciepe_memory_data_fixed18b_l2_mtu = + register_get_field(p->mp_reg_reciepe_memory_data, EPP_RCP_DATA_FIXED_18B_L2_MTU); + p->mp_fld_reciepe_memory_data_txp_qos_epp_enable = + register_get_field(p->mp_reg_reciepe_memory_data, EPP_RCP_DATA_TX_QOS_EPP_EN); + p->mp_fld_reciepe_memory_data_queue_qos_epp_enable = + register_get_field(p->mp_reg_reciepe_memory_data, EPP_RCP_DATA_QUEUE_QOS_EPP_EN); + + p->mp_reg_txp_port_mtu_control = + module_get_register(p->mp_mod_epp, EPP_TXP_MTU_CTRL); + p->mp_fld_txp_port_mtu_control_adr = + register_get_field(p->mp_reg_txp_port_mtu_control, EPP_TXP_MTU_CTRL_ADR); + p->mp_fld_txp_port_mtu_control_cnt = + register_get_field(p->mp_reg_txp_port_mtu_control, EPP_TXP_MTU_CTRL_CNT); + + p->mp_reg_txp_port_mtu_data = + module_get_register(p->mp_mod_epp, EPP_TXP_MTU_DATA); + p->mp_fld_txp_port_mtu_data_max_mtu = + register_get_field(p->mp_reg_txp_port_mtu_data, EPP_TXP_MTU_DATA_MAX_MTU); + + p->mp_reg_queue_mtu_control = + module_get_register(p->mp_mod_epp, EPP_QUEUE_MTU_CTRL); + p->mp_fld_queue_mtu_control_adr = + register_get_field(p->mp_reg_queue_mtu_control, EPP_QUEUE_MTU_CTRL_ADR); + p->mp_fld_queue_mtu_control_cnt = + register_get_field(p->mp_reg_queue_mtu_control, EPP_QUEUE_MTU_CTRL_CNT); + + p->mp_reg_queue_mtu_data = + module_get_register(p->mp_mod_epp, EPP_QUEUE_MTU_DATA); + p->mp_fld_queue_mtu_data_max_mtu = + register_get_field(p->mp_reg_queue_mtu_data, EPP_QUEUE_MTU_DATA_MAX_MTU); + + p->mp_reg_txp_qos_control = + module_get_register(p->mp_mod_epp, EPP_TXP_QOS_CTRL); + p->mp_fld_txp_qos_control_adr = + register_get_field(p->mp_reg_txp_qos_control, EPP_TXP_QOS_CTRL_ADR); + p->mp_fld_txp_qos_control_cnt = + register_get_field(p->mp_reg_txp_qos_control, EPP_TXP_QOS_CTRL_CNT); + + p->mp_reg_txp_qos_data = module_get_register(p->mp_mod_epp, EPP_TXP_QOS_DATA); + p->mp_fld_txp_qos_data_enable = + register_get_field(p->mp_reg_txp_qos_data, EPP_TXP_QOS_DATA_EN); + p->mp_fld_txp_qos_data_information_rate = + register_get_field(p->mp_reg_txp_qos_data, EPP_TXP_QOS_DATA_IR); + p->mp_fld_txp_qos_data_information_rate_fractional = + register_get_field(p->mp_reg_txp_qos_data, EPP_TXP_QOS_DATA_IR_FRACTION); + p->mp_fld_txp_qos_data_burst_size = + register_get_field(p->mp_reg_txp_qos_data, EPP_TXP_QOS_DATA_BS); + + p->mp_reg_vport_qos_control = + module_get_register(p->mp_mod_epp, EPP_VPORT_QOS_CTRL); + p->mp_fld_vport_qos_control_adr = + register_get_field(p->mp_reg_vport_qos_control, EPP_VPORT_QOS_CTRL_ADR); + p->mp_fld_vport_qos_control_cnt = + register_get_field(p->mp_reg_vport_qos_control, EPP_VPORT_QOS_CTRL_CNT); + + p->mp_reg_vport_qos_data = + module_get_register(p->mp_mod_epp, EPP_VPORT_QOS_DATA); + p->mp_fld_vport_qos_data_enable = + register_get_field(p->mp_reg_vport_qos_data, EPP_VPORT_QOS_DATA_EN); + p->mp_fld_vport_qos_data_information_rate = + register_get_field(p->mp_reg_vport_qos_data, EPP_VPORT_QOS_DATA_IR); + p->mp_fld_vport_qos_data_information_rate_fractional = + register_get_field(p->mp_reg_vport_qos_data, EPP_VPORT_QOS_DATA_IR_FRACTION); + p->mp_fld_vport_qos_data_burst_size = + register_get_field(p->mp_reg_vport_qos_data, EPP_VPORT_QOS_DATA_BS); + + p->mp_reg_queue_vport_control = + module_get_register(p->mp_mod_epp, EPP_QUEUE_VPORT_CTRL); + p->mp_fld_queue_vport_control_adr = + register_get_field(p->mp_reg_queue_vport_control, EPP_QUEUE_VPORT_CTRL_ADR); + p->mp_fld_queue_vport_control_cnt = + register_get_field(p->mp_reg_queue_vport_control, EPP_QUEUE_VPORT_CTRL_CNT); + + p->mp_reg_queue_vport_data = + module_get_register(p->mp_mod_epp, EPP_QUEUE_VPORT_DATA); + p->mp_fld_queue_vport_data_vport = + register_get_field(p->mp_reg_queue_vport_data, EPP_QUEUE_VPORT_DATA_VPORT); + + return 0; +} + +int nthw_epp_setup(nthw_epp_t *p) +{ + if (p == NULL) + return 0; + + /* Set recieps for 2 first records */ + field_set_val32(p->mp_fld_reciepe_memory_control_cnt, 1); + + /* Zero all categories */ + for (int i = 0; i < p->mn_epp_categories; ++i) { + field_set_val32(p->mp_fld_reciepe_memory_control_adr, i); + register_flush(p->mp_reg_reciepe_memory_control, 1); + + field_set_val32(p->mp_fld_reciepe_memory_data_tx_mtu_epp_enable, 0); + field_set_val32(p->mp_fld_reciepe_memory_data_queue_mtu_epp_enable, 0); + field_set_val32(p->mp_fld_reciepe_memory_data_size_adjust_tx_port, 0); + field_set_val32(p->mp_fld_reciepe_memory_data_size_adjust_virtual_port, + 0); + field_set_val32(p->mp_fld_reciepe_memory_data_fixed18b_l2_mtu, 0); + field_set_val32(p->mp_fld_reciepe_memory_data_txp_qos_epp_enable, 0); + field_set_val32(p->mp_fld_reciepe_memory_data_queue_qos_epp_enable, 0); + register_flush(p->mp_reg_reciepe_memory_data, 1); + } + + for (int i = 0; i < NRECIPE; ++i) { + field_set_val32(p->mp_fld_reciepe_memory_control_adr, i); + register_flush(p->mp_reg_reciepe_memory_control, 1); + + field_set_val32(p->mp_fld_reciepe_memory_data_tx_mtu_epp_enable, 1); + field_set_val32(p->mp_fld_reciepe_memory_data_queue_mtu_epp_enable, 1); + field_set_val32(p->mp_fld_reciepe_memory_data_size_adjust_tx_port, + rcp_data_size_adjust_txp[i]); + field_set_val32(p->mp_fld_reciepe_memory_data_size_adjust_virtual_port, + rcp_data_size_adjust_vport[i]); + field_set_val32(p->mp_fld_reciepe_memory_data_fixed18b_l2_mtu, 1); + field_set_val32(p->mp_fld_reciepe_memory_data_txp_qos_epp_enable, 1); + field_set_val32(p->mp_fld_reciepe_memory_data_queue_qos_epp_enable, 1); + register_flush(p->mp_reg_reciepe_memory_data, 1); + } + /* phy mtu setup */ + field_set_val32(p->mp_fld_txp_port_mtu_control_cnt, 1); + for (int i = 0; i < 2; ++i) { + field_set_val32(p->mp_fld_txp_port_mtu_control_adr, i); + register_flush(p->mp_reg_txp_port_mtu_control, 1); + + field_set_val32(p->mp_fld_txp_port_mtu_data_max_mtu, MTUINITVAL); + register_flush(p->mp_reg_txp_port_mtu_data, 1); + } + /* phy QoS setup */ + field_set_val32(p->mp_fld_txp_qos_control_cnt, 1); + for (int i = 0; i < 2; ++i) { + field_set_val32(p->mp_fld_txp_qos_control_adr, i); + register_flush(p->mp_reg_txp_qos_control, 1); + + field_set_val32(p->mp_fld_txp_qos_data_enable, 0); + register_flush(p->mp_reg_txp_qos_data, 1); + } + + /* virt mtu setup */ + field_set_val32(p->mp_fld_queue_mtu_control_cnt, 1); + for (int i = 0; i < 128; ++i) { + field_set_val32(p->mp_fld_queue_mtu_control_adr, i); + register_flush(p->mp_reg_queue_mtu_control, 1); + + field_set_val32(p->mp_fld_queue_mtu_data_max_mtu, MTUINITVAL); + register_flush(p->mp_reg_queue_mtu_data, 1); + } + + /* virt QoS setup */ + field_set_val32(p->mp_fld_vport_qos_control_cnt, 1); + for (int i = 0; i < 128; ++i) { + field_set_val32(p->mp_fld_vport_qos_control_adr, i); + register_flush(p->mp_reg_vport_qos_control, 1); + + field_set_val32(p->mp_fld_vport_qos_data_enable, 0); + register_flush(p->mp_reg_vport_qos_data, 1); + } + + return 0; +} + +/* + * Set the MTU registers in context with the current setMTU request. + */ +int nthw_epp_set_mtu(nthw_epp_t *p, uint32_t port, uint32_t max_mtu, + nt_meta_port_type_t port_type) +{ + if (p == NULL) + return 0; + + if (port_type == PORT_TYPE_PHYSICAL) { + /* Set the TXP Mtu control register */ + field_set_val32(p->mp_fld_txp_port_mtu_control_adr, port); + field_set_val32(p->mp_fld_txp_port_mtu_control_cnt, 1); + register_flush(p->mp_reg_txp_port_mtu_control, 1); + + /* Set the TXP Mtu control register */ + field_set_val32(p->mp_fld_txp_port_mtu_data_max_mtu, max_mtu); + register_flush(p->mp_reg_txp_port_mtu_data, 1); + } else if (port_type == PORT_TYPE_VIRTUAL) { + /* Set the TXP Mtu control register */ + field_set_val32(p->mp_fld_queue_mtu_control_adr, port); + field_set_val32(p->mp_fld_queue_mtu_control_cnt, 1); + register_flush(p->mp_reg_queue_mtu_control, 1); + + /* Set the TXP Mtu control register */ + field_set_val32(p->mp_fld_queue_mtu_data_max_mtu, max_mtu); + register_flush(p->mp_reg_queue_mtu_data, 1); + } else { + NT_LOG(DBG, NTHW, "NthwEpp::%s - port_type unsupported", + __func__); + register_reset(p->mp_reg_queue_mtu_control); + register_flush(p->mp_reg_queue_mtu_control, 1); + register_reset(p->mp_reg_queue_mtu_data); + register_flush(p->mp_reg_queue_mtu_data, 1); + register_reset(p->mp_reg_txp_port_mtu_control); + register_flush(p->mp_reg_txp_port_mtu_control, 1); + register_reset(p->mp_reg_txp_port_mtu_data); + register_flush(p->mp_reg_txp_port_mtu_data, 1); + + return -ENOTSUP; + } + + return 0; +} + +int nthw_epp_set_txp_qos(nthw_epp_t *p, uint32_t port, uint32_t information_rate, + uint32_t information_rate_fractional, uint32_t burst_size) +{ + if (p == NULL) + return 0; + + field_set_val32(p->mp_fld_txp_qos_control_adr, port); + field_set_val32(p->mp_fld_txp_qos_control_cnt, 1); + register_flush(p->mp_reg_txp_qos_control, 1); + + uint32_t enable = ((information_rate | information_rate_fractional | + burst_size) != 0); + field_set_val32(p->mp_fld_txp_qos_data_enable, enable); + field_set_val32(p->mp_fld_txp_qos_data_information_rate, information_rate); + field_set_val32(p->mp_fld_txp_qos_data_information_rate_fractional, + information_rate_fractional); + field_set_val32(p->mp_fld_txp_qos_data_burst_size, burst_size); + register_flush(p->mp_reg_txp_qos_data, 1); + + return 0; +} + +int nthw_epp_set_vport_qos(nthw_epp_t *p, uint32_t port, uint32_t information_rate, + uint32_t information_rate_fractional, uint32_t burst_size) +{ + if (p == NULL) + return 0; + + field_set_val32(p->mp_fld_vport_qos_control_adr, port); + field_set_val32(p->mp_fld_vport_qos_control_cnt, 1); + register_flush(p->mp_reg_vport_qos_control, 1); + + uint32_t enable = ((information_rate | information_rate_fractional | + burst_size) != 0); + field_set_val32(p->mp_fld_vport_qos_data_enable, enable); + field_set_val32(p->mp_fld_vport_qos_data_information_rate, information_rate); + field_set_val32(p->mp_fld_vport_qos_data_information_rate_fractional, + information_rate_fractional); + field_set_val32(p->mp_fld_vport_qos_data_burst_size, burst_size); + register_flush(p->mp_reg_vport_qos_data, 1); + + return 0; +} + +int nthw_epp_set_queue_to_vport(nthw_epp_t *p, uint32_t qid, uint32_t vport) +{ + if (p == NULL) + return 0; + + field_set_val32(p->mp_fld_queue_vport_control_adr, qid); + field_set_val32(p->mp_fld_queue_vport_control_cnt, 1); + register_flush(p->mp_reg_queue_vport_control, 1); + + field_set_val32(p->mp_fld_queue_vport_data_vport, vport); + register_flush(p->mp_reg_queue_vport_data, 1); + return 0; +} diff --git a/drivers/net/ntnic/nthw/nthw_epp.h b/drivers/net/ntnic/nthw/nthw_epp.h new file mode 100644 index 0000000000..b404c9b61a --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_epp.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef NTHW_EPP_HPP_ +#define NTHW_EPP_HPP_ + +/* VXLAN adds extra 50 bytes */ +#define VXLANDATASIZEADJUST 50 +#define VXLANDATASIZEADJUSTIPV6 70 +#define MTUINITVAL 1500 +#define NRECIPE 3 + +/* List of size adjust values to put in the recipe memory data register at startup */ +static const int rcp_data_size_adjust_txp[NRECIPE] = { 0, VXLANDATASIZEADJUST, + VXLANDATASIZEADJUSTIPV6 + }; +static const int rcp_data_size_adjust_vport[NRECIPE] = { 0, VXLANDATASIZEADJUST, + VXLANDATASIZEADJUSTIPV6 + }; + +struct nthw_epp_s { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_epp; + int mn_instance; + int mn_epp_categories; + + nt_register_t *mp_reg_reciepe_memory_control; + nt_field_t *mp_fld_reciepe_memory_control_adr; + nt_field_t *mp_fld_reciepe_memory_control_cnt; + + nt_register_t *mp_reg_reciepe_memory_data; + nt_field_t *mp_fld_reciepe_memory_data_tx_mtu_epp_enable; + nt_field_t *mp_fld_reciepe_memory_data_queue_mtu_epp_enable; + nt_field_t *mp_fld_reciepe_memory_data_size_adjust_tx_port; + nt_field_t *mp_fld_reciepe_memory_data_size_adjust_virtual_port; + nt_field_t *mp_fld_reciepe_memory_data_fixed18b_l2_mtu; + nt_field_t *mp_fld_reciepe_memory_data_txp_qos_epp_enable; + nt_field_t *mp_fld_reciepe_memory_data_queue_qos_epp_enable; + + nt_register_t *mp_reg_txp_port_mtu_control; + nt_field_t *mp_fld_txp_port_mtu_control_adr; + nt_field_t *mp_fld_txp_port_mtu_control_cnt; + + nt_register_t *mp_reg_txp_port_mtu_data; + nt_field_t *mp_fld_txp_port_mtu_data_max_mtu; + + nt_register_t *mp_reg_queue_mtu_control; + nt_field_t *mp_fld_queue_mtu_control_adr; + nt_field_t *mp_fld_queue_mtu_control_cnt; + + nt_register_t *mp_reg_queue_mtu_data; + nt_field_t *mp_fld_queue_mtu_data_max_mtu; + + nt_register_t *mp_reg_txp_qos_control; + nt_field_t *mp_fld_txp_qos_control_adr; + nt_field_t *mp_fld_txp_qos_control_cnt; + + nt_register_t *mp_reg_txp_qos_data; + nt_field_t *mp_fld_txp_qos_data_enable; + nt_field_t *mp_fld_txp_qos_data_information_rate; + nt_field_t *mp_fld_txp_qos_data_information_rate_fractional; + nt_field_t *mp_fld_txp_qos_data_burst_size; + + nt_register_t *mp_reg_vport_qos_control; + nt_field_t *mp_fld_vport_qos_control_adr; + nt_field_t *mp_fld_vport_qos_control_cnt; + + nt_register_t *mp_reg_vport_qos_data; + nt_field_t *mp_fld_vport_qos_data_enable; + nt_field_t *mp_fld_vport_qos_data_information_rate; + nt_field_t *mp_fld_vport_qos_data_information_rate_fractional; + nt_field_t *mp_fld_vport_qos_data_burst_size; + + nt_register_t *mp_reg_queue_vport_control; + nt_field_t *mp_fld_queue_vport_control_adr; + nt_field_t *mp_fld_queue_vport_control_cnt; + + nt_register_t *mp_reg_queue_vport_data; + nt_field_t *mp_fld_queue_vport_data_vport; +}; + +typedef struct nthw_epp_s nthw_epp_t; + +nthw_epp_t *nthw_epp_new(void); +void nthw_epp_delete(nthw_epp_t *p); + +int nthw_epp_present(nt_fpga_t *p_fpga, int n_instance); +int nthw_epp_init(nthw_epp_t *p, nt_fpga_t *p_fpga, int n_instance); +int nthw_epp_setup(nthw_epp_t *p); +int nthw_epp_set_mtu(nthw_epp_t *p, uint32_t port, uint32_t max_mtu, + nt_meta_port_type_t port_type); +int nthw_epp_set_txp_qos(nthw_epp_t *p, uint32_t port, uint32_t information_rate, + uint32_t information_rate_fractional, uint32_t burst_size); +int nthw_epp_set_vport_qos(nthw_epp_t *p, uint32_t port, uint32_t information_rate, + uint32_t information_rate_fractional, uint32_t burst_size); +int nthw_epp_set_queue_to_vport(nthw_epp_t *p, uint32_t qid, uint32_t vport); + +#endif /* NTHW_EPP_HPP_ */ diff --git a/drivers/net/ntnic/nthw/nthw_fpga_model.c b/drivers/net/ntnic/nthw/nthw_fpga_model.c new file mode 100644 index 0000000000..fca13e0f31 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_fpga_model.c @@ -0,0 +1,1677 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include /* ctime */ + +#include "nthw_drv.h" /* fpga_info_s */ +#include "nthw_register.h" +#include "nthw_fpga_model.h" +#include "nthw_rac.h" +#include "ntlog.h" + +#include "nthw_fpga_instances.h" +#include "nthw_fpga_modules_defs.h" + +/* Generated code */ +nt_fpga_prod_init_t *nthw_fpga_instances[] = { &nthw_fpga_9563_055_024_0000, + NULL + }; + +static const struct { + const int a; + const char *b; +} sa_nthw_fpga_mod_map[] = { + { MOD_CAT, "CAT" }, + { MOD_CB, "CB" }, + { MOD_CCIP, "CCIP" }, + { MOD_CFP4_CTRL_GBOX, "CFP4_CTRL_GBOX" }, + { MOD_COR, "COR" }, + { MOD_CPY, "CPY" }, + { MOD_CSU, "CSU" }, + { MOD_DBS, "DBS" }, + { MOD_DDP, "DDP" }, + { MOD_EPP, "EPP" }, + { MOD_EQM, "EQM" }, + { MOD_FHM, "FHM" }, + { MOD_FLM, "FLM" }, + { MOD_GFG, "GFG" }, + { MOD_GMF, "GMF" }, + { MOD_GPIO_PHY, "GPIO_PHY" }, + { MOD_GPIO_PHY_PORTS, "GPIO_PHY_PORTS" }, + { MOD_GPIO_SFPP, "GPIO_SFPP" }, + { MOD_HFU, "HFU" }, + { MOD_HIF, "HIF" }, + { MOD_HSH, "HSH" }, + { MOD_HST, "HST" }, + { MOD_ICORE_10G, "ICORE_10G" }, + { MOD_IFR, "IFR" }, + { MOD_IIC, "IIC" }, + { MOD_INS, "INS" }, + { MOD_IOA, "IOA" }, + { MOD_IPF, "IPF" }, + { MOD_KM, "KM" }, + { MOD_LAO, "LAO" }, + { MOD_MAC, "MAC" }, + { MOD_MAC10, "MAC10" }, + { MOD_MAC100, "MAC100" }, + { MOD_MAC10G, "MAC10G" }, + { MOD_MAC1G, "MAC1G" }, + { MOD_MAC_PCS, "MAC_PCS" }, + { MOD_MAC_PCS_XXV, "MAC_PCS_XXV" }, + { MOD_MAC_RX, "MAC_RX" }, + { MOD_MAC_TFG, "MAC_TFG" }, + { MOD_MAC_TX, "MAC_TX" }, + { MOD_MCU, "MCU" }, + { MOD_MDG, "MDG" }, + { MOD_MSK, "MSK" }, + { MOD_NIF, "NIF" }, + { MOD_PCIE3, "PCIE3" }, + { MOD_PCI_RD_TG, "PCI_RD_TG" }, + { MOD_PCI_TA, "PCI_TA" }, + { MOD_PCI_WR_TG, "PCI_WR_TG" }, + { MOD_PCM_NT100A01_01, "PCM_NT100A01_01" }, + { MOD_PCM_NT50B01_01, "PCM_NT50B01_01" }, + { MOD_PCS, "PCS" }, + { MOD_PCS100, "PCS100" }, + { MOD_PDB, "PDB" }, + { MOD_PDI, "PDI" }, + { MOD_PHY10G, "PHY10G" }, + { MOD_PHY3S10G, "PHY3S10G" }, + { MOD_PM, "PM" }, + { MOD_PRM_NT100A01_01, "PRM_NT100A01_01" }, + { MOD_PRM_NT50B01_01, "PRM_NT50B01_01" }, + { MOD_PTP1588, "PTP1588" }, + { MOD_QM, "QM" }, + { MOD_QSL, "QSL" }, + { MOD_QSPI, "QSPI" }, + { MOD_R2DRP, "R2DRP" }, + { MOD_RAC, "RAC" }, + { MOD_RBH, "RBH" }, + { MOD_RFD, "RFD" }, + { MOD_RMC, "RMC" }, + { MOD_RNTC, "RNTC" }, + { MOD_ROA, "ROA" }, + { MOD_RPL, "RPL" }, + { MOD_RPP_LR, "RPP_LR" }, + { MOD_RST7000, "RST7000" }, + { MOD_RST7001, "RST7001" }, + { MOD_RST9500, "RST9500" }, + { MOD_RST9501, "RST9501" }, + { MOD_RST9502, "RST9502" }, + { MOD_RST9503, "RST9503" }, + { MOD_RST9504, "RST9504" }, + { MOD_RST9505, "RST9505" }, + { MOD_RST9506, "RST9506" }, + { MOD_RST9507, "RST9507" }, + { MOD_RST9508, "RST9508" }, + { MOD_RST9509, "RST9509" }, + { MOD_RST9510, "RST9510" }, + { MOD_RST9512, "RST9512" }, + { MOD_RST9513, "RST9513" }, + { MOD_RST9515, "RST9515" }, + { MOD_RST9516, "RST9516" }, + { MOD_RST9517, "RST9517" }, + { MOD_RST9519, "RST9519" }, + { MOD_RST9520, "RST9520" }, + { MOD_RST9521, "RST9521" }, + { MOD_RST9522, "RST9522" }, + { MOD_RST9523, "RST9523" }, + { MOD_RST9524, "RST9524" }, + { MOD_RST9525, "RST9525" }, + { MOD_RST9526, "RST9526" }, + { MOD_RST9527, "RST9527" }, + { MOD_RST9528, "RST9528" }, + { MOD_RST9529, "RST9529" }, + { MOD_RST9530, "RST9530" }, + { MOD_RST9531, "RST9531" }, + { MOD_RST9532, "RST9532" }, + { MOD_RST9533, "RST9533" }, + { MOD_RST9534, "RST9534" }, + { MOD_RST9535, "RST9535" }, + { MOD_RST9536, "RST9536" }, + { MOD_RST9537, "RST9537" }, + { MOD_RST9538, "RST9538" }, + { MOD_RST9539, "RST9539" }, + { MOD_RST9540, "RST9540" }, + { MOD_RST9541, "RST9541" }, + { MOD_RST9542, "RST9542" }, + { MOD_RST9543, "RST9543" }, + { MOD_RST9544, "RST9544" }, + { MOD_RST9545, "RST9545" }, + { MOD_RST9546, "RST9546" }, + { MOD_RST9547, "RST9547" }, + { MOD_RST9548, "RST9548" }, + { MOD_RST9549, "RST9549" }, + { MOD_RST9553, "RST9553" }, + { MOD_RST9555, "RST9555" }, + { MOD_RST9559, "RST9559" }, + { MOD_RST9563, "RST9563" }, + { MOD_RTD, "RTD" }, + { MOD_RTD_HMP, "RTD_HMP" }, + { MOD_RTX, "RTX" }, + { MOD_SDC, "SDC" }, + { MOD_SLC, "SLC" }, + { MOD_SLC_LR, "SLC_LR" }, + { MOD_SMM, "SMM" }, + { MOD_SMM_RX, "SMM_RX" }, + { MOD_SMM_TX, "SMM_TX" }, + { MOD_SPIM, "SPIM" }, + { MOD_SPIS, "SPIS" }, + { MOD_STA, "STA" }, + { MOD_TBH, "TBH" }, + { MOD_TEMPMON, "TEMPMON" }, + { MOD_TINT, "TINT" }, + { MOD_TMC, "TMC" }, + { MOD_TSM, "TSM" }, + { MOD_TX_CPY, "TX_CPY" }, + { MOD_TX_CSI, "TX_CSI" }, + { MOD_TX_CSO, "TX_CSO" }, + { MOD_TX_INS, "TX_INS" }, + { MOD_TX_RPL, "TX_RPL" }, + { 0L, NULL }, +}; + +/* NOTE: this needs to be (manually) synced with enum */ +static const char *const a_bus_type[] = { + "ERR", /* BUS_TYPE_UNKNOWN, */ + "BAR", /* BUS_TYPE_BAR, */ + "PCI", /* BUS_TYPE_PCI, */ + "CCIP", /* BUS_TYPE_CCIP, */ + "RAB0", /* BUS_TYPE_RAB0, */ + "RAB1", /* BUS_TYPE_RAB1, */ + "RAB2", /* BUS_TYPE_RAB2, */ + "NMB", /* BUS_TYPE_NMB, */ + "NDM", /* BUS_TYPE_NDM, */ +}; + +static const char *get_bus_name(int n_bus_type_id) +{ + if (n_bus_type_id >= 1 && n_bus_type_id <= (int)ARRAY_SIZE(a_bus_type)) + return a_bus_type[n_bus_type_id]; + + else + return "ERR"; +} + +/* + * Module name lookup by id from array + * Uses naive linear search as performance is not an issue here... + */ +static const char *nthw_fpga_mod_id_to_str(uint64_t n_fpga_mod_id) +{ + int i; + + for (i = 0; i <= (int)ARRAY_SIZE(sa_nthw_fpga_mod_map); i++) { + if ((uint64_t)sa_nthw_fpga_mod_map[i].a == n_fpga_mod_id) + break; + } + return (sa_nthw_fpga_mod_map[i].b ? sa_nthw_fpga_mod_map[i].b : + "unknown"); +} + +/* + * Force C linkage for xxx_addr_bases and xxx_module_versions + */ +static int read_data(struct fpga_info_s *p_fpga_info, int n_bus_type_id, uint32_t addr, + uint32_t len, uint32_t *p_data) +{ + int rc = -1; + + assert(p_fpga_info); + assert(p_data); + + switch (n_bus_type_id) { + case BUS_TYPE_BAR: + case BUS_TYPE_PCI: + assert(len == 1); + nthw_rac_reg_read32(p_fpga_info, addr, p_data); + rc = 0; + break; + case BUS_TYPE_RAB0: + assert(p_fpga_info->mp_nthw_rac); + rc = nthw_rac_rab_read32(p_fpga_info->mp_nthw_rac, addr, 0, len, + p_data); + break; + case BUS_TYPE_RAB1: + assert(p_fpga_info->mp_nthw_rac); + rc = nthw_rac_rab_read32(p_fpga_info->mp_nthw_rac, addr, 1, len, + p_data); + break; + case BUS_TYPE_RAB2: + assert(p_fpga_info->mp_nthw_rac); + rc = nthw_rac_rab_read32(p_fpga_info->mp_nthw_rac, addr, 2, len, + p_data); + break; + default: + assert(false); + return -1; + } + + return rc; +} + +static int read_data_tsc(struct fpga_info_s *p_fpga_info, int n_bus_type_id, + uint32_t addr, uint32_t len, uint32_t *p_data, + uint64_t *p_tsc1, uint64_t *p_tsc2) +{ + int rc = -1; + + (void)p_tsc1; + (void)p_tsc2; + + rc = read_data(p_fpga_info, n_bus_type_id, addr, len, p_data); + + return rc; +} + +static int write_data(struct fpga_info_s *p_fpga_info, int n_bus_type_id, + uint32_t addr, uint32_t len, const uint32_t *p_data) +{ + int rc = -1; + + assert(p_fpga_info); + assert(p_data); + + switch (n_bus_type_id) { + case BUS_TYPE_BAR: + case BUS_TYPE_PCI: + assert(len == 1); + nthw_rac_reg_write32(p_fpga_info, addr, *p_data); + rc = 0; + break; + case BUS_TYPE_RAB0: + assert(p_fpga_info->mp_nthw_rac); + rc = nthw_rac_rab_write32(p_fpga_info->mp_nthw_rac, addr, 0, len, + p_data); + break; + case BUS_TYPE_RAB1: + assert(p_fpga_info->mp_nthw_rac); + rc = nthw_rac_rab_write32(p_fpga_info->mp_nthw_rac, addr, 1, len, + p_data); + break; + case BUS_TYPE_RAB2: + assert(p_fpga_info->mp_nthw_rac); + rc = nthw_rac_rab_write32(p_fpga_info->mp_nthw_rac, addr, 2, len, + p_data); + break; + default: + assert(false); + return -1; + } + + return rc; +} + +/* + * FpgaMgr + */ +nt_fpga_mgr_t *fpga_mgr_new(void) +{ + nt_fpga_mgr_t *p = malloc(sizeof(nt_fpga_mgr_t)); + return p; +} + +void fpga_mgr_delete(nt_fpga_mgr_t *p) +{ + memset(p, 0, sizeof(nt_fpga_mgr_t)); + free(p); +} + +void fpga_mgr_init(nt_fpga_mgr_t *p) +{ + size_t i; + + /* Count fpga instance in array */ + p->mpa_fpga_prod_init = nthw_fpga_instances; + for (i = 0; i < ARRAY_SIZE(nthw_fpga_instances); i++) { + if (p->mpa_fpga_prod_init[i] == NULL) + break; + } + p->mn_fpgas = (int)i; +} + +nt_fpga_t *fpga_mgr_query_fpga(nt_fpga_mgr_t *p, uint64_t n_fpga_id, + struct fpga_info_s *p_fpga_info) +{ + int i; + + const int n_fpga_prod = FPGAID_TO_PRODUCTCODE(n_fpga_id); + const int n_fpga_ver = FPGAID_TO_VERSIONCODE(n_fpga_id); + const int n_fpga_rev = FPGAID_TO_REVISIONCODE(n_fpga_id); + + for (i = 0; i < p->mn_fpgas; i++) { + nt_fpga_prod_init_t *p_init = p->mpa_fpga_prod_init[i]; + + if (p_init->fpga_product_id == n_fpga_prod && + p_init->fpga_version == n_fpga_ver && + p_init->fpga_revision == n_fpga_rev) { + { + nt_fpga_t *p_fpga = fpga_new(); + + fpga_init(p_fpga, p_init, p_fpga_info); + return p_fpga; + } + } + } + + NT_LOG(ERR, NTHW, + "FPGA Id 0x%" PRIX64 ": %04d: %d.%d: no match found\n", n_fpga_id, + n_fpga_prod, n_fpga_ver, n_fpga_rev); + + return NULL; +} + +void fpga_mgr_show(nt_fpga_mgr_t *p, FILE *fh_out, int detail_level) +{ + int i; + + fprintf(fh_out, "\n"); /* start of records */ + for (i = 0; i < p->mn_fpgas; i++) { + nt_fpga_prod_init_t *p_init = p->mpa_fpga_prod_init[i]; + + if (detail_level == 0) { + fprintf(fh_out, "%04d-%02d-%02d\n", + p_init->fpga_product_id, p_init->fpga_version, + p_init->fpga_revision); + } else { + time_t fpga_build_time = p_init->fpga_build_time; + + fprintf(fh_out, "%04d-%02d-%02d: 0x%08lX: %s\n", + p_init->fpga_product_id, p_init->fpga_version, + p_init->fpga_revision, fpga_build_time, + (fpga_build_time ? ctime(&fpga_build_time) : + "NA\n")); + } + } + fprintf(fh_out, "\n"); /* end of records */ + fflush(fh_out); +} + +void fpga_mgr_log_dump(nt_fpga_mgr_t *p) +{ + int i; + + NT_LOG(DBG, NTHW, "%s: fpgas=%d\n", __func__, p->mn_fpgas); + for (i = 0; i < p->mn_fpgas; i++) { + nt_fpga_prod_init_t *p_init _unused = p->mpa_fpga_prod_init[i]; + NT_LOG(DBG, NTHW, "%s: fpga=%d/%d: %04d-%02d-%02d\n", __func__, + i, p->mn_fpgas, p_init->fpga_product_id, p_init->fpga_version, + p_init->fpga_revision); + } +} + +/* + * Fpga + */ +nt_fpga_t *fpga_new(void) +{ + nt_fpga_t *p = malloc(sizeof(nt_fpga_t)); + + if (p) + memset(p, 0, sizeof(nt_fpga_t)); + return p; +} + +void fpga_delete(nt_fpga_t *p) +{ + memset(p, 0, sizeof(nt_fpga_t)); + free(p); +} + +void fpga_delete_all(nt_fpga_t *p) +{ + int i; + + for (i = 0; i < p->mn_modules; i++) { + nt_module_t *p_mod = p->mpa_modules[i]; + + if (p_mod) + module_delete(p_mod); + } + + fpga_delete(p); +} + +void fpga_init(nt_fpga_t *p, nt_fpga_prod_init_t *fpga_prod_init, + struct fpga_info_s *p_fpga_info) +{ + int i; + + p->p_fpga_info = p_fpga_info; + p->mp_init = fpga_prod_init; + + p->m_item_id = fpga_prod_init->fpga_item_id; + p->m_product_id = fpga_prod_init->fpga_product_id; + p->m_fpga_version = fpga_prod_init->fpga_version; + p->m_fpga_revision = fpga_prod_init->fpga_revision; + p->m_fpga_patch_no = fpga_prod_init->fpga_patch_no; + p->m_fpga_build_no = fpga_prod_init->fpga_build_no; + p->m_fpga_build_time = fpga_prod_init->fpga_build_time; + + p->mn_params = fpga_prod_init->nb_prod_params; + + if (p->mn_params) { + p->mpa_params = malloc(p->mn_params * sizeof(nt_param_t *)); + if (p->mpa_params) { + memset(p->mpa_params, 0, + (p->mn_params * sizeof(nt_param_t *))); + for (i = 0; i < p->mn_params; i++) { + nt_param_t *p_param = param_new(); + + param_init(p_param, p, + &fpga_prod_init->product_params[i]); + p->mpa_params[i] = p_param; + } + } + } + + p->mn_modules = fpga_prod_init->nb_modules; + + if (p->mn_modules) { + p->mpa_modules = + malloc(fpga_prod_init->nb_modules * sizeof(nt_module_t *)); + if (p->mpa_modules) { + memset(p->mpa_modules, 0, + (p->mn_modules * sizeof(nt_module_t *))); + for (i = 0; i < p->mn_modules; i++) { + nt_module_t *p_mod = module_new(); + + module_init(p_mod, p, &fpga_prod_init->modules[i]); + p->mpa_modules[i] = p_mod; + } + } + } +} + +void fpga_set_debug_mode(nt_fpga_t *p, int n_debug_mode) +{ + int i; + + p->m_debug_mode = n_debug_mode; + + for (i = 0; i < p->mn_modules; i++) { + nt_module_t *p_mod = p->mpa_modules[i]; + + if (p_mod) + module_set_debug_mode(p_mod, n_debug_mode); + } +} + +nt_module_t *fpga_query_module(const nt_fpga_t *p, int id, int instance) +{ + int i; + + for (i = 0; i < p->mn_modules; i++) { + nt_module_t *p_mod = p->mpa_modules[i]; + + if (p_mod->m_mod_id == id && p_mod->m_instance == instance) + return p_mod; + } + return NULL; +} + +bool fpga_query(nt_fpga_t *p, int id, int instance) +{ + return (fpga_query_module(p, id, instance) != NULL); +} + +nt_fpga_module_init_t *fpga_lookup_init(nt_fpga_t *p, int id, int instance) +{ + int i; + + for (i = 0; i < p->mp_init->nb_modules; i++) { + nt_fpga_module_init_t *p_mod_init = &p->mp_init->modules[i]; + + if (p_mod_init->id == id && p_mod_init->instance == instance) + return p_mod_init; + } + return NULL; +} + +int fpga_get_product_param(const nt_fpga_t *p, const int n_param_id, + const int n_default_value) +{ + int i; + + for (i = 0; i < p->mn_params; i++) { + nt_param_t *p_param = p->mpa_params[i]; + + if (p_param->param_id == n_param_id) + return p_param->param_value; + } + + return n_default_value; +} + +int fpga_get_product_id(const nt_fpga_t *p) +{ + return p->m_product_id; +} + +int fpga_get_fpga_version(const nt_fpga_t *p) +{ + return p->m_fpga_version; +} + +int fpga_get_fpga_revision(const nt_fpga_t *p) +{ + return p->m_fpga_revision; +} + +void fpga_log_info(const nt_fpga_t *p _unused) +{ + NT_LOG(INF, NTHW, "FPGA: %d-%d-%d-%d-%d-%d (%08X)\n", p->m_item_id, + p->m_product_id, p->m_fpga_version, p->m_fpga_revision, + p->m_fpga_patch_no, p->m_fpga_build_no, p->m_fpga_build_time); +} + +void fpga_dump(const nt_fpga_t *p) +{ + NT_LOG(DBG, NTHW, "%s: id=%d ver=%d.%d params=%d modules=%d\n", + __func__, p->m_product_id, p->m_fpga_version, p->m_fpga_revision, + p->mn_params, p->mn_modules); + fpga_dump_params(p); + fpga_dump_modules(p); +} + +void fpga_dump_params(const nt_fpga_t *p) +{ + int i; + + NT_LOG(DBG, NTHW, "%s: params=%d\n", __func__, p->mn_params); + + for (i = 0; i < p->mn_params; i++) { + nt_param_t *p_par = p->mpa_params[i]; + + param_dump(p_par); + } +} + +void fpga_dump_modules(const nt_fpga_t *p) +{ + int i; + + NT_LOG(DBG, NTHW, "%s: modules=%d\n", __func__, p->mn_modules); + + for (i = 0; i < p->mn_modules; i++) { + nt_module_t *p_mod = p->mpa_modules[i]; + + module_dump(p_mod); + } +} + +/* + * Param + */ +nt_param_t *param_new(void) +{ + nt_param_t *p = malloc(sizeof(nt_param_t)); + return p; +} + +void param_delete(nt_param_t *p) +{ + if (p) { + memset(p, 0, sizeof(nt_param_t)); + free(p); + } +} + +void param_init(nt_param_t *p, nt_fpga_t *p_fpga, nt_fpga_prod_param_t *p_init) +{ + p->mp_owner = p_fpga; + p->mp_init = p_init; + + p->param_id = p_init->param_id; + p->param_value = p_init->param_value; +} + +void param_dump(const nt_param_t *p _unused) +{ + NT_LOG(DBG, NTHW, "%s: id=%d value=%d\n", __func__, p->param_id, + p->param_value); +} + +/* + * Module + */ +nt_module_t *module_new(void) +{ + nt_module_t *p = malloc(sizeof(nt_module_t)); + return p; +} + +void module_delete(nt_module_t *p) +{ + int i; + + for (i = 0; i < p->mn_registers; i++) { + nt_register_t *p_reg = p->mpa_registers[i]; + + if (p_reg) + register_delete(p_reg); + } + memset(p, 0, sizeof(nt_module_t)); + free(p); +} + +void module_init(nt_module_t *p, nt_fpga_t *p_fpga, nt_fpga_module_init_t *p_init) +{ + int i; + + p->mp_owner = p_fpga; + p->mp_init = p_init; + + p->m_mod_id = p_init->id; + p->m_instance = p_init->instance; + + /* Copy debug mode from owner */ + if (p->mp_owner) + p->m_debug_mode = p->mp_owner->m_debug_mode; + + else + p->m_debug_mode = 0; + + p->m_mod_def_id = p_init->def_id; + p->m_major_version = p_init->major_version; + p->m_minor_version = p_init->minor_version; + p->m_bus = p_init->bus_id; + p->m_addr_base = p_init->addr_base; + + p->mn_registers = p_init->nb_registers; + if (p->mn_registers) { + p->mpa_registers = + malloc(p->mn_registers * sizeof(nt_register_t *)); + if (p->mpa_registers) { + memset(p->mpa_registers, 0, + (p->mn_registers * sizeof(nt_register_t *))); + for (i = 0; i < p->mn_registers; i++) { + nt_register_t *p_reg = register_new(); + + register_init(p_reg, p, &p_init->registers[i]); + p->mpa_registers[i] = p_reg; + } + } + } +} + +void module_init2(nt_module_t *p, nt_fpga_t *p_fpga, int mod_id, int instance, + int debug_mode) +{ + nt_fpga_module_init_t *p_init = NULL; + + p_init = fpga_lookup_init(p_fpga, mod_id, instance); + module_init(p, p_fpga, p_init); + + /* set debug mode after regulat init... */ + p->m_debug_mode = debug_mode; +} + +void module_dump(const nt_module_t *p) +{ + NT_LOG(DBG, NTHW, + "%s: id=%d inst=%d def=%d ver=%d.%d busid=%d base=0x%X regs=%d\n", + __func__, p->m_mod_id, p->m_instance, p->m_mod_def_id, + p->m_major_version, p->m_minor_version, p->m_bus, p->m_addr_base, + p->mn_registers); + module_dump_registers(p); +} + +void module_dump_registers(const nt_module_t *p) +{ + int i; + + NT_LOG(DBG, NTHW, "%s: regs=%d\n", __func__, p->mn_registers); + + for (i = 0; i < p->mn_registers; i++) { + nt_register_t *p_reg = p->mpa_registers[i]; + + register_dump(p_reg); + } +} + +int module_get_major_version(const nt_module_t *p) +{ + return p->m_major_version; +} + +int module_get_minor_version(const nt_module_t *p) +{ + return p->m_minor_version; +} + +uint64_t module_get_version_packed64(const nt_module_t *p) +{ + return (((uint64_t)p->m_major_version & 0xFFFFFFFF) << 32) | + (p->m_minor_version & 0xFFFFFFFF); +} + +bool module_is_version_newer(const nt_module_t *p, int major_version, + int minor_version) +{ + if (major_version == p->m_major_version) + return p->m_minor_version >= minor_version; + return p->m_major_version >= major_version; +} + +static nt_register_t *module_lookup_register(nt_module_t *p, uint32_t id) +{ + int i; + nt_register_t *p_register = NULL; + + for (i = 0; i < p->mn_registers; i++) { + if (p->mpa_registers[i]->m_id == id) { + p_register = p->mpa_registers[i]; + break; + } + } + return p_register; +} + +nt_register_t *module_get_register(nt_module_t *p, uint32_t id) +{ + nt_register_t *p_register; + + if (p == NULL) { + NT_LOG(ERR, NTHW, "Illegal module context for register %d\n", + id); + return NULL; + } + + p_register = module_lookup_register(p, id); + if (!p_register) { + NT_LOG(ERR, NTHW, "Register %d not found in module: %s (%d)\n", + id, nthw_fpga_mod_id_to_str(p->m_mod_id), p->m_mod_id); + } + return p_register; +} + +nt_register_t *module_query_register(nt_module_t *p, uint32_t id) +{ + return module_lookup_register(p, id); +} + +int module_get_debug_mode(const nt_module_t *p) +{ + return p->m_debug_mode; +} + +void module_set_debug_mode(nt_module_t *p, unsigned int n_debug_mode) +{ + int i; + nt_register_t *p_register = NULL; + + p->m_debug_mode = n_debug_mode; + + for (i = 0; i < p->mn_registers; i++) { + p_register = p->mpa_registers[i]; + if (p_register) + register_set_debug_mode(p_register, n_debug_mode); + } +} + +int module_get_bus(const nt_module_t *p) +{ + return p->m_bus; +} + +uint32_t module_get_addr_base(const nt_module_t *p) +{ + return p->m_addr_base; +} + +void module_unsuppported(const nt_module_t *p) +{ + NT_LOG(ERR, NTHW, "Module %d not supported", p->mp_init->id); +} + +/* + * Register + */ +nt_register_t *register_new(void) +{ + nt_register_t *p = malloc(sizeof(nt_register_t)); + return p; +} + +void register_delete(nt_register_t *p) +{ + int i; + + for (i = 0; i < p->mn_fields; i++) { + nt_field_t *p_field = p->mpa_fields[i]; + + if (p_field) + field_delete(p_field); + } + + if (p->mp_shadow) + free(p->mp_shadow); + + if (p->mp_dirty) + free(p->mp_dirty); + + memset(p, 0, sizeof(nt_register_t)); + free(p); +} + +void register_init(nt_register_t *p, nt_module_t *p_module, + nt_fpga_register_init_t *p_init) +{ + int i; + + p->mp_owner = p_module; + + p->m_id = p_init->id; + p->mn_bit_width = p_init->bw; + p->mn_addr_rel = p_init->addr_rel; + p->m_addr = p_module->m_addr_base + p_init->addr_rel; + p->m_type = p_init->type; + p->m_len = + ((p_init->bw != (uint16_t)-1) ? + ((p_init->bw + 31) >> 5) : + 1); /* Old P200 registers have no bw at register level - default to BW=-1 */ + p->m_debug_mode = p_module->m_debug_mode; + + p->mn_fields = p_init->nb_fields; + if (p->mn_fields) { + p->mpa_fields = malloc(p->mn_fields * sizeof(nt_field_t *)); + + if (p->mpa_fields) { + memset(p->mpa_fields, 0, + (p->mn_fields * sizeof(nt_field_t *))); + for (i = 0; i < p->mn_fields; i++) { + nt_field_t *p_field = field_new(); + + field_init(p_field, p, &p_init->fields[i]); + p->mpa_fields[i] = p_field; + } + + p->mp_shadow = malloc(p->m_len * sizeof(uint32_t)); + if (p->mp_shadow) { + memset(p->mp_shadow, 0x00, + (p->m_len * sizeof(uint32_t))); + } + + p->mp_dirty = malloc(p->m_len * sizeof(bool)); + if (p->mp_dirty) { + memset(p->mp_dirty, 0x00, + (p->m_len * sizeof(bool))); + } + } + } +} + +void register_dump(const nt_register_t *p) +{ + NT_LOG(DBG, NTHW, + "%s(id=%d type=%d addr=0x%08X addrrel=0x%08X len=%d bw=%d\n", + __func__, p->m_id, p->m_type, p->m_addr, p->mn_addr_rel, p->m_len, + p->mn_bit_width); + register_dump_fields(p); +} + +void register_dump_fields(const nt_register_t *p) +{ + int i; + + NT_LOG(DBG, NTHW, "%s(addr=0x%08X fields=%d\n", __func__, p->m_addr, + p->mn_fields); + for (i = 0; i < p->mn_fields; i++) + field_dump(p->mpa_fields[i]); + NT_LOG(DBG, NTHW, "\n"); +} + +uint32_t register_get_address(const nt_register_t *p) +{ + return p->m_addr; +} + +void register_reset(const nt_register_t *p) +{ + int i; + nt_field_t *p_field = NULL; + + for (i = 0; i < p->mn_fields; i++) { + p_field = p->mpa_fields[i]; + if (p_field) + field_reset(p_field); + } +} + +static nt_field_t *register_lookup_field(const nt_register_t *p, uint32_t id) +{ + int i; + nt_field_t *p_field = NULL; + + if (!p) + return NULL; + + for (i = 0; i < p->mn_fields; i++) { + if (p->mpa_fields[i]->m_id == id) { + p_field = p->mpa_fields[i]; + break; + } + } + return p_field; +} + +nt_field_t *register_get_field(const nt_register_t *p, uint32_t id) +{ + nt_field_t *p_field; + + if (p == NULL) { + NT_LOG(ERR, NTHW, "Illegal register context for field %d\n", + id); + return NULL; + } + + p_field = register_lookup_field(p, id); + if (!p_field) { + NT_LOG(ERR, NTHW, "Field %d not found in module: %s (%d)\n", id, + nthw_fpga_mod_id_to_str(p->mp_owner->m_mod_id), + p->mp_owner->m_mod_id); + } + return p_field; +} + +nt_field_t *register_query_field(const nt_register_t *p, uint32_t id) +{ + return register_lookup_field(p, id); +} + +int register_get_bit_width(const nt_register_t *p) +{ + return p->mn_bit_width; +} + +uint32_t register_get_addr_rel(const nt_register_t *p) +{ + return p->mn_addr_rel; +} + +int register_get_debug_mode(const nt_module_t *p) +{ + return p->m_debug_mode; +} + +/* + * NOTE: do not set debug on fields - as register operation dumps typically are enough + */ +void register_set_debug_mode(nt_register_t *p, unsigned int n_debug_mode) +{ + int i; + nt_field_t *p_field = NULL; + + p->m_debug_mode = n_debug_mode; + + for (i = 0; i < p->mn_fields; i++) { + p_field = p->mpa_fields[i]; + if (p_field) + field_set_debug_mode(p_field, n_debug_mode); + } +} + +static int register_read_data(const nt_register_t *p) +{ + int rc = -1; + + const int n_bus_type_id = module_get_bus(p->mp_owner); + const uint32_t addr = p->m_addr; + const uint32_t len = p->m_len; + uint32_t *const p_data = p->mp_shadow; + + struct fpga_info_s *p_fpga_info = NULL; + + if (p && p->mp_owner && p->mp_owner->mp_owner) + p_fpga_info = p->mp_owner->mp_owner->p_fpga_info; + assert(p_fpga_info); + assert(p_data); + + rc = read_data(p_fpga_info, n_bus_type_id, addr, len, p_data); + return rc; +} + +static int register_read_data_tsc(const nt_register_t *p, uint64_t *p_tsc1, + uint64_t *p_tsc2) +{ + int rc = -1; + + const int n_bus_type_id = module_get_bus(p->mp_owner); + const uint32_t addr = p->m_addr; + const uint32_t len = p->m_len; + uint32_t *const p_data = p->mp_shadow; + + struct fpga_info_s *p_fpga_info = NULL; + + if (p && p->mp_owner && p->mp_owner->mp_owner) + p_fpga_info = p->mp_owner->mp_owner->p_fpga_info; + + rc = read_data_tsc(p_fpga_info, n_bus_type_id, addr, len, p_data, p_tsc1, p_tsc2); + + return rc; +} + +static int register_write_data(const nt_register_t *p, uint32_t cnt) +{ + int rc = -1; + + const int n_bus_type_id = module_get_bus(p->mp_owner); + const uint32_t addr = p->m_addr; + const uint32_t len = p->m_len; + uint32_t *const p_data = p->mp_shadow; + + struct fpga_info_s *p_fpga_info = NULL; + + if (p && p->mp_owner && p->mp_owner->mp_owner) + p_fpga_info = p->mp_owner->mp_owner->p_fpga_info; + assert(p_fpga_info); + assert(p_data); + + rc = write_data(p_fpga_info, n_bus_type_id, addr, (len * cnt), p_data); + + return rc; +} + +void register_get_val(const nt_register_t *p, uint32_t *p_data, uint32_t len) +{ + uint32_t i; + + if (len == (uint32_t)-1 || len > p->m_len) + len = p->m_len; + + assert(len <= p->m_len); + assert(p_data); + + for (i = 0; i < len; i++) + p_data[i] = p->mp_shadow[i]; +} + +uint32_t register_get_val32(const nt_register_t *p) +{ + uint32_t val = 0; + + register_get_val(p, &val, 1); + return val; +} + +void register_update(const nt_register_t *p) +{ + if (p && p->m_type != REGISTER_TYPE_WO) { + const char *const p_dev_name _unused = "NA"; + const int n_bus_type_id = module_get_bus(p->mp_owner); + + const char *const p_bus_name _unused = get_bus_name(n_bus_type_id); + const uint32_t addr _unused = p->m_addr; + const uint32_t len = p->m_len; + uint32_t *const p_data = p->mp_shadow; + + register_read_data(p); + if (p->m_debug_mode & ON_READ) { + uint32_t i = len; + + uint32_t *ptr _unused = p_data; + NT_LOG(DBG, NTHW, + "Register::read(Dev: %s, Bus: %s, Addr: 0x%08X, _cnt: %d, Data:", + p_dev_name, p_bus_name, addr, len); + while (i--) + NT_LOG(DBG, NTHW, " 0x%08X ", *ptr++); + NT_LOG(DBG, NTHW, ")\n"); + } + } +} + +uint32_t register_get_val_updated32(const nt_register_t *p) +{ + uint32_t val = 0; + + register_update(p); + register_get_val(p, &val, 1); + return val; +} + +void register_make_dirty(nt_register_t *p) +{ + uint32_t i; + + for (i = 0; i < p->m_len; i++) + p->mp_dirty[i] = true; +} + +void register_set_val(nt_register_t *p, const uint32_t *p_data, uint32_t len) +{ + assert(len <= p->m_len); + assert(p_data); + + if (len == (uint32_t)-1 || len > p->m_len) + len = p->m_len; + + if (p->mp_shadow != p_data) + memcpy(p->mp_shadow, p_data, (len * sizeof(uint32_t))); +} + +void register_set_val_flush(nt_register_t *p, const uint32_t *p_data, uint32_t len) +{ + register_set_val(p, p_data, len); + register_flush(p, 1); +} + +void register_flush(const nt_register_t *p, uint32_t cnt) +{ + int rc; + + if (p->m_type != REGISTER_TYPE_RO) { + const char *const p_dev_name = "NA"; + const int n_bus_type_id = module_get_bus(p->mp_owner); + const char *p_bus_name = get_bus_name(n_bus_type_id); + const uint32_t addr = p->m_addr; + const uint32_t len = p->m_len; + uint32_t *const p_data = p->mp_shadow; + uint32_t i; + + assert(len * cnt <= 256); + + if (p->m_debug_mode & ON_WRITE) { + uint32_t i = len * cnt; + uint32_t *ptr = p_data; + char *tmp_string = + ntlog_helper_str_alloc("Register::write"); + ntlog_helper_str_add(tmp_string, + "(Dev: %s, Bus: %s, Addr: 0x%08X, _cnt: %d, Data:", + p_dev_name, p_bus_name, addr, i); + while (i--) { + ntlog_helper_str_add(tmp_string, " 0x%08X", + *ptr++); + } + ntlog_helper_str_add(tmp_string, ")\n"); + NT_LOG(DBG, NTHW, "%s", tmp_string); + ntlog_helper_str_free(tmp_string); + } + + rc = register_write_data(p, cnt); + + if (rc) + NT_LOG(ERR, NTHW, "Register write error %d\n", rc); + + for (i = 0; i < cnt; i++) + p->mp_dirty[i] = false; + } +} + +void register_do_read_trig_ts(const nt_register_t *p, uint64_t *tsc1, + uint64_t *tsc2) +{ + register_read_data_tsc(p, tsc1, tsc2); +} + +void register_clr(nt_register_t *p) +{ + memset(p->mp_shadow, 0, p->m_len * sizeof(uint32_t)); + register_make_dirty(p); +} + +void register_set(nt_register_t *p) +{ + memset(p->mp_shadow, 0xff, p->m_len * sizeof(uint32_t)); + register_make_dirty(p); +} + +/* + * Field + */ +nt_field_t *field_new(void) +{ + nt_field_t *p = malloc(sizeof(nt_field_t)); + return p; +} + +void field_delete(nt_field_t *p) +{ + memset(p, 0, sizeof(nt_field_t)); + free(p); +} + +void field_init(nt_field_t *p, nt_register_t *p_reg, + const nt_fpga_field_init_t *p_init) +{ + p->mp_owner = p_reg; + + p->m_debug_mode = p_reg->m_debug_mode; + + p->m_id = p_init->id; + p->mn_bit_width = p_init->bw; + p->mn_bit_pos_low = p_init->low; + p->m_reset_val = (uint32_t)p_init->reset_val; + p->m_first_word = p_init->low / 32; + p->m_first_bit = p_init->low % 32; + p->m_front_mask = 0; + p->m_body_length = 0; + p->mn_words = (p_init->bw + 0x1f) / 0x20; + p->m_tail_mask = 0; + + { + int bits_remaining = p_init->bw; + int front_mask_length = 32 - p->m_first_bit; + + if (front_mask_length > bits_remaining) + front_mask_length = bits_remaining; + bits_remaining -= front_mask_length; + + p->m_front_mask = (uint32_t)(((1ULL << front_mask_length) - 1) + << p->m_first_bit); + + p->m_body_length = bits_remaining / 32; + bits_remaining -= p->m_body_length * 32; + p->m_tail_mask = (1 << bits_remaining) - 1; + + if (p->m_debug_mode >= 0x100) { + NT_LOG(DBG, NTHW, + "%s: fldid=%08d: [%08d:%08d] %08d/%08d: (%08d,%08d) (0x%08X,%08d,0x%08X)\n", + __func__, p_init->id, p_init->low, + (p_init->low + p_init->bw), p_init->bw, + ((p_init->bw + 31) / 32), p->m_first_word, + p->m_first_bit, p->m_front_mask, p->m_body_length, + p->m_tail_mask); + } + } +} + +int field_get_debug_mode(const nt_module_t *p) +{ + return p->m_debug_mode; +} + +void field_set_debug_mode(nt_field_t *p, unsigned int n_debug_mode) +{ + p->m_debug_mode = n_debug_mode; +} + +int field_get_bit_width(const nt_field_t *p) +{ + return p->mn_bit_width; +} + +int field_get_bit_pos_low(const nt_field_t *p) +{ + return p->mn_bit_pos_low; +} + +int field_get_bit_pos_high(const nt_field_t *p) +{ + return p->mn_bit_pos_low + p->mn_bit_width - 1; +} + +uint32_t field_get_mask(const nt_field_t *p) +{ + return p->m_front_mask; +} + +void field_reset(const nt_field_t *p) +{ + field_set_val32(p, (uint32_t)p->m_reset_val); +} + +uint32_t field_get_val_mask(const nt_field_t *p) +{ + return (p->m_front_mask >> p->mn_bit_pos_low); +} + +uint32_t field_get_reset_val(const nt_field_t *p) +{ + return (uint32_t)p->m_reset_val; +} + +void field_get_val(const nt_field_t *p, uint32_t *p_data, uint32_t len) +{ + uint32_t i; + uint32_t data_index = 0; + uint32_t shadow_index = p->m_first_word; + + union { + uint32_t w32[2]; + uint64_t w64; + } buf; + + (void)len; + assert(len == p->mn_words); + + /* handle front */ + buf.w32[0] = p->mp_owner->mp_shadow[shadow_index++] & p->m_front_mask; + + /* handle body */ + for (i = 0; i < p->m_body_length; i++) { + buf.w32[1] = p->mp_owner->mp_shadow[shadow_index++]; + buf.w64 = buf.w64 >> (p->m_first_bit); + assert(data_index < len); + p_data[data_index++] = buf.w32[0]; + buf.w64 = buf.w64 >> (32 - p->m_first_bit); + } + + /* handle tail */ + if (p->m_tail_mask) + buf.w32[1] = p->mp_owner->mp_shadow[shadow_index++] & p->m_tail_mask; + + else + buf.w32[1] = 0; + buf.w64 = buf.w64 >> (p->m_first_bit); + p_data[data_index++] = buf.w32[0]; + if (data_index < p->mn_words) + p_data[data_index++] = buf.w32[1]; +} + +void field_set_val(const nt_field_t *p, const uint32_t *p_data, uint32_t len) +{ + uint32_t i; + uint32_t data_index = 0; + uint32_t shadow_index = p->m_first_word; + + union { + uint32_t w32[2]; + uint64_t w64; + } buf; + + (void)len; + assert(len == p->mn_words); + + /* handle front */ + buf.w32[0] = 0; + buf.w32[1] = p_data[data_index++]; + buf.w64 = buf.w64 >> (32 - p->m_first_bit); + p->mp_owner->mp_shadow[shadow_index] = + (p->mp_owner->mp_shadow[shadow_index] & ~p->m_front_mask) | + (buf.w32[0] & p->m_front_mask); + shadow_index++; + + /* handle body */ + for (i = 0; i < p->m_body_length; i++) { + buf.w64 = buf.w64 >> (p->m_first_bit); + assert(data_index < len); + buf.w32[1] = p_data[data_index++]; + buf.w64 = buf.w64 >> (32 - p->m_first_bit); + p->mp_owner->mp_shadow[shadow_index++] = buf.w32[0]; + } + + /* handle tail */ + if (p->m_tail_mask) { + buf.w64 = buf.w64 >> (p->m_first_bit); + if (data_index < len) + buf.w32[1] = p_data[data_index]; + buf.w64 = buf.w64 >> (32 - p->m_first_bit); + p->mp_owner->mp_shadow[shadow_index] = + (p->mp_owner->mp_shadow[shadow_index] & ~p->m_tail_mask) | + (buf.w32[0] & p->m_tail_mask); + } + + register_make_dirty(p->mp_owner); +} + +void field_set_val_flush(const nt_field_t *p, const uint32_t *p_data, uint32_t len) +{ + field_set_val(p, p_data, len); + field_flush_register(p); +} + +uint32_t field_get_val32(const nt_field_t *p) +{ + uint32_t val; + + field_get_val(p, &val, 1); + return val; +} + +uint32_t field_get_updated(const nt_field_t *p) +{ + uint32_t val; + + register_update(p->mp_owner); + field_get_val(p, &val, 1); + + return val; +} + +void field_read_trig_with_tsc(const nt_field_t *p, uint64_t *tsc1, uint64_t *tsc2) +{ + register_do_read_trig_ts(p->mp_owner, tsc1, tsc2); +} + +void field_update_register(const nt_field_t *p) +{ + register_update(p->mp_owner); +} + +void field_flush_register(const nt_field_t *p) +{ + register_flush(p->mp_owner, 1); +} + +void field_set_val32(const nt_field_t *p, uint32_t val) +{ + field_set_val(p, &val, 1); +} + +void field_set_val_flush32(const nt_field_t *p, uint32_t val) +{ + field_set_val(p, &val, 1); + register_flush(p->mp_owner, 1); +} + +void field_clr_all(const nt_field_t *p) +{ + assert(p->m_body_length == 0); + field_set_val32(p, 0); +} + +void field_clr_flush(const nt_field_t *p) +{ + field_clr_all(p); + register_flush(p->mp_owner, 1); +} + +void field_set_all(const nt_field_t *p) +{ + assert(p->m_body_length == 0); + field_set_val32(p, ~0); +} + +void field_set_flush(const nt_field_t *p) +{ + field_set_all(p); + register_flush(p->mp_owner, 1); +} + +enum field_match { + FIELD_MATCH_CLR_ALL, + FIELD_MATCH_SET_ALL, + FIELD_MATCH_CLR_ANY, + FIELD_MATCH_SET_ANY, +}; + +static int field_wait_cond32(const nt_field_t *p, enum field_match e_match, + int n_poll_iterations, int n_poll_interval) +{ + const uint32_t n_mask = (1 << p->mn_bit_width) - 1; + + if (n_poll_iterations == -1) + n_poll_iterations = 10000; + if (n_poll_interval == -1) + n_poll_interval = 100; /* usec */ + + if (p->m_debug_mode) { + const char *const p_cond_name _unused = + ((e_match == FIELD_MATCH_SET_ALL) ? + "SetAll" : + ((e_match == FIELD_MATCH_CLR_ALL) ? + "ClrAll" : + ((e_match == FIELD_MATCH_CLR_ANY) ? + "ClrAny" : + "SetAny"))); + const char *const p_dev_name _unused = "NA"; + const char *const p_bus_name _unused = + get_bus_name(module_get_bus(p->mp_owner->mp_owner)); + uint32_t n_reg_addr _unused = register_get_address(p->mp_owner); + + uint32_t n_reg_mask _unused = + (((1 << p->mn_bit_width) - 1) << p->mn_bit_pos_low); + + NT_LOG(DBG, NTHW, + "Register::Field::wait%s32(Dev: %s, Bus: %s, Addr: 0x%08X, Mask: 0x%08X, Iterations: %d, Interval: %d)\n", + p_cond_name, p_dev_name, p_bus_name, n_reg_addr, n_reg_mask, + n_poll_iterations, n_poll_interval); + } + + while (true) { + uint32_t val = field_get_updated(p); + + if (e_match == FIELD_MATCH_SET_ANY && val != 0) { + return 0; + } else if (e_match == FIELD_MATCH_SET_ALL && val == n_mask) { + return 0; + } else if (e_match == FIELD_MATCH_CLR_ALL && val == 0) { + return 0; + } else if (e_match == FIELD_MATCH_CLR_ANY) { + uint32_t mask = field_get_mask(p); + + if (val != mask) + return 0; + } + + n_poll_iterations--; + if (n_poll_iterations <= 0) + return -1; + NT_OS_WAIT_USEC(n_poll_interval); + } + return 0; +} + +int field_wait_set_all32(const nt_field_t *p, int n_poll_iterations, + int n_poll_interval) +{ + return field_wait_cond32(p, FIELD_MATCH_SET_ALL, n_poll_iterations, + n_poll_interval); +} + +int field_wait_clr_all32(const nt_field_t *p, int n_poll_iterations, + int n_poll_interval) +{ + return field_wait_cond32(p, FIELD_MATCH_CLR_ALL, n_poll_iterations, + n_poll_interval); +} + +int field_wait_set_any32(const nt_field_t *p, int n_poll_iterations, + int n_poll_interval) +{ + return field_wait_cond32(p, FIELD_MATCH_SET_ANY, n_poll_iterations, + n_poll_interval); +} + +int field_wait_clr_any32(const nt_field_t *p, int n_poll_iterations, + int n_poll_interval) +{ + return field_wait_cond32(p, FIELD_MATCH_CLR_ANY, n_poll_iterations, + n_poll_interval); +} + +int field_wait_val_mask32(const nt_field_t *p, uint32_t n_wait_cond_value, + uint32_t n_wait_cond_mask, int n_poll_iterations, + int n_poll_interval) +{ + if (n_poll_iterations == -1) + n_poll_iterations = 10000; + if (n_poll_interval == -1) + n_poll_interval = 100; + + while (true) { + uint32_t val = field_get_updated(p); + + if (val == (n_wait_cond_value & n_wait_cond_mask)) + break; + n_poll_iterations--; + if (n_poll_iterations <= 0) + return -1; + NT_OS_WAIT_USEC(n_poll_interval); + } + return 0; +} + +void field_dump(const nt_field_t *p _unused) +{ + NT_LOG(DBG, NTHW, "%s: %02d: %02d %02d %02d: %02d: %X\n", __func__, + p->m_id, p->mn_bit_pos_low, (p->mn_bit_pos_low + p->mn_bit_width), + p->mn_bit_width, p->mn_words, p->m_reset_val); +} + +void field_dump_val(const nt_field_t *p) +{ + int i; + uint32_t buf[32]; + + field_get_val(p, buf, p->mn_words); + NT_LOG(DBG, NTHW, " @%d:", p->m_first_bit + p->m_first_word * 32); + NT_LOG(DBG, NTHW, "%X", buf[p->mn_words - 1]); + for (i = p->mn_words - 1; i > 0; i--) + NT_LOG(DBG, NTHW, "%08X", buf[i - 1]); + NT_LOG(DBG, NTHW, "\n"); +} + +void field_dump_init(const nt_fpga_field_init_t *p _unused) +{ + NT_LOG(DBG, NTHW, "%s: %02d: %02d %02d %02d: 0x%" PRIX64 "\n", __func__, + p->id, p->low, p->low + p->bw, p->bw, p->reset_val); +} + +/* + * nthw fpga model helpers + */ + +nt_fpga_t *nthw_get_fpga(struct fpga_info_s *p_fpga_info, uint64_t n_fpga_ident) +{ + nt_fpga_mgr_t *p_fpga_mgr = NULL; + nt_fpga_t *p_fpga = NULL; + int n_fpga_type_id, n_fpga_prod_id, n_fpga_ver_id, n_fpga_rev_id; + char s_fpga_prod_ver_rev_str[32]; + + p_fpga_mgr = fpga_mgr_new(); + fpga_mgr_init(p_fpga_mgr); + p_fpga = fpga_mgr_query_fpga(p_fpga_mgr, n_fpga_ident, p_fpga_info); + + n_fpga_type_id = FPGAID_TO_PRODUCTTYPE(n_fpga_ident); + n_fpga_prod_id = FPGAID_TO_PRODUCTCODE(n_fpga_ident); + n_fpga_ver_id = FPGAID_TO_VERSIONCODE(n_fpga_ident); + n_fpga_rev_id = FPGAID_TO_REVISIONCODE(n_fpga_ident); + + snprintf(s_fpga_prod_ver_rev_str, sizeof(s_fpga_prod_ver_rev_str), + "%04d-%04d-%02d-%02d", n_fpga_type_id, n_fpga_prod_id, n_fpga_ver_id, + n_fpga_rev_id); + + if (p_fpga == NULL) { + NT_LOG(ERR, NTHW, "%s: no match for FPGA: %s\n", __func__, + s_fpga_prod_ver_rev_str); + /* do not return here... */ + } + + if (p_fpga_mgr) { + fpga_mgr_delete(p_fpga_mgr); + p_fpga_mgr = NULL; + } + + return p_fpga; +} + +nt_module_t *nthw_get_module(nt_fpga_t *p_fpga, int n_mod, int n_instance) +{ + nt_module_t *p_mod = fpga_query_module(p_fpga, n_mod, n_instance); + return p_mod; +} + +nt_register_t *nthw_get_register(nt_module_t *p_mod, int n_reg) +{ + nt_register_t *p_reg = module_get_register(p_mod, n_reg); + return p_reg; +} + +nt_field_t *nthw_get_field(nt_register_t *p_reg, int n_fld) +{ + nt_field_t *p_fld = register_get_field(p_reg, n_fld); + return p_fld; +} diff --git a/drivers/net/ntnic/nthw/nthw_fpga_model.h b/drivers/net/ntnic/nthw/nthw_fpga_model.h new file mode 100644 index 0000000000..b00b7b6cfa --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_fpga_model.h @@ -0,0 +1,308 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_FPGA_MODEL_H__ +#define __NTHW_FPGA_MODEL_H__ + +#include +#include +#include "fpga_model.h" + +#ifndef FPGAID_TO_PRODUCTCODE +#define FPGAID_TO_PRODUCTTYPE(fpga_id) ((uint16_t)((fpga_id) >> 32) & 0xFF) +#define FPGAID_TO_PRODUCTCODE(fpga_id) ((uint16_t)((fpga_id) >> 16) & 0xFFFF) +#define FPGAID_TO_VERSIONCODE(fpga_id) ((uint16_t)((fpga_id) >> 8 & 0xFF)) +#define FPGAID_TO_REVISIONCODE(fpga_id) ((uint16_t)((fpga_id) >> 0 & 0xFF)) +#endif + +#define VERSION_PACKED64(_major_, _minor_) \ + ((((uint64_t)(_major_) & 0xFFFFFFFF) << 32) | ((_minor_) & 0xFFFFFFFF)) + +enum debug_mode { NO_DEBUG, ON_READ, ON_WRITE }; + +enum nthw_bus_type { + NTHW_BUS_UNKNOWN, + NTHW_BUS_BAR, + NTHW_BUS_PCI, + NTHW_BUS_NMB, + NTHW_BUS_NDM, + NTHW_BUS_RAB0, + NTHW_BUS_RAB1, + NTHW_BUS_RAB2 +}; + +struct nt_fpga_s; + +struct nt_param_s; + +struct nt_module_s; + +struct nt_register_s; + +struct nt_field_s; + +struct nt_fpga_mgr_s { + int mn_fpgas; + struct nt_fpga_prod_init **mpa_fpga_prod_init; +}; + +typedef struct nt_fpga_mgr_s nt_fpga_mgr_t; + +struct nt_fpga_s { + struct fpga_info_s *p_fpga_info; + + int m_item_id; + int m_product_id; + int m_fpga_version; + int m_fpga_revision; + int m_fpga_patch_no; + int m_fpga_build_no; + uint32_t m_fpga_build_time; + + int mn_params; + struct nt_param_s **mpa_params; + + int mn_modules; + struct nt_module_s **mpa_modules; + + nt_fpga_prod_init_t *mp_init; + + int m_debug_mode; +}; + +typedef struct nt_fpga_s nt_fpga_t; + +struct nt_param_s { + nt_fpga_t *mp_owner; + + int param_id; + int param_value; + + nt_fpga_prod_param_t *mp_init; +}; + +typedef struct nt_param_s nt_param_t; + +struct nt_module_s { + nt_fpga_t *mp_owner; + + int m_mod_id; + + int m_instance; + + int m_mod_def_id; + int m_major_version; + int m_minor_version; + + int m_bus; + uint32_t m_addr_base; + + int m_debug_mode; + + int mn_registers; + struct nt_register_s **mpa_registers; + + nt_fpga_module_init_t *mp_init; +}; + +typedef struct nt_module_s nt_module_t; + +struct nt_register_s { + nt_module_t *mp_owner; + + uint32_t m_id; + + uint32_t mn_bit_width; + uint32_t mn_addr_rel; + uint32_t m_addr; + uint32_t m_type; + uint32_t m_len; + + int m_debug_mode; + + int mn_fields; + struct nt_field_s **mpa_fields; + + uint32_t *mp_shadow; + bool *mp_dirty; + + nt_fpga_register_init_t *mp_init; +}; + +typedef struct nt_register_s nt_register_t; + +struct nt_field_s { + nt_register_t *mp_owner; + + uint32_t m_id; + + uint32_t mn_bit_width; + uint32_t mn_bit_pos_low; + uint32_t m_reset_val; + uint32_t m_first_word; + uint32_t m_first_bit; + uint32_t m_front_mask; + uint32_t m_body_length; + uint32_t mn_words; + uint32_t m_tail_mask; + + int m_debug_mode; + + nt_fpga_field_init_t *mp_init; +}; + +typedef struct nt_field_s nt_field_t; + +nt_fpga_mgr_t *fpga_mgr_new(void); +void fpga_mgr_init(nt_fpga_mgr_t *p); +void fpga_mgr_delete(nt_fpga_mgr_t *p); +nt_fpga_t *fpga_mgr_query_fpga(nt_fpga_mgr_t *p, uint64_t n_fpga_id, + struct fpga_info_s *p_fpga_info); + +void fpga_mgr_log_dump(nt_fpga_mgr_t *p); +void fpga_mgr_show(nt_fpga_mgr_t *p, FILE *out, int detail_level); + +nt_fpga_t *fpga_new(void); +void fpga_delete(nt_fpga_t *p); +void fpga_delete_all(nt_fpga_t *p); +void fpga_init(nt_fpga_t *p, nt_fpga_prod_init_t *fpga_prod_init, + struct fpga_info_s *p_fpga_info); + +int fpga_get_product_param(const nt_fpga_t *p, const int n_param_id, + const int default_value); +int fpga_get_product_id(const nt_fpga_t *p); +int fpga_get_fpga_version(const nt_fpga_t *p); +int fpga_get_fpga_revision(const nt_fpga_t *p); +nt_module_t *fpga_query_module(const nt_fpga_t *p, int id, int instance); +nt_fpga_module_init_t *fpga_lookup_init(nt_fpga_t *p, int id, int instance); +bool fpga_query(nt_fpga_t *p, int id, int instance); +void fpga_set_debug_mode(nt_fpga_t *p, int n_debug_mode); + +void fpga_log_info(const nt_fpga_t *p); +void fpga_dump(const nt_fpga_t *p); +void fpga_dump_params(const nt_fpga_t *p); +void fpga_dump_modules(const nt_fpga_t *p); + +nt_param_t *param_new(void); +void param_delete(nt_param_t *p); +void param_init(nt_param_t *p, nt_fpga_t *p_fpga, nt_fpga_prod_param_t *p_init); + +void param_dump(const nt_param_t *p); + +nt_module_t *module_new(void); +void module_delete(nt_module_t *p); +void module_init(nt_module_t *p, nt_fpga_t *p_fpga, + nt_fpga_module_init_t *p_init); +void module_init2(nt_module_t *p, nt_fpga_t *p_fpga, int mod_id, int instance, + int debug_mode); + +int module_get_major_version(const nt_module_t *p); +int module_get_minor_version(const nt_module_t *p); +uint64_t module_get_version_packed64(const nt_module_t *p); +bool module_is_version_newer(const nt_module_t *p, int major_version, + int minor_version); + +int module_get_bus(const nt_module_t *p); +nt_register_t *module_get_register(nt_module_t *p, uint32_t id); +nt_register_t *module_query_register(nt_module_t *p, uint32_t id); +int module_get_debug_mode(const nt_module_t *p); +void module_set_debug_mode(nt_module_t *p, unsigned int debug_mode); +uint32_t module_get_addr_base(const nt_module_t *p); +void module_unsuppported(const nt_module_t *p); + +void module_dump(const nt_module_t *p); +void module_dump_registers(const nt_module_t *p); + +nt_register_t *register_new(void); +void register_delete(nt_register_t *p); +void register_init(nt_register_t *p, nt_module_t *p_module, + nt_fpga_register_init_t *p_init); + +nt_field_t *register_get_field(const nt_register_t *p, uint32_t id); +nt_field_t *register_query_field(const nt_register_t *p, uint32_t id); + +uint32_t register_get_address(const nt_register_t *p); +uint32_t register_get_addr_rel(const nt_register_t *p); +int register_get_bit_width(const nt_register_t *p); +int register_get_debug_mode(const nt_module_t *p); +void register_set_debug_mode(nt_register_t *p, unsigned int debug_mode); + +void register_get_val(const nt_register_t *p, uint32_t *p_data, uint32_t len); +uint32_t register_get_val32(const nt_register_t *p); +uint32_t register_get_val_updated32(const nt_register_t *p); + +void register_set_val(nt_register_t *p, const uint32_t *p_data, uint32_t len); +void register_set_val_flush(nt_register_t *p, const uint32_t *p_data, + uint32_t len); + +void register_make_dirty(nt_register_t *p); +void register_update(const nt_register_t *p); +void register_reset(const nt_register_t *p); +void register_flush(const nt_register_t *p, uint32_t cnt); +void register_clr(nt_register_t *p); +void register_set(nt_register_t *p); + +void register_do_read_trig_ts(const nt_register_t *p, uint64_t *tsc1, + uint64_t *tsc2); + +void register_dump(const nt_register_t *p); +void register_dump_fields(const nt_register_t *p); + +nt_field_t *field_new(void); +void field_delete(nt_field_t *p); +void field_init(nt_field_t *p, nt_register_t *p_reg, + const nt_fpga_field_init_t *p_init); + +int field_get_debug_mode(const nt_module_t *p); +void field_set_debug_mode(nt_field_t *p, unsigned int n_debug_mode); +int field_get_bit_width(const nt_field_t *p); +int field_get_bit_pos_low(const nt_field_t *p); +int field_get_bit_pos_high(const nt_field_t *p); +uint32_t field_get_mask(const nt_field_t *p); +void field_reset(const nt_field_t *p); +uint32_t field_get_reset_val(const nt_field_t *p); +void field_get_val(const nt_field_t *p, uint32_t *p_data, uint32_t len); +void field_set_val(const nt_field_t *p, const uint32_t *p_data, uint32_t len); +void field_set_val_flush(const nt_field_t *p, const uint32_t *p_data, + uint32_t len); +uint32_t field_get_val_mask(const nt_field_t *p); +uint32_t field_get_val32(const nt_field_t *p); +uint32_t field_get_updated(const nt_field_t *p); +void field_read_trig_with_tsc(const nt_field_t *p, uint64_t *tsc1, uint64_t *tsc2); +void field_update_register(const nt_field_t *p); +void field_flush_register(const nt_field_t *p); +void field_set_val32(const nt_field_t *p, uint32_t val); +void field_set_val_flush32(const nt_field_t *p, uint32_t val); +void field_clr_all(const nt_field_t *p); +void field_clr_flush(const nt_field_t *p); +void field_set_all(const nt_field_t *p); +void field_set_flush(const nt_field_t *p); + +int field_wait_clr_all32(const nt_field_t *p, int n_poll_iterations, + int n_poll_interval); +int field_wait_set_all32(const nt_field_t *p, int n_poll_iterations, + int n_poll_interval); + +int field_wait_clr_any32(const nt_field_t *p, int n_poll_iterations, + int n_poll_interval); +int field_wait_set_any32(const nt_field_t *p, int n_poll_iterations, + int n_poll_interval); + +int field_wait_val_mask32(const nt_field_t *p, uint32_t n_wait_cond_value, + uint32_t n_wait_cond_mask, int n_poll_iterations, + int n_poll_interval); + +void field_dump(const nt_field_t *p); +void field_dump_val(const nt_field_t *p); +void field_dump_init(const nt_fpga_field_init_t *p); + +/* + * nthw helpers + */ +nt_fpga_t *nthw_get_fpga(struct fpga_info_s *p_fpga_info, uint64_t n_fpga_ident); +nt_module_t *nthw_get_module(nt_fpga_t *p_fpga, int n_mod, int n_instance); +nt_register_t *nthw_get_register(nt_module_t *p_mod, int n_reg); +nt_field_t *nthw_get_field(nt_register_t *p_reg, int n_fld); + +#endif /* __NTHW_FPGA_MODEL_H__ */ diff --git a/drivers/net/ntnic/nthw/nthw_helper.h b/drivers/net/ntnic/nthw/nthw_helper.h new file mode 100644 index 0000000000..22f6a0d471 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_helper.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_HELPER_H__ +#define __NTHW_HELPER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +#endif /* __NTHW_HELPER_H__ */ diff --git a/drivers/net/ntnic/nthw/nthw_platform.c b/drivers/net/ntnic/nthw/nthw_platform.c new file mode 100644 index 0000000000..203947e03a --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_platform.c @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "nthw_platform_drv.h" + +nthw_adapter_id_t nthw_platform_get_nthw_adapter_id(const uint16_t n_pci_device_id) +{ + switch (n_pci_device_id) { + case NT_HW_PCI_DEVICE_ID_NT40E3: + return NT_HW_ADAPTER_ID_NT40E3; + case NT_HW_PCI_DEVICE_ID_NT100E3: + return NT_HW_ADAPTER_ID_NT100E3; + case NT_HW_PCI_DEVICE_ID_NT80E3: + return NT_HW_ADAPTER_ID_NT80E3; + case NT_HW_PCI_DEVICE_ID_NT40A00: + return NT_HW_ADAPTER_ID_NT40E3; + case NT_HW_PCI_DEVICE_ID_NT40A01: + return NT_HW_ADAPTER_ID_NT40E3; + case NT_HW_PCI_DEVICE_ID_NT200E3: + return NT_HW_ADAPTER_ID_NT200E3; + case NT_HW_PCI_DEVICE_ID_NT200A01: + return NT_HW_ADAPTER_ID_NT200A01; + case NT_HW_PCI_DEVICE_ID_NT200D01: + return NT_HW_ADAPTER_ID_NT200D01; + case NT_HW_PCI_DEVICE_ID_NT200A02: + return NT_HW_ADAPTER_ID_NT200A02; + case NT_HW_PCI_DEVICE_ID_NT50B01: + return NT_HW_ADAPTER_ID_NT50B01; + case NT_HW_PCI_DEVICE_ID_NT100A01: + return NT_HW_ADAPTER_ID_NT100A01; + default: + return NT_HW_ADAPTER_ID_UNKNOWN; + } +} diff --git a/drivers/net/ntnic/nthw/nthw_platform_drv.h b/drivers/net/ntnic/nthw/nthw_platform_drv.h new file mode 100644 index 0000000000..fee2dc4853 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_platform_drv.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_PLATFORM_DRV_H__ +#define __NTHW_PLATFORM_DRV_H__ + +#include "nthw_helper.h" + +#define NT_HW_PCI_VENDOR_ID (0x18f4) + +#define NT_HW_PCI_DEVICE_ID_NT40E3 (0x145) +#define NT_HW_PCI_DEVICE_ID_NT100E3 (0x155) +#define NT_HW_PCI_DEVICE_ID_NT80E3 (0x165) +#define NT_HW_PCI_DEVICE_ID_NT40A00 (0x175) +#define NT_HW_PCI_DEVICE_ID_NT40A01 (0x185) +#define NT_HW_PCI_DEVICE_ID_NT200E3 (0x195) +#define NT_HW_PCI_DEVICE_ID_NT200A01 (0x1A5) +#define NT_HW_PCI_DEVICE_ID_NT200D01 (0x1B5) +#define NT_HW_PCI_DEVICE_ID_NT200A02 (0x1C5) +#define NT_HW_PCI_DEVICE_ID_NT50B01 (0x1D5) +#define NT_HW_PCI_DEVICE_ID_NT100A01 (0x1E5) + +enum nthw_adapter_id_e { + NT_HW_ADAPTER_ID_UNKNOWN = 0, + NT_HW_ADAPTER_ID_NT40E3, + NT_HW_ADAPTER_ID_NT40A01 = NT_HW_ADAPTER_ID_NT40E3, + NT_HW_ADAPTER_ID_NT50B01, + NT_HW_ADAPTER_ID_NT80E3, + NT_HW_ADAPTER_ID_NT100E3, + NT_HW_ADAPTER_ID_NT100A01, + NT_HW_ADAPTER_ID_NT200E3, + NT_HW_ADAPTER_ID_NT200A01, + NT_HW_ADAPTER_ID_NT200D01, + NT_HW_ADAPTER_ID_NT200A02, +}; + +typedef enum nthw_adapter_id_e nthw_adapter_id_t; + +nthw_adapter_id_t nthw_platform_get_nthw_adapter_id(const uint16_t n_pci_device_id); + +#endif /* __NTHW_PLATFORM_DRV_H__ */ diff --git a/drivers/net/ntnic/nthw/nthw_profile.h b/drivers/net/ntnic/nthw/nthw_profile.h new file mode 100644 index 0000000000..2fcb7b4adf --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_profile.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_PROFILE_H__ +#define __NTHW_PROFILE_H__ + +enum fpga_info_profile { + FPGA_INFO_PROFILE_UNKNOWN = 0, + FPGA_INFO_PROFILE_VSWITCH = 1, + FPGA_INFO_PROFILE_INLINE = 2, + FPGA_INFO_PROFILE_CAPTURE = 3, +}; + +#endif /* __NTHW_PROFILE_H__ */ diff --git a/drivers/net/ntnic/nthw/nthw_rac.c b/drivers/net/ntnic/nthw/nthw_rac.c new file mode 100644 index 0000000000..f3f6bee223 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_rac.c @@ -0,0 +1,976 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "nt_util.h" +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" +#include "nthw_rac.h" + +#include + +/* + * Prevent that RAB echo debug trace ever gets into a release build + */ +#if defined(DEBUG) +#undef RAB_DEBUG_ECHO +#else +#undef RAB_DEBUG_ECHO +#endif /* DEBUG */ + +#define RAB_DMA_WAIT (1000000) +#define RAB_DMA_BUF_CNT (0x4000) + +#define RAB_READ (0x01) +#define RAB_WRITE (0x02) +#define RAB_ECHO (0x08) +#define RAB_COMPLETION (0x0F) + +#define RAB_READ_ECHO (RAB_READ | RAB_ECHO) +#define RAB_WRITE_ECHO (RAB_WRITE | RAB_ECHO) + +#define RAB_OPR_LO (28) +#define RAB_OPR_HI (31) +#define RAB_OPR_BW (4) + +#define RAB_CNT_LO (20) +#define RAB_CNT_HI (27) +#define RAB_CNT_BW (8) + +#define RAB_BUSID_LO (16) +#define RAB_BUSID_HI (19) +#define RAB_BUSID_BW (4) + +#define RAB_ADDR_LO (0) +#define RAB_ADDR_HI (15) +#define RAB_ADDR_BW (16) + +nthw_rac_t *nthw_rac_new(void) +{ + nthw_rac_t *p = malloc(sizeof(nthw_rac_t)); + + memset(p, 0, sizeof(nthw_rac_t)); + return p; +} + +void nthw_rac_delete(nthw_rac_t *p) +{ + if (p) { + memset(p, 0, sizeof(nthw_rac_t)); + free(p); + } +} + +int nthw_rac_init(nthw_rac_t *p, nt_fpga_t *p_fpga, struct fpga_info_s *p_fpga_info) +{ + assert(p_fpga_info); + + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + nt_module_t *mod = fpga_query_module(p_fpga, MOD_RAC, 0); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: RAC %d: no such instance\n", + p_adapter_id_str, 0); + return -1; + } + + p->mp_fpga = p_fpga; + p->mp_mod_rac = mod; + + { + /* + * RAC is a primary communication channel + * turn off debug by default + * except for rac_rab_init + */ + const int n_debug_mode = module_get_debug_mode(p->mp_mod_rac); + + if (n_debug_mode && n_debug_mode <= 0xff) { + module_set_debug_mode(p->mp_mod_rac, 0); + register_set_debug_mode(p->mp_reg_rab_init, n_debug_mode); + } + } + + /* Params */ + p->mn_param_rac_rab_interfaces = + fpga_get_product_param(p->mp_fpga, NT_RAC_RAB_INTERFACES, 3); + NT_LOG(DBG, NTHW, "%s: NT_RAC_RAB_INTERFACES=%d\n", p_adapter_id_str, + p->mn_param_rac_rab_interfaces); + + p->mn_param_rac_rab_ob_update = + fpga_get_product_param(p->mp_fpga, NT_RAC_RAB_OB_UPDATE, 0); + NT_LOG(DBG, NTHW, "%s: NT_RAC_RAB_OB_UPDATE=%d\n", p_adapter_id_str, + p->mn_param_rac_rab_ob_update); + + /* Optional dummy test registers */ + p->mp_reg_dummy0 = module_query_register(p->mp_mod_rac, RAC_DUMMY0); + p->mp_reg_dummy1 = module_query_register(p->mp_mod_rac, RAC_DUMMY1); + p->mp_reg_dummy2 = module_query_register(p->mp_mod_rac, RAC_DUMMY2); + + p->mp_reg_rab_init = module_get_register(p->mp_mod_rac, RAC_RAB_INIT); + p->mp_fld_rab_init = register_get_field(p->mp_reg_rab_init, RAC_RAB_INIT_RAB); + p->mn_fld_rab_init_bw = field_get_bit_width(p->mp_fld_rab_init); + p->mn_fld_rab_init_mask = field_get_mask(p->mp_fld_rab_init); + + /* RAC_RAB_INIT_RAB reg/field sanity checks: */ + assert(p->mn_fld_rab_init_mask == ((1UL << p->mn_fld_rab_init_bw) - 1)); + assert(p->mn_fld_rab_init_bw == p->mn_param_rac_rab_interfaces); + + p->mp_reg_dbg_ctrl = module_query_register(p->mp_mod_rac, RAC_DBG_CTRL); + if (p->mp_reg_dbg_ctrl) { + p->mp_fld_dbg_ctrl = + register_query_field(p->mp_reg_dbg_ctrl, RAC_DBG_CTRL_C); + } else { + p->mp_fld_dbg_ctrl = NULL; + } + p->mp_reg_dbg_data = module_query_register(p->mp_mod_rac, RAC_DBG_DATA); + if (p->mp_reg_dbg_data) { + p->mp_fld_dbg_data = + register_query_field(p->mp_reg_dbg_data, RAC_DBG_DATA_D); + } else { + p->mp_reg_dbg_data = NULL; + } + p->mp_reg_rab_ib_data = module_get_register(p->mp_mod_rac, RAC_RAB_IB_DATA); + p->mp_fld_rab_ib_data = + register_get_field(p->mp_reg_rab_ib_data, RAC_RAB_IB_DATA_D); + + p->mp_reg_rab_ob_data = module_get_register(p->mp_mod_rac, RAC_RAB_OB_DATA); + p->mp_fld_rab_ob_data = + register_get_field(p->mp_reg_rab_ob_data, RAC_RAB_OB_DATA_D); + + p->mp_reg_rab_buf_free = module_get_register(p->mp_mod_rac, RAC_RAB_BUF_FREE); + p->mp_fld_rab_buf_free_ib_free = + register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_IB_FREE); + p->mp_fld_rab_buf_free_ib_ovf = + register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_IB_OVF); + p->mp_fld_rab_buf_free_ob_free = + register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_OB_FREE); + p->mp_fld_rab_buf_free_ob_ovf = + register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_OB_OVF); + p->mp_fld_rab_buf_free_timeout = + register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_TIMEOUT); + + p->mp_reg_rab_buf_used = module_get_register(p->mp_mod_rac, RAC_RAB_BUF_USED); + p->mp_fld_rab_buf_used_ib_used = + register_get_field(p->mp_reg_rab_buf_used, RAC_RAB_BUF_USED_IB_USED); + p->mp_fld_rab_buf_used_ob_used = + register_get_field(p->mp_reg_rab_buf_used, RAC_RAB_BUF_USED_OB_USED); + p->mp_fld_rab_buf_used_flush = + register_get_field(p->mp_reg_rab_buf_used, RAC_RAB_BUF_USED_FLUSH); + + /* + * RAC_RAB_DMA regs are optional - only found in real NT4GA - not found in 9231/9232 and + * earlier + */ + p->mp_reg_rab_dma_ib_lo = module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_LO); + p->mp_fld_rab_dma_ib_lo_phy_addr = + register_get_field(p->mp_reg_rab_dma_ib_lo, RAC_RAB_DMA_IB_LO_PHYADDR); + + p->mp_reg_rab_dma_ib_hi = module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_HI); + p->mp_fld_rab_dma_ib_hi_phy_addr = + register_get_field(p->mp_reg_rab_dma_ib_hi, RAC_RAB_DMA_IB_HI_PHYADDR); + + p->mp_reg_rab_dma_ob_lo = module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_LO); + p->mp_fld_rab_dma_ob_lo_phy_addr = + register_get_field(p->mp_reg_rab_dma_ob_lo, RAC_RAB_DMA_OB_LO_PHYADDR); + + p->mp_reg_rab_dma_ob_hi = module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_HI); + p->mp_fld_rab_dma_ob_hi_phy_addr = + register_get_field(p->mp_reg_rab_dma_ob_hi, RAC_RAB_DMA_OB_HI_PHYADDR); + + p->mp_reg_rab_dma_ib_wr = module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_WR); + p->mp_fld_rab_dma_ib_wr_ptr = + register_get_field(p->mp_reg_rab_dma_ib_wr, RAC_RAB_DMA_IB_WR_PTR); + + p->mp_reg_rab_dma_ib_rd = module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_RD); + p->mp_fld_rab_dma_ib_rd_ptr = + register_get_field(p->mp_reg_rab_dma_ib_rd, RAC_RAB_DMA_IB_RD_PTR); + + p->mp_reg_rab_dma_ob_wr = module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_WR); + p->mp_fld_rab_dma_ob_wr_ptr = + register_get_field(p->mp_reg_rab_dma_ob_wr, RAC_RAB_DMA_OB_WR_PTR); + + p->rac_rab_init_addr = register_get_address(p->mp_reg_rab_init); + p->rac_rab_ib_data_addr = register_get_address(p->mp_reg_rab_ib_data); + p->rac_rab_ob_data_addr = register_get_address(p->mp_reg_rab_ob_data); + p->rac_rab_buf_free_addr = register_get_address(p->mp_reg_rab_buf_free); + p->rac_rab_buf_used_addr = register_get_address(p->mp_reg_rab_buf_used); + + /* + * RAC_RAB_DMA regs are optional - only found in real NT4GA - + * not found in 9231/9232 and earlier + */ + + p->rac_rab_dma_ib_lo_addr = register_get_address(p->mp_reg_rab_dma_ib_lo); + p->rac_rab_dma_ib_hi_addr = register_get_address(p->mp_reg_rab_dma_ib_hi); + p->rac_rab_dma_ob_lo_addr = register_get_address(p->mp_reg_rab_dma_ob_lo); + p->rac_rab_dma_ob_hi_addr = register_get_address(p->mp_reg_rab_dma_ob_hi); + p->rac_rab_dma_ib_rd_addr = register_get_address(p->mp_reg_rab_dma_ib_rd); + p->rac_rab_dma_ob_wr_addr = register_get_address(p->mp_reg_rab_dma_ob_wr); + p->rac_rab_dma_ib_wr_addr = register_get_address(p->mp_reg_rab_dma_ib_wr); + + p->rac_rab_buf_free_ib_free_mask = + field_get_mask(p->mp_fld_rab_buf_free_ib_free); + p->rac_rab_buf_free_ob_free_mask = + field_get_mask(p->mp_fld_rab_buf_free_ob_free); + p->rac_rab_buf_used_ib_used_mask = + field_get_mask(p->mp_fld_rab_buf_used_ib_used); + p->rac_rab_buf_used_ob_used_mask = + field_get_mask(p->mp_fld_rab_buf_used_ob_used); + + p->rac_rab_buf_used_flush_mask = field_get_mask(p->mp_fld_rab_buf_used_flush); + + p->rac_rab_buf_used_ob_used_low = + field_get_bit_pos_low(p->mp_fld_rab_buf_used_ob_used); + + p->mp_reg_rab_nmb_rd = module_query_register(p->mp_mod_rac, RAC_NMB_RD_ADR); + if (p->mp_reg_rab_nmb_rd) + p->rac_nmb_rd_adr_addr = register_get_address(p->mp_reg_rab_nmb_rd); + + p->mp_reg_rab_nmb_data = module_query_register(p->mp_mod_rac, RAC_NMB_DATA); + if (p->mp_reg_rab_nmb_data) + p->rac_nmb_data_addr = register_get_address(p->mp_reg_rab_nmb_data); + + p->mp_reg_rab_nmb_wr = module_query_register(p->mp_mod_rac, RAC_NMB_WR_ADR); + if (p->mp_reg_rab_nmb_wr) + p->rac_nmb_wr_adr_addr = register_get_address(p->mp_reg_rab_nmb_wr); + + p->mp_reg_rab_nmb_status = + module_query_register(p->mp_mod_rac, RAC_NMB_STATUS); + if (p->mp_reg_rab_nmb_status) { + p->rac_nmb_status_addr = + register_get_address(p->mp_reg_rab_nmb_status); + } + + p->m_dma = NULL; + + pthread_mutex_init(&p->m_mutex, NULL); + + return 0; +} + +int nthw_rac_get_rab_interface_count(const nthw_rac_t *p) +{ + return p->mn_param_rac_rab_interfaces; +} + +static inline int nthw_rac_wait_for_rab_done(const nthw_rac_t *p, uint32_t address, + uint32_t word_cnt) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + uint32_t used = 0; + uint32_t retry; + + for (retry = 0; retry < 100000; retry++) { + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_buf_used_addr, &used); + used = (used & p->rac_rab_buf_used_ob_used_mask) >> + p->rac_rab_buf_used_ob_used_low; + if (used >= word_cnt) + break; + } + + if (used < word_cnt) { + NT_LOG(ERR, NTHW, + "%s: Fail rab bus r/w addr=0x%08X used=%x wordcount=%d\n", + p_adapter_id_str, address, used, word_cnt); + return -1; + } + return 0; +} + +/* + * NT_PCI_REG_P9xyz_RAC_RAB_INIT + * + * Initializes (resets) the programmable registers on the Register Access Buses (RAB). + * This initialization must be performed by software as part of the driver load procedure. + * + * Bit n of this field initializes the programmable registers on RAB interface n. + * Software must write one to the bit and then clear the bit again. + * + * All RAB module registers will be reset to their defaults. + * This includes the product specific RESET module (eg RST9xyz) + * As a consequence of this behavior the official reset sequence + * must be excersised - as all RAB modules will be held in reset. + */ +int nthw_rac_rab_init(nthw_rac_t *p, uint32_t n_rab_intf_mask) +{ + /* + * Write rac_rab_init + * Perform operation twice - first to get trace of operation - + * second to get things done... + */ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + + field_set_val_flush32(p->mp_fld_rab_init, n_rab_intf_mask); + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_init_addr, n_rab_intf_mask); + return 0; +} + +int nthw_rac_rab_reset(nthw_rac_t *p) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + + const char *const p_adapter_id_str _unused = p_fpga_info->mp_adapter_id_str; + + /* RAC RAB bus "flip/flip" reset */ + const int n_rac_rab_bus_count = nthw_rac_get_rab_interface_count(p); + const int n_rac_rab_bus_mask = (1 << n_rac_rab_bus_count) - 1; + + NT_LOG(DBG, NTHW, "%s: NT_RAC_RAB_INTERFACES=%d (0x%02X)\n", + p_adapter_id_str, n_rac_rab_bus_count, n_rac_rab_bus_mask); + assert(n_rac_rab_bus_count); + assert(n_rac_rab_bus_mask); + + /* RAC RAB bus "flip/flip" reset first stage - new impl (ref RMT#37020) */ + nthw_rac_rab_init(p, 0); + nthw_rac_rab_init(p, n_rac_rab_bus_mask); + nthw_rac_rab_init(p, n_rac_rab_bus_mask & ~0x01); + + return 0; +} + +int nthw_rac_rab_setup(nthw_rac_t *p) +{ + int rc = 0; + + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + uint32_t n_dma_buf_size = 2L * RAB_DMA_BUF_CNT * sizeof(uint32_t); + const size_t align_size = ALIGN_SIZE(n_dma_buf_size); + int numa_node = p_fpga_info->numa_node; + uint64_t dma_addr; + uint32_t buf; + + if (!p->m_dma) { + struct nt_dma_s *vfio_dma; + /* FPGA needs Page alignment (4K) */ + vfio_dma = nt_dma_alloc(align_size, 0x1000, numa_node); + + if (vfio_dma == NULL) { + NT_LOG(ERR, ETHDEV, "%s: nt_dma_alloc failed\n", + __func__); + return -1; + } + p->m_dma_in_buf = (uint32_t *)vfio_dma->addr; + p->m_dma_out_buf = p->m_dma_in_buf + RAB_DMA_BUF_CNT; + p->m_dma = vfio_dma; + } + + /* Setup DMA on the adapter */ + dma_addr = p->m_dma->iova; + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_dma_ib_lo_addr, + dma_addr & 0xffffffff); + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_dma_ib_hi_addr, + (uint32_t)(dma_addr >> 32) & 0xffffffff); + dma_addr += RAB_DMA_BUF_CNT * sizeof(uint32_t); + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_dma_ob_lo_addr, + dma_addr & 0xffffffff); + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_dma_ob_hi_addr, + (uint32_t)(dma_addr >> 32) & 0xffffffff); + + /* Set initial value of internal pointers */ + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_dma_ib_rd_addr, &buf); + p->m_dma_in_ptr_wr = (uint16_t)(buf / sizeof(uint32_t)); + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_dma_ob_wr_addr, &buf); + p->m_dma_out_ptr_rd = (uint16_t)(buf / sizeof(uint32_t)); + p->m_in_free = RAB_DMA_BUF_CNT; + + return rc; +} + +int nthw_rac_rab_dma_begin(nthw_rac_t *p) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + + pthread_mutex_lock(&p->m_mutex); + + if (p->m_dma_active) { + pthread_mutex_unlock(&p->m_mutex); + NT_LOG(ERR, NTHW, + "%s: DMA begin requested, but a DMA transaction is already active\n", + p_adapter_id_str); + return -1; + } + + p->m_dma_active = true; + + return 0; +} + +static void nthw_rac_rab_dma_activate(nthw_rac_t *p) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + const uint32_t completion = RAB_COMPLETION << RAB_OPR_LO; + + /* Write completion word */ + p->m_dma_in_buf[p->m_dma_in_ptr_wr] = completion; + p->m_dma_in_ptr_wr = + (uint16_t)((p->m_dma_in_ptr_wr + 1) & (RAB_DMA_BUF_CNT - 1)); + + /* Clear output completion word */ + p->m_dma_out_buf[p->m_dma_out_ptr_rd] = 0; + + /* _update DMA pointer and start transfer */ + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_dma_ib_wr_addr, + (uint32_t)(p->m_dma_in_ptr_wr * sizeof(uint32_t))); +} + +static int nthw_rac_rab_dma_wait(nthw_rac_t *p) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + const uint32_t completion = RAB_COMPLETION << RAB_OPR_LO; + uint32_t i; + + for (i = 0; i < RAB_DMA_WAIT; i++) { + NT_OS_WAIT_USEC_POLL(1); + if ((p->m_dma_out_buf[p->m_dma_out_ptr_rd] & completion) == + completion) + break; + } + + if (i == RAB_DMA_WAIT) { + NT_LOG(ERR, NTHW, + "%s: RAB: Unexpected value of completion (0x%08X)\n", + p_fpga_info->mp_adapter_id_str, + p->m_dma_out_buf[p->m_dma_out_ptr_rd]); + return -1; + } + + p->m_dma_out_ptr_rd = + (uint16_t)((p->m_dma_out_ptr_rd + 1) & (RAB_DMA_BUF_CNT - 1)); + p->m_in_free = RAB_DMA_BUF_CNT; + + return 0; +} + +int nthw_rac_rab_dma_commit(nthw_rac_t *p) +{ + int ret; + + if (!p->m_dma_active) { + /* Expecting mutex not to be locked! */ + assert(0); /* alert developer that something is wrong */ + return -1; + } + + nthw_rac_rab_dma_activate(p); + ret = nthw_rac_rab_dma_wait(p); + + p->m_dma_active = false; + + pthread_mutex_unlock(&p->m_mutex); + + return ret; +} + +void nthw_rac_reg_read32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t *p_data) +{ + *p_data = *(volatile uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + + reg_addr); +} + +void nthw_rac_reg_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t p_data) +{ + *(volatile uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + reg_addr) = + p_data; +} + +int nthw_rac_rab_write32_dma(nthw_rac_t *p, uint32_t address, rab_bus_id_t bus_id, + uint32_t word_cnt, const uint32_t *p_data) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + + if (word_cnt == 0 || word_cnt > 256) { + NT_LOG(ERR, NTHW, + "%s: Failed rab dma write length check - bus: %d addr: 0x%08X wordcount: %d - inBufFree: 0x%08X\n", + p_fpga_info->mp_adapter_id_str, bus_id, address, word_cnt, + p->m_in_free); + assert(0); /* alert developer that something is wrong */ + return -1; + } + + if (p->m_in_free < (word_cnt + 3)) { + /* + * No more memory available. + * nthw_rac_rab_dma_commit() needs to be called to start and finish pending + * transfers. + */ + return -1; + } + + p->m_in_free -= (word_cnt + 1); + + /* Write the command word */ +#if defined(RAB_DEBUG_ECHO) + p->m_dma_in_buf[p->m_dma_in_ptr_wr] = + (RAB_WRITE_ECHO << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; + p->m_dma_out_ptr_rd = (uint16_t)((p->m_dma_out_ptr_rd + word_cnt + 1) & + (RAB_DMA_BUF_CNT - 1)); +#else + p->m_dma_in_buf[p->m_dma_in_ptr_wr] = + (RAB_WRITE << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; +#endif + p->m_dma_in_ptr_wr = + (uint16_t)((p->m_dma_in_ptr_wr + 1) & (RAB_DMA_BUF_CNT - 1)); + + for (uint32_t i = 0; i < word_cnt; i++) { + p->m_dma_in_buf[p->m_dma_in_ptr_wr] = p_data[i]; + p->m_dma_in_ptr_wr = (uint16_t)((p->m_dma_in_ptr_wr + 1) & + (RAB_DMA_BUF_CNT - 1)); + } + + return 0; +} + +int nthw_rac_rab_read32_dma(nthw_rac_t *p, uint32_t address, rab_bus_id_t bus_id, + uint32_t word_cnt, struct dma_buf_ptr *buf_ptr) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + + if (word_cnt == 0 || word_cnt > 256) { + NT_LOG(ERR, NTHW, + "%s: Failed rab dma read length check - bus: %d addr: 0x%08X wordcount: %d - inBufFree: 0x%08X\n", + p_fpga_info->mp_adapter_id_str, bus_id, address, word_cnt, + p->m_in_free); + assert(0); /* alert developer that something is wrong */ + return -1; + } + + if ((word_cnt + 3) > RAB_DMA_BUF_CNT) { + NT_LOG(ERR, NTHW, + "%s: Failed rab dma read length check - bus: %d addr: 0x%08X wordcount: %d: 0x%08X", + p_fpga_info->mp_adapter_id_str, bus_id, address, word_cnt); + return -1; + } + + if (p->m_in_free < 3) { + /* + * No more memory available. + * nthw_rac_rab_dma_commit() needs to be called to start and finish pending + * transfers. + */ + return -1; + } + + p->m_in_free -= 1; + + /* Write the command word */ +#if defined(RAB_DEBUG_ECHO) + p->m_dma_in_buf[p->m_dma_in_ptr_wr] = + (RAB_READ_ECHO << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; + p->m_dma_out_ptr_rd = + (uint16_t)((p->m_dma_out_ptr_rd + 1) & (RAB_DMA_BUF_CNT - 1)); +#else + p->m_dma_in_buf[p->m_dma_in_ptr_wr] = + (RAB_READ << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; +#endif + p->m_dma_in_ptr_wr = + (uint16_t)((p->m_dma_in_ptr_wr + 1) & (RAB_DMA_BUF_CNT - 1)); + + buf_ptr->index = p->m_dma_out_ptr_rd; + buf_ptr->size = RAB_DMA_BUF_CNT; + buf_ptr->base = p->m_dma_out_buf; + p->m_dma_out_ptr_rd = (uint16_t)((p->m_dma_out_ptr_rd + word_cnt) & + (RAB_DMA_BUF_CNT - 1U)); + + return 0; +} + +int nthw_rac_rab_write32(nthw_rac_t *p, uint32_t address, rab_bus_id_t bus_id, + uint32_t word_cnt, const uint32_t *p_data) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + int res = 0; + uint32_t rab_oper_wr; + uint32_t rab_oper_cmpl; + uint32_t rab_echo_oper_cmpl; + uint32_t word_cnt_expected; + uint32_t buf_used; + uint32_t buf_free; + uint32_t in_buf_free; + uint32_t out_buf_free; + + if (address > (1 << RAB_ADDR_BW)) { + NT_LOG(ERR, NTHW, + "%s: RAB: Illegal address: value too large %d - max %d\n", + p_adapter_id_str, address, (1 << RAB_ADDR_BW)); + return -1; + } + + if (bus_id > (1 << RAB_BUSID_BW)) { + NT_LOG(ERR, NTHW, + "%s: RAB: Illegal bus id: value too large %d - max %d\n", + p_adapter_id_str, bus_id, (1 << RAB_BUSID_BW)); + return -1; + } + + if (word_cnt == 0) { + NT_LOG(ERR, NTHW, + "%s: RAB: Illegal word count: value is zero (%d)\n", + p_adapter_id_str, word_cnt); + return -1; + } + + if (word_cnt > (1 << RAB_CNT_BW)) { + NT_LOG(ERR, NTHW, + "%s: RAB: Illegal word count: value too large %d - max %d\n", + p_adapter_id_str, word_cnt, (1 << RAB_CNT_BW)); + return -1; + } + + pthread_mutex_lock(&p->m_mutex); + + if (p->m_dma_active) { + NT_LOG(ERR, NTHW, "%s: RAB: Illegal operation: DMA enabled\n", + p_adapter_id_str); + res = -1; + goto exit_unlock_res; + } + + /* Read buffer free register */ + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_buf_free_addr, &buf_free); + + in_buf_free = buf_free & p->rac_rab_buf_free_ib_free_mask; + out_buf_free = (buf_free & p->rac_rab_buf_free_ob_free_mask) >> 16; + + /* Read buffer used register */ + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_buf_used_addr, &buf_used); + + buf_used = buf_used & (p->rac_rab_buf_used_ib_used_mask | + p->rac_rab_buf_used_ob_used_mask); + + /* + * Verify that output buffer can hold one completion word, + * input buffer can hold the number of words to be written + + * one write and one completion command + * and that the input and output "used" buffer is 0 + */ + if ((out_buf_free >= 1 && (in_buf_free >= word_cnt + 2)) && buf_used == 0) { + uint32_t i; + + word_cnt_expected = 0; + + /* Compose write command */ +#if defined(RAB_DEBUG_ECHO) + rab_oper_wr = + (RAB_WRITE_ECHO << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; + word_cnt_expected += word_cnt + 1; +#else + rab_oper_wr = + (RAB_WRITE << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; +#endif /* RAB_DEBUG_ECHO */ + + /* Write command */ + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_ib_data_addr, + rab_oper_wr); + + /* Write da to input buffer */ + for (i = 0; i < word_cnt; i++) { + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_ib_data_addr, + *p_data); + p_data++; + } + + /* Compose completion command */ + rab_oper_cmpl = (RAB_COMPLETION << RAB_OPR_LO); + word_cnt_expected++; + + /* Write command */ + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_ib_data_addr, + rab_oper_cmpl); + + /* Wait until done */ + if (nthw_rac_wait_for_rab_done(p, address, word_cnt_expected)) { + res = -1; + goto exit_unlock_res; + } + +#if defined(RAB_DEBUG_ECHO) + { + uint32_t rab_echo_oper_wr; + + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_ob_data_addr, + &rab_echo_oper_wr); + if (p->mn_param_rac_rab_ob_update) { + nthw_rac_reg_write32(p_fpga_info, + p->rac_rab_ob_data_addr, 0); + } + if (rab_oper_wr != rab_echo_oper_wr) { + NT_LOG(ERR, NTHW, + "%s: expected rab read echo oper (0x%08X) - read (0x%08X)\n", + p_adapter_id_str, rab_oper_wr, rab_echo_oper_wr); + } + } + + { + /* Read data from output buffer */ + uint32_t data; + + for (i = 0; i < word_cnt; i++) { + nthw_rac_reg_read32(p_fpga_info, + p->rac_rab_ob_data_addr, + &data); + if (p->mn_param_rac_rab_ob_update) { + nthw_rac_reg_write32(p_fpga_info, + p->rac_rab_ob_data_addr, 0); + } + } + } +#endif /* RAB_DEBUG_ECHO */ + + /* Read completion from out buffer */ + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_ob_data_addr, + &rab_echo_oper_cmpl); + if (p->mn_param_rac_rab_ob_update) { + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_ob_data_addr, + 0); + } + if (rab_echo_oper_cmpl != rab_oper_cmpl) { + NT_LOG(ERR, NTHW, + "%s: RAB: Unexpected value of completion (0x%08X)- inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n", + p_adapter_id_str, rab_echo_oper_cmpl, in_buf_free, + out_buf_free, buf_used); + res = -1; + goto exit_unlock_res; + } + + /* Read buffer free register */ + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_buf_free_addr, + &buf_free); + if (buf_free & 0x80000000) { + /* Clear Timeout and overflow bits */ + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_buf_free_addr, + 0x0); + NT_LOG(ERR, NTHW, + "%s: RAB: timeout - Access outside register - bus: %d addr: 0x%08X - inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n", + p_adapter_id_str, bus_id, address, in_buf_free, + out_buf_free, buf_used); + res = -1; + goto exit_unlock_res; + } + + res = 0; + goto exit_unlock_res; + } else { + NT_LOG(ERR, NTHW, + "%s: RAB: Fail rab bus buffer check - bus: %d addr: 0x%08X wordcount: %d - inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n", + p_adapter_id_str, bus_id, address, word_cnt, in_buf_free, + out_buf_free, buf_used); + res = -1; + goto exit_unlock_res; + } + +exit_unlock_res: + pthread_mutex_unlock(&p->m_mutex); + return res; +} + +int nthw_rac_rab_read32(nthw_rac_t *p, uint32_t address, rab_bus_id_t bus_id, + uint32_t word_cnt, uint32_t *p_data) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + int res = 0; + uint32_t rab_oper_rd; + uint32_t word_cnt_expected; + uint32_t buf_used; + uint32_t buf_free; + uint32_t in_buf_free; + uint32_t out_buf_free; + + pthread_mutex_lock(&p->m_mutex); + + if (address > (1 << RAB_ADDR_BW)) { + NT_LOG(ERR, NTHW, + "%s: RAB: Illegal address: value too large %d - max %d\n", + p_adapter_id_str, address, (1 << RAB_ADDR_BW)); + res = -1; + goto exit_unlock_res; + } + + if (bus_id > (1 << RAB_BUSID_BW)) { + NT_LOG(ERR, NTHW, + "%s: RAB: Illegal bus id: value too large %d - max %d\n", + p_adapter_id_str, bus_id, (1 << RAB_BUSID_BW)); + res = -1; + goto exit_unlock_res; + } + + if (word_cnt == 0) { + NT_LOG(ERR, NTHW, + "%s: RAB: Illegal word count: value is zero (%d)\n", + p_adapter_id_str, word_cnt); + res = -1; + goto exit_unlock_res; + } + + if (word_cnt > (1 << RAB_CNT_BW)) { + NT_LOG(ERR, NTHW, + "%s: RAB: Illegal word count: value too large %d - max %d\n", + p_adapter_id_str, word_cnt, (1 << RAB_CNT_BW)); + res = -1; + goto exit_unlock_res; + } + + /* Read buffer free register */ + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_buf_free_addr, &buf_free); + + in_buf_free = buf_free & p->rac_rab_buf_free_ib_free_mask; + out_buf_free = (buf_free & p->rac_rab_buf_free_ob_free_mask) >> 16; + + /* Read buffer used register */ + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_buf_used_addr, &buf_used); + + buf_used = buf_used & (p->rac_rab_buf_used_ib_used_mask | + p->rac_rab_buf_used_ob_used_mask); + + /* + * Verify that output buffer can hold the number of words to be read, + * input buffer can hold one read command + * and that the input and output "used" buffer is 0 + */ + if ((out_buf_free >= word_cnt && in_buf_free >= 1) && buf_used == 0) { + word_cnt_expected = word_cnt; + +#if defined(RAB_DEBUG_ECHO) + rab_oper_rd = + (RAB_READ_ECHO << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; + word_cnt_expected++; +#else + rab_oper_rd = (RAB_READ << RAB_OPR_LO) | (word_cnt << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; +#endif /* RAB_DEBUG_ECHO */ + + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_ib_data_addr, + rab_oper_rd); + + /* Wait until done */ + if (nthw_rac_wait_for_rab_done(p, address, word_cnt_expected)) { + res = -1; + goto exit_unlock_res; + } + +#if defined(RAB_DEBUG_ECHO) + uint32_t rab_echo_oper_rd; + + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_ob_data_addr, + &rab_echo_oper_rd); + if (p->mn_param_rac_rab_ob_update) { + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_ob_data_addr, + 0); + } + if (rab_oper_rd != rab_echo_oper_rd) { + NT_LOG(ERR, NTHW, + "%s: RAB: expected rab read echo oper (0x%08X) - read (0x%08X)\n", + p_adapter_id_str, rab_oper_rd, rab_echo_oper_rd); + } +#endif /* RAB_DEBUG_ECHO */ + + /* Read data from output buffer */ + { + uint32_t i; + + for (i = 0; i < word_cnt; i++) { + nthw_rac_reg_read32(p_fpga_info, + p->rac_rab_ob_data_addr, + p_data); + if (p->mn_param_rac_rab_ob_update) { + nthw_rac_reg_write32(p_fpga_info, + p->rac_rab_ob_data_addr, + 0); + } + p_data++; + } + } + + /* Read buffer free register */ + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_buf_free_addr, + &buf_free); + if (buf_free & 0x80000000) { + /* Clear Timeout and overflow bits */ + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_buf_free_addr, + 0x0); + NT_LOG(ERR, NTHW, + "%s: RAB: timeout - Access outside register - bus: %d addr: 0x%08X - inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n", + p_adapter_id_str, bus_id, address, in_buf_free, + out_buf_free, buf_used); + res = -1; + goto exit_unlock_res; + } + + res = 0; + goto exit_unlock_res; + } else { + NT_LOG(ERR, NTHW, + "%s: RAB: Fail rab bus buffer check - bus: %d addr: 0x%08X wordcount: %d - inBufFree: 0x%08X, outBufFree: 0x%08X, bufUsed: 0x%08X\n", + p_adapter_id_str, bus_id, address, word_cnt, in_buf_free, + out_buf_free, buf_used); + res = -1; + goto exit_unlock_res; + } + +exit_unlock_res: + pthread_mutex_unlock(&p->m_mutex); + return res; +} + +int nthw_rac_rab_flush(nthw_rac_t *p) +{ + const struct fpga_info_s *const p_fpga_info = p->mp_fpga->p_fpga_info; + const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str; + uint32_t data = 0; + uint32_t retry; + int res = 0; + + pthread_mutex_lock(&p->m_mutex); + + /* Set the flush bit */ + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_buf_used_addr, + p->rac_rab_buf_used_flush_mask); + + /* Reset BUF FREE register */ + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_buf_free_addr, 0x0); + + /* Wait until OB_USED and IB_USED are 0 */ + for (retry = 0; retry < 100000; retry++) { + nthw_rac_reg_read32(p_fpga_info, p->rac_rab_buf_used_addr, &data); + + if ((data & 0xFFFFFFFF) == p->rac_rab_buf_used_flush_mask) + break; + } + + if (data != p->rac_rab_buf_used_flush_mask) { + NT_LOG(ERR, NTHW, "%s: RAB: Rab bus flush error.\n", + p_adapter_id_str); + res = -1; + } + + /* Clear flush bit when done */ + nthw_rac_reg_write32(p_fpga_info, p->rac_rab_buf_used_addr, 0x0); + + pthread_mutex_unlock(&p->m_mutex); + return res; +} diff --git a/drivers/net/ntnic/nthw/nthw_rac.h b/drivers/net/ntnic/nthw/nthw_rac.h new file mode 100644 index 0000000000..737598d95a --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_rac.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_RAC_H__ +#define __NTHW_RAC_H__ + +#include "nt_util.h" +#include "nthw_bus.h" + +#include + +struct nthw_rac { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_rac; + + pthread_mutex_t m_mutex; + + int mn_param_rac_rab_interfaces; + int mn_param_rac_rab_ob_update; + + nt_register_t *mp_reg_dummy0; + nt_register_t *mp_reg_dummy1; + nt_register_t *mp_reg_dummy2; + + nt_register_t *mp_reg_rab_init; + nt_field_t *mp_fld_rab_init; + + int mn_fld_rab_init_bw; + uint32_t mn_fld_rab_init_mask; + + nt_register_t *mp_reg_dbg_ctrl; + nt_field_t *mp_fld_dbg_ctrl; + + nt_register_t *mp_reg_dbg_data; + nt_field_t *mp_fld_dbg_data; + + nt_register_t *mp_reg_rab_ib_data; + nt_field_t *mp_fld_rab_ib_data; + + nt_register_t *mp_reg_rab_ob_data; + nt_field_t *mp_fld_rab_ob_data; + + nt_register_t *mp_reg_rab_buf_free; + nt_field_t *mp_fld_rab_buf_free_ib_free; + nt_field_t *mp_fld_rab_buf_free_ib_ovf; + nt_field_t *mp_fld_rab_buf_free_ob_free; + nt_field_t *mp_fld_rab_buf_free_ob_ovf; + nt_field_t *mp_fld_rab_buf_free_timeout; + + nt_register_t *mp_reg_rab_buf_used; + nt_field_t *mp_fld_rab_buf_used_ib_used; + nt_field_t *mp_fld_rab_buf_used_ob_used; + nt_field_t *mp_fld_rab_buf_used_flush; + + nt_register_t *mp_reg_rab_dma_ib_lo; + nt_field_t *mp_fld_rab_dma_ib_lo_phy_addr; + + nt_register_t *mp_reg_rab_dma_ib_hi; + nt_field_t *mp_fld_rab_dma_ib_hi_phy_addr; + + nt_register_t *mp_reg_rab_dma_ob_hi; + nt_field_t *mp_fld_rab_dma_ob_hi_phy_addr; + + nt_register_t *mp_reg_rab_dma_ob_lo; + nt_field_t *mp_fld_rab_dma_ob_lo_phy_addr; + + nt_register_t *mp_reg_rab_dma_ib_wr; + nt_field_t *mp_fld_rab_dma_ib_wr_ptr; + + nt_register_t *mp_reg_rab_dma_ib_rd; + nt_field_t *mp_fld_rab_dma_ib_rd_ptr; + + nt_register_t *mp_reg_rab_dma_ob_wr; + nt_field_t *mp_fld_rab_dma_ob_wr_ptr; + + nt_register_t *mp_reg_rab_nmb_rd; + nt_register_t *mp_reg_rab_nmb_data; + nt_register_t *mp_reg_rab_nmb_wr; + nt_register_t *mp_reg_rab_nmb_status; + + uint32_t rac_rab_init_addr; + uint32_t rac_rab_ib_data_addr; + uint32_t rac_rab_ob_data_addr; + uint32_t rac_rab_buf_free_addr; + uint32_t rac_rab_buf_used_addr; + + uint32_t rac_rab_dma_ib_lo_addr; + uint32_t rac_rab_dma_ib_hi_addr; + uint32_t rac_rab_dma_ob_lo_addr; + uint32_t rac_rab_dma_ob_hi_addr; + uint32_t rac_rab_dma_ib_rd_addr; + uint32_t rac_rab_dma_ob_wr_addr; + uint32_t rac_rab_dma_ib_wr_addr; + + uint32_t rac_rab_buf_free_ib_free_mask; + uint32_t rac_rab_buf_free_ob_free_mask; + uint32_t rac_rab_buf_used_ib_used_mask; + uint32_t rac_rab_buf_used_ob_used_mask; + uint32_t rac_rab_buf_used_flush_mask; + + uint32_t rac_rab_buf_used_ob_used_low; + + uint32_t rac_nmb_rd_adr_addr; + uint32_t rac_nmb_data_addr; + uint32_t rac_nmb_wr_adr_addr; + uint32_t rac_nmb_status_addr; + + bool m_dma_active; + + struct nt_dma_s *m_dma; + + volatile uint32_t *m_dma_in_buf; + volatile uint32_t *m_dma_out_buf; + + uint16_t m_dma_out_ptr_rd; + uint16_t m_dma_in_ptr_wr; + uint32_t m_in_free; +}; + +typedef struct nthw_rac nthw_rac_t; +typedef struct nthw_rac nthw_rac; + +struct dma_buf_ptr { + uint32_t size; + uint32_t index; + volatile uint32_t *base; +}; + +nthw_rac_t *nthw_rac_new(void); +void nthw_rac_delete(nthw_rac_t *p); +int nthw_rac_init(nthw_rac_t *p, nt_fpga_t *p_fpga, struct fpga_info_s *p_fpga_info); + +int nthw_rac_get_rab_interface_count(const nthw_rac_t *p); + +int nthw_rac_rab_init(nthw_rac_t *p, uint32_t rab_intf_mask); + +int nthw_rac_rab_setup(nthw_rac_t *p); + +int nthw_rac_rab_reset(nthw_rac_t *p); + +int nthw_rac_rab_write32(nthw_rac_t *p, uint32_t address, rab_bus_id_t bus_id, + uint32_t word_cnt, const uint32_t *p_data); +int nthw_rac_rab_write32_dma(nthw_rac_t *p, uint32_t address, rab_bus_id_t bus_id, + uint32_t word_cnt, const uint32_t *p_data); +int nthw_rac_rab_read32(nthw_rac_t *p, uint32_t address, rab_bus_id_t bus_id, + uint32_t word_cnt, uint32_t *p_data); +int nthw_rac_rab_read32_dma(nthw_rac_t *p, uint32_t address, rab_bus_id_t bus_id, + uint32_t word_cnt, struct dma_buf_ptr *buf_ptr); + +int nthw_rac_rab_flush(nthw_rac_t *p); + +int nthw_rac_rab_dma_begin(nthw_rac_t *p); +int nthw_rac_rab_dma_commit(nthw_rac_t *p); + +void nthw_rac_reg_read32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t *p_data); +void nthw_rac_reg_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t p_data); + +#endif /* __NTHW_RAC_H__ */ diff --git a/drivers/net/ntnic/nthw/nthw_register.h b/drivers/net/ntnic/nthw/nthw_register.h index 5cdbd9fc5d..4fe3496b9f 100644 --- a/drivers/net/ntnic/nthw/nthw_register.h +++ b/drivers/net/ntnic/nthw/nthw_register.h @@ -10,6 +10,8 @@ #include #include +#include "nthw_fpga_model.h" + #include "fpga_model.h" #include "nthw_fpga_modules_defs.h" diff --git a/drivers/net/ntnic/nthw/nthw_stat.c b/drivers/net/ntnic/nthw/nthw_stat.c new file mode 100644 index 0000000000..fbecbc2dba --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_stat.c @@ -0,0 +1,266 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "nt_util.h" +#include "ntlog.h" + +#include "nthw_drv.h" +#include "nthw_register.h" + +#include "nthw_stat.h" + +#include + +nthw_stat_t *nthw_stat_new(void) +{ + nthw_stat_t *p = malloc(sizeof(nthw_stat_t)); + + if (p) + memset(p, 0, sizeof(nthw_stat_t)); + return p; +} + +void nthw_stat_delete(nthw_stat_t *p) +{ + if (p) + free(p); +} + +int nthw_stat_init(nthw_stat_t *p, nt_fpga_t *p_fpga, int n_instance) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + uint64_t n_module_version_packed64 = -1; + nt_module_t *mod = fpga_query_module(p_fpga, MOD_STA, n_instance); + + if (p == NULL) + return mod == NULL ? -1 : 0; + + if (mod == NULL) { + NT_LOG(ERR, NTHW, "%s: STAT %d: no such instance\n", + p_adapter_id_str, n_instance); + return -1; + } + + p->mp_fpga = p_fpga; + p->mn_instance = n_instance; + p->mp_mod_stat = mod; + + n_module_version_packed64 = module_get_version_packed64(p->mp_mod_stat); + NT_LOG(DBG, NTHW, "%s: STAT %d: version=0x%08lX\n", p_adapter_id_str, + p->mn_instance, n_module_version_packed64); + + { + nt_register_t *p_reg; + /* STA_CFG register */ + p_reg = module_get_register(p->mp_mod_stat, STA_CFG); + p->mp_fld_dma_ena = register_get_field(p_reg, STA_CFG_DMA_ENA); + p->mp_fld_cnt_clear = register_get_field(p_reg, STA_CFG_CNT_CLEAR); + + /* CFG: fields NOT available from v. 3 */ + p->mp_fld_tx_disable = + register_query_field(p_reg, STA_CFG_TX_DISABLE); + p->mp_fld_cnt_freeze = register_query_field(p_reg, STA_CFG_CNT_FRZ); + + /* STA_STATUS register */ + p_reg = module_get_register(p->mp_mod_stat, STA_STATUS); + p->mp_fld_stat_toggle_missed = + register_get_field(p_reg, STA_STATUS_STAT_TOGGLE_MISSED); + + /* HOST_ADR registers */ + p_reg = module_get_register(p->mp_mod_stat, STA_HOST_ADR_LSB); + p->mp_fld_dma_lsb = register_get_field(p_reg, STA_HOST_ADR_LSB_LSB); + + p_reg = module_get_register(p->mp_mod_stat, STA_HOST_ADR_MSB); + p->mp_fld_dma_msb = register_get_field(p_reg, STA_HOST_ADR_MSB_MSB); + } + + /* Params */ + p->mb_is_vswitch = p_fpga->p_fpga_info->profile == FPGA_INFO_PROFILE_VSWITCH; + + p->m_nb_nim_ports = fpga_get_product_param(p_fpga, NT_NIMS, 0); + p->m_nb_phy_ports = fpga_get_product_param(p_fpga, NT_PHY_PORTS, 0); + + p->m_nb_rx_ports = + fpga_get_product_param(p_fpga, NT_STA_RX_PORTS, -1); /* VSWITCH */ + if (p->m_nb_rx_ports == -1) { + p->m_nb_rx_ports = fpga_get_product_param(p_fpga, NT_RX_PORTS, + -1); /* non-VSWITCH */ + if (p->m_nb_rx_ports == -1) { + p->m_nb_rx_ports = fpga_get_product_param(p_fpga, + NT_PORTS, + 0); /* non-VSWITCH */ + } + } + + p->m_nb_tx_ports = fpga_get_product_param(p_fpga, NT_TX_PORTS, 0); + p->m_rx_port_replicate = + fpga_get_product_param(p_fpga, NT_RX_PORT_REPLICATE, 0); + + p->m_nb_color_counters = fpga_get_product_param(p_fpga, NT_STA_COLORS, 64) * + 2; /* VSWITCH */ + if (p->m_nb_color_counters == 0) { + p->m_nb_color_counters = + fpga_get_product_param(p_fpga, NT_CAT_FUNCS, 0) * + 2; /* non-VSWITCH */ + } + + p->m_nb_rx_host_buffers = fpga_get_product_param(p_fpga, NT_QUEUES, 0); + p->m_nb_tx_host_buffers = p->m_nb_rx_host_buffers; + + p->m_dbs_present = fpga_get_product_param(p_fpga, NT_DBS_PRESENT, 0); + + p->m_nb_rx_hb_counters = + (p->m_nb_rx_host_buffers * + (6 + 2 * (n_module_version_packed64 >= VERSION_PACKED64(0, 6) ? + p->m_dbs_present : + 0))); + + p->m_nb_tx_hb_counters = 0; + + p->m_nb_rx_port_counters = + 42 + 2 * (n_module_version_packed64 >= VERSION_PACKED64(0, 6) ? + p->m_dbs_present : + 0); + p->m_nb_tx_port_counters = 0; + + p->m_nb_counters = + p->m_nb_color_counters + p->m_nb_rx_hb_counters + p->m_nb_tx_hb_counters; + + p->mn_stat_layout_version = 0; + if (n_module_version_packed64 >= VERSION_PACKED64(0, 8)) { + p->mn_stat_layout_version = 6; + } else if (n_module_version_packed64 >= VERSION_PACKED64(0, 6)) { + p->mn_stat_layout_version = 5; + } else if (n_module_version_packed64 >= VERSION_PACKED64(0, 4)) { + p->mn_stat_layout_version = 4; + } else if (n_module_version_packed64 >= VERSION_PACKED64(0, 3)) { + p->mn_stat_layout_version = 3; + } else if (n_module_version_packed64 >= VERSION_PACKED64(0, 2)) { + p->mn_stat_layout_version = 2; + } else if (n_module_version_packed64 > VERSION_PACKED64(0, 0)) { + p->mn_stat_layout_version = 1; + } else { + p->mn_stat_layout_version = 0; + NT_LOG(ERR, NTHW, + "%s: unknown module_version 0x%08lX layout=%d\n", + p_adapter_id_str, n_module_version_packed64, + p->mn_stat_layout_version); + } + assert(p->mn_stat_layout_version); + + /* STA module 0.2+ adds IPF counters per port (Rx feature) */ + if (n_module_version_packed64 >= VERSION_PACKED64(0, 2)) + p->m_nb_rx_port_counters += 6; + + /* STA module 0.3+ adds TX stats */ + if (n_module_version_packed64 >= VERSION_PACKED64(0, 3) || + p->m_nb_tx_ports >= 1) + p->mb_has_tx_stats = true; + + /* STA module 0.3+ adds TX stat counters */ + if (n_module_version_packed64 >= VERSION_PACKED64(0, 3)) + p->m_nb_tx_port_counters += 22; + + /* STA module 0.4+ adds TX drop event counter */ + if (n_module_version_packed64 >= VERSION_PACKED64(0, 4)) + p->m_nb_tx_port_counters += 1; /* TX drop event counter */ + + /* + * STA module 0.6+ adds pkt filter drop octets+pkts, retransmit and + * duplicate counters + */ + if (n_module_version_packed64 >= VERSION_PACKED64(0, 6)) { + p->m_nb_rx_port_counters += 4; + p->m_nb_tx_port_counters += 1; + } + + if (p->mb_is_vswitch) { + p->m_nb_rx_port_counters = 5; + p->m_nb_tx_port_counters = 5; + } + + p->m_nb_counters += (p->m_nb_rx_ports * p->m_nb_rx_port_counters); + + if (p->mb_has_tx_stats) + p->m_nb_counters += (p->m_nb_tx_ports * p->m_nb_tx_port_counters); + + /* Output params (debug) */ + NT_LOG(DBG, NTHW, + "%s: nims=%d rxports=%d txports=%d rxrepl=%d colors=%d queues=%d\n", + p_adapter_id_str, p->m_nb_nim_ports, p->m_nb_rx_ports, p->m_nb_tx_ports, + p->m_rx_port_replicate, p->m_nb_color_counters, p->m_nb_rx_host_buffers); + NT_LOG(DBG, NTHW, + "%s: hbs=%d hbcounters=%d rxcounters=%d txcounters=%d\n", + p_adapter_id_str, p->m_nb_rx_host_buffers, p->m_nb_rx_hb_counters, + p->m_nb_rx_port_counters, p->m_nb_tx_port_counters); + NT_LOG(DBG, NTHW, "%s: layout=%d\n", p_adapter_id_str, + p->mn_stat_layout_version); + NT_LOG(DBG, NTHW, "%s: counters=%d (0x%X)\n", p_adapter_id_str, + p->m_nb_counters, p->m_nb_counters); + NT_LOG(DBG, NTHW, "%s: vswitch=%d\n", p_adapter_id_str, p->mb_is_vswitch); + + /* Init */ + if (p->mp_fld_tx_disable) + field_set_flush(p->mp_fld_tx_disable); + + field_update_register(p->mp_fld_cnt_clear); + field_set_flush(p->mp_fld_cnt_clear); + field_clr_flush(p->mp_fld_cnt_clear); + + field_update_register(p->mp_fld_stat_toggle_missed); + field_set_flush(p->mp_fld_stat_toggle_missed); + + field_update_register(p->mp_fld_dma_ena); + field_clr_flush(p->mp_fld_dma_ena); + field_update_register(p->mp_fld_dma_ena); + + return 0; +} + +int nthw_stat_set_dma_address(nthw_stat_t *p, uint64_t stat_dma_physical, + uint32_t *p_stat_dma_virtual) +{ + assert(p_stat_dma_virtual); + p->mp_timestamp = NULL; + + p->m_stat_dma_physical = stat_dma_physical; + p->mp_stat_dma_virtual = p_stat_dma_virtual; + + memset(p->mp_stat_dma_virtual, 0, (p->m_nb_counters * sizeof(uint32_t))); + + field_set_val_flush32(p->mp_fld_dma_msb, + (uint32_t)((p->m_stat_dma_physical >> 32) & + 0xffffffff)); + field_set_val_flush32(p->mp_fld_dma_lsb, + (uint32_t)(p->m_stat_dma_physical & 0xffffffff)); + + p->mp_timestamp = (uint64_t *)(p->mp_stat_dma_virtual + p->m_nb_counters); + NT_LOG(DBG, NTHW, + "%s: statDmaPhysical=%" PRIX64 " p_stat_dma_virtual=%" PRIX64 + " mp_timestamp=%" PRIX64 "\n", + __func__, p->m_stat_dma_physical, p->mp_stat_dma_virtual, + p->mp_timestamp); + if (p->mb_is_vswitch) + *p->mp_timestamp = NT_OS_GET_TIME_NS(); + + else + *p->mp_timestamp = (uint64_t)(int64_t)-1; + return 0; +} + +int nthw_stat_trigger(nthw_stat_t *p) +{ + int n_toggle_miss = field_get_updated(p->mp_fld_stat_toggle_missed); + + if (n_toggle_miss) + field_set_flush(p->mp_fld_stat_toggle_missed); + + if (p->mp_timestamp) + *p->mp_timestamp = -1; /* Clear old ts */ + + field_update_register(p->mp_fld_dma_ena); + field_set_flush(p->mp_fld_dma_ena); + + return 0; +} diff --git a/drivers/net/ntnic/nthw/nthw_stat.h b/drivers/net/ntnic/nthw/nthw_stat.h new file mode 100644 index 0000000000..7bce7ecd15 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_stat.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_STAT_H__ +#define __NTHW_STAT_H__ + +struct nthw_stat { + nt_fpga_t *mp_fpga; + nt_module_t *mp_mod_stat; + int mn_instance; + + int mn_stat_layout_version; + + bool mb_is_vswitch; + bool mb_has_tx_stats; + + int m_nb_phy_ports; + int m_nb_nim_ports; + + int m_nb_rx_ports; + int m_nb_tx_ports; + + int m_nb_rx_host_buffers; + int m_nb_tx_host_buffers; + + int m_dbs_present; + + int m_rx_port_replicate; + + int m_nb_color_counters; + + int m_nb_rx_hb_counters; + int m_nb_tx_hb_counters; + + int m_nb_rx_port_counters; + int m_nb_tx_port_counters; + + int m_nb_counters; + + nt_field_t *mp_fld_dma_ena; + nt_field_t *mp_fld_cnt_clear; + + nt_field_t *mp_fld_tx_disable; + + nt_field_t *mp_fld_cnt_freeze; + + nt_field_t *mp_fld_stat_toggle_missed; + + nt_field_t *mp_fld_dma_lsb; + nt_field_t *mp_fld_dma_msb; + + uint64_t m_stat_dma_physical; + uint32_t *mp_stat_dma_virtual; + + uint64_t last_ts; + + uint64_t *mp_timestamp; +}; + +typedef struct nthw_stat nthw_stat_t; +typedef struct nthw_stat nthw_stat; + +nthw_stat_t *nthw_stat_new(void); +int nthw_stat_init(nthw_stat_t *p, nt_fpga_t *p_fpga, int n_instance); +void nthw_stat_delete(nthw_stat_t *p); + +int nthw_stat_set_dma_address(nthw_stat_t *p, uint64_t stat_dma_physical, + uint32_t *p_stat_dma_virtual); +int nthw_stat_trigger(nthw_stat_t *p); + +#endif /* __NTHW_STAT_H__ */ diff --git a/drivers/net/ntnic/ntlog/include/ntlog.h b/drivers/net/ntnic/ntlog/include/ntlog.h new file mode 100644 index 0000000000..81bc014d66 --- /dev/null +++ b/drivers/net/ntnic/ntlog/include/ntlog.h @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef NTOSS_SYSTEM_NTLOG_H +#define NTOSS_SYSTEM_NTLOG_H + +#include +#include + +#ifndef NT_LOG_MODULE_PREFIX + +/* DPDK modules */ +#define NT_LOG_MODULE_EAL 0 +#define NT_LOG_MODULE_MALLOC 1 +#define NT_LOG_MODULE_RING 2 +#define NT_LOG_MODULE_MEMPOOL 3 +#define NT_LOG_MODULE_TIMER 4 +#define NT_LOG_MODULE_PMD 5 +#define NT_LOG_MODULE_HASH 6 +#define NT_LOG_MODULE_LPM 7 +#define NT_LOG_MODULE_KNI 8 +#define NT_LOG_MODULE_ACL 9 +#define NT_LOG_MODULE_POWER 10 +#define NT_LOG_MODULE_METER 11 +#define NT_LOG_MODULE_SCHED 12 +#define NT_LOG_MODULE_PORT 13 +#define NT_LOG_MODULE_TABLE 14 +#define NT_LOG_MODULE_PIPELINE 15 +#define NT_LOG_MODULE_MBUF 16 +#define NT_LOG_MODULE_CRYPTODEV 17 +#define NT_LOG_MODULE_EFD 18 +#define NT_LOG_MODULE_EVENTDEV 19 +#define NT_LOG_MODULE_GSO 20 +#define NT_LOG_MODULE_USER1 24 +#define NT_LOG_MODULE_USER2 25 +#define NT_LOG_MODULE_USER3 26 +#define NT_LOG_MODULE_USER4 27 +#define NT_LOG_MODULE_USER5 28 +#define NT_LOG_MODULE_USER6 29 +#define NT_LOG_MODULE_USER7 30 +#define NT_LOG_MODULE_USER8 31 + +/* NT modules */ +#define NT_LOG_MODULE_GENERAL 10000 /* Should always be a first (smallest) */ +#define NT_LOG_MODULE_NTHW 10001 +#define NT_LOG_MODULE_FILTER 10002 +#define NT_LOG_MODULE_VDPA 10003 +#define NT_LOG_MODULE_FPGA 10004 +#define NT_LOG_MODULE_NTCONNECT 10005 +#define NT_LOG_MODULE_ETHDEV 10006 +#define NT_LOG_MODULE_END 10007 /* Mark for the range end of NT_LOG */ + +#define NT_LOG_MODULE_COUNT (NT_LOG_MODULE_END - NT_LOG_MODULE_GENERAL) +#define NT_LOG_MODULE_INDEX(module) ((module) - NT_LOG_MODULE_GENERAL) +#define NT_LOG_MODULE_PREFIX(type) NT_LOG_MODULE_##type + +#endif + +#ifndef NT_LOG_ENABLE +#define NT_LOG_ENABLE 1 +#endif + +#if defined NT_LOG_ENABLE && NT_LOG_ENABLE > 0 +#ifndef NT_LOG_ENABLE_ERR +#define NT_LOG_ENABLE_ERR 1 +#endif +#ifndef NT_LOG_ENABLE_WRN +#define NT_LOG_ENABLE_WRN 1 +#endif +#ifndef NT_LOG_ENABLE_INF +#define NT_LOG_ENABLE_INF 1 +#endif +#ifndef NT_LOG_ENABLE_DBG +#define NT_LOG_ENABLE_DBG 1 +#endif +#ifndef NT_LOG_ENABLE_DB1 +#define NT_LOG_ENABLE_DB1 0 +#endif +#ifndef NT_LOG_ENABLE_DB2 +#define NT_LOG_ENABLE_DB2 0 +#endif +#endif + +#if defined NT_LOG_ENABLE_ERR && NT_LOG_ENABLE_ERR > 0 +#define NT_LOG_NT_LOG_ERR(...) nt_log(__VA_ARGS__) +#else +#define NT_LOG_NT_LOG_ERR(...) +#endif + +#if defined NT_LOG_ENABLE_WRN && NT_LOG_ENABLE_WRN > 0 +#define NT_LOG_NT_LOG_WRN(...) nt_log(__VA_ARGS__) +#else +#define NT_LOG_NT_LOG_WRN(...) +#endif + +#if defined NT_LOG_ENABLE_INF && NT_LOG_ENABLE_INF > 0 +#define NT_LOG_NT_LOG_INF(...) nt_log(__VA_ARGS__) +#else +#define NT_LOG_NT_LOG_INF(...) +#endif + +#if defined NT_LOG_ENABLE_DBG && NT_LOG_ENABLE_DBG > 0 +#define NT_LOG_NT_LOG_DBG(...) nt_log(__VA_ARGS__) +#else +#define NT_LOG_NT_LOG_DBG(...) +#endif + +#if defined NT_LOG_ENABLE_DB1 && NT_LOG_ENABLE_DB1 > 0 +#define NT_LOG_NT_LOG_DB1(...) nt_log(__VA_ARGS__) +#else +#define NT_LOG_NT_LOG_DB1(...) +#endif + +#if defined NT_LOG_ENABLE_DB2 && NT_LOG_ENABLE_DB2 > 0 +#define NT_LOG_NT_LOG_DB2(...) nt_log(__VA_ARGS__) +#else +#define NT_LOG_NT_LOG_DB2(...) +#endif + +#define NT_LOG(level, module, ...) \ + NT_LOG_NT_LOG_##level(NT_LOG_##level, NT_LOG_MODULE_PREFIX(module), \ + #module ": " #level ": " __VA_ARGS__) + +enum nt_log_level { + NT_LOG_ERR = 0x001, + NT_LOG_WRN = 0x002, + NT_LOG_INF = 0x004, + NT_LOG_DBG = 0x008, + NT_LOG_DB1 = 0x010, + NT_LOG_DB2 = 0x020, +}; + +struct nt_log_impl { + int (*init)(void); + int (*log)(enum nt_log_level level, uint32_t module, const char *format, + va_list args); + int (*is_debug)(uint32_t module); +}; + +int nt_log_init(struct nt_log_impl *impl); + +int nt_log(enum nt_log_level level, uint32_t module, const char *format, ...); + +/* Returns 1 if RTE_DEBUG, 0 if lower log level, -1 if incorrect module */ +int nt_log_is_debug(uint32_t module); + +/* + * nt log helper functions + * to create a string for NT_LOG usage to output a one-liner log + * to use when one single function call to NT_LOG is not optimal - that is + * you do not know the number of parameters at programming time or it is variable + */ +char *ntlog_helper_str_alloc(const char *sinit); + +void ntlog_helper_str_reset(char *s, const char *sinit); + +void ntlog_helper_str_add(char *s, const char *format, ...); + +void ntlog_helper_str_free(char *s); + +#endif /* NTOSS_SYSTEM_NTLOG_H */ diff --git a/drivers/net/ntnic/ntlog/ntlog.c b/drivers/net/ntnic/ntlog/ntlog.c new file mode 100644 index 0000000000..def07f15d0 --- /dev/null +++ b/drivers/net/ntnic/ntlog/ntlog.c @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include "ntlog.h" + +#include +#include +#include +#include +#include +#include + +#include + +#define NTLOG_HELPER_STR_SIZE_MAX (1024) + +static struct nt_log_impl *user_impl; + +int nt_log_init(struct nt_log_impl *impl) +{ + user_impl = impl; + return user_impl->init(); +} + +static char *last_trailing_eol(char *s) +{ + int i = strlen(s) - 1; + /* Skip spaces */ + while (i > 0 && s[i] == ' ') + --i; + if (s[i] != '\n') + return NULL; + /* + * Find the last trailing EOL "hello_world\n\n\n" + * ^ + */ + while (i > 1 && s[i] == '\n' && s[i - 1] == '\n') + --i; + return &s[i]; +} + +/* Always terminates the NT_LOG statement with a !!!single!!! EOL. */ +int nt_log(enum nt_log_level level, uint32_t module, const char *format, ...) +{ + int rv = -1; + va_list args; + + if (user_impl == NULL) + return rv; + + char *actual_format = ntlog_helper_str_alloc(format); + char *eol = last_trailing_eol(actual_format); + + if (!eol) { /* If log line is not terminated with '\n' we add it. */ + strncat(actual_format, "\n", + NTLOG_HELPER_STR_SIZE_MAX - strlen(actual_format)); + } else { /* If multiple trailing EOLs, then keep just one of them. */ + *(eol + 1) = '\0'; + } + + va_start(args, format); + rv = user_impl->log(level, module, actual_format, args); + va_end(args); + + ntlog_helper_str_free(actual_format); + return rv; +} + +int nt_log_is_debug(uint32_t module) +{ + return user_impl->is_debug(module); +} + +char *ntlog_helper_str_alloc(const char *sinit) +{ + char *s = malloc(NTLOG_HELPER_STR_SIZE_MAX); + + if (!s) + return NULL; + if (sinit) + rte_strscpy(s, sinit, NTLOG_HELPER_STR_SIZE_MAX); + else + s[0] = '\0'; + return s; +} + +void ntlog_helper_str_reset(char *s, const char *sinit) +{ + if (s) { + if (sinit) + rte_strscpy(s, sinit, NTLOG_HELPER_STR_SIZE_MAX); + else + s[0] = '\0'; + } +} + +__rte_format_printf(2, 0) +void ntlog_helper_str_add(char *s, const char *format, ...) +{ + if (!s) + return; + va_list args; + + va_start(args, format); + int len = strlen(s); + + vsnprintf(&s[len], (NTLOG_HELPER_STR_SIZE_MAX - 1 - len), format, args); + va_end(args); +} + +void ntlog_helper_str_free(char *s) +{ + free(s); +} diff --git a/drivers/net/ntnic/ntutil/include/nt_util.h b/drivers/net/ntnic/ntutil/include/nt_util.h new file mode 100644 index 0000000000..cc6891e82c --- /dev/null +++ b/drivers/net/ntnic/ntutil/include/nt_util.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef NTOSS_SYSTEM_NT_UTIL_H +#define NTOSS_SYSTEM_NT_UTIL_H + +#include +#include +#include + +#define _unused __rte_unused + +#define PCIIDENT_TO_DOMAIN(pci_ident) \ + ((uint16_t)(((unsigned int)(pci_ident) >> 16) & 0xFFFFU)) +#define PCIIDENT_TO_BUSNR(pci_ident) \ + ((uint8_t)(((unsigned int)(pci_ident) >> 8) & 0xFFU)) +#define PCIIDENT_TO_DEVNR(pci_ident) \ + ((uint8_t)(((unsigned int)(pci_ident) >> 3) & 0x1FU)) +#define PCIIDENT_TO_FUNCNR(pci_ident) \ + ((uint8_t)(((unsigned int)(pci_ident) >> 0) & 0x7U)) + +#define PCIIDENT_PRINT_STR "%04x:%02x:%02x.%x" +#define BDF_TO_PCIIDENT(dom, bus, dev, fnc) \ + (((dom) << 16) | ((bus) << 8) | ((dev) << 3) | (fnc)) + +/* ALIGN: Align x to a boundary */ +#define ALIGN(x, a) \ + ({ \ + __typeof__(x) _a = (a); \ + ((x) + (_a - 1)) & ~(_a - 1); \ + }) + +/* PALIGN: Align pointer p to a boundary */ +#define PALIGN(p, a) ((__typeof__(p))ALIGN((unsigned long)(p), (a))) + +/* Allocation size matching minimum alignment of specified size */ +#define ALIGN_SIZE(_size_) (1 << rte_log2_u64(_size_)) + +#define NT_OS_WAIT_USEC(x) \ + rte_delay_us_sleep( \ + x) /* uses usleep which schedules out the calling thread */ +/* spins in a waiting loop calling pause asm instruction uses RDTSC - precise wait */ +#define NT_OS_WAIT_USEC_POLL(x) \ + rte_delay_us( \ + x) + +#define NT_OS_GET_TIME_US() \ + (rte_get_timer_cycles() / (rte_get_timer_hz() / 1000 / 1000)) +#define NT_OS_GET_TIME_NS() \ + (rte_get_timer_cycles() * 10 / (rte_get_timer_hz() / 1000 / 1000 / 100)) +#define NT_OS_GET_TIME_MONOTONIC_COUNTER() (rte_get_timer_cycles()) + +struct nt_dma_s { + uint64_t iova; + uint64_t addr; + uint64_t size; +}; + +struct nt_dma_s *nt_dma_alloc(uint64_t size, uint64_t align, int numa); +void nt_dma_free(struct nt_dma_s *vfio_addr); + +struct nt_util_vfio_impl { + int (*vfio_dma_map)(int vf_num, void *virt_addr, uint64_t *iova_addr, + uint64_t size); + int (*vfio_dma_unmap)(int vf_num, void *virt_addr, uint64_t iova_addr, + uint64_t size); +}; + +void nt_util_vfio_init(struct nt_util_vfio_impl *impl); + +#endif /* NTOSS_SYSTEM_NT_UTIL_H */ diff --git a/drivers/net/ntnic/ntutil/nt_util.c b/drivers/net/ntnic/ntutil/nt_util.c new file mode 100644 index 0000000000..8f5812bf8b --- /dev/null +++ b/drivers/net/ntnic/ntutil/nt_util.c @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "ntlog.h" +#include "nt_util.h" + +static struct nt_util_vfio_impl vfio_cb; + +void nt_util_vfio_init(struct nt_util_vfio_impl *impl) +{ + vfio_cb = *impl; +} + +struct nt_dma_s *nt_dma_alloc(uint64_t size, uint64_t align, int numa) +{ + int res; + struct nt_dma_s *vfio_addr; + + vfio_addr = rte_malloc(NULL, sizeof(struct nt_dma_s), 0); + if (!vfio_addr) { + NT_LOG(ERR, GENERAL, "VFIO rte_malloc failed\n"); + return NULL; + } + void *addr = rte_malloc_socket(NULL, size, align, numa); + + if (!addr) { + rte_free(vfio_addr); + NT_LOG(ERR, GENERAL, "VFIO rte_malloc_socket failed\n"); + return NULL; + } + res = vfio_cb.vfio_dma_map(0, addr, &vfio_addr->iova, + ALIGN_SIZE(size)); + if (res != 0) { + rte_free(addr); + rte_free(vfio_addr); + NT_LOG(ERR, GENERAL, "VFIO nt_dma_map failed\n"); + return NULL; + } + + vfio_addr->addr = (uint64_t)addr; + vfio_addr->size = ALIGN_SIZE(size); + + NT_LOG(DBG, GENERAL, + "VFIO DMA alloc addr=%" PRIX64 ", iova=%" PRIX64 + ", size=%u, align=0x%X\n", + vfio_addr->addr, vfio_addr->iova, vfio_addr->size, align); + + return vfio_addr; +} + +void nt_dma_free(struct nt_dma_s *vfio_addr) +{ + NT_LOG(DBG, GENERAL, + "VFIO DMA free addr=%" PRIX64 ", iova=%" PRIX64 ", size=%u\n", + vfio_addr->addr, vfio_addr->iova, vfio_addr->size); + + int res = vfio_cb.vfio_dma_unmap(0, (void *)(vfio_addr->addr), + vfio_addr->iova, vfio_addr->size); + if (res != 0) { + NT_LOG(WRN, GENERAL, + "VFIO DMA free FAILED addr=%" PRIX64 ", iova=%" PRIX64 + ", size=%u\n", + vfio_addr->addr, vfio_addr->iova, vfio_addr->size); + } + rte_free((void *)(vfio_addr->addr)); + rte_free(vfio_addr); +}