From patchwork Wed Jul 17 13:32:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serhii Iliushyk X-Patchwork-Id: 142468 X-Patchwork-Delegate: ferruh.yigit@amd.com 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 B090445635; Wed, 17 Jul 2024 15:34:39 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 0EC1D427C4; Wed, 17 Jul 2024 15:33:37 +0200 (CEST) Received: from egress-ip42a.ess.de.barracuda.com (egress-ip42a.ess.de.barracuda.com [18.185.115.201]) by mails.dpdk.org (Postfix) with ESMTP id 01CF940ED3 for ; Wed, 17 Jul 2024 15:33:29 +0200 (CEST) Received: from EUR05-DB8-obe.outbound.protection.outlook.com (mail-db8eur05lp2105.outbound.protection.outlook.com [104.47.17.105]) by mx-outbound13-209.eu-central-1a.ess.aws.cudaops.com (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Wed, 17 Jul 2024 13:33:26 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Po6dtzaQ64J/wz75rEkm5RkTcn9VUaXBg8OKjnlwKqJbW69f21UZgzBfSfF1DlFLaMiJVKOVqJxuxLU2rQFkRMHbrlCvWuyqqEGJq4YiTnBuy6FD5l/oE9Eg+fnig1A6iLE6lOtCN9rL6eMT9XYHswSEIhFS74lqARKq/wuI5KUXRoVr/N8eavwkYugcd2wCso1sn+lF/uFFJCd1GIvvxOcXZBSjndcdvzCzqfCKOuzfO1ebvH0P7TC/52txBknd5ViteHfmNJbrYN83Oh0diGR7EGeDs5xLVbZ4/TiuGWbFLN9d+8CVcQqF2etdVE3MNm+vgrkyzA7PyEYmk3TPOA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=PBzfeAFHYLTRgWZ8pGr8Any840AH2+FXJInP+Ivdm1s=; b=nn0vd7ujkWNf7QC7zKCJeCsUiOtnfqA664WESxwbQC0LXc70+AZa7go4lJcJm/a8qs8I+HzRuXOY7xzT8ef01JSWKKDeJw83dwfTYUhKZe/b5ytKPDLPxiTVidap9HMogQIko5Dmsv8S7Vk15uOOwfGDaLoK9cHkFbQxBmK9zhcawWswMMMSJWVOgar6GHXkApMCgOn7a3uUu+0jXXol5VOVs5cZXThiOMe8azGMGvpTO1p+3o62SXtXy2oIWhsG6URL7mxtX1yZmLmJjMqMXvawwd12ZmQF7oey8vJXA3TbhqbF8plvZqgZI5OHt4gibrAG1DLc5nFcnKnfev01yQ== 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=reject sp=reject pct=100) action=oreject header.from=napatech.com; dkim=none (message not signed); arc=none (0) 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=PBzfeAFHYLTRgWZ8pGr8Any840AH2+FXJInP+Ivdm1s=; b=CK30qstLPFn5JjCm6j/05JUIvHRrLvQMUE2PHCzOtklsLRd2gcjzF4vwuq9buzi85GqxJqIv5khP+hUxiIIo+b1qCF0X4cq+8PHh7Kylmh0AHZYycY3zppAob6RyUalCu4Ni5uZcUl6zv9J2g3OpmbcD0rlS7WjM5gG81hpNxkM= Received: from AM0PR04CA0092.eurprd04.prod.outlook.com (2603:10a6:208:be::33) by DB9P190MB1082.EURP190.PROD.OUTLOOK.COM (2603:10a6:10:22b::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7784.16; Wed, 17 Jul 2024 13:33:23 +0000 Received: from AM3PEPF0000A799.eurprd04.prod.outlook.com (2603:10a6:208:be:cafe::fd) by AM0PR04CA0092.outlook.office365.com (2603:10a6:208:be::33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7762.31 via Frontend Transport; Wed, 17 Jul 2024 13:33:23 +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=oreject 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=localhost.localdomain; Received: from localhost.localdomain (178.72.21.4) by AM3PEPF0000A799.mail.protection.outlook.com (10.167.16.104) with Microsoft SMTP Server id 15.20.7784.11 via Frontend Transport; Wed, 17 Jul 2024 13:33:22 +0000 From: Serhii Iliushyk To: dev@dpdk.org Cc: mko-plv@napatech.com, sil-plv@napatech.com, ckm@napatech.com, andrew.rybchenko@oktetlabs.ru, ferruh.yigit@amd.com Subject: [PATCH v10 10/21] net/ntnic: add FPGA modules for initialization Date: Wed, 17 Jul 2024 15:32:57 +0200 Message-ID: <20240717133313.3104239-10-sil-plv@napatech.com> X-Mailer: git-send-email 2.45.0 In-Reply-To: <20240717133313.3104239-1-sil-plv@napatech.com> References: <20240530144929.4127931-1-sil-plv@napatech.com> <20240717133313.3104239-1-sil-plv@napatech.com> MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: AM3PEPF0000A799:EE_|DB9P190MB1082:EE_ X-MS-Office365-Filtering-Correlation-Id: 7e228515-7cc9-48fd-876e-08dca66507a5 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|376014|36860700013|82310400026|1800799024; X-Microsoft-Antispam-Message-Info: 9BHUj+KUdQ5ePHsn9iMYi+8Uvo6apFXuOj6s0oos6ekIRk+p8i5hUgd+UzzhM4d3np6BphASCcicPojAX6UlU1VehpQcclMQMSaPqwDfast8SQ5fx4+hRl3v0sojyaLW5EpWhij5xpsl/jSk1PfMtnStqa60jU0z825MEmjOxNPAvRMkkZKowtqfEHZ4YAAWjH3VcSwrllA5nkEhYnbQcfCp6smV5l60h3wBHQycng9nfCOOZXciTonoBzvHs4MWHNZff42ooIxKOhdtaVjoi/9qfTMkeC3orUtd4//hzsh6jxJ4Ny4Wpy1Ppinp/CLOKUWyJGObAhPMJ6md1VidMa3imo/eaVC2DUMOrwcqtAXrM5RYzTcQpv4pfUK6g1crnXKibSTgwKUoPTGiF3dJhoaFoUF+zm8BImJdyZ9mNIF6gbYrrJugPDSnQ902I9NoYzxFrGhS9xseCVYuBUvxR+FVCWizFZT6h4firBVDDPQ/V9ZqE3ghVSbsZdmuwpVH1pqyEGdIXpFKsLeqctCRRzjO4GM3oGIPkTtEZfh+Mw6uZ3FBbeLF8F319WFGR4/9VktrHG9GYd9RGZFkSWV09Vgauqb01ogpUeXtUXCznVqySVJPNc6ptjxYsgIEcDG6rlDkH8x9cRLW9NO0K+q5jnxzIy7RzUvzm6BPmTQSewP4dkieiGJQ8/UrL2NEevfX0wiVIoJ+1VKRGjtRViiXBFMotxf1izZ6gFddeedapJZtqp2qPjx36umZ660o+Dsp4pXUu1RR6sYiHHUSTi5u2SG4NGH+Iix8BbzMHnqKyforwSVWc2MY4zYyC+0vj/nflKJaeF3DcuLQ97tA8ziPXzg+QcRg7JQz1FtSzoRCkhzSH8Py2eHWEQtHtenivMI9bBVAeCeysEAbcR+YGx4Z93mQVXSVd8lBp8FRweAXl/42/xzUjEJHWS3olyYDnWRUA5aNY+nzSlZYokVO+TIBtrokN2DxbP+UHdMzhxqAJ+EJhZHm8AvuCuqeAkT0eYgMPvQPmqQUvBs4NoC2egoZzZuWPYDj+9vtXU5v8tYn6pE04k55V8hOS59yHrKhbABQcuMwok3GkVOovyS1AjSK/0rIpBmOO4cG5kyrIsesT9lp9TnU7U7JkgkrCYJkjLXn/OoL9xI3tOA1pfL69itn6bmGUQ/EKxDQCxhUr1AfyIV+6TR8yC9FrrAd5+Xhu/2ZAMoeGv2NFaMA4YoSGA2TjXf6hcPvo6qYe3T8hT7SeRpdd4zrQ3Ujxo8B3WCUB6GkwTBnt7l4YKNehPnIqZ2hoDAbHLJf5wHlqk8lLIcGESV6+N08GNKPa+3+eubY1owdgCBiIIhl6K+7A/k5Uq6Pov12PnfS5/i1fa4I2GtTFTo9AHLk2hJ51oxUJb/i8T3kIh0RhkMs2oKxvzPonEytfV6vzq+zpTKND/TyCvp5ReM5QK1lzZ5ZLkCwVUrhHL35 X-Forefront-Antispam-Report: CIP:178.72.21.4; CTRY:DK; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:localhost.localdomain; PTR:InfoDomainNonexistent; CAT:NONE; SFS:(13230040)(376014)(36860700013)(82310400026)(1800799024); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0: hxp9+JYJ8sfDTYlEFgEnEsTw9Pt0tmsYyjrtusszLDliad6kH5ZDdkrjqbPG/m85//VJLG41OGTzLFClYFt2aq3DtJT6ZHLAA5JJnOqntmMN8JXHYNpMsxfxJpDeNFAvBV0WqweTjv1w32kSu2cZt7avrSelv592MNpBVAPopcBwPaLWbd4jIUlHGGHp2wlhGY9y83QW3X9voigZIhMyRt5B5dTUpr4f6hPX4DRbWmib1MfN53VngjuhhDG1UjfnWWNuYwUSmFxsideI1aQIivo2MhhoUJ/YyYl3rpF8dVMsuWSPsdQW9+ReGUzVr43rBceeCG9Slixda1UhFIRAJj3L5bIvzbDd86ktJKSlKwKvcNQr++/Q5Hp2VmKq2P9KGkTOU8OU7urjWzAOb1hjqzQRgzhb5OfFygYxt/2AV0Dy6sVENoGb72PR96dpEzUu3QxPUwv0piMH6ntakvfkPm0NUqUPrRAGh8Zl+6qc4Q4dASzVTfUqrmH3rM06eFlqDilrLbNQGliOqUdHP4HLvpwUy4AvWG0g5PguyfsGfyNLmWssGN1zZWnXZhMAA/gKZAf3a4f6myTk3eQhSJEUqc2b/0wmxExHj2lfv5EiMwne31G704t38rTTFTPVmqeHUjZtjIcu5Ok84GDAmEyHDw== X-OriginatorOrg: napatech.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Jul 2024 13:33:22.8557 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7e228515-7cc9-48fd-876e-08dca66507a5 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=[localhost.localdomain] X-MS-Exchange-CrossTenant-AuthSource: AM3PEPF0000A799.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9P190MB1082 X-BESS-ID: 1721223206-303537-12650-15880-1 X-BESS-VER: 2019.1_20240716.1757 X-BESS-Apparent-Source-IP: 104.47.17.105 X-BESS-Parts: H4sIAAAAAAACA4uuVkqtKFGyUioBkjpK+cVKVuaWlqYGQGYGUDTFKNnUMtkw2d Q0zSzZKDXNNNXC0Ngw0dzY0NwiOTElVak2FgAPYuJbQgAAAA== X-BESS-Outbound-Spam-Score: 0.50 X-BESS-Outbound-Spam-Report: Code version 3.2, rules version 3.2.2.257687 [from cloudscan22-138.eu-central-1b.ess.aws.cudaops.com] Rule breakdown below pts rule name description ---- ---------------------- -------------------------------- 0.50 BSF_RULE7568M META: Custom Rule 7568M 0.00 BSF_BESS_OUTBOUND META: BESS Outbound X-BESS-Outbound-Spam-Status: SCORE=0.50 using account:ESS113687 scores of KILL_LEVEL=7.0 tests=BSF_RULE7568M, BSF_BESS_OUTBOUND 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 New ntnic FPGA modules: - Host Interface (HIF): Basic FPGA info such as prod ID and build time. - Inter-Integrated Circuit Controller (IIC): Use the FPGA to access the other integrated circuits on the ntnic. - PCI Express Gen3 (PCIE3): The FPGA part of PCIe3 initialization, speed tests, and configuration. Signed-off-by: Serhii Iliushyk --- v6 * Remove unnecessary comments v10 * Use 8 spaces as indentation in meson DVO: Remove unnecessary comments --- drivers/net/ntnic/meson.build | 1 + .../net/ntnic/nthw/core/include/nthw_core.h | 16 + .../net/ntnic/nthw/core/include/nthw_hif.h | 151 ++++ .../net/ntnic/nthw/core/include/nthw_iic.h | 100 +++ .../net/ntnic/nthw/core/include/nthw_pcie3.h | 96 +++ drivers/net/ntnic/nthw/core/nthw_hif.c | 312 +++++++ drivers/net/ntnic/nthw/core/nthw_iic.c | 527 ++++++++++++ drivers/net/ntnic/nthw/core/nthw_pcie3.c | 259 ++++++ drivers/net/ntnic/nthw/nthw_drv.h | 3 +- drivers/net/ntnic/nthw/nthw_rac.c | 784 ++++++++++++++++++ drivers/net/ntnic/nthw/nthw_rac.h | 153 ++++ 11 files changed, 2400 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_core.h create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_hif.h create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_iic.h create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_pcie3.h create mode 100644 drivers/net/ntnic/nthw/core/nthw_hif.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_iic.c create mode 100644 drivers/net/ntnic/nthw/core/nthw_pcie3.c create mode 100644 drivers/net/ntnic/nthw/nthw_rac.c create mode 100644 drivers/net/ntnic/nthw/nthw_rac.h diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build index 399b616278..a3522ca20b 100644 --- a/drivers/net/ntnic/meson.build +++ b/drivers/net/ntnic/meson.build @@ -13,6 +13,7 @@ includes = [ include_directories('include'), include_directories('ntlog'), include_directories('ntutil'), + include_directories('nthw/core/include'), include_directories('nthw'), include_directories('nthw/supported'), ] diff --git a/drivers/net/ntnic/nthw/core/include/nthw_core.h b/drivers/net/ntnic/nthw/core/include/nthw_core.h new file mode 100644 index 0000000000..c2602e396f --- /dev/null +++ b/drivers/net/ntnic/nthw/core/include/nthw_core.h @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_CORE_H__ +#define __NTHW_CORE_H__ + +#include +#include +#include + +#include "nthw_platform_drv.h" + + +#endif /* __NTHW_CORE_H__ */ diff --git a/drivers/net/ntnic/nthw/core/include/nthw_hif.h b/drivers/net/ntnic/nthw/core/include/nthw_hif.h new file mode 100644 index 0000000000..c8f4669f83 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/include/nthw_hif.h @@ -0,0 +1,151 @@ +/* + * 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 { + nthw_fpga_t *mp_fpga; + nthw_module_t *mp_mod_hif; + int mn_instance; + + nthw_register_t *mp_reg_ctrl; + nthw_field_t *mp_fld_ctrl_fsr; + + nthw_register_t *mp_reg_prod_id_lsb; + nthw_field_t *mp_fld_prod_id_lsb_rev_id; + nthw_field_t *mp_fld_prod_id_lsb_ver_id; + nthw_field_t *mp_fld_prod_id_lsb_group_id; + + nthw_register_t *mp_reg_prod_id_msb; + nthw_field_t *mp_fld_prod_id_msb_type_id; + nthw_field_t *mp_fld_prod_id_msb_build_no; + + nthw_register_t *mp_reg_build_time; + nthw_field_t *mp_fld_build_time; + + nthw_register_t *mp_reg_build_seed; + nthw_field_t *mp_fld_build_seed; + + nthw_register_t *mp_reg_core_speed; + nthw_field_t *mp_fld_core_speed; + nthw_field_t *mp_fld_ddr3_speed; + + nthw_register_t *mp_reg_int_mask; + nthw_field_t *mp_fld_int_mask_timer; + nthw_field_t *mp_fld_int_mask_port; + nthw_field_t *mp_fld_int_mask_pps; + + nthw_register_t *mp_reg_int_clr; + nthw_field_t *mp_fld_int_clr_timer; + nthw_field_t *mp_fld_int_clr_port; + nthw_field_t *mp_fld_int_clr_pps; + + nthw_register_t *mp_reg_int_force; + nthw_field_t *mp_fld_int_force_timer; + nthw_field_t *mp_fld_int_force_port; + nthw_field_t *mp_fld_int_force_pps; + + nthw_register_t *mp_reg_sample_time; + nthw_field_t *mp_fld_sample_time; + + nthw_register_t *mp_reg_status; + nthw_field_t *mp_fld_status_tags_in_use; + nthw_field_t *mp_fld_status_wr_err; + nthw_field_t *mp_fld_status_rd_err; + + nthw_register_t *mp_reg_stat_ctrl; + nthw_field_t *mp_fld_stat_ctrl_ena; + nthw_field_t *mp_fld_stat_ctrl_req; + + nthw_register_t *mp_reg_stat_rx; + nthw_field_t *mp_fld_stat_rx_counter; + + nthw_register_t *mp_reg_stat_tx; + nthw_field_t *mp_fld_stat_tx_counter; + + nthw_register_t *mp_reg_stat_ref_clk; + nthw_field_t *mp_fld_stat_ref_clk_ref_clk; + + nthw_register_t *mp_reg_pci_test0; + nthw_field_t *mp_fld_pci_test0; + + nthw_register_t *mp_reg_pci_test1; + nthw_field_t *mp_fld_pci_test1; + + nthw_register_t *mp_reg_pci_test2; + nthw_field_t *mp_fld_pci_test2; + + nthw_register_t *mp_reg_pci_test3; + nthw_field_t *mp_fld_pci_test3; + + nthw_register_t *mp_reg_config; + nthw_field_t *mp_fld_max_tlp; + nthw_field_t *mp_fld_max_read; + nthw_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; + +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, nthw_fpga_t *p_fpga, int n_instance); + +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_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/include/nthw_iic.h b/drivers/net/ntnic/nthw/core/include/nthw_iic.h new file mode 100644 index 0000000000..41574f51f3 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/include/nthw_iic.h @@ -0,0 +1,100 @@ +/* + * 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 { + nthw_fpga_t *mp_fpga; + nthw_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; + + nthw_register_t *mp_reg_tsusta; + nthw_field_t *mp_fld_tsusta; + + nthw_register_t *mp_reg_tsusto; + nthw_field_t *mp_fld_tsusto; + + nthw_register_t *mp_reg_thdsta; + nthw_field_t *mp_fld_thdsta; + + nthw_register_t *mp_reg_tsudat; + nthw_field_t *mp_fld_tsudat; + + nthw_register_t *mp_reg_tbuf; + nthw_field_t *mp_fld_tbuf; + + nthw_register_t *mp_reg_thigh; + nthw_field_t *mp_fld_thigh; + + nthw_register_t *mp_reg_tlow; + nthw_field_t *mp_fld_tlow; + + nthw_register_t *mp_reg_thddat; + nthw_field_t *mp_fld_thddat; + + nthw_register_t *mp_reg_cr; + nthw_field_t *mp_fld_cr_en; + nthw_field_t *mp_fld_cr_msms; + nthw_field_t *mp_fld_cr_txfifo_reset; + nthw_field_t *mp_fld_cr_txak; + + nthw_register_t *mp_reg_sr; + nthw_field_t *mp_fld_sr_bb; + nthw_field_t *mp_fld_sr_rxfifo_full; + nthw_field_t *mp_fld_sr_rxfifo_empty; + nthw_field_t *mp_fld_sr_txfifo_full; + nthw_field_t *mp_fld_sr_txfifo_empty; + + nthw_register_t *mp_reg_tx_fifo; + nthw_field_t *mp_fld_tx_fifo_txdata; + nthw_field_t *mp_fld_tx_fifo_start; + nthw_field_t *mp_fld_tx_fifo_stop; + + nthw_register_t *mp_reg_rx_fifo_pirq; + nthw_field_t *mp_fld_rx_fifo_pirq_cmp_val; + + nthw_register_t *mp_reg_rx_fifo; + nthw_field_t *mp_fld_rx_fifo_rxdata; + + nthw_register_t *mp_reg_softr; + nthw_field_t *mp_fld_softr_rkey; +}; + +typedef struct nthw_iic nthw_iic_t; + +nthw_iic_t *nthw_iic_new(void); +int nthw_iic_init(nthw_iic_t *p, nthw_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 a_reg_addr, uint8_t data_len, + void *p_void); +int nthw_iic_readbyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_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 a_reg_addr, uint8_t data_len, + void *p_void); +int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_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); + +#endif /* __NTHW_IIC_H__ */ diff --git a/drivers/net/ntnic/nthw/core/include/nthw_pcie3.h b/drivers/net/ntnic/nthw/core/include/nthw_pcie3.h new file mode 100644 index 0000000000..846c09b1b9 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/include/nthw_pcie3.h @@ -0,0 +1,96 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_PCIE3_H__ +#define __NTHW_PCIE3_H__ + +struct nthw_pcie3 { + nthw_fpga_t *mp_fpga; + nthw_module_t *mp_mod_pcie3; + int mn_instance; + + nthw_register_t *mp_reg_stat_ctrl; + nthw_field_t *mp_fld_stat_ctrl_req; + nthw_field_t *mp_fld_stat_ctrl_ena; + + nthw_register_t *mp_reg_stat_rx; + nthw_field_t *mp_fld_stat_rx_counter; + + nthw_register_t *mp_reg_stat_tx; + nthw_field_t *mp_fld_stat_tx_counter; + + nthw_register_t *mp_reg_stat_rq_rdy; + nthw_field_t *mp_fld_stat_rq_rdy_counter; + + nthw_register_t *mp_reg_stat_rq_vld; + nthw_field_t *mp_fld_stat_rq_vld_counter; + + nthw_register_t *mp_reg_status0; + nthw_field_t *mp_fld_status0_tags_in_use; + + nthw_register_t *mp_reg_stat_ref_clk; + nthw_field_t *mp_fld_stat_ref_clk_ref_clk; + + nthw_register_t *mp_reg_rp_to_ep_err; + nthw_field_t *mp_fld_rp_to_ep_err_cor; + nthw_field_t *mp_fld_rp_to_ep_err_non_fatal; + nthw_field_t *mp_fld_rp_to_ep_err_fatal; + + nthw_register_t *mp_reg_ep_to_rp_err; + nthw_field_t *mp_fld_ep_to_rp_err_cor; + nthw_field_t *mp_fld_ep_to_rp_err_non_fatal; + nthw_field_t *mp_fld_ep_to_rp_err_fatal; + + nthw_register_t *mp_reg_sample_time; + nthw_field_t *mp_fld_sample_time; + + nthw_register_t *mp_reg_pci_end_point; + nthw_field_t *mp_fld_pci_end_point_if_id; + nthw_field_t *mp_fld_pci_end_point_send_msg; + nthw_field_t *mp_fld_pci_end_point_get_msg; + nthw_field_t *mp_fld_pci_end_point_dmaep0_allow_mask; + nthw_field_t *mp_fld_pci_end_point_dmaep1_allow_mask; + + nthw_register_t *mp_reg_pci_e3_mark_adr_lsb; + nthw_field_t *mp_fld_pci_e3_mark_adr_lsb_adr; + + nthw_register_t *mp_reg_pci_e3_mark_adr_msb; + nthw_field_t *mp_fld_pci_e3_mark_adr_msb_adr; + + nthw_register_t *mp_reg_pci_test0; + nthw_field_t *mp_fld_pci_test0; + + nthw_register_t *mp_reg_pci_test1; + nthw_field_t *mp_fld_pci_test1; + + nthw_register_t *mp_reg_pci_test2; + nthw_field_t *mp_fld_pci_test2; + + nthw_register_t *mp_reg_pci_test3; + nthw_field_t *mp_fld_pci_test3; +}; + +typedef struct nthw_pcie3 nthw_pcie3_t; + +nthw_pcie3_t *nthw_pcie3_new(void); +void nthw_pcie3_delete(nthw_pcie3_t *p); +int nthw_pcie3_init(nthw_pcie3_t *p, nthw_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_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_hif.c b/drivers/net/ntnic/nthw/core/nthw_hif.c new file mode 100644 index 0000000000..f05e1a0c51 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_hif.c @@ -0,0 +1,312 @@ +/* + * 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, nthw_fpga_t *p_fpga, int n_instance) +{ + const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str; + (void)p_adapter_id_str; + nthw_module_t *mod = nthw_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 = nthw_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 = nthw_module_get_register(p->mp_mod_hif, HIF_PROD_ID_LSB); + p->mp_fld_prod_id_lsb_rev_id = + nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_REV_ID); + p->mp_fld_prod_id_lsb_ver_id = + nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_VER_ID); + p->mp_fld_prod_id_lsb_group_id = + nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_GROUP_ID); + + p->mp_reg_prod_id_msb = nthw_module_get_register(p->mp_mod_hif, HIF_PROD_ID_MSB); + p->mp_fld_prod_id_msb_type_id = + nthw_register_get_field(p->mp_reg_prod_id_msb, HIF_PROD_ID_MSB_TYPE_ID); + p->mp_fld_prod_id_msb_build_no = + nthw_register_get_field(p->mp_reg_prod_id_msb, HIF_PROD_ID_MSB_BUILD_NO); + + p->mp_reg_build_time = nthw_module_get_register(p->mp_mod_hif, HIF_BUILD_TIME); + p->mp_fld_build_time = nthw_register_get_field(p->mp_reg_build_time, HIF_BUILD_TIME_TIME); + + p->mn_fpga_id_prod = nthw_field_get_updated(p->mp_fld_prod_id_lsb_group_id); + p->mn_fpga_id_ver = nthw_field_get_updated(p->mp_fld_prod_id_lsb_ver_id); + p->mn_fpga_id_rev = nthw_field_get_updated(p->mp_fld_prod_id_lsb_rev_id); + p->mn_fpga_id_build_no = nthw_field_get_updated(p->mp_fld_prod_id_msb_build_no); + p->mn_fpga_id_item = nthw_field_get_updated(p->mp_fld_prod_id_msb_type_id); + + NT_LOG(DBG, NTHW, "%s: HIF %d: %d-%d-%d-%d-%d\n", p_adapter_id_str, p->mn_instance, + 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: HIF ref clock: %d Hz (%d ticks/ps)\n", p_adapter_id_str, + p->mn_instance, 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_ctrl = nthw_module_get_register(p->mp_mod_hif, HIF_CONTROL); + p->mp_fld_ctrl_fsr = nthw_register_query_field(p->mp_reg_ctrl, HIF_CONTROL_FSR); + + p->mp_reg_stat_ctrl = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_CTRL); + p->mp_fld_stat_ctrl_ena = + nthw_register_get_field(p->mp_reg_stat_ctrl, HIF_STAT_CTRL_STAT_ENA); + p->mp_fld_stat_ctrl_req = + nthw_register_get_field(p->mp_reg_stat_ctrl, HIF_STAT_CTRL_STAT_REQ); + + p->mp_reg_stat_rx = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_RX); + p->mp_fld_stat_rx_counter = + nthw_register_get_field(p->mp_reg_stat_rx, HIF_STAT_RX_COUNTER); + + p->mp_reg_stat_tx = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_TX); + p->mp_fld_stat_tx_counter = + nthw_register_get_field(p->mp_reg_stat_tx, HIF_STAT_TX_COUNTER); + + p->mp_reg_stat_ref_clk = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_REFCLK); + p->mp_fld_stat_ref_clk_ref_clk = + nthw_register_get_field(p->mp_reg_stat_ref_clk, HIF_STAT_REFCLK_REFCLK250); + + p->mp_reg_status = nthw_module_query_register(p->mp_mod_hif, HIF_STATUS); + + if (p->mp_reg_status) { + p->mp_fld_status_tags_in_use = + nthw_register_query_field(p->mp_reg_status, HIF_STATUS_TAGS_IN_USE); + p->mp_fld_status_wr_err = + nthw_register_query_field(p->mp_reg_status, HIF_STATUS_WR_ERR); + p->mp_fld_status_rd_err = + nthw_register_query_field(p->mp_reg_status, HIF_STATUS_RD_ERR); + + } else { + p->mp_reg_status = nthw_module_query_register(p->mp_mod_hif, HIF_STATUS); + p->mp_fld_status_tags_in_use = + nthw_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 = nthw_module_get_register(p->mp_mod_hif, HIF_TEST0); + p->mp_fld_pci_test0 = nthw_register_get_field(p->mp_reg_pci_test0, HIF_TEST0_DATA); + + p->mp_reg_pci_test1 = nthw_module_get_register(p->mp_mod_hif, HIF_TEST1); + p->mp_fld_pci_test1 = nthw_register_get_field(p->mp_reg_pci_test1, HIF_TEST1_DATA); + + /* Module::Version({2, 0})+ */ + p->mp_reg_pci_test2 = nthw_module_query_register(p->mp_mod_hif, HIF_TEST2); + + if (p->mp_reg_pci_test2) + p->mp_fld_pci_test2 = nthw_register_get_field(p->mp_reg_pci_test2, HIF_TEST2_DATA); + + else + p->mp_fld_pci_test2 = NULL; + + /* Module::Version({1, 2})+ */ + p->mp_reg_pci_test3 = nthw_module_query_register(p->mp_mod_hif, HIF_TEST3); + + if (p->mp_reg_pci_test3) + p->mp_fld_pci_test3 = nthw_register_get_field(p->mp_reg_pci_test3, HIF_TEST3_DATA); + + else + p->mp_fld_pci_test3 = NULL; + + /* Required to run TSM */ + p->mp_reg_sample_time = nthw_module_get_register(p->mp_mod_hif, HIF_SAMPLE_TIME); + + if (p->mp_reg_sample_time) { + p->mp_fld_sample_time = nthw_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 = nthw_module_query_register(p->mp_mod_hif, HIF_CONFIG); + + if (p->mp_reg_config) { + p->mp_fld_max_tlp = + nthw_register_get_field(p->mp_reg_config, HIF_CONFIG_MAX_TLP); + p->mp_fld_max_read = + nthw_register_get_field(p->mp_reg_config, HIF_CONFIG_MAX_READ); + p->mp_fld_ext_tag = + nthw_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_trigger_sample_time(nthw_hif_t *p) +{ + nthw_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 = nthw_field_get_updated(p->mp_fld_stat_rx_counter); + *p_tx_cnt = nthw_field_get_updated(p->mp_fld_stat_tx_counter); + + *p_ref_clk_cnt = nthw_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 + ? nthw_field_get_updated(p->mp_fld_status_tags_in_use) + : 0); + + *p_rd_err = + (p->mp_fld_status_rd_err ? nthw_field_get_updated(p->mp_fld_status_rd_err) : 0); + *p_wr_err = + (p->mp_fld_status_wr_err ? nthw_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) +{ + nthw_field_set_all(p->mp_fld_stat_ctrl_ena); + nthw_field_set_all(p->mp_fld_stat_ctrl_req); + nthw_field_flush_register(p->mp_fld_stat_ctrl_req); + return 0; +} + +int nthw_hif_stat_req_disable(nthw_hif_t *p) +{ + nthw_field_clr_all(p->mp_fld_stat_ctrl_ena); + nthw_field_set_all(p->mp_fld_stat_ctrl_req); + nthw_field_flush_register(p->mp_fld_stat_ctrl_req); + 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_iic.c b/drivers/net/ntnic/nthw/core/nthw_iic.c new file mode 100644 index 0000000000..7f324dec78 --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_iic.c @@ -0,0 +1,527 @@ +/* + * 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) +{ + nthw_field_update_register(p->mp_fld_cr_txfifo_reset); + + nthw_field_set_all(p->mp_fld_cr_txfifo_reset); + nthw_field_flush_register(p->mp_fld_cr_txfifo_reset); + + nthw_field_clr_all(p->mp_fld_cr_txfifo_reset); + nthw_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) + nthw_field_set_all(p->mp_fld_tx_fifo_start); + + else + nthw_field_clr_all(p->mp_fld_tx_fifo_start); + + if (stop) + nthw_field_set_all(p->mp_fld_tx_fifo_stop); + + else + nthw_field_clr_all(p->mp_fld_tx_fifo_stop); + + nthw_field_set_val32(p->mp_fld_tx_fifo_txdata, data); + + nthw_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)nthw_field_get_updated(p->mp_fld_rx_fifo_rxdata); + + return 0; +} + +static int nthw_iic_reg_softr(nthw_iic_t *p) +{ + nthw_field_update_register(p->mp_fld_cr_en); + nthw_field_set_val_flush32(p->mp_fld_softr_rkey, 0x0A); + + return 0; +} + +static int nthw_iic_reg_enable(nthw_iic_t *p) +{ + nthw_field_update_register(p->mp_fld_cr_en); + nthw_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 = nthw_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 = nthw_field_get_updated(p->mp_fld_sr_rxfifo_empty) ? true : false; + + return 0; +} + +/* + * n_iic_cycle_time 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; + nthw_field_set_val_flush(p->mp_fld_tsusta, &val, 1); + + val = SUSTO / n_iic_cycle_time; + nthw_field_set_val_flush(p->mp_fld_tsusto, &val, 1); + + val = HDSTA / n_iic_cycle_time; + nthw_field_set_val_flush(p->mp_fld_thdsta, &val, 1); + + val = SUDAT / n_iic_cycle_time; + nthw_field_set_val_flush(p->mp_fld_tsudat, &val, 1); + + val = BUF / n_iic_cycle_time; + nthw_field_set_val_flush(p->mp_fld_tbuf, &val, 1); + + val = HIGH / n_iic_cycle_time; + nthw_field_set_val_flush(p->mp_fld_thigh, &val, 1); + + val = LOW / n_iic_cycle_time; + nthw_field_set_val_flush(p->mp_fld_tlow, &val, 1); + + val = HDDAT / n_iic_cycle_time; + nthw_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, nthw_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; + nthw_module_t *mod = nthw_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 */ + nthw_module_set_debug_mode(p->mp_mod_iic, 0x00); + + p->mp_reg_tsusta = nthw_module_get_register(p->mp_mod_iic, IIC_TSUSTA); + p->mp_fld_tsusta = nthw_register_get_field(p->mp_reg_tsusta, IIC_TSUSTA_TSUSTA_VAL); + + p->mp_reg_tsusto = nthw_module_get_register(p->mp_mod_iic, IIC_TSUSTO); + p->mp_fld_tsusto = nthw_register_get_field(p->mp_reg_tsusto, IIC_TSUSTO_TSUSTO_VAL); + + p->mp_reg_thdsta = nthw_module_get_register(p->mp_mod_iic, IIC_THDSTA); + p->mp_fld_thdsta = nthw_register_get_field(p->mp_reg_thdsta, IIC_THDSTA_THDSTA_VAL); + + p->mp_reg_tsudat = nthw_module_get_register(p->mp_mod_iic, IIC_TSUDAT); + p->mp_fld_tsudat = nthw_register_get_field(p->mp_reg_tsudat, IIC_TSUDAT_TSUDAT_VAL); + + p->mp_reg_tbuf = nthw_module_get_register(p->mp_mod_iic, IIC_TBUF); + p->mp_fld_tbuf = nthw_register_get_field(p->mp_reg_tbuf, IIC_TBUF_TBUF_VAL); + + p->mp_reg_thigh = nthw_module_get_register(p->mp_mod_iic, IIC_THIGH); + p->mp_fld_thigh = nthw_register_get_field(p->mp_reg_thigh, IIC_THIGH_THIGH_VAL); + + p->mp_reg_tlow = nthw_module_get_register(p->mp_mod_iic, IIC_TLOW); + p->mp_fld_tlow = nthw_register_get_field(p->mp_reg_tlow, IIC_TLOW_TLOW_VAL); + + p->mp_reg_thddat = nthw_module_get_register(p->mp_mod_iic, IIC_THDDAT); + p->mp_fld_thddat = nthw_register_get_field(p->mp_reg_thddat, IIC_THDDAT_THDDAT_VAL); + + p->mp_reg_cr = nthw_module_get_register(p->mp_mod_iic, IIC_CR); + p->mp_fld_cr_en = nthw_register_get_field(p->mp_reg_cr, IIC_CR_EN); + p->mp_fld_cr_msms = nthw_register_get_field(p->mp_reg_cr, IIC_CR_MSMS); + p->mp_fld_cr_txfifo_reset = nthw_register_get_field(p->mp_reg_cr, IIC_CR_TXFIFO_RESET); + p->mp_fld_cr_txak = nthw_register_get_field(p->mp_reg_cr, IIC_CR_TXAK); + + p->mp_reg_sr = nthw_module_get_register(p->mp_mod_iic, IIC_SR); + p->mp_fld_sr_bb = nthw_register_get_field(p->mp_reg_sr, IIC_SR_BB); + p->mp_fld_sr_rxfifo_full = nthw_register_get_field(p->mp_reg_sr, IIC_SR_RXFIFO_FULL); + p->mp_fld_sr_rxfifo_empty = nthw_register_get_field(p->mp_reg_sr, IIC_SR_RXFIFO_EMPTY); + p->mp_fld_sr_txfifo_full = nthw_register_get_field(p->mp_reg_sr, IIC_SR_TXFIFO_FULL); + p->mp_fld_sr_txfifo_empty = nthw_register_get_field(p->mp_reg_sr, IIC_SR_TXFIFO_EMPTY); + + p->mp_reg_tx_fifo = nthw_module_get_register(p->mp_mod_iic, IIC_TX_FIFO); + p->mp_fld_tx_fifo_txdata = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_TXDATA); + p->mp_fld_tx_fifo_start = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_START); + p->mp_fld_tx_fifo_stop = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_STOP); + + p->mp_reg_rx_fifo_pirq = nthw_module_get_register(p->mp_mod_iic, IIC_RX_FIFO_PIRQ); + p->mp_fld_rx_fifo_pirq_cmp_val = + nthw_register_get_field(p->mp_reg_rx_fifo_pirq, IIC_RX_FIFO_PIRQ_CMP_VAL); + + p->mp_reg_rx_fifo = nthw_module_get_register(p->mp_mod_iic, IIC_RX_FIFO); + p->mp_fld_rx_fifo_rxdata = nthw_register_get_field(p->mp_reg_rx_fifo, IIC_RX_FIFO_RXDATA); + + p->mp_reg_softr = nthw_module_get_register(p->mp_mod_iic, IIC_SOFTR); + p->mp_fld_softr_rkey = nthw_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 a_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 = nthw_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, + a_reg_addr, data_len); + } + + while (nthw_iic_readbyte(p, dev_addr, a_reg_addr, data_len, pb) != 0) { + retry--; + + if (retry <= 0) { + NT_LOG(ERR, NTHW, + "%s: I2C%d: Read retry exhausted (dev_addr=%d a_reg_addr=%d)\n", + p_adapter_id_str, p->mn_iic_instance, dev_addr, a_reg_addr); + return -1; + + } else { + NT_LOG(DBG, NTHW, "%s: I2C%d: Read retry=%d (dev_addr=%d a_reg_addr=%d)\n", + p_adapter_id_str, p->mn_iic_instance, retry, dev_addr, a_reg_addr); + } + } + + 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, a_reg_addr, data_len, retry); + } + + return 0; +} + +int nthw_iic_readbyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_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 a_reg_addr to TX FIFO */ + nthw_iic_reg_tx_fifo_write(p, a_reg_addr, 0, 1); + + if (!nthw_iic_bus_ready(p)) { + NT_LOG_DBGX(ERR, NTHW, "%s: error:\n", p_adapter_id_str); + 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 data_len 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 data_len bytes from RX_FIFO */ + nthw_iic_reg_read_i2c_rx_fifo(p, p_byte); + p_byte++; + } + + return 0; + + } else { + NT_LOG_DBGX(ERR, NTHW, "%s: error\n", p_adapter_id_str); + return -1; + } + + return 0; +} + +int nthw_iic_write_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_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, a_reg_addr, data_len, pb) != 0) { + retry--; + + if (retry <= 0) { + NT_LOG(ERR, NTHW, + "%s: I2C%d: Write retry exhausted (dev_addr=%d a_reg_addr=%d)\n", + p_adapter_id_str, p->mn_iic_instance, dev_addr, a_reg_addr); + return -1; + + } else { + NT_LOG(DBG, NTHW, + "%s: I2C%d: Write retry=%d (dev_addr=%d a_reg_addr=%d)\n", + p_adapter_id_str, p->mn_iic_instance, retry, dev_addr, a_reg_addr); + } + } + + return 0; +} + +int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_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 a_reg_addr to TX FIFO */ + nthw_iic_reg_tx_fifo_write(p, a_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_DBGX(WARNING, NTHW, "%s: warn: !busReady\n", p_adapter_id_str); + + while (true) + if (nthw_iic_bus_ready(p)) { + NT_LOG_DBGX(DEBUG, NTHW, "%s: info: busReady\n", + p_adapter_id_str); + break; + } + } + + return 0; + + } else { + NT_LOG_DBGX(WARNING, NTHW, "%s\n", p_adapter_id_str); + 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 = p->mp_fpga->p_fpga_info->mp_adapter_id_str; + (void)p_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(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_pcie3.c b/drivers/net/ntnic/nthw/core/nthw_pcie3.c new file mode 100644 index 0000000000..c6cb3ce8de --- /dev/null +++ b/drivers/net/ntnic/nthw/core/nthw_pcie3.c @@ -0,0 +1,259 @@ +/* + * 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, nthw_fpga_t *p_fpga, int n_instance) +{ + nthw_module_t *mod = nthw_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 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_CTRL); + p->mp_fld_stat_ctrl_ena = + nthw_register_get_field(p->mp_reg_stat_ctrl, PCIE3_STAT_CTRL_STAT_ENA); + p->mp_fld_stat_ctrl_req = + nthw_register_get_field(p->mp_reg_stat_ctrl, PCIE3_STAT_CTRL_STAT_REQ); + + p->mp_reg_stat_rx = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RX); + p->mp_fld_stat_rx_counter = + nthw_register_get_field(p->mp_reg_stat_rx, PCIE3_STAT_RX_COUNTER); + + p->mp_reg_stat_tx = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_TX); + p->mp_fld_stat_tx_counter = + nthw_register_get_field(p->mp_reg_stat_tx, PCIE3_STAT_TX_COUNTER); + + p->mp_reg_stat_ref_clk = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_REFCLK); + p->mp_fld_stat_ref_clk_ref_clk = + nthw_register_get_field(p->mp_reg_stat_ref_clk, PCIE3_STAT_REFCLK_REFCLK250); + + p->mp_reg_stat_rq_rdy = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RQ_RDY); + p->mp_fld_stat_rq_rdy_counter = + nthw_register_get_field(p->mp_reg_stat_rq_rdy, PCIE3_STAT_RQ_RDY_COUNTER); + + p->mp_reg_stat_rq_vld = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RQ_VLD); + p->mp_fld_stat_rq_vld_counter = + nthw_register_get_field(p->mp_reg_stat_rq_vld, PCIE3_STAT_RQ_VLD_COUNTER); + + p->mp_reg_status0 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STATUS0); + p->mp_fld_status0_tags_in_use = + nthw_register_get_field(p->mp_reg_status0, PCIE3_STATUS0_TAGS_IN_USE); + + p->mp_reg_rp_to_ep_err = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_RP_TO_EP_ERR); + p->mp_fld_rp_to_ep_err_cor = + nthw_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 = + nthw_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 = + nthw_register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_FATAL); + + p->mp_reg_ep_to_rp_err = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_EP_TO_RP_ERR); + p->mp_fld_ep_to_rp_err_cor = + nthw_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 = + nthw_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 = + nthw_register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_FATAL); + + p->mp_reg_sample_time = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_SAMPLE_TIME); + p->mp_fld_sample_time = + nthw_register_get_field(p->mp_reg_sample_time, PCIE3_SAMPLE_TIME_SAMPLE_TIME); + + p->mp_reg_pci_end_point = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_ENDPOINT); + p->mp_fld_pci_end_point_if_id = + nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_IF_ID); + p->mp_fld_pci_end_point_send_msg = + nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_SEND_MSG); + p->mp_fld_pci_end_point_get_msg = + nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_GET_MSG); + p->mp_fld_pci_end_point_dmaep0_allow_mask = + nthw_register_get_field(p->mp_reg_pci_end_point, + PCIE3_PCI_ENDPOINT_DMA_EP0_ALLOW_MASK); + p->mp_fld_pci_end_point_dmaep1_allow_mask = + nthw_register_get_field(p->mp_reg_pci_end_point, + PCIE3_PCI_ENDPOINT_DMA_EP1_ALLOW_MASK); + + if (p->mp_reg_pci_end_point) + nthw_register_update(p->mp_reg_pci_end_point); + + p->mp_reg_pci_test0 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_TEST0); + p->mp_fld_pci_test0 = nthw_register_get_field(p->mp_reg_pci_test0, PCIE3_PCI_TEST0_DATA); + + if (p->mp_reg_pci_test0) + nthw_register_update(p->mp_reg_pci_test0); + + p->mp_reg_pci_test1 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_TEST1); + p->mp_fld_pci_test1 = nthw_register_get_field(p->mp_reg_pci_test1, PCIE3_PCI_TEST1_DATA); + + if (p->mp_reg_pci_test1) + nthw_register_update(p->mp_reg_pci_test1); + + p->mp_reg_pci_e3_mark_adr_lsb = + nthw_module_get_register(p->mp_mod_pcie3, PCIE3_MARKADR_LSB); + p->mp_fld_pci_e3_mark_adr_lsb_adr = + nthw_register_get_field(p->mp_reg_pci_e3_mark_adr_lsb, PCIE3_MARKADR_LSB_ADR); + + if (p->mp_reg_pci_e3_mark_adr_lsb) + nthw_register_update(p->mp_reg_pci_e3_mark_adr_lsb); + + p->mp_reg_pci_e3_mark_adr_msb = + nthw_module_get_register(p->mp_mod_pcie3, PCIE3_MARKADR_MSB); + p->mp_fld_pci_e3_mark_adr_msb_adr = + nthw_register_get_field(p->mp_reg_pci_e3_mark_adr_msb, PCIE3_MARKADR_MSB_ADR); + + if (p->mp_reg_pci_e3_mark_adr_msb) + nthw_register_update(p->mp_reg_pci_e3_mark_adr_msb); + + /* Initial setup - disable markerscheme and bifurcation */ + if (p->mp_fld_pci_end_point_dmaep0_allow_mask) + nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep0_allow_mask); + + if (p->mp_fld_pci_end_point_dmaep1_allow_mask) + nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep1_allow_mask); + + if (p->mp_fld_pci_e3_mark_adr_lsb_adr) + nthw_field_set_val_flush32(p->mp_fld_pci_e3_mark_adr_lsb_adr, 0UL); + + if (p->mp_fld_pci_e3_mark_adr_msb_adr) + nthw_field_set_val_flush32(p->mp_fld_pci_e3_mark_adr_msb_adr, 0UL); + + if (p->mp_fld_pci_end_point_dmaep0_allow_mask) + nthw_field_set_flush(p->mp_fld_pci_end_point_dmaep0_allow_mask); + + if (p->mp_fld_pci_end_point_dmaep1_allow_mask) + nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep1_allow_mask); + + return 0; +}; + +int nthw_pcie3_trigger_sample_time(nthw_pcie3_t *p) +{ + nthw_field_set_val_flush32(p->mp_fld_sample_time, 0xfee1dead); + + return 0; +} + +int nthw_pcie3_stat_req_enable(nthw_pcie3_t *p) +{ + nthw_field_set_all(p->mp_fld_stat_ctrl_ena); + nthw_field_set_all(p->mp_fld_stat_ctrl_req); + nthw_field_flush_register(p->mp_fld_stat_ctrl_req); + return 0; +} + +int nthw_pcie3_stat_req_disable(nthw_pcie3_t *p) +{ + nthw_field_clr_all(p->mp_fld_stat_ctrl_ena); + nthw_field_set_all(p->mp_fld_stat_ctrl_req); + nthw_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 = nthw_field_get_updated(p->mp_fld_stat_rx_counter); + *p_tx_cnt = nthw_field_get_updated(p->mp_fld_stat_tx_counter); + + *p_ref_clk_cnt = nthw_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 = nthw_field_get_updated(p->mp_fld_status0_tags_in_use); + + *p_rq_rdy_cnt = nthw_field_get_updated(p->mp_fld_stat_rq_rdy_counter); + *p_rq_vld_cnt = nthw_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_post(nthw_pcie3_t *p, + struct nthw_hif_end_point_counters *epc) +{ + NT_LOG_DBGX(DEBUG, NTHW); + 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/nthw_drv.h b/drivers/net/ntnic/nthw/nthw_drv.h index 0b89a5c5a0..d7cd64bb1d 100644 --- a/drivers/net/ntnic/nthw/nthw_drv.h +++ b/drivers/net/ntnic/nthw/nthw_drv.h @@ -6,8 +6,7 @@ #ifndef __NTHW_DRV_H__ #define __NTHW_DRV_H__ -#include -#include "nthw_platform_drv.h" +#include "nthw_core.h" typedef enum nt_meta_port_type_e { PORT_TYPE_PHYSICAL, diff --git a/drivers/net/ntnic/nthw/nthw_rac.c b/drivers/net/ntnic/nthw/nthw_rac.c new file mode 100644 index 0000000000..2aef0c148f --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_rac.c @@ -0,0 +1,784 @@ +/* + * 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 + + +#define RAB_READ (0x01) +#define RAB_WRITE (0x02) +#define RAB_ECHO (0x08) +#define RAB_COMPLETION (0x0F) + +#define RAB_OPR_LO (28) + +#define RAB_CNT_LO (20) +#define RAB_CNT_BW (8) + +#define RAB_BUSID_LO (16) +#define RAB_BUSID_BW (4) + +#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; +} + +int nthw_rac_init(nthw_rac_t *p, nthw_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; + nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_RAC, 0); + + if (p == NULL) + return p_mod == NULL ? -1 : 0; + + if (p_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 = p_mod; + + p->mn_param_rac_rab_interfaces = + nthw_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 = + nthw_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 = nthw_module_query_register(p->mp_mod_rac, RAC_DUMMY0); + p->mp_reg_dummy1 = nthw_module_query_register(p->mp_mod_rac, RAC_DUMMY1); + p->mp_reg_dummy2 = nthw_module_query_register(p->mp_mod_rac, RAC_DUMMY2); + + p->mp_reg_rab_init = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_INIT); + p->mp_fld_rab_init = nthw_register_get_field(p->mp_reg_rab_init, RAC_RAB_INIT_RAB); + p->mn_fld_rab_init_bw = nthw_field_get_bit_width(p->mp_fld_rab_init); + p->mn_fld_rab_init_mask = nthw_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 = nthw_module_query_register(p->mp_mod_rac, RAC_DBG_CTRL); + + if (p->mp_reg_dbg_ctrl) + p->mp_fld_dbg_ctrl = nthw_register_query_field(p->mp_reg_dbg_ctrl, RAC_DBG_CTRL_C); + + else + p->mp_fld_dbg_ctrl = NULL; + + p->mp_reg_dbg_data = nthw_module_query_register(p->mp_mod_rac, RAC_DBG_DATA); + + if (p->mp_reg_dbg_data) + p->mp_fld_dbg_data = nthw_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 = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_IB_DATA); + p->mp_fld_rab_ib_data = nthw_register_get_field(p->mp_reg_rab_ib_data, RAC_RAB_IB_DATA_D); + + p->mp_reg_rab_ob_data = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_OB_DATA); + p->mp_fld_rab_ob_data = nthw_register_get_field(p->mp_reg_rab_ob_data, RAC_RAB_OB_DATA_D); + + p->mp_reg_rab_buf_free = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_BUF_FREE); + p->mp_fld_rab_buf_free_ib_free = + nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_IB_FREE); + p->mp_fld_rab_buf_free_ib_ovf = + nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_IB_OVF); + p->mp_fld_rab_buf_free_ob_free = + nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_OB_FREE); + p->mp_fld_rab_buf_free_ob_ovf = + nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_OB_OVF); + p->mp_fld_rab_buf_free_timeout = + nthw_register_get_field(p->mp_reg_rab_buf_free, RAC_RAB_BUF_FREE_TIMEOUT); + + p->mp_reg_rab_buf_used = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_BUF_USED); + p->mp_fld_rab_buf_used_ib_used = + nthw_register_get_field(p->mp_reg_rab_buf_used, RAC_RAB_BUF_USED_IB_USED); + p->mp_fld_rab_buf_used_ob_used = + nthw_register_get_field(p->mp_reg_rab_buf_used, RAC_RAB_BUF_USED_OB_USED); + p->mp_fld_rab_buf_used_flush = + nthw_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 = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_LO); + p->mp_fld_rab_dma_ib_lo_phy_addr = + nthw_register_get_field(p->mp_reg_rab_dma_ib_lo, RAC_RAB_DMA_IB_LO_PHYADDR); + + p->mp_reg_rab_dma_ib_hi = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_HI); + p->mp_fld_rab_dma_ib_hi_phy_addr = + nthw_register_get_field(p->mp_reg_rab_dma_ib_hi, RAC_RAB_DMA_IB_HI_PHYADDR); + + p->mp_reg_rab_dma_ob_lo = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_LO); + p->mp_fld_rab_dma_ob_lo_phy_addr = + nthw_register_get_field(p->mp_reg_rab_dma_ob_lo, RAC_RAB_DMA_OB_LO_PHYADDR); + + p->mp_reg_rab_dma_ob_hi = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_HI); + p->mp_fld_rab_dma_ob_hi_phy_addr = + nthw_register_get_field(p->mp_reg_rab_dma_ob_hi, RAC_RAB_DMA_OB_HI_PHYADDR); + + p->mp_reg_rab_dma_ib_wr = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_WR); + p->mp_fld_rab_dma_ib_wr_ptr = + nthw_register_get_field(p->mp_reg_rab_dma_ib_wr, RAC_RAB_DMA_IB_WR_PTR); + + p->mp_reg_rab_dma_ib_rd = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_IB_RD); + p->mp_fld_rab_dma_ib_rd_ptr = + nthw_register_get_field(p->mp_reg_rab_dma_ib_rd, RAC_RAB_DMA_IB_RD_PTR); + + p->mp_reg_rab_dma_ob_wr = nthw_module_get_register(p->mp_mod_rac, RAC_RAB_DMA_OB_WR); + p->mp_fld_rab_dma_ob_wr_ptr = + nthw_register_get_field(p->mp_reg_rab_dma_ob_wr, RAC_RAB_DMA_OB_WR_PTR); + + p->RAC_RAB_INIT_ADDR = nthw_register_get_address(p->mp_reg_rab_init); + p->RAC_RAB_IB_DATA_ADDR = nthw_register_get_address(p->mp_reg_rab_ib_data); + p->RAC_RAB_OB_DATA_ADDR = nthw_register_get_address(p->mp_reg_rab_ob_data); + p->RAC_RAB_BUF_FREE_ADDR = nthw_register_get_address(p->mp_reg_rab_buf_free); + p->RAC_RAB_BUF_USED_ADDR = nthw_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 = nthw_register_get_address(p->mp_reg_rab_dma_ib_lo); + p->RAC_RAB_DMA_IB_HI_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ib_hi); + p->RAC_RAB_DMA_OB_LO_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ob_lo); + p->RAC_RAB_DMA_OB_HI_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ob_hi); + p->RAC_RAB_DMA_IB_RD_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ib_rd); + p->RAC_RAB_DMA_OB_WR_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ob_wr); + p->RAC_RAB_DMA_IB_WR_ADDR = nthw_register_get_address(p->mp_reg_rab_dma_ib_wr); + + p->RAC_RAB_BUF_FREE_IB_FREE_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_free_ib_free); + p->RAC_RAB_BUF_FREE_OB_FREE_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_free_ob_free); + p->RAC_RAB_BUF_USED_IB_USED_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_used_ib_used); + p->RAC_RAB_BUF_USED_OB_USED_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_used_ob_used); + + p->RAC_RAB_BUF_USED_FLUSH_MASK = nthw_field_get_mask(p->mp_fld_rab_buf_used_flush); + + p->RAC_RAB_BUF_USED_OB_USED_LOW = + nthw_field_get_bit_pos_low(p->mp_fld_rab_buf_used_ob_used); + + p->mp_reg_rab_nmb_rd = nthw_module_query_register(p->mp_mod_rac, RAC_NMB_RD_ADR); + + if (p->mp_reg_rab_nmb_rd) + p->RAC_NMB_RD_ADR_ADDR = nthw_register_get_address(p->mp_reg_rab_nmb_rd); + + p->mp_reg_rab_nmb_data = nthw_module_query_register(p->mp_mod_rac, RAC_NMB_DATA); + + if (p->mp_reg_rab_nmb_data) + p->RAC_NMB_DATA_ADDR = nthw_register_get_address(p->mp_reg_rab_nmb_data); + + p->mp_reg_rab_nmb_wr = nthw_module_query_register(p->mp_mod_rac, RAC_NMB_WR_ADR); + + if (p->mp_reg_rab_nmb_wr) + p->RAC_NMB_WR_ADR_ADDR = nthw_register_get_address(p->mp_reg_rab_nmb_wr); + + p->mp_reg_rab_nmb_status = nthw_module_query_register(p->mp_mod_rac, RAC_NMB_STATUS); + + if (p->mp_reg_rab_nmb_status) + p->RAC_NMB_STATUS_ADDR = nthw_register_get_address(p->mp_reg_rab_nmb_status); + + p->m_dma = NULL; + + { + /* + * RAC is a primary communication channel - debug will be messy + * turn off debug by default - except for rac_rab_init + * NOTE: currently debug will not work - due to optimizations + */ + const int n_debug_mode = nthw_module_get_debug_mode(p->mp_mod_rac); + + if (n_debug_mode && n_debug_mode <= 0xff) { + nthw_module_set_debug_mode(p->mp_mod_rac, 0); + nthw_register_set_debug_mode(p->mp_reg_rab_init, n_debug_mode); + } + } + + pthread_mutex_init(&p->m_mutex, NULL); + + return 0; +} + +static int nthw_rac_get_rab_interface_count(const nthw_rac_t *p) +{ + return p->mn_param_rac_rab_interfaces; +} + +/* private function for internal RAC operations - + * improves log flexibility and prevents log flooding + */ +static 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); +} + +/* private function for internal RAC operations - + * improves log flexibility and prevents log flooding + */ +static void nthw_rac_reg_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t n_data) +{ + *(volatile uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + reg_addr) = n_data; +} + +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; + nthw_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 = p_fpga_info->mp_adapter_id_str; + (void)p_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 = nt_util_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, NTNIC, "nt_dma_alloc failed\n"); + 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; +} + +void nthw_rac_bar0_read32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t word_cnt, uint32_t *p_data) +{ + volatile const uint32_t *const src_addr = + (uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + reg_addr); + + for (uint32_t i = 0; i < word_cnt; i++) + p_data[i] = src_addr[i]; +} + +void nthw_rac_bar0_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t word_cnt, const uint32_t *p_data) +{ + volatile uint32_t *const dst_addr = + (uint32_t *)((uint8_t *)p_fpga_info->bar0_addr + reg_addr); + + for (uint32_t i = 0; i < word_cnt; i++) + dst_addr[i] = p_data[i]; +} + +int nthw_rac_rab_write32(nthw_rac_t *p, bool trc, nthw_rab_bus_id_t bus_id, uint32_t address, + 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; + uint32_t buf_used; + uint32_t buf_free; + uint32_t in_buf_free; + uint32_t out_buf_free; + int res = 0; + + 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) { + const uint32_t rab_oper_cmpl = (RAB_COMPLETION << RAB_OPR_LO); + uint32_t rab_echo_oper_cmpl; + uint32_t word_cnt_expected = 1; + uint32_t rab_oper_wr; + uint32_t i; + + rab_oper_wr = (RAB_WRITE << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; + + if (trc) { + rab_oper_wr |= (RAB_ECHO << RAB_OPR_LO); + word_cnt_expected += word_cnt + 1; + } + + /* Write command */ + nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_IB_DATA_ADDR, rab_oper_wr); + + /* Write data 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[i]); + + /* Write completion 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 (trc) { + 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; + char *tmp_string; + + if (trc) { + tmp_string = ntlog_helper_str_alloc("Register::write"); + ntlog_helper_str_add(tmp_string, + "(Dev: NA, Bus: RAB%u, Addr: 0x%08X, Cnt: %d, Data:", + bus_id, address, word_cnt); + } + + 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); + } + + if (trc) + ntlog_helper_str_add(tmp_string, " 0x%08X", data); + } + + if (trc) { + ntlog_helper_str_add(tmp_string, ")"); + NT_LOG(DBG, NTHW, "%s", tmp_string); + ntlog_helper_str_free(tmp_string); + } + } + + /* 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, bool trc, nthw_rab_bus_id_t bus_id, uint32_t address, + 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; + uint32_t buf_used; + uint32_t buf_free; + uint32_t in_buf_free; + uint32_t out_buf_free; + int res = 0; + + 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) { + const uint32_t rab_oper_cmpl = (RAB_COMPLETION << RAB_OPR_LO); + uint32_t rab_read_oper_cmpl; + uint32_t word_cnt_expected = word_cnt + 1; + uint32_t rab_oper_rd; + + rab_oper_rd = (RAB_READ << RAB_OPR_LO) | + ((word_cnt & ((1 << RAB_CNT_BW) - 1)) << RAB_CNT_LO) | + (bus_id << RAB_BUSID_LO) | address; + + if (trc) { + rab_oper_rd |= (RAB_ECHO << RAB_OPR_LO); + word_cnt_expected++; + } + + /* Write command */ + nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_IB_DATA_ADDR, rab_oper_rd); + + /* Write completion 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 (trc) { + 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); + } + } + + { + /* 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[i]); + + if (p->mn_param_rac_rab_ob_update) { + nthw_rac_reg_write32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, + 0); + } + } + + if (trc) { + char *tmp_string = ntlog_helper_str_alloc("Register::read"); + ntlog_helper_str_add(tmp_string, + "(Dev: NA, Bus: RAB%u, Addr: 0x%08X, Cnt: %d, Data:", + bus_id, address, word_cnt); + + for (i = 0; i < word_cnt; i++) + ntlog_helper_str_add(tmp_string, " 0x%08X", p_data[i]); + + ntlog_helper_str_add(tmp_string, ")"); + NT_LOG(DBG, NTHW, "%s", tmp_string); + ntlog_helper_str_free(tmp_string); + } + } + + /* Read completion from out buffer */ + nthw_rac_reg_read32(p_fpga_info, p->RAC_RAB_OB_DATA_ADDR, &rab_read_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_read_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_read_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_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..c16ff77189 --- /dev/null +++ b/drivers/net/ntnic/nthw/nthw_rac.h @@ -0,0 +1,153 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 Napatech A/S + */ + +#ifndef __NTHW_RAC_H__ +#define __NTHW_RAC_H__ + +#include "nt_util.h" + +#define RAB_DMA_BUF_CNT (0x4000) + +typedef uint8_t nthw_rab_bus_id_t; + +struct nthw_rac { + nthw_fpga_t *mp_fpga; + nthw_module_t *mp_mod_rac; + + pthread_mutex_t m_mutex; + + int mn_param_rac_rab_interfaces; + int mn_param_rac_rab_ob_update; + + nthw_register_t *mp_reg_dummy0; + nthw_register_t *mp_reg_dummy1; + nthw_register_t *mp_reg_dummy2; + + nthw_register_t *mp_reg_rab_init; + nthw_field_t *mp_fld_rab_init; + + int mn_fld_rab_init_bw; + uint32_t mn_fld_rab_init_mask; + + nthw_register_t *mp_reg_dbg_ctrl; + nthw_field_t *mp_fld_dbg_ctrl; + + nthw_register_t *mp_reg_dbg_data; + nthw_field_t *mp_fld_dbg_data; + + nthw_register_t *mp_reg_rab_ib_data; + nthw_field_t *mp_fld_rab_ib_data; + + nthw_register_t *mp_reg_rab_ob_data; + nthw_field_t *mp_fld_rab_ob_data; + + nthw_register_t *mp_reg_rab_buf_free; + nthw_field_t *mp_fld_rab_buf_free_ib_free; + nthw_field_t *mp_fld_rab_buf_free_ib_ovf; + nthw_field_t *mp_fld_rab_buf_free_ob_free; + nthw_field_t *mp_fld_rab_buf_free_ob_ovf; + nthw_field_t *mp_fld_rab_buf_free_timeout; + + nthw_register_t *mp_reg_rab_buf_used; + nthw_field_t *mp_fld_rab_buf_used_ib_used; + nthw_field_t *mp_fld_rab_buf_used_ob_used; + nthw_field_t *mp_fld_rab_buf_used_flush; + + nthw_register_t *mp_reg_rab_dma_ib_lo; + nthw_field_t *mp_fld_rab_dma_ib_lo_phy_addr; + + nthw_register_t *mp_reg_rab_dma_ib_hi; + nthw_field_t *mp_fld_rab_dma_ib_hi_phy_addr; + + nthw_register_t *mp_reg_rab_dma_ob_hi; + nthw_field_t *mp_fld_rab_dma_ob_hi_phy_addr; + + nthw_register_t *mp_reg_rab_dma_ob_lo; + nthw_field_t *mp_fld_rab_dma_ob_lo_phy_addr; + + nthw_register_t *mp_reg_rab_dma_ib_wr; + nthw_field_t *mp_fld_rab_dma_ib_wr_ptr; + + nthw_register_t *mp_reg_rab_dma_ib_rd; + nthw_field_t *mp_fld_rab_dma_ib_rd_ptr; + + nthw_register_t *mp_reg_rab_dma_ob_wr; + nthw_field_t *mp_fld_rab_dma_ob_wr_ptr; + + nthw_register_t *mp_reg_rab_nmb_rd; + nthw_register_t *mp_reg_rab_nmb_data; + nthw_register_t *mp_reg_rab_nmb_wr; + nthw_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); +int nthw_rac_init(nthw_rac_t *p, nthw_fpga_t *p_fpga, struct fpga_info_s *p_fpga_info); + +int nthw_rac_rab_init(nthw_rac_t *p, uint32_t n_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, bool trc, nthw_rab_bus_id_t bus_id, uint32_t address, + uint32_t word_cnt, const uint32_t *p_data); +int nthw_rac_rab_read32(nthw_rac_t *p, bool trc, nthw_rab_bus_id_t bus_id, uint32_t address, + uint32_t word_cnt, uint32_t *p_data); + +int nthw_rac_rab_flush(nthw_rac_t *p); + +void nthw_rac_bar0_read32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t word_cnt, uint32_t *p_data); +void nthw_rac_bar0_write32(const struct fpga_info_s *p_fpga_info, uint32_t reg_addr, + uint32_t word_cnt, const uint32_t *p_data); + +#endif /* __NTHW_RAC_H__ */